diff --git a/binding/Binding/GRGlInterface.cs b/binding/Binding/GRGlInterface.cs index 91aad235..8562d631 100644 --- a/binding/Binding/GRGlInterface.cs +++ b/binding/Binding/GRGlInterface.cs @@ -8,11 +8,27 @@ // using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; namespace SkiaSharp { + // public delegates + public delegate IntPtr GRGlGetProcDelegate (object context, string name); + + // internal proxy delegates + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate IntPtr GRGlGetProcDelegateInternal (IntPtr context, string name); + public class GRGlInterface : SKObject { + // so the GC doesn't collect the delegate + private static readonly GRGlGetProcDelegateInternal getProcDelegate; + static GRGlInterface () + { + getProcDelegate = new GRGlGetProcDelegateInternal (GrGLGetProcInternal); + } + [Preserve] internal GRGlInterface (IntPtr h, bool owns) : base (h, owns) @@ -29,6 +45,54 @@ namespace SkiaSharp return GetObject (SkiaApi.gr_glinterface_create_native_interface ()); } + public static GRGlInterface AssembleInterface (GRGlGetProcDelegate get) + { + return AssembleInterface (null, get); + } + + public static GRGlInterface AssembleInterface (object context, GRGlGetProcDelegate get) + { + var del = Marshal.GetFunctionPointerForDelegate (getProcDelegate); + + var ctx = new GRGlGetProcDelegateContext (context, get); + var ptr = ctx.Wrap (); + var glInterface = GetObject (SkiaApi.gr_glinterface_assemble_interface (ptr, del)); + GRGlGetProcDelegateContext.Free (ptr); + return glInterface; + } + + public static GRGlInterface AssembleGlInterface (GRGlGetProcDelegate get) + { + return AssembleGlInterface (null, get); + } + + public static GRGlInterface AssembleGlInterface (object context, GRGlGetProcDelegate get) + { + var del = Marshal.GetFunctionPointerForDelegate (getProcDelegate); + + var ctx = new GRGlGetProcDelegateContext (context, get); + var ptr = ctx.Wrap (); + var glInterface = GetObject (SkiaApi.gr_glinterface_assemble_gl_interface (ptr, del)); + GRGlGetProcDelegateContext.Free (ptr); + return glInterface; + } + + public static GRGlInterface AssembleGlesInterface (GRGlGetProcDelegate get) + { + return AssembleGlesInterface (null, get); + } + + public static GRGlInterface AssembleGlesInterface (object context, GRGlGetProcDelegate get) + { + var del = Marshal.GetFunctionPointerForDelegate (getProcDelegate); + + var ctx = new GRGlGetProcDelegateContext (context, get); + var ptr = ctx.Wrap (); + var glInterface = GetObject (SkiaApi.gr_glinterface_assemble_gles_interface (ptr, del)); + GRGlGetProcDelegateContext.Free (ptr); + return glInterface; + } + public GRGlInterface Clone () { return GetObject (SkiaApi.gr_glinterface_clone (Handle)); @@ -52,6 +116,54 @@ namespace SkiaSharp base.Dispose (disposing); } + + // internal proxy + #if __IOS__ + [ObjCRuntime.MonoPInvokeCallback (typeof (GRGlGetProcDelegateInternal))] + #endif + private static IntPtr GrGLGetProcInternal (IntPtr context, string name) + { + var ctx = GRGlGetProcDelegateContext.Unwrap (context); + return ctx.GetProc (ctx.Context, name); + } + + // This is the actual context passed to native code. + // Instead of marshalling the user's data as an IntPtr and requiring + // him to wrap/unwarp, we do it via a proxy class. This also prevents + // us from having to marshal the user's callback too. + private struct GRGlGetProcDelegateContext + { + // the "managed version" of the callback + public readonly GRGlGetProcDelegate GetProc; + public readonly object Context; + + public GRGlGetProcDelegateContext (object context, GRGlGetProcDelegate get) + { + Context = context; + GetProc = get; + } + + // wrap this context into a "native" pointer + public IntPtr Wrap () + { + var gc = GCHandle.Alloc (this, GCHandleType.Pinned); + return GCHandle.ToIntPtr (gc); + } + + // unwrap the "native" pointer into a managed context + public static GRGlGetProcDelegateContext Unwrap (IntPtr ptr) + { + var gchandle = GCHandle.FromIntPtr (ptr); + return (GRGlGetProcDelegateContext) gchandle.Target; + } + + // unwrap and free the context + public static void Free (IntPtr ptr) + { + var gchandle = GCHandle.FromIntPtr (ptr); + gchandle.Free (); + } + } } } diff --git a/binding/Binding/SkiaApi.cs b/binding/Binding/SkiaApi.cs index 95c71cc1..073d2014 100755 --- a/binding/Binding/SkiaApi.cs +++ b/binding/Binding/SkiaApi.cs @@ -1056,6 +1056,12 @@ namespace SkiaSharp // GLInterface + [DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)] + public extern static gr_glinterface_t gr_glinterface_assemble_interface (IntPtr ctx, IntPtr get); + [DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)] + public extern static gr_glinterface_t gr_glinterface_assemble_gl_interface (IntPtr ctx, IntPtr get); + [DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)] + public extern static gr_glinterface_t gr_glinterface_assemble_gles_interface (IntPtr ctx, IntPtr get); [DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)] public extern static gr_glinterface_t gr_glinterface_default_interface (); [DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)] diff --git a/skia b/skia index 18f95a79..065c1e63 160000 --- a/skia +++ b/skia @@ -1 +1 @@ -Subproject commit 18f95a7963dd1eac6ef8b4cdab94c92f8ca9b63b +Subproject commit 065c1e637d3bc0e3766ab286cf2f0335f019616b