SkiaSharp/binding/Binding/GRGlInterface.cs

216 строки
6.5 KiB
C#

//
// Bindings for GRContext
//
// Author:
// Matthew Leibowitz
//
// Copyright 2016 Xamarin Inc
//
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, [MarshalAs(UnmanagedType.LPStr)] string name);
public class GRGlInterface : SKObject
{
// so the GC doesn't collect the delegate
private static readonly GRGlGetProcDelegateInternal getProcDelegateInternal;
private static readonly IntPtr getProcDelegate;
static GRGlInterface ()
{
getProcDelegateInternal = new GRGlGetProcDelegateInternal (GrGLGetProcInternal);
getProcDelegate = Marshal.GetFunctionPointerForDelegate (getProcDelegateInternal);
}
[Preserve]
internal GRGlInterface (IntPtr h, bool owns)
: base (h, owns)
{
}
public static GRGlInterface CreateDefaultInterface ()
{
// first try ANGLE, then fall back to the OpenGL-based
return CreateNativeAngleInterface () ?? CreateNativeGlInterface ();
}
public static GRGlInterface CreateNativeGlInterface ()
{
// the native code will automatically return null on non-OpenGL platforms, such as UWP
return GetObject<GRGlInterface> (SkiaApi.gr_glinterface_create_native_interface ());
}
public static GRGlInterface CreateNativeAngleInterface ()
{
if (PlatformConfiguration.IsWindows) {
return AssembleAngleInterface (AngleLoader.GetProc);
} else {
// return null on non-DirectX platforms: everything except Windows
return null;
}
}
public static GRGlInterface AssembleInterface (GRGlGetProcDelegate get)
{
return AssembleInterface (null, get);
}
public static GRGlInterface AssembleInterface (object context, GRGlGetProcDelegate get)
{
// if on Windows, try ANGLE
if (PlatformConfiguration.IsWindows) {
var angle = AssembleAngleInterface (context, get);
if (angle != null) {
return angle;
}
}
// try the native default
using (var ctx = new NativeDelegateContext (context, get)) {
return GetObject<GRGlInterface> (SkiaApi.gr_glinterface_assemble_interface (ctx.NativeContext, getProcDelegate));
}
}
public static GRGlInterface AssembleAngleInterface (GRGlGetProcDelegate get)
{
return AssembleAngleInterface (null, get);
}
public static GRGlInterface AssembleAngleInterface (object context, GRGlGetProcDelegate get)
{
// ANGLE is just a GLES v2 over DX v9+
return AssembleGlesInterface (context, get);
}
public static GRGlInterface AssembleGlInterface (GRGlGetProcDelegate get)
{
return AssembleGlInterface (null, get);
}
public static GRGlInterface AssembleGlInterface (object context, GRGlGetProcDelegate get)
{
using (var ctx = new NativeDelegateContext (context, get)) {
return GetObject<GRGlInterface> (SkiaApi.gr_glinterface_assemble_gl_interface (ctx.NativeContext, getProcDelegate));
}
}
public static GRGlInterface AssembleGlesInterface (GRGlGetProcDelegate get)
{
return AssembleGlesInterface (null, get);
}
public static GRGlInterface AssembleGlesInterface (object context, GRGlGetProcDelegate get)
{
using (var ctx = new NativeDelegateContext (context, get)) {
return GetObject<GRGlInterface> (SkiaApi.gr_glinterface_assemble_gles_interface (ctx.NativeContext, getProcDelegate));
}
}
public GRGlInterface Clone ()
{
return GetObject<GRGlInterface> (SkiaApi.gr_glinterface_clone (Handle));
}
public bool Validate ()
{
return SkiaApi.gr_glinterface_validate (Handle);
}
public bool HasExtension (string extension)
{
return SkiaApi.gr_glinterface_has_extension (Handle, extension);
}
protected override void Dispose (bool disposing)
{
if (Handle != IntPtr.Zero && OwnsHandle) {
SkiaApi.gr_glinterface_unref (Handle);
}
base.Dispose (disposing);
}
// internal proxy
[MonoPInvokeCallback (typeof (GRGlGetProcDelegateInternal))]
private static IntPtr GrGLGetProcInternal (IntPtr context, string name)
{
var ctx = NativeDelegateContext.Unwrap (context);
return ctx.GetDelegate<GRGlGetProcDelegate> () (ctx.ManagedContext, name);
}
private static class AngleLoader
{
private static readonly IntPtr libEGL;
private static readonly IntPtr libGLESv2;
#if WINDOWS_UWP
// https://msdn.microsoft.com/en-us/library/windows/desktop/mt186421(v=vs.85).aspx
[DllImport ("api-ms-win-core-libraryloader-l2-1-0.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr LoadPackagedLibrary ([MarshalAs (UnmanagedType.LPWStr)] string lpFileName, uint Reserved);
[DllImport ("api-ms-win-core-libraryloader-l1-2-0.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress (IntPtr hModule, [MarshalAs (UnmanagedType.LPStr)] string lpProcName);
private static IntPtr LoadLibrary (string lpFileName) => LoadPackagedLibrary(lpFileName, 0);
#else
[DllImport ("Kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr LoadLibrary ([MarshalAs (UnmanagedType.LPStr)] string lpFileName);
[DllImport ("Kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress (IntPtr hModule, [MarshalAs (UnmanagedType.LPStr)] string lpProcName);
#endif
[DllImport ("libEGL.dll")]
private static extern IntPtr eglGetProcAddress ([MarshalAs (UnmanagedType.LPStr)] string procname);
static AngleLoader()
{
// this is not supported at all on non-Windows platforms
if (!PlatformConfiguration.IsWindows) {
return;
}
libEGL = LoadLibrary ("libEGL.dll");
if (Marshal.GetLastWin32Error () != 0 || libEGL == IntPtr.Zero)
throw new DllNotFoundException ("Unable to load libEGL.dll.");
libGLESv2 = LoadLibrary ("libGLESv2.dll");
if (Marshal.GetLastWin32Error () != 0 || libGLESv2 == IntPtr.Zero)
throw new DllNotFoundException ("Unable to load libGLESv2.dll.");
}
// function to assemble the ANGLE interface
public static IntPtr GetProc (object context, string name)
{
// this is not supported at all on non-Windows platforms
if (!PlatformConfiguration.IsWindows) {
return IntPtr.Zero;
}
IntPtr proc = GetProcAddress (libGLESv2, name);
if (proc == IntPtr.Zero)
{
proc = GetProcAddress (libEGL, name);
}
if (proc == IntPtr.Zero)
{
proc = eglGetProcAddress (name);
}
return proc;
}
}
}
}