Forum

Trying to use Skia ImageReader inside AsyncTask crashes vvvv instantly [2020.1.7]

See patch.
SkiaCrash.vl (27.9 KB)

From Windows Eventviewer:

Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
at SkiaSharp.SkiaApi.sk_image_get_height(IntPtr)
at _VL_Skia_.Graphics.Skia.Layers.DrawImage_Ff5nplF14r4OY4tRx45O9o.Update(SkiaSharp.SKImage, Xenko.Core.Mathematics.Vector2, Xenko.Core.Mathematics.Vector2, VL.Skia.SizeMode, VL.Lib.Mathematics.RectangleAnchor, VL.Skia.VaryingSKPaint, Boolean, VL.Skia.ILayer ByRef, Xenko.Core.Mathematics.RectangleF ByRef)
at _SkiaPerf2_.Main.SkiaPerf2Application_HMEv3JWHfvpPS0uF6d3UMo+<>c__DisplayClass3_0.<Update>g____TRACE__|0()
at _SkiaPerf2_.Main.SkiaPerf2Application_HMEv3JWHfvpPS0uF6d3UMo.Update()
at _SkiaPerf2_.Main.SkiaPerf2Application_HMEv3JWHfvpPS0uF6d3UMo.__RunSkiaPerf2Application(_SkiaPerf2_.Main.SkiaPerf2Application_HMEv3JWHfvpPS0uF6d3UMo)

Exception Info: System.Reflection.TargetInvocationException
at System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[])
at System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
at VL.Lang.Platforms.ImplicitEntryPointInstanceManager+RuntimeInstance.Step()
at VL.Lang.Platforms.ImplicitEntryPointInstanceManager.StepInstances()
at VL.Lang.Platforms.RuntimeHost.SharedStep()
at VL.Lang.Platforms.RuntimeHost.StepOnRuntimeThread(System.TimeSpan)
at VL.Lang.Platforms.RuntimeHost+<>c__DisplayClass57_0.<FTimer_TickSend>b__0(System.Object)

Exception Info: System.Reflection.TargetInvocationException
at System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[])
at System.Delegate.DynamicInvokeImpl(System.Object[])
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
at System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
at System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)
at System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
at System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
at VL.Applications.Program.Main(System.String[])

Sorry for this super late reply. Indeed, accessing an SKImage from another thread is tricky.

  1. The image must be a raster image. It’s pixels must be in CPU memory. Sharing GPU images across threads / contexts is not possible (even though OpenGL would allow for texture sharing). Found some details about that topic here
  2. Creating a raster image out of a texture backed image needs to be done on the render thread which created the image in the first place
  3. Images usually require a lot of memory. A deterministic memory management is therefor mandatory. Leaving it up to the garbage collector usually leads to super expensive Gen2 collections (which usually freezes the rendering for a short moment). We can achieve that by reference counting. Only in the latest preview builds we found a nice internal abstraction to so without having to change the signature of many nodes.
  4. With ref counting in place we need to increase the ref count of the raster image on the render thread, hand the image over to the IO thread and once done writing to disk decrease the ref count again so a future needed raster image can re-use the memory.

See my reply over in the other thread showing one way of how all those steps can look like in a patch.

1 Like