Browse Source

Use codegen to populate OpenGL functions

pull/8589/head
Nikita Tsukanov 4 years ago
parent
commit
952b80df2a
  1. 44
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  2. 4
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  3. 1
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  4. 14
      src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
  5. 2
      src/Avalonia.OpenGL/Egl/EglContext.cs
  6. 4
      src/Avalonia.OpenGL/Egl/EglDisplay.cs
  7. 225
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  8. 44
      src/Avalonia.OpenGL/GlBasicInfoInterface.cs
  9. 103
      src/Avalonia.OpenGL/GlEntryPointAttribute.cs
  10. 494
      src/Avalonia.OpenGL/GlInterface.cs
  11. 79
      src/Avalonia.OpenGL/GlInterfaceBase.cs
  12. 2
      src/Avalonia.X11/Avalonia.X11.csproj
  13. 111
      src/Avalonia.X11/Glx/Glx.cs
  14. 2
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  15. 24
      src/Shared/SourceGeneratorAttributes.cs
  16. 28
      src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs
  17. 2
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs
  18. 11
      src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs
  19. 346
      src/tools/DevGenerators/GetProcAddressInitialization.cs
  20. 31
      src/tools/DevGenerators/Helpers.cs

44
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@ -90,7 +90,6 @@ namespace ControlCatalog.Pages
private int _vertexBufferObject; private int _vertexBufferObject;
private int _indexBufferObject; private int _indexBufferObject;
private int _vertexArrayObject; private int _vertexArrayObject;
private GlExtrasInterface _glExt;
private string GetShader(bool fragment, string shader) private string GetShader(bool fragment, string shader)
{ {
@ -258,7 +257,6 @@ namespace ControlCatalog.Pages
protected unsafe override void OnOpenGlInit(GlInterface GL, int fb) protected unsafe override void OnOpenGlInit(GlInterface GL, int fb)
{ {
CheckError(GL); CheckError(GL);
_glExt = new GlExtrasInterface(GL);
Info = $"Renderer: {GL.GetString(GL_RENDERER)} Version: {GL.GetString(GL_VERSION)}"; Info = $"Renderer: {GL.GetString(GL_RENDERER)} Version: {GL.GetString(GL_VERSION)}";
@ -298,8 +296,8 @@ namespace ControlCatalog.Pages
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata), GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata),
GL_STATIC_DRAW); GL_STATIC_DRAW);
CheckError(GL); CheckError(GL);
_vertexArrayObject = _glExt.GenVertexArray(); _vertexArrayObject = GL.GenVertexArray();
_glExt.BindVertexArray(_vertexArrayObject); GL.BindVertexArray(_vertexArrayObject);
CheckError(GL); CheckError(GL);
GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT, GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT,
0, vertexSize, IntPtr.Zero); 0, vertexSize, IntPtr.Zero);
@ -316,12 +314,13 @@ namespace ControlCatalog.Pages
// Unbind everything // Unbind everything
GL.BindBuffer(GL_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ARRAY_BUFFER, 0);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
_glExt.BindVertexArray(0); GL.BindVertexArray(0);
GL.UseProgram(0); GL.UseProgram(0);
// Delete all resources. // Delete all resources.
GL.DeleteBuffers(2, new[] { _vertexBufferObject, _indexBufferObject }); GL.DeleteBuffer(_vertexBufferObject);
_glExt.DeleteVertexArrays(1, new[] { _vertexArrayObject }); GL.DeleteBuffer(_indexBufferObject);
GL.DeleteVertexArray(_vertexArrayObject);
GL.DeleteProgram(_shaderProgram); GL.DeleteProgram(_shaderProgram);
GL.DeleteShader(_fragmentShader); GL.DeleteShader(_fragmentShader);
GL.DeleteShader(_vertexShader); GL.DeleteShader(_vertexShader);
@ -338,7 +337,7 @@ namespace ControlCatalog.Pages
GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject); GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject);
_glExt.BindVertexArray(_vertexArrayObject); GL.BindVertexArray(_vertexArrayObject);
GL.UseProgram(_shaderProgram); GL.UseProgram(_shaderProgram);
CheckError(GL); CheckError(GL);
var projection = var projection =
@ -369,34 +368,5 @@ namespace ControlCatalog.Pages
if (_disco > 0.01) if (_disco > 0.01)
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
} }
class GlExtrasInterface : GlInterfaceBase<GlInterface.GlContextInfo>
{
public GlExtrasInterface(GlInterface gl) : base(gl.GetProcAddress, gl.ContextInfo)
{
}
public delegate void GlDeleteVertexArrays(int count, int[] buffers);
[GlMinVersionEntryPoint("glDeleteVertexArrays", 3,0)]
[GlExtensionEntryPoint("glDeleteVertexArraysOES", "GL_OES_vertex_array_object")]
public GlDeleteVertexArrays DeleteVertexArrays { get; }
public delegate void GlBindVertexArray(int array);
[GlMinVersionEntryPoint("glBindVertexArray", 3,0)]
[GlExtensionEntryPoint("glBindVertexArrayOES", "GL_OES_vertex_array_object")]
public GlBindVertexArray BindVertexArray { get; }
public delegate void GlGenVertexArrays(int n, int[] rv);
[GlMinVersionEntryPoint("glGenVertexArrays",3,0)]
[GlExtensionEntryPoint("glGenVertexArraysOES", "GL_OES_vertex_array_object")]
public GlGenVertexArrays GenVertexArrays { get; }
public int GenVertexArray()
{
var rv = new int[1];
GenVertexArrays(1, rv);
return rv[0];
}
}
} }
} }

4
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

@ -21,7 +21,7 @@ namespace Avalonia.OpenGL.Angle
var display = IntPtr.Zero; var display = IntPtr.Zero;
AngleOptions.PlatformApi angleApi = default; AngleOptions.PlatformApi angleApi = default;
{ {
if (_egl.GetPlatformDisplayEXT == null) if (!_egl.IsGetPlatformDisplayExtAvailable)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll"); throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll");
var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis
@ -37,7 +37,7 @@ namespace Avalonia.OpenGL.Angle
else else
continue; continue;
display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, display = _egl.GetPlatformDisplayExt(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE }); new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE });
if (display != IntPtr.Zero) if (display != IntPtr.Zero)
{ {

1
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

@ -11,4 +11,5 @@
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\DevAnalyzers.props" /> <Import Project="..\..\build\DevAnalyzers.props" />
<Import Project="..\..\build\SourceGenerators.props" />
</Project> </Project>

14
src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

@ -66,11 +66,9 @@ namespace Avalonia.OpenGL.Controls
return; return;
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer); gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer);
if (_depthBuffer != 0) gl.DeleteRenderbuffers(1, new[] { _depthBuffer }); if (_depthBuffer != 0) gl.DeleteRenderbuffer(_depthBuffer);
var oneArr = new int[1]; _depthBuffer = gl.GenRenderbuffer();
gl.GenRenderbuffers(1, oneArr);
_depthBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthBuffer); gl.BindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER, gl.RenderbufferStorage(GL_RENDERBUFFER,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT, GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
@ -88,9 +86,9 @@ namespace Avalonia.OpenGL.Controls
var gl = _context.GlInterface; var gl = _context.GlInterface;
gl.BindTexture(GL_TEXTURE_2D, 0); gl.BindTexture(GL_TEXTURE_2D, 0);
gl.BindFramebuffer(GL_FRAMEBUFFER, 0); gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
gl.DeleteFramebuffers(1, new[] { _fb }); gl.DeleteFramebuffer(_fb);
_fb = 0; _fb = 0;
gl.DeleteRenderbuffers(1, new[] { _depthBuffer }); gl.DeleteRenderbuffer(_depthBuffer);
_depthBuffer = 0; _depthBuffer = 0;
_attachment?.Dispose(); _attachment?.Dispose();
_attachment = null; _attachment = null;
@ -174,9 +172,7 @@ namespace Avalonia.OpenGL.Controls
{ {
_depthBufferSize = GetPixelSize(); _depthBufferSize = GetPixelSize();
var gl = _context.GlInterface; var gl = _context.GlInterface;
var oneArr = new int[1]; _fb = gl.GenFramebuffer();
gl.GenFramebuffers(1, oneArr);
_fb = oneArr[0];
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb); gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
EnsureDepthBufferAttachment(gl); EnsureDepthBufferAttachment(gl);

2
src/Avalonia.OpenGL/Egl/EglContext.cs

@ -24,7 +24,7 @@ namespace Avalonia.OpenGL.Egl
SampleCount = sampleCount; SampleCount = sampleCount;
StencilSize = stencilSize; StencilSize = stencilSize;
using (MakeCurrent()) using (MakeCurrent())
GlInterface = GlInterface.FromNativeUtf8GetProcAddress(version, b => _egl.GetProcAddress(b)); GlInterface = GlInterface.FromNativeUtf8GetProcAddress(version, _egl.GetProcAddress);
} }
public IntPtr Context { get; } public IntPtr Context { get; }

4
src/Avalonia.OpenGL/Egl/EglDisplay.cs

@ -34,9 +34,9 @@ namespace Avalonia.OpenGL.Egl
} }
else else
{ {
if (egl.GetPlatformDisplayEXT == null) if (!egl.IsGetPlatformDisplayExtAvailable)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl"); throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl");
display = egl.GetPlatformDisplayEXT(platformType, platformDisplay, attrs); display = egl.GetPlatformDisplayExt(platformType, platformDisplay, attrs);
} }
if (display == IntPtr.Zero) if (display == IntPtr.Zero)

225
src/Avalonia.OpenGL/Egl/EglInterface.cs

@ -2,31 +2,26 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
using Avalonia.SourceGenerator;
namespace Avalonia.OpenGL.Egl namespace Avalonia.OpenGL.Egl
{ {
public class EglInterface : GlInterfaceBase public unsafe partial class EglInterface
{ {
public EglInterface() : base(Load()) public EglInterface(Func<string, IntPtr> getProcAddress)
{ {
Initialize(getProcAddress);
}
public EglInterface(Func<Utf8Buffer,IntPtr> getProcAddress) : base(getProcAddress)
{
} }
public EglInterface(Func<string, IntPtr> getProcAddress) : base(getProcAddress) public EglInterface(string library) : this(Load(library))
{ {
} }
public EglInterface(string library) : base(Load(library)) public EglInterface() : this(Load())
{ {
} }
static Func<string, IntPtr> Load() static Func<string, IntPtr> Load()
{ {
var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem; var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem;
@ -46,119 +41,75 @@ namespace Avalonia.OpenGL.Egl
} }
// ReSharper disable UnassignedGetOnlyAutoProperty // ReSharper disable UnassignedGetOnlyAutoProperty
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int EglGetError(); [GetProcAddress("eglGetError")]
[GlEntryPoint("eglGetError")] public partial int GetError();
public EglGetError GetError { get; }
[GetProcAddress("eglGetDisplay")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public partial IntPtr GetDisplay(IntPtr nativeDisplay);
public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
[GlEntryPoint("eglGetDisplay")] [GetProcAddress("eglGetPlatformDisplayEXT", true)]
public EglGetDisplay GetDisplay { get; } public partial IntPtr GetPlatformDisplayExt(int platform, IntPtr nativeDisplay, int[] attrs);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("eglInitialize")]
public delegate IntPtr EglGetPlatformDisplayEXT(int platform, IntPtr nativeDisplay, int[] attrs); public partial bool Initialize(IntPtr display, out int major, out int minor);
[GlEntryPoint("eglGetPlatformDisplayEXT")]
[GlOptionalEntryPoint] [GetProcAddress("eglGetProcAddress")]
public EglGetPlatformDisplayEXT GetPlatformDisplayEXT { get; } public partial IntPtr GetProcAddress(IntPtr proc);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglInitialize(IntPtr display, out int major, out int minor);
[GlEntryPoint("eglInitialize")]
public EglInitialize Initialize { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglGetProcAddress(Utf8Buffer proc);
[GlEntryPoint("eglGetProcAddress")]
public EglGetProcAddress GetProcAddress { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglBindApi(int api);
[GlEntryPoint("eglBindAPI")]
public EglBindApi BindApi { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglChooseConfig(IntPtr display, int[] attribs,
out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
[GlEntryPoint("eglChooseConfig")]
public EglChooseConfig ChooseConfig { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("eglBindAPI")]
public delegate IntPtr EglCreateContext(IntPtr display, IntPtr config, public partial bool BindApi(int api);
[GetProcAddress("eglChooseConfig")]
public partial bool ChooseConfig(IntPtr display, int[] attribs,
out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
[GetProcAddress("eglCreateContext")]
public partial IntPtr CreateContext(IntPtr display, IntPtr config,
IntPtr share, int[] attrs); IntPtr share, int[] attrs);
[GlEntryPoint("eglCreateContext")]
public EglCreateContext CreateContext { get; } [GetProcAddress("eglDestroyContext")]
public partial bool DestroyContext(IntPtr display, IntPtr context);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglDestroyContext(IntPtr display, IntPtr context); [GetProcAddress("eglCreatePbufferSurface")]
[GlEntryPoint("eglDestroyContext")] public partial IntPtr CreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
public EglDestroyContext DestroyContext { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglCreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
[GlEntryPoint("eglCreatePbufferSurface")]
public EglCreatePBufferSurface CreatePBufferSurface { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglMakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
[GlEntryPoint("eglMakeCurrent")]
public EglMakeCurrent MakeCurrent { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglGetCurrentContext();
[GlEntryPoint("eglGetCurrentContext")]
public EglGetCurrentContext GetCurrentContext { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglGetCurrentDisplay();
[GlEntryPoint("eglGetCurrentDisplay")]
public EglGetCurrentContext GetCurrentDisplay { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglGetCurrentSurface(int readDraw);
[GlEntryPoint("eglGetCurrentSurface")]
public EglGetCurrentSurface GetCurrentSurface { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void EglDisplaySurfaceVoidDelegate(IntPtr display, IntPtr surface);
[GlEntryPoint("eglDestroySurface")]
public EglDisplaySurfaceVoidDelegate DestroySurface { get; }
[GlEntryPoint("eglSwapBuffers")]
public EglDisplaySurfaceVoidDelegate SwapBuffers { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr
EglCreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs);
[GlEntryPoint("eglCreateWindowSurface")]
public EglCreateWindowSurface CreateWindowSurface { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglGetConfigAttrib(IntPtr display, IntPtr config, int attr, out int rv);
[GlEntryPoint("eglGetConfigAttrib")]
public EglGetConfigAttrib GetConfigAttrib { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglWaitGL();
[GlEntryPoint("eglWaitGL")]
public EglWaitGL WaitGL { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglWaitClient();
[GlEntryPoint("eglWaitClient")]
public EglWaitGL WaitClient { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglWaitNative(int engine);
[GlEntryPoint("eglWaitNative")]
public EglWaitNative WaitNative { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglQueryString(IntPtr display, int i);
[GlEntryPoint("eglQueryString")]
public EglQueryString QueryStringNative { get; }
[GetProcAddress("eglMakeCurrent")]
public partial bool MakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
[GetProcAddress("eglGetCurrentContext")]
public partial IntPtr GetCurrentContext();
[GetProcAddress("eglGetCurrentDisplay")]
public partial IntPtr GetCurrentDisplay();
[GetProcAddress("eglGetCurrentSurface")]
public partial IntPtr GetCurrentSurface(int readDraw);
[GetProcAddress("eglDestroySurface")]
public partial void DestroySurface(IntPtr display, IntPtr surface);
[GetProcAddress("eglSwapBuffers")]
public partial void SwapBuffers(IntPtr display, IntPtr surface);
[GetProcAddress("eglCreateWindowSurface")]
public partial IntPtr CreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs);
[GetProcAddress("eglGetConfigAttrib")]
public partial bool GetConfigAttrib(IntPtr display, IntPtr config, int attr, out int rv);
[GetProcAddress("eglWaitGL")]
public partial bool WaitGL();
[GetProcAddress("eglWaitClient")]
public partial bool WaitClient();
[GetProcAddress("eglWaitNative")]
public partial bool WaitNative(int engine);
[GetProcAddress("eglQueryString")]
public partial IntPtr QueryStringNative(IntPtr display, int i);
public string QueryString(IntPtr display, int i) public string QueryString(IntPtr display, int i)
{ {
var rv = QueryStringNative(display, i); var rv = QueryStringNative(display, i);
@ -166,25 +117,15 @@ namespace Avalonia.OpenGL.Egl
return null; return null;
return Marshal.PtrToStringAnsi(rv); return Marshal.PtrToStringAnsi(rv);
} }
[GetProcAddress("eglCreatePbufferFromClientBuffer")]
public partial IntPtr CreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[] attrib_list);
[GetProcAddress("eglQueryDisplayAttribEXT", true)]
public partial bool QueryDisplayAttribExt(IntPtr display, int attr, out IntPtr res);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr EglCreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[] attrib_list); [GetProcAddress("eglQueryDeviceAttribEXT", true)]
[GlEntryPoint("eglCreatePbufferFromClientBuffer")] public partial bool QueryDeviceAttribExt(IntPtr display, int attr, out IntPtr res);
public EglCreatePbufferFromClientBuffer CreatePbufferFromClientBuffer { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglQueryDisplayAttribEXT(IntPtr display, int attr, out IntPtr res);
[GlEntryPoint("eglQueryDisplayAttribEXT"), GlOptionalEntryPoint]
public EglQueryDisplayAttribEXT QueryDisplayAttribExt { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool EglQueryDeviceAttribEXT(IntPtr display, int attr, out IntPtr res);
[GlEntryPoint("eglQueryDeviceAttribEXT"), GlOptionalEntryPoint]
public EglQueryDisplayAttribEXT QueryDeviceAttribExt { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
} }
} }

44
src/Avalonia.OpenGL/GlBasicInfoInterface.cs

@ -3,46 +3,24 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
using Avalonia.SourceGenerator;
namespace Avalonia.OpenGL namespace Avalonia.OpenGL
{ {
public class GlBasicInfoInterface : GlBasicInfoInterface<object> public unsafe partial class GlBasicInfoInterface
{ {
public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress) : base(getProcAddress, null) public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress){
{ Initialize(getProcAddress);
}
public GlBasicInfoInterface(Func<Utf8Buffer, IntPtr> nativeGetProcAddress) : base(nativeGetProcAddress, null)
{
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlGetIntegerv(int name, out int rv);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr GlGetString(int v);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr GlGetStringi(int v, int v1);
}
public class GlBasicInfoInterface<TContextInfo> : GlInterfaceBase<TContextInfo> [GetProcAddress("glGetIntegerv")]
{ public partial void GetIntegerv(int name, out int rv);
public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress, TContextInfo context) : base(getProcAddress, context)
{
}
public GlBasicInfoInterface(Func<Utf8Buffer, IntPtr> nativeGetProcAddress, TContextInfo context) : base(nativeGetProcAddress, context) [GetProcAddress("glGetString")]
{ public partial IntPtr GetStringNative(int v);
}
[GetProcAddress("glGetStringi")]
[GlEntryPoint("glGetIntegerv")] public partial IntPtr GetStringiNative(int v, int v1);
public GlBasicInfoInterface.GlGetIntegerv GetIntegerv { get; }
[GlEntryPoint("glGetString")]
public GlBasicInfoInterface.GlGetString GetStringNative { get; }
[GlEntryPoint("glGetStringi")]
public GlBasicInfoInterface.GlGetStringi GetStringiNative { get; }
public string GetString(int v) public string GetString(int v)
{ {

103
src/Avalonia.OpenGL/GlEntryPointAttribute.cs

@ -2,117 +2,54 @@ using System;
namespace Avalonia.OpenGL namespace Avalonia.OpenGL
{ {
public interface IGlEntryPointAttribute [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
class GlMinVersionEntryPoint : Attribute
{ {
IntPtr GetProcAddress(Func<string, IntPtr> getProcAddress); public GlMinVersionEntryPoint(string entry, int minVersionMajor, int minVersionMinor)
}
public interface IGlEntryPointAttribute<in TContext>
{
IntPtr GetProcAddress(TContext context, Func<string, IntPtr> getProcAddress);
}
[AttributeUsage(AttributeTargets.Property)]
public class GlOptionalEntryPoint : Attribute
{
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class GlEntryPointAttribute : Attribute, IGlEntryPointAttribute
{
public string[] EntryPoints { get; }
public GlEntryPointAttribute(string entryPoint)
{
EntryPoints = new []{entryPoint};
}
/*
public GlEntryPointAttribute(params string[] entryPoints)
{ {
EntryPoints = entryPoints;
}
*/
public IntPtr GetProcAddress(Func<string, IntPtr> getProcAddress)
{
foreach (var name in EntryPoints)
{
var rv = getProcAddress(name);
if (rv != IntPtr.Zero)
return rv;
}
return IntPtr.Zero;
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class GlMinVersionEntryPoint : Attribute, IGlEntryPointAttribute<GlInterface.GlContextInfo>
{
private readonly string _entry;
private readonly GlProfileType? _profile;
private readonly int _minVersionMajor;
private readonly int _minVersionMinor;
public GlMinVersionEntryPoint(string entry, GlProfileType profile, int minVersionMajor,
int minVersionMinor)
{
_entry = entry;
_profile = profile;
_minVersionMajor = minVersionMajor;
_minVersionMinor = minVersionMinor;
} }
public GlMinVersionEntryPoint(string entry, int minVersionMajor, public GlMinVersionEntryPoint(string entry, int minVersionMajor, int minVersionMinor, GlProfileType profile)
int minVersionMinor)
{ {
_entry = entry;
_minVersionMajor = minVersionMajor;
_minVersionMinor = minVersionMinor;
} }
public IntPtr GetProcAddress(GlInterface.GlContextInfo context, Func<string, IntPtr> getProcAddress) public static IntPtr GetProcAddress(Func<string, IntPtr> getProcAddress, GlInterface.GlContextInfo context,
string entry, int minVersionMajor, int minVersionMinor, GlProfileType? profile = null)
{ {
if(_profile.HasValue && context.Version.Type != _profile) if(profile.HasValue && context.Version.Type != profile)
return IntPtr.Zero; return IntPtr.Zero;
if(context.Version.Major<_minVersionMajor) if(context.Version.Major<minVersionMajor)
return IntPtr.Zero; return IntPtr.Zero;
if (context.Version.Major == _minVersionMajor && context.Version.Minor < _minVersionMinor) if (context.Version.Major == minVersionMajor && context.Version.Minor < minVersionMinor)
return IntPtr.Zero; return IntPtr.Zero;
return getProcAddress(_entry); return getProcAddress(entry);
} }
} }
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class GlExtensionEntryPoint : Attribute, IGlEntryPointAttribute<GlInterface.GlContextInfo> class GlExtensionEntryPoint : Attribute
{ {
private readonly string _entry; public GlExtensionEntryPoint(string entry, string extension)
private readonly GlProfileType? _profile;
private readonly string _extension;
public GlExtensionEntryPoint(string entry, GlProfileType profile, string extension)
{ {
_entry = entry;
_profile = profile;
_extension = extension;
} }
public GlExtensionEntryPoint(string entry, string extension) public GlExtensionEntryPoint(string entry, string extension, GlProfileType profile)
{ {
_entry = entry;
_extension = extension;
} }
public IntPtr GetProcAddress(GlInterface.GlContextInfo context, Func<string, IntPtr> getProcAddress) public static IntPtr GetProcAddress(Func<string, IntPtr> getProcAddress, GlInterface.GlContextInfo context,
string entry, string extension, GlProfileType? profile = null)
{ {
// Ignore different profile type // Ignore different profile type
if (_profile.HasValue && _profile != context.Version.Type) if (profile.HasValue && profile != context.Version.Type)
return IntPtr.Zero; return IntPtr.Zero;
// Check if extension is supported by the current context // Check if extension is supported by the current context
if (!context.Extensions.Contains(_extension)) if (!context.Extensions.Contains(extension))
return IntPtr.Zero; return IntPtr.Zero;
return getProcAddress(_entry); return getProcAddress(entry);
} }
} }
} }

494
src/Avalonia.OpenGL/GlInterface.cs

@ -3,14 +3,14 @@ using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
using Avalonia.SourceGenerator;
using static Avalonia.OpenGL.GlConsts; using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.OpenGL namespace Avalonia.OpenGL
{ {
public delegate IntPtr GlGetProcAddressDelegate(string procName); public unsafe partial class GlInterface : GlBasicInfoInterface
public unsafe class GlInterface : GlBasicInfoInterface<GlInterface.GlContextInfo>
{ {
private readonly Func<string, IntPtr> _getProcAddress;
public string Version { get; } public string Version { get; }
public string Vendor { get; } public string Vendor { get; }
public string Renderer { get; } public string Renderer { get; }
@ -35,12 +35,14 @@ namespace Avalonia.OpenGL
} }
} }
private GlInterface(GlContextInfo info, Func<string, IntPtr> getProcAddress) : base(getProcAddress, info) private GlInterface(GlContextInfo info, Func<string, IntPtr> getProcAddress) : base(getProcAddress)
{ {
_getProcAddress = getProcAddress;
ContextInfo = info; ContextInfo = info;
Version = GetString(GlConsts.GL_VERSION); Version = GetString(GlConsts.GL_VERSION);
Renderer = GetString(GlConsts.GL_RENDERER); Renderer = GetString(GlConsts.GL_RENDERER);
Vendor = GetString(GlConsts.GL_VENDOR); Vendor = GetString(GlConsts.GL_VENDOR);
Initialize(getProcAddress, ContextInfo);
} }
public GlInterface(GlVersion version, Func<string, IntPtr> getProcAddress) : this( public GlInterface(GlVersion version, Func<string, IntPtr> getProcAddress) : this(
@ -48,92 +50,58 @@ namespace Avalonia.OpenGL
{ {
} }
public GlInterface(GlVersion version, Func<Utf8Buffer, IntPtr> n) : this(version, ConvertNative(n)) public IntPtr GetProcAddress(string proc) => _getProcAddress(proc);
[GetProcAddress("glGetError")]
public partial int GetError();
[GetProcAddress("glClearStencil")]
public partial void ClearStencil(int s);
[GetProcAddress("glClearColor")]
public partial void ClearColor(float r, float g, float b, float a);
[GetProcAddress("glClear")]
public partial void Clear(int bits);
[GetProcAddress("glViewport")]
public partial void Viewport(int x, int y, int width, int height);
[GetProcAddress("glFlush")]
public partial void Flush();
[GetProcAddress("glFinish")]
public partial void Finish();
[GetProcAddress("glGetIntegerv")]
public partial void GetIntegerv(int name, out int rv);
[GetProcAddress("glGenFramebuffers")]
public partial void GenFramebuffers(int count, int* res);
public int GenFramebuffer()
{ {
int rv = 0;
GenFramebuffers(1, &rv);
return rv;
} }
public static GlInterface FromNativeUtf8GetProcAddress(GlVersion version, Func<Utf8Buffer, IntPtr> getProcAddress) => [GetProcAddress("glDeleteFramebuffers")]
new GlInterface(version, getProcAddress); public partial void DeleteFramebuffers(int count, int* framebuffers);
public void DeleteFramebuffer(int fb)
public T GetProcAddress<T>(string proc) => Marshal.GetDelegateForFunctionPointer<T>(GetProcAddress(proc));
// ReSharper disable UnassignedGetOnlyAutoProperty
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int GlGetError();
[GlEntryPoint("glGetError")]
public GlGetError GetError { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlClearStencil(int s);
[GlEntryPoint("glClearStencil")]
public GlClearStencil ClearStencil { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlClearColor(float r, float g, float b, float a);
[GlEntryPoint("glClearColor")]
public GlClearColor ClearColor { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlClear(int bits);
[GlEntryPoint("glClear")]
public GlClear Clear { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlViewport(int x, int y, int width, int height);
[GlEntryPoint("glViewport")]
public GlViewport Viewport { get; }
[GlEntryPoint("glFlush")]
public UnmanagedAction Flush { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void UnmanagedAction();
[GlEntryPoint("glFinish")]
public UnmanagedAction Finish { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr GlGetString(int v);
[GlEntryPoint("glGetString")]
public GlGetString GetStringNative { get; }
public string GetString(int v)
{ {
var ptr = GetStringNative(v); DeleteFramebuffers(1, &fb);
if (ptr != IntPtr.Zero)
return Marshal.PtrToStringAnsi(ptr);
return null;
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glBindFramebuffer")]
public delegate void GlGetIntegerv(int name, out int rv); public partial void BindFramebuffer(int target, int fb);
[GlEntryPoint("glGetIntegerv")]
public GlGetIntegerv GetIntegerv { get; } [GetProcAddress("glCheckFramebufferStatus")]
public partial int CheckFramebufferStatus(int target);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlGenFramebuffers(int count, int[] res); [GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0), GetProcAddress(true)]
[GlEntryPoint("glGenFramebuffers")] public partial void BlitFramebuffer(int srcX0,
public GlGenFramebuffers GenFramebuffers { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlDeleteFramebuffers(int count, int[] framebuffers);
[GlEntryPoint("glDeleteFramebuffers")]
public GlDeleteFramebuffers DeleteFramebuffers { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlBindFramebuffer(int target, int fb);
[GlEntryPoint("glBindFramebuffer")]
public GlBindFramebuffer BindFramebuffer { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int GlCheckFramebufferStatus(int target);
[GlEntryPoint("glCheckFramebufferStatus")]
public GlCheckFramebufferStatus CheckFramebufferStatus { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlBlitFramebuffer(int srcX0,
int srcY0, int srcY0,
int srcX1, int srcX1,
int srcY1, int srcY1,
@ -143,89 +111,78 @@ namespace Avalonia.OpenGL
int dstY1, int dstY1,
int mask, int mask,
int filter); int filter);
[GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0), GlOptionalEntryPoint]
public GlBlitFramebuffer BlitFramebuffer { get; }
[GetProcAddress("glGenRenderbuffers")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public partial void GenRenderbuffers(int count, int* res);
public delegate void GlGenRenderbuffers(int count, int[] res);
[GlEntryPoint("glGenRenderbuffers")] public int GenRenderbuffer()
public GlGenRenderbuffers GenRenderbuffers { get; } {
int rv = 0;
[UnmanagedFunctionPointer(CallingConvention.StdCall)] GenRenderbuffers(1, &rv);
public delegate void GlDeleteRenderbuffers(int count, int[] renderbuffers); return rv;
[GlEntryPoint("glDeleteRenderbuffers")] }
public GlDeleteTextures DeleteRenderbuffers { get; }
[GetProcAddress("glDeleteRenderbuffers")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public partial void DeleteRenderbuffers(int count, int* renderbuffers);
public delegate void GlBindRenderbuffer(int target, int fb);
[GlEntryPoint("glBindRenderbuffer")] public void DeleteRenderbuffer(int renderbuffer)
public GlBindRenderbuffer BindRenderbuffer { get; } {
DeleteRenderbuffers(1, &renderbuffer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] }
public delegate void GlRenderbufferStorage(int target, int internalFormat, int width, int height);
[GlEntryPoint("glRenderbufferStorage")] [GetProcAddress("glBindRenderbuffer")]
public GlRenderbufferStorage RenderbufferStorage { get; } public partial void BindRenderbuffer(int target, int fb);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glRenderbufferStorage")]
public delegate void GlFramebufferRenderbuffer(int target, int attachment, public partial void RenderbufferStorage(int target, int internalFormat, int width, int height);
[GetProcAddress("glFramebufferRenderbuffer")]
public partial void FramebufferRenderbuffer(int target, int attachment,
int renderbufferTarget, int renderbuffer); int renderbufferTarget, int renderbuffer);
[GlEntryPoint("glFramebufferRenderbuffer")]
public GlFramebufferRenderbuffer FramebufferRenderbuffer { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGenTextures")]
public delegate void GlGenTextures(int count, int[] res); public partial void GenTextures(int count, int* res);
[GlEntryPoint("glGenTextures")]
public GlGenTextures GenTextures { get; } public int GenTexture()
{
int rv = 0;
GenTextures(1, &rv);
return rv;
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glBindTexture")]
public delegate void GlBindTexture(int target, int fb); public partial void BindTexture(int target, int fb);
[GlEntryPoint("glBindTexture")]
public GlBindTexture BindTexture { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glActiveTexture")]
public delegate void GlActiveTexture(int texture); public partial void ActiveTexture(int texture);
[GlEntryPoint("glActiveTexture")]
public GlActiveTexture ActiveTexture { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glDeleteTextures")]
public delegate void GlDeleteTextures(int count, int[] textures); public partial void DeleteTextures(int count, int* textures);
[GlEntryPoint("glDeleteTextures")]
public GlDeleteTextures DeleteTextures { get; }
public void DeleteTexture(int texture) => DeleteTextures(1, &texture);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glTexImage2D")]
public delegate void GlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, public partial void TexImage2D(int target, int level, int internalFormat, int width, int height, int border,
int format, int type, IntPtr data); int format, int type, IntPtr data);
[GlEntryPoint("glTexImage2D")]
public GlTexImage2D TexImage2D { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glCopyTexSubImage2D")]
public delegate void GlCopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y, public partial void CopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y,
int width, int height); int width, int height);
[GlEntryPoint("glCopyTexSubImage2D")]
public GlCopyTexSubImage2D CopyTexSubImage2D { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glTexParameteri")]
public delegate void GlTexParameteri(int target, int name, int value); public partial void TexParameteri(int target, int name, int value);
[GlEntryPoint("glTexParameteri")]
public GlTexParameteri TexParameteri { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlFramebufferTexture2D(int target, int attachment, [GetProcAddress("glFramebufferTexture2D")]
public partial void FramebufferTexture2D(int target, int attachment,
int texTarget, int texture, int level); int texTarget, int texture, int level);
[GlEntryPoint("glFramebufferTexture2D")]
public GlFramebufferTexture2D FramebufferTexture2D { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glCreateShader")]
public delegate int GlCreateShader(int shaderType); public partial int CreateShader(int shaderType);
[GlEntryPoint("glCreateShader")]
public GlCreateShader CreateShader { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glShaderSource")]
public delegate void GlShaderSource(int shader, int count, IntPtr strings, IntPtr lengths); public partial void ShaderSource(int shader, int count, IntPtr strings, IntPtr lengths);
[GlEntryPoint("glShaderSource")]
public GlShaderSource ShaderSource { get; }
public void ShaderSourceString(int shader, string source) public void ShaderSourceString(int shader, string source)
{ {
@ -237,20 +194,14 @@ namespace Avalonia.OpenGL
} }
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glCompileShader")]
public delegate void GlCompileShader(int shader); public partial void CompileShader(int shader);
[GlEntryPoint("glCompileShader")]
public GlCompileShader CompileShader { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetShaderiv")]
public delegate void GlGetShaderiv(int shader, int name, int* parameters); public partial void GetShaderiv(int shader, int name, int* parameters);
[GlEntryPoint("glGetShaderiv")]
public GlGetShaderiv GetShaderiv { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetShaderInfoLog")]
public delegate void GlGetShaderInfoLog(int shader, int maxLength, out int length, void*infoLog); public partial void GetShaderInfoLog(int shader, int maxLength, out int length, void* infoLog);
[GlEntryPoint("glGetShaderInfoLog")]
public GlGetShaderInfoLog GetShaderInfoLog { get; }
public unsafe string CompileShaderAndGetError(int shader, string source) public unsafe string CompileShaderAndGetError(int shader, string source)
{ {
@ -268,33 +219,24 @@ namespace Avalonia.OpenGL
int len; int len;
fixed (void* ptr = logData) fixed (void* ptr = logData)
GetShaderInfoLog(shader, logLength, out len, ptr); GetShaderInfoLog(shader, logLength, out len, ptr);
return Encoding.UTF8.GetString(logData,0, len); return Encoding.UTF8.GetString(logData, 0, len);
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int GlCreateProgram();
[GlEntryPoint("glCreateProgram")]
public GlCreateProgram CreateProgram { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glCreateProgram")]
public delegate void GlAttachShader(int program, int shader); public partial int CreateProgram();
[GlEntryPoint("glAttachShader")]
public GlAttachShader AttachShader { get; } [GetProcAddress("glAttachShader")]
public partial void AttachShader(int program, int shader);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glLinkProgram")]
public delegate void GlLinkProgram(int program); public partial void LinkProgram(int program);
[GlEntryPoint("glLinkProgram")]
public GlLinkProgram LinkProgram { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetProgramiv")]
public delegate void GlGetProgramiv(int program, int name, int* parameters); public partial void GetProgramiv(int program, int name, int* parameters);
[GlEntryPoint("glGetProgramiv")]
public GlGetProgramiv GetProgramiv { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetProgramInfoLog")]
public delegate void GlGetProgramInfoLog(int program, int maxLength, out int len, void* infoLog); public partial void GetProgramInfoLog(int program, int maxLength, out int len, void* infoLog);
[GlEntryPoint("glGetProgramInfoLog")]
public GlGetProgramInfoLog GetProgramInfoLog { get; }
public unsafe string LinkProgramAndGetError(int program) public unsafe string LinkProgramAndGetError(int program)
{ {
@ -309,13 +251,11 @@ namespace Avalonia.OpenGL
int len; int len;
fixed (void* ptr = logData) fixed (void* ptr = logData)
GetProgramInfoLog(program, logLength, out len, ptr); GetProgramInfoLog(program, logLength, out len, ptr);
return Encoding.UTF8.GetString(logData,0, len); return Encoding.UTF8.GetString(logData, 0, len);
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glBindAttribLocation")]
public delegate void GlBindAttribLocation(int program, int index, IntPtr name); public partial void BindAttribLocation(int program, int index, IntPtr name);
[GlEntryPoint("glBindAttribLocation")]
public GlBindAttribLocation BindAttribLocation { get; }
public void BindAttribLocationString(int program, int index, string name) public void BindAttribLocationString(int program, int index, string name)
{ {
@ -323,32 +263,24 @@ namespace Avalonia.OpenGL
BindAttribLocation(program, index, b.DangerousGetHandle()); BindAttribLocation(program, index, b.DangerousGetHandle());
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGenBuffers")]
public delegate void GlGenBuffers(int len, int[] rv); public partial void GenBuffers(int len, int* rv);
[GlEntryPoint("glGenBuffers")]
public GlGenBuffers GenBuffers { get; }
public int GenBuffer() public int GenBuffer()
{ {
var rv = new int[1]; int rv;
GenBuffers(1, rv); GenBuffers(1, &rv);
return rv[0]; return rv;
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glBindBuffer")]
public delegate void GlBindBuffer(int target, int buffer); public partial void BindBuffer(int target, int buffer);
[GlEntryPoint("glBindBuffer")]
public GlBindBuffer BindBuffer { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glBufferData")]
public delegate void GlBufferData(int target, IntPtr size, IntPtr data, int usage); public partial void BufferData(int target, IntPtr size, IntPtr data, int usage);
[GlEntryPoint("glBufferData")]
public GlBufferData BufferData { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetAttribLocation")]
public delegate int GlGetAttribLocation(int program, IntPtr name); public partial int GetAttribLocation(int program, IntPtr name);
[GlEntryPoint("glGetAttribLocation")]
public GlGetAttribLocation GetAttribLocation { get; }
public int GetAttribLocationString(int program, string name) public int GetAttribLocationString(int program, string name)
{ {
@ -356,36 +288,24 @@ namespace Avalonia.OpenGL
return GetAttribLocation(program, b.DangerousGetHandle()); return GetAttribLocation(program, b.DangerousGetHandle());
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glVertexAttribPointer")]
public delegate void GlVertexAttribPointer(int index, int size, int type, public partial void VertexAttribPointer(int index, int size, int type,
int normalized, int stride, IntPtr pointer); int normalized, int stride, IntPtr pointer);
[GlEntryPoint("glVertexAttribPointer")]
public GlVertexAttribPointer VertexAttribPointer { get; } [GetProcAddress("glEnableVertexAttribArray")]
public partial void EnableVertexAttribArray(int index);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlEnableVertexAttribArray(int index); [GetProcAddress("glUseProgram")]
[GlEntryPoint("glEnableVertexAttribArray")] public partial void UseProgram(int program);
public GlEnableVertexAttribArray EnableVertexAttribArray { get; }
[GetProcAddress("glDrawArrays")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public partial void DrawArrays(int mode, int first, IntPtr count);
public delegate void GlUseProgram(int program);
[GlEntryPoint("glUseProgram")] [GetProcAddress("glDrawElements")]
public GlUseProgram UseProgram { get; } public partial void DrawElements(int mode, int count, int type, IntPtr indices);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetUniformLocation")]
public delegate void GlDrawArrays(int mode, int first, IntPtr count); public partial int GetUniformLocation(int program, IntPtr name);
[GlEntryPoint("glDrawArrays")]
public GlDrawArrays DrawArrays { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlDrawElements(int mode, int count, int type, IntPtr indices);
[GlEntryPoint("glDrawElements")]
public GlDrawElements DrawElements { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int GlGetUniformLocation(int program, IntPtr name);
[GlEntryPoint("glGetUniformLocation")]
public GlGetUniformLocation GetUniformLocation { get; }
public int GetUniformLocationString(int program, string name) public int GetUniformLocationString(int program, string name)
{ {
@ -393,41 +313,65 @@ namespace Avalonia.OpenGL
return GetUniformLocation(program, b.DangerousGetHandle()); return GetUniformLocation(program, b.DangerousGetHandle());
} }
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glUniform1f")]
public delegate void GlUniform1f(int location, float falue); public partial void Uniform1f(int location, float falue);
[GlEntryPoint("glUniform1f")]
public GlUniform1f Uniform1f { get; }
[GetProcAddress("glUniformMatrix4fv")]
public partial void UniformMatrix4fv(int location, int count, bool transpose, void* value);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlUniformMatrix4fv(int location, int count, bool transpose, void* value); [GetProcAddress("glEnable")]
[GlEntryPoint("glUniformMatrix4fv")] public partial void Enable(int what);
public GlUniformMatrix4fv UniformMatrix4fv { get; }
[GetProcAddress("glDeleteBuffers")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public partial void DeleteBuffers(int count, int* buffers);
public delegate void GlEnable(int what);
[GlEntryPoint("glEnable")] public void DeleteBuffer(int buffer) => DeleteBuffers(1, &buffer);
public GlEnable Enable { get; }
[GetProcAddress("glDeleteProgram")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public partial void DeleteProgram(int program);
public delegate void GlDeleteBuffers(int count, int[] buffers);
[GlEntryPoint("glDeleteBuffers")] [GetProcAddress("glDeleteShader")]
public GlDeleteBuffers DeleteBuffers { get; } public partial void DeleteShader(int shader);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] [GetProcAddress("glGetRenderbufferParameteriv")]
public delegate void GlDeleteProgram(int program); public partial void GLGetRenderbufferParameteriv(int target, int name, int* value);
[GlEntryPoint("glDeleteProgram")]
public GlDeleteProgram DeleteProgram { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GlDeleteShader(int shader);
[GlEntryPoint("glDeleteShader")]
public GlDeleteShader DeleteShader { get; }
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void GLGetRenderbufferParameteriv(int target, int name, int[] value);
[GlEntryPoint("glGetRenderbufferParameteriv")]
public GLGetRenderbufferParameteriv GetRenderbufferParameteriv { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty // ReSharper restore UnassignedGetOnlyAutoProperty
[GetProcAddress(true)]
[GlMinVersionEntryPoint("glDeleteVertexArrays", 3, 0)]
[GlExtensionEntryPoint("glDeleteVertexArraysOES", "GL_OES_vertex_array_object")]
public partial void DeleteVertexArrays(int count, int* arrays);
public void DeleteVertexArray(int array) => DeleteVertexArrays(1, &array);
[GetProcAddress(true)]
[GlMinVersionEntryPoint("glBindVertexArray", 3, 0)]
[GlExtensionEntryPoint("glBindVertexArrayOES", "GL_OES_vertex_array_object")]
public partial void BindVertexArray(int array);
[GetProcAddress(true)]
[GlMinVersionEntryPoint("glGenVertexArrays", 3, 0)]
[GlExtensionEntryPoint("glGenVertexArraysOES", "GL_OES_vertex_array_object")]
public partial void GenVertexArrays(int n, int* rv);
public int GenVertexArray()
{
int rv = 0;
GenVertexArrays(1, &rv);
return rv;
}
public static GlInterface FromNativeUtf8GetProcAddress(GlVersion version, Func<IntPtr, IntPtr> getProcAddress)
{
return new GlInterface(version, s =>
{
var ptr = Marshal.StringToHGlobalAnsi(s);
var rv = getProcAddress(ptr);
Marshal.FreeHGlobal(ptr);
return rv;
});
}
} }
} }

79
src/Avalonia.OpenGL/GlInterfaceBase.cs

@ -1,79 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL
{
public class GlInterfaceBase : GlInterfaceBase<object>
{
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 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)
{
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)
break;
}
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, IntPtr> ConvertNative(Func<Utf8Buffer, IntPtr> func) =>
(proc) =>
{
using (var u = new Utf8Buffer(proc))
{
var rv = func(u);
return rv;
}
};
public GlInterfaceBase(Func<Utf8Buffer, IntPtr> nativeGetProcAddress, TContext context) : this(ConvertNative(nativeGetProcAddress), context)
{
}
public IntPtr GetProcAddress(string proc) => _getProcAddress(proc);
}
}

2
src/Avalonia.X11/Avalonia.X11.csproj

@ -11,5 +11,5 @@
<ProjectReference Include="..\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj" /> <ProjectReference Include="..\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj" />
<Compile Include="..\Shared\RawEventGrouping.cs" /> <Compile Include="..\Shared\RawEventGrouping.cs" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\SourceGenerators.props" />
</Project> </Project>

111
src/Avalonia.X11/Glx/Glx.cs

@ -4,111 +4,97 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.OpenGL; using Avalonia.OpenGL;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
using Avalonia.SourceGenerator;
// ReSharper disable UnassignedGetOnlyAutoProperty // ReSharper disable UnassignedGetOnlyAutoProperty
namespace Avalonia.X11.Glx namespace Avalonia.X11.Glx
{ {
unsafe class GlxInterface : GlInterfaceBase unsafe partial class GlxInterface
{ {
private const string libGL = "libGL.so.1"; private const string libGL = "libGL.so.1";
[GlEntryPointAttribute("glXMakeContextCurrent")] [GetProcAddress("glXMakeContextCurrent")]
public GlxMakeContextCurrent MakeContextCurrent { get; } public partial bool MakeContextCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
public delegate bool GlxMakeContextCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
[GlEntryPoint("glXGetCurrentContext")] [GetProcAddress("glXGetCurrentContext")]
public GlxGetCurrentContext GetCurrentContext { get; } public partial IntPtr GetCurrentContext();
public delegate IntPtr GlxGetCurrentContext();
[GlEntryPoint("glXGetCurrentDisplay")] [GetProcAddress("glXGetCurrentDisplay")]
public GlxGetCurrentDisplay GetCurrentDisplay { get; } public partial IntPtr GetCurrentDisplay();
public delegate IntPtr GlxGetCurrentDisplay();
[GlEntryPoint("glXGetCurrentDrawable")] [GetProcAddress("glXGetCurrentDrawable")]
public GlxGetCurrentDrawable GetCurrentDrawable { get; } public partial IntPtr GetCurrentDrawable();
public delegate IntPtr GlxGetCurrentDrawable();
[GlEntryPoint("glXGetCurrentReadDrawable")] [GetProcAddress("glXGetCurrentReadDrawable")]
public GlxGetCurrentReadDrawable GetCurrentReadDrawable { get; } public partial IntPtr GetCurrentReadDrawable();
public delegate IntPtr GlxGetCurrentReadDrawable();
[GlEntryPoint("glXCreatePbuffer")] [GetProcAddress("glXCreatePbuffer")]
public GlxCreatePbuffer CreatePbuffer { get; } public partial IntPtr CreatePbuffer(IntPtr dpy, IntPtr fbc, int[] attrib_list);
public delegate IntPtr GlxCreatePbuffer(IntPtr dpy, IntPtr fbc, int[] attrib_list);
[GlEntryPoint("glXDestroyPbuffer")] [GetProcAddress("glXDestroyPbuffer")]
public GlxDestroyPbuffer DestroyPbuffer { get; } public partial IntPtr DestroyPbuffer(IntPtr dpy, IntPtr fb);
public delegate IntPtr GlxDestroyPbuffer(IntPtr dpy, IntPtr fb);
[GlEntryPointAttribute("glXChooseVisual")] [GetProcAddress("glXChooseVisual")]
public GlxChooseVisual ChooseVisual { get; } public partial XVisualInfo* ChooseVisual(IntPtr dpy, int screen, int[] attribList);
public delegate XVisualInfo* GlxChooseVisual(IntPtr dpy, int screen, int[] attribList);
[GlEntryPointAttribute("glXCreateContext")] [GetProcAddress("glXCreateContext")]
public GlxCreateContext CreateContext { get; } public partial IntPtr CreateContext(IntPtr dpy, XVisualInfo* vis, IntPtr shareList, bool direct);
public delegate IntPtr GlxCreateContext(IntPtr dpy, XVisualInfo* vis, IntPtr shareList, bool direct);
[GlEntryPointAttribute("glXCreateContextAttribsARB")] [GetProcAddress("glXCreateContextAttribsARB")]
public GlxCreateContextAttribsARB CreateContextAttribsARB { get; } public partial IntPtr CreateContextAttribsARB(IntPtr dpy, IntPtr fbconfig, IntPtr shareList,
public delegate IntPtr GlxCreateContextAttribsARB(IntPtr dpy, IntPtr fbconfig, IntPtr shareList,
bool direct, int[] attribs); bool direct, int[] attribs);
[DllImport(libGL, EntryPoint = "glXGetProcAddress")] [DllImport(libGL, EntryPoint = "glXGetProcAddress")]
public static extern IntPtr GlxGetProcAddress(Utf8Buffer buffer); public static extern IntPtr GlxGetProcAddress(string buffer);
[GlEntryPointAttribute("glXDestroyContext")] [GetProcAddress("glXDestroyContext")]
public GlxDestroyContext DestroyContext { get; } public partial void DestroyContext(IntPtr dpy, IntPtr ctx);
public delegate void GlxDestroyContext(IntPtr dpy, IntPtr ctx);
[GlEntryPointAttribute("glXChooseFBConfig")] [GetProcAddress("glXChooseFBConfig")]
public GlxChooseFBConfig ChooseFBConfig { get; } public partial IntPtr* ChooseFBConfig(IntPtr dpy, int screen, int[] attrib_list, out int nelements);
public delegate IntPtr* GlxChooseFBConfig(IntPtr dpy, int screen, int[] attrib_list, out int nelements);
public IntPtr* GlxChooseFbConfig(IntPtr dpy, int screen, IEnumerable<int> attribs, out int nelements) public IntPtr* ChooseFbConfig(IntPtr dpy, int screen, IEnumerable<int> attribs, out int nelements)
{ {
var arr = attribs.Concat(new[]{0}).ToArray(); var arr = attribs.Concat(new[]{0}).ToArray();
return ChooseFBConfig(dpy, screen, arr, out nelements); return ChooseFBConfig(dpy, screen, arr, out nelements);
} }
[GlEntryPointAttribute("glXGetVisualFromFBConfig")] [GetProcAddress("glXGetVisualFromFBConfig")]
public GlxGetVisualFromFBConfig GetVisualFromFBConfig { get; } public partial XVisualInfo * GetVisualFromFBConfig(IntPtr dpy, IntPtr config);
public delegate XVisualInfo * GlxGetVisualFromFBConfig(IntPtr dpy, IntPtr config);
[GlEntryPointAttribute("glXGetFBConfigAttrib")] [GetProcAddress("glXGetFBConfigAttrib")]
public GlxGetFBConfigAttrib GetFBConfigAttrib { get; } public partial int GetFBConfigAttrib(IntPtr dpy, IntPtr config, int attribute, out int value);
public delegate int GlxGetFBConfigAttrib(IntPtr dpy, IntPtr config, int attribute, out int value);
[GlEntryPointAttribute("glXSwapBuffers")] [GetProcAddress("glXSwapBuffers")]
public GlxSwapBuffers SwapBuffers { get; } public partial void SwapBuffers(IntPtr dpy, IntPtr drawable);
public delegate void GlxSwapBuffers(IntPtr dpy, IntPtr drawable);
[GlEntryPointAttribute("glXWaitX")] [GetProcAddress("glXWaitX")]
public GlxWaitX WaitX { get; } public partial void WaitX();
public delegate void GlxWaitX();
[GlEntryPointAttribute("glXWaitGL")] [GetProcAddress("glXWaitGL")]
public GlxWaitGL WaitGL { get; } public partial void WaitGL();
public delegate void GlxWaitGL();
public delegate int GlGetError();
[GlEntryPoint("glGetError")]
public GlGetError GetError { get; }
public delegate IntPtr GlxQueryExtensionsString(IntPtr display, int screen); [GetProcAddress("glGetError")]
[GlEntryPoint("glXQueryExtensionsString")] public partial int GlGetError();
public GlxQueryExtensionsString QueryExtensionsString { get; }
[GetProcAddress("glXQueryExtensionsString")]
public partial IntPtr QueryExtensionsString(IntPtr display, int screen);
public GlxInterface() : base(SafeGetProcAddress) public GlxInterface()
{ {
Initialize(SafeGetProcAddress);
} }
// Ignores egl functions. // Ignores egl functions.
@ -122,10 +108,9 @@ namespace Avalonia.X11.Glx
return IntPtr.Zero; return IntPtr.Zero;
} }
return GlxConverted(proc); return GlxGetProcAddress(proc);
} }
private static readonly Func<string, IntPtr> GlxConverted = ConvertNative(GlxGetProcAddress);
public string[] GetExtensions(IntPtr display) public string[] GetExtensions(IntPtr display)
{ {

2
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@ -50,7 +50,7 @@ namespace Avalonia.LinuxFramebuffer.Output
} }
[DllImport("libEGL.so.1")] [DllImport("libEGL.so.1")]
static extern IntPtr eglGetProcAddress(Utf8Buffer proc); static extern IntPtr eglGetProcAddress(string proc);
private GbmBoUserDataDestroyCallbackDelegate FbDestroyDelegate; private GbmBoUserDataDestroyCallbackDelegate FbDestroyDelegate;
private drmModeModeInfo _mode; private drmModeModeInfo _mode;

24
src/Shared/SourceGeneratorAttributes.cs

@ -14,4 +14,28 @@ namespace Avalonia.SourceGenerator
public string Namespace { get; } public string Namespace { get; }
public Type BaseType { get; } public Type BaseType { get; }
} }
internal class GetProcAddressAttribute : Attribute
{
public GetProcAddressAttribute(string proc)
{
}
public GetProcAddressAttribute(string proc, bool optional = false)
{
}
public GetProcAddressAttribute(bool optional)
{
}
public GetProcAddressAttribute()
{
}
}
} }

28
src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs

@ -27,16 +27,13 @@ namespace Avalonia.Skia
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderbuffer); gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderbuffer);
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture); gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture);
var arr = new int[2];
// Generate FBO // Generate FBO
gl.GenFramebuffers(1, arr); _fbo = gl.GenFramebuffer();
_fbo = arr[0];
gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo); gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo);
// Create a texture to render into // Create a texture to render into
gl.GenTextures(1, arr); _texture = gl.GenTexture();
_texture = arr[0];
gl.BindTexture(GL_TEXTURE_2D, _texture); gl.BindTexture(GL_TEXTURE_2D, _texture);
gl.TexImage2D(GL_TEXTURE_2D, 0, gl.TexImage2D(GL_TEXTURE_2D, 0,
InternalFormat, pixelSize.Width, pixelSize.Height, InternalFormat, pixelSize.Width, pixelSize.Height,
@ -48,8 +45,7 @@ namespace Avalonia.Skia
var success = false; var success = false;
foreach (var useStencil8 in TrueFalse) foreach (var useStencil8 in TrueFalse)
{ {
gl.GenRenderbuffers(1, arr); _depthStencil = gl.GenRenderbuffer();
_depthStencil = arr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthStencil); gl.BindRenderbuffer(GL_RENDERBUFFER, _depthStencil);
if (useStencil8) if (useStencil8)
@ -73,7 +69,7 @@ namespace Avalonia.Skia
else else
{ {
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer);
gl.DeleteRenderbuffers(1, arr); gl.DeleteRenderbuffer(_depthStencil);
} }
} }
@ -83,10 +79,8 @@ namespace Avalonia.Skia
if (!success) if (!success)
{ {
arr[0] = _fbo; gl.DeleteFramebuffer(_fbo);
gl.DeleteFramebuffers(1, arr); gl.DeleteTexture(_texture);
arr[0] = _texture;
gl.DeleteTextures(1, arr);
throw new OpenGlException("Unable to create FBO with stencil"); throw new OpenGlException("Unable to create FBO with stencil");
} }
@ -94,7 +88,7 @@ namespace Avalonia.Skia
new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat())); new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat()));
Surface = SKSurface.Create(_grContext, target, Surface = SKSurface.Create(_grContext, target,
surfaceOrigin, SKColorType.Rgba8888); surfaceOrigin, SKColorType.Rgba8888);
CanBlit = gl.BlitFramebuffer != null; CanBlit = gl.IsBlitFramebufferAvailable;
} }
public void Dispose() public void Dispose()
@ -106,9 +100,9 @@ namespace Avalonia.Skia
var gl = _glContext.GlInterface; var gl = _glContext.GlInterface;
if (_fbo != 0) if (_fbo != 0)
{ {
gl.DeleteFramebuffers(1, new[] { _fbo }); gl.DeleteFramebuffer(_fbo);
gl.DeleteTextures(1, new[] { _texture }); gl.DeleteTexture(_texture);
gl.DeleteRenderbuffers(1, new[] { _depthStencil }); gl.DeleteRenderbuffer(_depthStencil);
_fbo = _texture = _depthStencil = 0; _fbo = _texture = _depthStencil = 0;
} }
} }

2
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@ -54,7 +54,7 @@ namespace Avalonia.Skia
return null; return null;
// Blit feature requires glBlitFramebuffer // Blit feature requires glBlitFramebuffer
if (_glContext.GlInterface.BlitFramebuffer == null) if (!_glContext.GlInterface.IsBlitFramebufferAvailable)
return null; return null;
size = new PixelSize(Math.Max(size.Width, 1), Math.Max(size.Height, 1)); size = new PixelSize(Math.Max(size.Width, 1), Math.Max(size.Height, 1));

11
src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs

@ -101,7 +101,7 @@ namespace Avalonia.Skia
private bool _disposed; private bool _disposed;
private readonly DisposableLock _lock = new DisposableLock(); private readonly DisposableLock _lock = new DisposableLock();
public SharedOpenGlBitmapAttachment(GlOpenGlBitmapImpl bitmap, IGlContext context, Action presentCallback) public unsafe SharedOpenGlBitmapAttachment(GlOpenGlBitmapImpl bitmap, IGlContext context, Action presentCallback)
{ {
_bitmap = bitmap; _bitmap = bitmap;
_context = context; _context = context;
@ -119,7 +119,8 @@ namespace Avalonia.Skia
var gl = _context.GlInterface; var gl = _context.GlInterface;
var textures = new int[2]; var textures = new int[2];
gl.GenTextures(2, textures); fixed (int* ptex = textures)
gl.GenTextures(2, ptex);
_texture = textures[0]; _texture = textures[0];
_frontBuffer = textures[1]; _frontBuffer = textures[1];
@ -178,7 +179,7 @@ namespace Avalonia.Skia
_presentCallback(); _presentCallback();
} }
public void Dispose() public unsafe void Dispose()
{ {
var gl = _context.GlInterface; var gl = _context.GlInterface;
_bitmap.Present(null); _bitmap.Present(null);
@ -191,7 +192,9 @@ namespace Avalonia.Skia
if(_disposed) if(_disposed)
return; return;
_disposed = true; _disposed = true;
gl.DeleteTextures(2, new[] { _texture, _frontBuffer }); var tex = new[] { _texture, _frontBuffer };
fixed (int* ptex = tex)
gl.DeleteTextures(2, ptex);
} }
} }

346
src/tools/DevGenerators/GetProcAddressInitialization.cs

@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Generator;
[Generator(LanguageNames.CSharp)]
public class GetProcAddressInitializationGenerator : IIncrementalGenerator
{
const string GetProcAddressFullName = "global::Avalonia.SourceGenerator.GetProcAddressAttribute";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
/*
Console.WriteLine("PID: " + Process.GetCurrentProcess().Id);
File.WriteAllText("/tmp/pid", "PID: " + Process.GetCurrentProcess().Id);
while (!Debugger.IsAttached)
{
Thread.Sleep(1000);
}*/
var allMethodsWithAttributes = context.SyntaxProvider
.CreateSyntaxProvider(
static (s, _) => s is MethodDeclarationSyntax
{
AttributeLists.Count: > 0,
} md && md.Modifiers.Any(m=>m.IsKind(SyntaxKind.PartialKeyword)),
static (context, _) =>
(IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
var fieldsWithAttribute = allMethodsWithAttributes
.Where(s => s.HasAttributeWithFullyQualifiedName(GetProcAddressFullName));
var all = fieldsWithAttribute.Collect();
context.RegisterSourceOutput(all, static (context, methods) =>
{
foreach (var typeGroup in methods.GroupBy(f => f.ContainingType))
{
var nextContext = 0;
var contexts = new Dictionary<string, int>();
string GetContextNameFromIndex(int c) => "context" + (c == 0 ? "" : c);
string GetContextName(string type)
{
if (contexts.TryGetValue(type, out var idx))
return GetContextNameFromIndex(idx);
if (nextContext != 0)
idx += nextContext;
nextContext++;
return GetContextNameFromIndex(contexts[type] = idx);
}
var classBuilder = new StringBuilder();
if (typeGroup.Key.ContainingNamespace != null)
classBuilder
.AppendLine("using System;")
.Append("namespace ")
.Append(typeGroup.Key.ContainingNamespace)
.AppendLine(";");
classBuilder
.Append("unsafe partial class ")
.AppendLine(typeGroup.Key.Name)
.AppendLine("{");
var initializeBody = new StringBuilder()
.Pad(2)
.AppendLine("var addr = IntPtr.Zero;");
foreach (var method in typeGroup)
{
var isOptional = false;
var first = true;
var fieldName = "_addr_" + method.Name;
var delegateType = BuildDelegateType(method);
void AppendNextAddr()
{
if (first)
{
first = false;
initializeBody.Pad(2);
}
else
initializeBody
.Pad(2)
.Append("if(addr == IntPtr.Zero) ");
}
initializeBody
.Pad(2).Append("// Initializing ").AppendLine(method.Name)
.Pad(2)
.AppendLine("addr = IntPtr.Zero;");
foreach (var attr in method.GetAttributes())
{
if (attr.AttributeClass?.HasFullyQualifiedName(GetProcAddressFullName) == true)
{
string? primaryName = null;
foreach (var arg in attr.ConstructorArguments)
{
if (arg.Value is string name)
primaryName = name;
if (arg.Value is bool opt)
isOptional = opt;
}
if (primaryName != null)
{
AppendNextAddr();
initializeBody
.Append("addr = getProcAddress(\"")
.Append(primaryName)
.AppendLine("\");");
}
}
else
{
if (attr.AttributeClass != null
&& attr.AttributeClass.MemberNames.Contains("GetProcAddress"))
{
var getProcMethod = attr.AttributeClass.GetMembers()
.FirstOrDefault(m => m.Name == "GetProcAddress") as IMethodSymbol;
if (getProcMethod == null || !getProcMethod.IsStatic || getProcMethod.Parameters.Length < 2)
continue;
var contextName =
GetContextName(getProcMethod
.Parameters[1].Type
.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
AppendNextAddr();
initializeBody
.Append("addr = ")
.Append(attr.AttributeClass.GetFullyQualifiedName())
.Append(".GetProcAddress(")
.Append("getProcAddress, ")
.Append(contextName);
var syntaxNode = (AttributeSyntax)attr.ApplicationSyntaxReference.GetSyntax();
foreach (var arg in syntaxNode.ArgumentList.Arguments)
initializeBody.Append(", ").Append(arg.GetText());
initializeBody.AppendLine(");");
}
}
}
if (!isOptional)
{
initializeBody
.Pad(2)
.Append("if (addr == IntPtr.Zero) throw new System.EntryPointNotFoundException(\"")
.Append(fieldName).AppendLine("\");");
}
initializeBody
.Pad(2)
.Append(fieldName)
.Append(" = (")
.Append(delegateType)
.AppendLine(")addr;");
classBuilder
.Pad(1)
.Append(delegateType);
classBuilder
.Append(fieldName)
.AppendLine(";");
classBuilder
.Pad(1)
.Append("public partial ")
.Append(method.ReturnType.GetFullyQualifiedName())
.Append(" ")
.Append(method.Name)
.Append("(");
var firstArg = true;
foreach (var p in method.Parameters)
{
if (firstArg)
firstArg = false;
else
classBuilder.Append(", ");
AppendRefKind(classBuilder, p.RefKind);
classBuilder
.Append(p.Type.GetFullyQualifiedName())
.Append(" @")
.Append(p.Name);
}
classBuilder
.AppendLine(")")
.Pad(1)
.AppendLine("{");
if (isOptional)
classBuilder
.Pad(2)
.Append("if (")
.Append(fieldName)
.Append(" == null) throw new System.EntryPointNotFoundException(\"")
.Append(method.Name)
.AppendLine("\");");
foreach(var p in method.Parameters)
if (NeedsPin(p.Type))
classBuilder.Pad(2)
.Append("fixed(")
.Append(MapToNative(p.Type))
.Append(" @__p_")
.Append(p.Name)
.Append(" = ")
.Append(p.Name)
.AppendLine(")");
classBuilder.Pad(2);
if (!method.ReturnsVoid)
classBuilder.Append("return ");
var invokeBuilder = new StringBuilder();
invokeBuilder
.Append(fieldName)
.Append("(");
firstArg = true;
foreach (var p in method.Parameters)
{
if (firstArg)
firstArg = false;
else
invokeBuilder.Append(", ");
AppendRefKind(invokeBuilder, p.RefKind);
invokeBuilder
.Append("@")
.Append(ConvertToNative(p.Name, p.Type));
}
invokeBuilder.Append(")");
classBuilder.Append(ConvertToManaged(method.ReturnType, invokeBuilder.ToString()));
classBuilder.AppendLine(";").Pad(1).AppendLine("}");
if (isOptional)
classBuilder
.Pad(1)
.Append("public bool Is")
.Append(method.Name)
.Append("Available => ")
.Append(fieldName)
.AppendLine(" != null;");
}
classBuilder
.Pad(1)
.Append("void Initialize(Func<string, IntPtr> getProcAddress");
foreach (var kv in contexts.OrderBy(x => x.Value))
{
classBuilder
.Append(", ")
.Append(kv.Key)
.Append(" ")
.Append(GetContextNameFromIndex(kv.Value));
}
classBuilder.AppendLine(")").Pad(1).AppendLine("{");
classBuilder.Append(initializeBody.ToString());
classBuilder.Append("}\n}");
context.AddSource(typeGroup.Key.GetFullyQualifiedName().Replace(":", ""), classBuilder.ToString());
}
});
}
static StringBuilder AppendRefKind(StringBuilder sb, RefKind kind)
{
if (kind == RefKind.Ref)
sb.Append("ref ");
if (kind == RefKind.Out)
sb.Append("out ");
return sb;
}
static bool NeedsPin(ITypeSymbol type)
{
if (type.TypeKind == TypeKind.Array)
return true;
return false;
}
static string ConvertToNative(string name, ITypeSymbol type)
{
if (NeedsPin(type))
return "__p_" + name;
if (IsBool(type))
return $"{name} ? 1 : 0";
return name;
}
static string ConvertToManaged(ITypeSymbol type, string expr)
{
if (IsBool(type))
return expr + " != 0";
return expr;
}
static bool IsBool(ITypeSymbol type) => type.GetFullyQualifiedName() == "global::System.Boolean" ||
type.GetFullyQualifiedName() == "bool";
static string MapToNative(ITypeSymbol type)
{
if (type.TypeKind == TypeKind.Array)
return ((IArrayTypeSymbol)type).ElementType.GetFullyQualifiedName() + "*";
if (IsBool(type))
return "int";
return type.GetFullyQualifiedName();
}
static string BuildDelegateType(IMethodSymbol method)
{
StringBuilder name = new("delegate* unmanaged[Stdcall]<");
var firstArg = true;
void AppendArg(string a, RefKind kind)
{
if (firstArg)
firstArg = false;
else
name.Append(",");
AppendRefKind(name, kind);
name.Append(a);
}
foreach (var p in method.Parameters)
{
AppendArg(MapToNative(p.Type), p.RefKind);
}
AppendArg(MapToNative(method.ReturnType), RefKind.None);
name.Append(">");
return name.ToString();
}
}

31
src/tools/DevGenerators/Helpers.cs

@ -0,0 +1,31 @@
using System.Collections.Immutable;
using System.Text;
using Microsoft.CodeAnalysis;
namespace Generator;
static class Helpers
{
public static StringBuilder Pad(this StringBuilder sb, int count) => sb.Append(' ', count * 4);
public static string GetFullyQualifiedName(this ISymbol symbol)
{
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}
public static bool HasFullyQualifiedName(this ISymbol symbol, string name)
{
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == name;
}
public static bool HasAttributeWithFullyQualifiedName(this ISymbol symbol, string name)
{
ImmutableArray<AttributeData> attributes = symbol.GetAttributes();
foreach (AttributeData attribute in attributes)
if (attribute.AttributeClass?.HasFullyQualifiedName(name) == true)
return true;
return false;
}
}
Loading…
Cancel
Save