10 changed files with 261 additions and 81 deletions
@ -0,0 +1,46 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Platform.Interop; |
|||
|
|||
namespace Avalonia.OpenGL |
|||
{ |
|||
public class GlBasicInfoInterface : GlBasicInfoInterface<object> |
|||
{ |
|||
public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress) : base(getProcAddress, null) |
|||
{ |
|||
} |
|||
|
|||
public GlBasicInfoInterface(Func<Utf8Buffer, IntPtr> nativeGetProcAddress) : base(nativeGetProcAddress, null) |
|||
{ |
|||
} |
|||
|
|||
public delegate void GlGetIntegerv(int name, out int rv); |
|||
public delegate IntPtr GlGetString(int v); |
|||
} |
|||
|
|||
public class GlBasicInfoInterface<TContextInfo> : GlInterfaceBase<TContextInfo> |
|||
{ |
|||
public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress, TContextInfo context) : base(getProcAddress, context) |
|||
{ |
|||
} |
|||
|
|||
public GlBasicInfoInterface(Func<Utf8Buffer, IntPtr> nativeGetProcAddress, TContextInfo context) : base(nativeGetProcAddress, context) |
|||
{ |
|||
} |
|||
|
|||
[GlEntryPoint("glGetIntegerv")] |
|||
public GlBasicInfoInterface.GlGetIntegerv GetIntegerv { get; } |
|||
|
|||
|
|||
[GlEntryPoint("glGetString")] |
|||
public GlBasicInfoInterface.GlGetString GetStringNative { get; } |
|||
|
|||
public string GetString(int v) |
|||
{ |
|||
var ptr = GetStringNative(v); |
|||
if (ptr != IntPtr.Zero) |
|||
return Marshal.PtrToStringAnsi(ptr); |
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,69 +1,77 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Platform.Interop; |
|||
|
|||
namespace Avalonia.OpenGL |
|||
{ |
|||
public class GlInterfaceBase |
|||
public class GlInterfaceBase : GlInterfaceBase<object> |
|||
{ |
|||
|
|||
private readonly Func<string, bool, IntPtr> _getProcAddress; |
|||
public GlInterfaceBase(Func<string, bool, IntPtr> getProcAddress) |
|||
public GlInterfaceBase(Func<string, IntPtr> getProcAddress) : base(getProcAddress, null) |
|||
{ |
|||
} |
|||
|
|||
public GlInterfaceBase(Func<Utf8Buffer, IntPtr> nativeGetProcAddress) : base(nativeGetProcAddress, null) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public class GlInterfaceBase<TContext> |
|||
{ |
|||
private readonly Func<string, IntPtr> _getProcAddress; |
|||
public GlInterfaceBase(Func<string, IntPtr> getProcAddress, TContext context) |
|||
{ |
|||
_getProcAddress = getProcAddress; |
|||
foreach (var prop in this.GetType().GetProperties()) |
|||
{ |
|||
var a = prop.GetCustomAttribute<GlEntryPointAttribute>(); |
|||
if (a != null) |
|||
var attrs = prop.GetCustomAttributes() |
|||
.Where(a => |
|||
a is IGlEntryPointAttribute || a is IGlEntryPointAttribute<TContext>) |
|||
.ToList(); |
|||
if(attrs.Count == 0) |
|||
continue; |
|||
|
|||
var isOptional = prop.GetCustomAttribute<GlOptionalEntryPoint>() != null; |
|||
|
|||
var fieldName = $"<{prop.Name}>k__BackingField"; |
|||
var field = prop.DeclaringType.GetField(fieldName, |
|||
BindingFlags.Instance | BindingFlags.NonPublic); |
|||
if (field == null) |
|||
throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}"); |
|||
|
|||
|
|||
IntPtr proc = IntPtr.Zero; |
|||
foreach (var attr in attrs) |
|||
{ |
|||
var fieldName = $"<{prop.Name}>k__BackingField"; |
|||
var field = prop.DeclaringType.GetField(fieldName, |
|||
BindingFlags.Instance | BindingFlags.NonPublic); |
|||
if (field == null) |
|||
throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}"); |
|||
IntPtr proc = IntPtr.Zero; |
|||
if (a.EntryPoints.Length == 1) |
|||
proc = getProcAddress(a.EntryPoints[0], a.Optional); |
|||
else |
|||
{ |
|||
foreach (var ep in a.EntryPoints) |
|||
{ |
|||
proc = getProcAddress(ep, true); |
|||
if(proc != IntPtr.Zero) |
|||
break; |
|||
} |
|||
|
|||
if (proc == IntPtr.Zero && !a.Optional) |
|||
throw new OpenGlException("Unable to resolve function by any of aliases " + |
|||
string.Join(", ", a.EntryPoints)); |
|||
} |
|||
|
|||
if (proc != IntPtr.Zero) |
|||
field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType)); |
|||
if (attr is IGlEntryPointAttribute<TContext> typed) |
|||
proc = typed.GetProcAddress(context, getProcAddress); |
|||
else if (attr is IGlEntryPointAttribute untyped) |
|||
proc = untyped.GetProcAddress(getProcAddress); |
|||
} |
|||
|
|||
if (proc != IntPtr.Zero) |
|||
field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType)); |
|||
else if (!isOptional) |
|||
throw new OpenGlException("Unable to find a suitable GL function for " + prop.Name); |
|||
} |
|||
} |
|||
|
|||
protected static Func<string, bool, IntPtr> ConvertNative(Func<Utf8Buffer, IntPtr> func) => |
|||
(proc, optional) => |
|||
protected static Func<string, IntPtr> ConvertNative(Func<Utf8Buffer, IntPtr> func) => |
|||
(proc) => |
|||
{ |
|||
using (var u = new Utf8Buffer(proc)) |
|||
{ |
|||
var rv = func(u); |
|||
if (rv == IntPtr.Zero && !optional) |
|||
throw new OpenGlException("Missing function " + proc); |
|||
return rv; |
|||
} |
|||
}; |
|||
|
|||
public GlInterfaceBase(Func<Utf8Buffer, IntPtr> nativeGetProcAddress) : this(ConvertNative(nativeGetProcAddress)) |
|||
public GlInterfaceBase(Func<Utf8Buffer, IntPtr> nativeGetProcAddress, TContext context) : this(ConvertNative(nativeGetProcAddress), context) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public IntPtr GetProcAddress(string proc) => _getProcAddress(proc, true); |
|||
public IntPtr GetProcAddress(string proc, bool optional) => _getProcAddress(proc, optional); |
|||
|
|||
public IntPtr GetProcAddress(string proc) => _getProcAddress(proc); |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue