Browse Source

Use codegen to populate OpenGL functions

Nikita Tsukanov 3 years ago
parent
commit
952b80df2a

+ 7 - 37
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@@ -90,7 +90,6 @@ namespace ControlCatalog.Pages
         private int _vertexBufferObject;
         private int _indexBufferObject;
         private int _vertexArrayObject;
-        private GlExtrasInterface _glExt;
 
         private string GetShader(bool fragment, string shader)
         {
@@ -258,7 +257,6 @@ namespace ControlCatalog.Pages
         protected unsafe override void OnOpenGlInit(GlInterface GL, int fb)
         {
             CheckError(GL);
-            _glExt = new GlExtrasInterface(GL);
 
             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_STATIC_DRAW);
             CheckError(GL);
-            _vertexArrayObject = _glExt.GenVertexArray();
-            _glExt.BindVertexArray(_vertexArrayObject);
+            _vertexArrayObject = GL.GenVertexArray();
+            GL.BindVertexArray(_vertexArrayObject);
             CheckError(GL);
             GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT,
                 0, vertexSize, IntPtr.Zero);
@@ -316,12 +314,13 @@ namespace ControlCatalog.Pages
             // Unbind everything
             GL.BindBuffer(GL_ARRAY_BUFFER, 0);
             GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-            _glExt.BindVertexArray(0);
+            GL.BindVertexArray(0);
             GL.UseProgram(0);
 
             // Delete all resources.
-            GL.DeleteBuffers(2, new[] { _vertexBufferObject, _indexBufferObject });
-            _glExt.DeleteVertexArrays(1, new[] { _vertexArrayObject });
+            GL.DeleteBuffer(_vertexBufferObject);
+            GL.DeleteBuffer(_indexBufferObject);
+            GL.DeleteVertexArray(_vertexArrayObject);
             GL.DeleteProgram(_shaderProgram);
             GL.DeleteShader(_fragmentShader);
             GL.DeleteShader(_vertexShader);
@@ -338,7 +337,7 @@ namespace ControlCatalog.Pages
 
             GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject);
             GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject);
-            _glExt.BindVertexArray(_vertexArrayObject);
+            GL.BindVertexArray(_vertexArrayObject);
             GL.UseProgram(_shaderProgram);
             CheckError(GL);
             var projection =
@@ -369,34 +368,5 @@ namespace ControlCatalog.Pages
             if (_disco > 0.01)
                 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];
-            }
-        }
     }
 }

+ 2 - 2
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

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

+ 1 - 0
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

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

+ 5 - 9
src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

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

+ 1 - 1
src/Avalonia.OpenGL/Egl/EglContext.cs

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

+ 2 - 2
src/Avalonia.OpenGL/Egl/EglDisplay.cs

@@ -34,9 +34,9 @@ namespace Avalonia.OpenGL.Egl
             }
             else
             {
-                if (egl.GetPlatformDisplayEXT == null)
+                if (!egl.IsGetPlatformDisplayExtAvailable)
                     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)

+ 83 - 142
src/Avalonia.OpenGL/Egl/EglInterface.cs

@@ -2,31 +2,26 @@
 using System.Runtime.InteropServices;
 using Avalonia.Platform;
 using Avalonia.Platform.Interop;
+using Avalonia.SourceGenerator;
 
 namespace Avalonia.OpenGL.Egl
 {
-    public class EglInterface : GlInterfaceBase
+    public unsafe partial class EglInterface
     {
-        public EglInterface() : base(Load())
+        public EglInterface(Func<string, IntPtr> getProcAddress)
         {
-            
-        }
-
-        public EglInterface(Func<Utf8Buffer,IntPtr> getProcAddress) : base(getProcAddress)
-        {
-            
+            Initialize(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()
         {
             var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem;
@@ -46,119 +41,75 @@ namespace Avalonia.OpenGL.Egl
         }
 
         // ReSharper disable UnassignedGetOnlyAutoProperty
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate int EglGetError();
-        [GlEntryPoint("eglGetError")]
-        public EglGetError GetError { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
-        [GlEntryPoint("eglGetDisplay")]
-        public EglGetDisplay GetDisplay { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate IntPtr EglGetPlatformDisplayEXT(int platform, IntPtr nativeDisplay, int[] attrs);
-        [GlEntryPoint("eglGetPlatformDisplayEXT")]
-        [GlOptionalEntryPoint]
-        public EglGetPlatformDisplayEXT GetPlatformDisplayEXT { get; }
-
-        [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; }
+        
+        [GetProcAddress("eglGetError")]
+        public partial int GetError();
+        
+        [GetProcAddress("eglGetDisplay")]
+        public partial IntPtr GetDisplay(IntPtr nativeDisplay);
+        
+        [GetProcAddress("eglGetPlatformDisplayEXT", true)]
+        public partial IntPtr GetPlatformDisplayExt(int platform, IntPtr nativeDisplay, int[] attrs);
+
+        [GetProcAddress("eglInitialize")]        
+        public partial bool Initialize(IntPtr display, out int major, out int minor);
+
+        [GetProcAddress("eglGetProcAddress")]        
+        public partial IntPtr GetProcAddress(IntPtr proc);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate IntPtr EglCreateContext(IntPtr display, IntPtr config,
+        [GetProcAddress("eglBindAPI")]
+        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);
-        [GlEntryPoint("eglCreateContext")]
-        public EglCreateContext CreateContext { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate bool EglDestroyContext(IntPtr display, IntPtr context);
-        [GlEntryPoint("eglDestroyContext")]
-        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("eglDestroyContext")]
+        public partial bool DestroyContext(IntPtr display, IntPtr context);
+        
+        [GetProcAddress("eglCreatePbufferSurface")]
+        public partial IntPtr CreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
 
+        [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)
         {
             var rv = QueryStringNative(display, i);
@@ -166,25 +117,15 @@ namespace Avalonia.OpenGL.Egl
                 return null;
             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);
-        [GlEntryPoint("eglCreatePbufferFromClientBuffer")]
-
-        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
+        
+        [GetProcAddress("eglQueryDeviceAttribEXT", true)]
+        public partial bool QueryDeviceAttribExt(IntPtr display, int attr, out IntPtr res);
     }
 }

+ 11 - 33
src/Avalonia.OpenGL/GlBasicInfoInterface.cs

@@ -3,46 +3,24 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.InteropServices;
 using Avalonia.Platform.Interop;
+using Avalonia.SourceGenerator;
 
 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<Utf8Buffer, IntPtr> nativeGetProcAddress) : base(nativeGetProcAddress, null)
-        {
+        public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress){
+            Initialize(getProcAddress);
         }
-
-        [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>
-    {
-        public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress, TContextInfo context) : base(getProcAddress, context)
-        {
-        }
+        [GetProcAddress("glGetIntegerv")]
+        public partial void GetIntegerv(int name, out int rv);
 
-        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; }
-        
-        [GlEntryPoint("glGetStringi")]
-        public GlBasicInfoInterface.GlGetStringi GetStringiNative { get; }
+        [GetProcAddress("glGetString")]
+        public partial IntPtr GetStringNative(int v);
+
+        [GetProcAddress("glGetStringi")]
+        public partial IntPtr GetStringiNative(int v, int v1);
 
         public string GetString(int v)
         {

+ 20 - 83
src/Avalonia.OpenGL/GlEntryPointAttribute.cs

@@ -2,117 +2,54 @@ using System;
 
 namespace Avalonia.OpenGL
 {
-    public interface IGlEntryPointAttribute
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    class GlMinVersionEntryPoint : Attribute
     {
-        IntPtr GetProcAddress(Func<string, IntPtr> getProcAddress);
-    }
-    
-    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)
+        public GlMinVersionEntryPoint(string entry, int minVersionMajor, int minVersionMinor)
         {
-            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,
-            int minVersionMinor)
+        public GlMinVersionEntryPoint(string entry, int minVersionMajor, int minVersionMinor, GlProfileType profile)
         {
-            _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;
-            if(context.Version.Major<_minVersionMajor)
+            if(context.Version.Major<minVersionMajor)
                 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 getProcAddress(_entry);
+            return getProcAddress(entry);
         }
     }
     
-    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
-    public class GlExtensionEntryPoint : Attribute, IGlEntryPointAttribute<GlInterface.GlContextInfo>
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    class GlExtensionEntryPoint : Attribute
     {
-        private readonly string _entry;
-        private readonly GlProfileType? _profile;
-        private readonly string _extension;
-
-        public GlExtensionEntryPoint(string entry, GlProfileType profile, string extension)
+        public GlExtensionEntryPoint(string entry, 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
-            if (_profile.HasValue && _profile != context.Version.Type)
+            if (profile.HasValue && profile != context.Version.Type)
                 return IntPtr.Zero;
 
             // Check if extension is supported by the current context
-            if (!context.Extensions.Contains(_extension))
+            if (!context.Extensions.Contains(extension))
                 return IntPtr.Zero;
 
-            return getProcAddress(_entry);
+            return getProcAddress(entry);
         }
     }
 }

+ 219 - 275
src/Avalonia.OpenGL/GlInterface.cs

@@ -3,14 +3,14 @@ using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Text;
 using Avalonia.Platform.Interop;
+using Avalonia.SourceGenerator;
 using static Avalonia.OpenGL.GlConsts;
 
 namespace Avalonia.OpenGL
 {
-    public delegate IntPtr GlGetProcAddressDelegate(string procName);
-    
-    public unsafe class GlInterface : GlBasicInfoInterface<GlInterface.GlContextInfo>
+    public unsafe partial class GlInterface : GlBasicInfoInterface
     {
+        private readonly Func<string, IntPtr> _getProcAddress;
         public string Version { get; }
         public string Vendor { 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;
             Version = GetString(GlConsts.GL_VERSION);
             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(
@@ -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) =>
-            new GlInterface(version, getProcAddress);
-
-        
-        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)
+        [GetProcAddress("glDeleteFramebuffers")]
+        public partial void DeleteFramebuffers(int count, int* framebuffers);
+
+        public void DeleteFramebuffer(int fb)
         {
-            var ptr = GetStringNative(v);
-            if (ptr != IntPtr.Zero)
-                return Marshal.PtrToStringAnsi(ptr);
-            return null;
+            DeleteFramebuffers(1, &fb);
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGetIntegerv(int name, out int rv);
-        [GlEntryPoint("glGetIntegerv")]
-        public GlGetIntegerv GetIntegerv { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGenFramebuffers(int count, int[] res);
-        [GlEntryPoint("glGenFramebuffers")]
-        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,
+        [GetProcAddress("glBindFramebuffer")]
+        public partial void BindFramebuffer(int target, int fb);
+
+        [GetProcAddress("glCheckFramebufferStatus")]
+        public partial int CheckFramebufferStatus(int target);
+
+        [GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0), GetProcAddress(true)]
+        public partial void BlitFramebuffer(int srcX0,
             int srcY0,
             int srcX1,
             int srcY1,
@@ -143,89 +111,78 @@ namespace Avalonia.OpenGL
             int dstY1,
             int mask,
             int filter);
-        [GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0), GlOptionalEntryPoint]
-        public GlBlitFramebuffer BlitFramebuffer { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGenRenderbuffers(int count, int[] res);
-        [GlEntryPoint("glGenRenderbuffers")]
-        public GlGenRenderbuffers GenRenderbuffers { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlDeleteRenderbuffers(int count, int[] renderbuffers);
-        [GlEntryPoint("glDeleteRenderbuffers")]
-        public GlDeleteTextures DeleteRenderbuffers { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlBindRenderbuffer(int target, int fb);
-        [GlEntryPoint("glBindRenderbuffer")]
-        public GlBindRenderbuffer BindRenderbuffer { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlRenderbufferStorage(int target, int internalFormat, int width, int height);
-        [GlEntryPoint("glRenderbufferStorage")]
-        public GlRenderbufferStorage RenderbufferStorage { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlFramebufferRenderbuffer(int target, int attachment,
+
+
+        [GetProcAddress("glGenRenderbuffers")]
+        public partial void GenRenderbuffers(int count, int* res);
+
+        public int GenRenderbuffer()
+        {
+            int rv = 0;
+            GenRenderbuffers(1, &rv);
+            return rv;
+        }
+
+        [GetProcAddress("glDeleteRenderbuffers")]
+        public partial void DeleteRenderbuffers(int count, int* renderbuffers);
+
+        public void DeleteRenderbuffer(int renderbuffer)
+        {
+            DeleteRenderbuffers(1, &renderbuffer);
+        }
+
+        [GetProcAddress("glBindRenderbuffer")]
+        public partial void BindRenderbuffer(int target, int fb);
+
+        [GetProcAddress("glRenderbufferStorage")]
+        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);
-        [GlEntryPoint("glFramebufferRenderbuffer")]
-        public GlFramebufferRenderbuffer FramebufferRenderbuffer { get; }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGenTextures(int count, int[] res);
-        [GlEntryPoint("glGenTextures")]
-        public GlGenTextures GenTextures { get; }
+        [GetProcAddress("glGenTextures")]
+        public partial void GenTextures(int count, int* res);
+
+        public int GenTexture()
+        {
+            int rv = 0;
+            GenTextures(1, &rv);
+            return rv;
+        }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlBindTexture(int target, int fb);
-        [GlEntryPoint("glBindTexture")]
-        public GlBindTexture BindTexture { get; }
+        [GetProcAddress("glBindTexture")]
+        public partial void BindTexture(int target, int fb);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlActiveTexture(int texture);
-        [GlEntryPoint("glActiveTexture")]
-        public GlActiveTexture ActiveTexture { get; }
+        [GetProcAddress("glActiveTexture")]
+        public partial void ActiveTexture(int texture);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlDeleteTextures(int count, int[] textures);
-        [GlEntryPoint("glDeleteTextures")]
-        public GlDeleteTextures DeleteTextures { get; }
+        [GetProcAddress("glDeleteTextures")]
+        public partial void DeleteTextures(int count, int* textures);
 
+        public void DeleteTexture(int texture) => DeleteTextures(1, &texture);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlTexImage2D(int target, int level, int internalFormat, int width, int height, int border,
+        [GetProcAddress("glTexImage2D")]
+        public partial void TexImage2D(int target, int level, int internalFormat, int width, int height, int border,
             int format, int type, IntPtr data);
-        [GlEntryPoint("glTexImage2D")]
-        public GlTexImage2D TexImage2D { get; }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlCopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y,
+        [GetProcAddress("glCopyTexSubImage2D")]
+        public partial void CopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y,
             int width, int height);
-        
-        [GlEntryPoint("glCopyTexSubImage2D")]
-        public GlCopyTexSubImage2D CopyTexSubImage2D { get; }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlTexParameteri(int target, int name, int value);
-        [GlEntryPoint("glTexParameteri")]
-        public GlTexParameteri TexParameteri { get; }
+        [GetProcAddress("glTexParameteri")]
+        public partial void TexParameteri(int target, int name, int value);
 
-        [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);
-        [GlEntryPoint("glFramebufferTexture2D")]
-        public GlFramebufferTexture2D FramebufferTexture2D { get; }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate int GlCreateShader(int shaderType);
-        [GlEntryPoint("glCreateShader")]
-        public GlCreateShader CreateShader { get; }
+        [GetProcAddress("glCreateShader")]
+        public partial int CreateShader(int shaderType);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlShaderSource(int shader, int count, IntPtr strings, IntPtr lengths);
-        [GlEntryPoint("glShaderSource")]
-        public GlShaderSource ShaderSource { get; }
+        [GetProcAddress("glShaderSource")]
+        public partial void ShaderSource(int shader, int count, IntPtr strings, IntPtr lengths);
 
         public void ShaderSourceString(int shader, string source)
         {
@@ -237,20 +194,14 @@ namespace Avalonia.OpenGL
             }
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlCompileShader(int shader);
-        [GlEntryPoint("glCompileShader")]
-        public GlCompileShader CompileShader { get; }
+        [GetProcAddress("glCompileShader")]
+        public partial void CompileShader(int shader);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGetShaderiv(int shader, int name, int* parameters);
-        [GlEntryPoint("glGetShaderiv")]
-        public GlGetShaderiv GetShaderiv { get; }
+        [GetProcAddress("glGetShaderiv")]
+        public partial void GetShaderiv(int shader, int name, int* parameters);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGetShaderInfoLog(int shader, int maxLength, out int length, void*infoLog);
-        [GlEntryPoint("glGetShaderInfoLog")]
-        public GlGetShaderInfoLog GetShaderInfoLog { get; }
+        [GetProcAddress("glGetShaderInfoLog")]
+        public partial void GetShaderInfoLog(int shader, int maxLength, out int length, void* infoLog);
 
         public unsafe string CompileShaderAndGetError(int shader, string source)
         {
@@ -268,33 +219,24 @@ namespace Avalonia.OpenGL
             int len;
             fixed (void* ptr = logData)
                 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)]
-        public delegate void GlAttachShader(int program, int shader);
-        [GlEntryPoint("glAttachShader")]
-        public GlAttachShader AttachShader { get; }
+        [GetProcAddress("glCreateProgram")]
+        public partial int CreateProgram();
+
+        [GetProcAddress("glAttachShader")]
+        public partial void AttachShader(int program, int shader);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlLinkProgram(int program);
-        [GlEntryPoint("glLinkProgram")]
-        public GlLinkProgram LinkProgram { get; }
+        [GetProcAddress("glLinkProgram")]
+        public partial void LinkProgram(int program);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGetProgramiv(int program, int name, int* parameters);
-        [GlEntryPoint("glGetProgramiv")]
-        public GlGetProgramiv GetProgramiv { get; }
+        [GetProcAddress("glGetProgramiv")]
+        public partial void GetProgramiv(int program, int name, int* parameters);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGetProgramInfoLog(int program, int maxLength, out int len, void* infoLog);
-        [GlEntryPoint("glGetProgramInfoLog")]
-        public GlGetProgramInfoLog GetProgramInfoLog { get; }
+        [GetProcAddress("glGetProgramInfoLog")]
+        public partial void GetProgramInfoLog(int program, int maxLength, out int len, void* infoLog);
 
         public unsafe string LinkProgramAndGetError(int program)
         {
@@ -309,13 +251,11 @@ namespace Avalonia.OpenGL
             int len;
             fixed (void* ptr = logData)
                 GetProgramInfoLog(program, logLength, out len, ptr);
-            return Encoding.UTF8.GetString(logData,0, len);
+            return Encoding.UTF8.GetString(logData, 0, len);
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlBindAttribLocation(int program, int index, IntPtr name);
-        [GlEntryPoint("glBindAttribLocation")]
-        public GlBindAttribLocation BindAttribLocation { get; }
+        [GetProcAddress("glBindAttribLocation")]
+        public partial void BindAttribLocation(int program, int index, IntPtr name);
 
         public void BindAttribLocationString(int program, int index, string name)
         {
@@ -323,32 +263,24 @@ namespace Avalonia.OpenGL
                 BindAttribLocation(program, index, b.DangerousGetHandle());
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlGenBuffers(int len, int[] rv);
-        [GlEntryPoint("glGenBuffers")]
-        public GlGenBuffers GenBuffers { get; }
+        [GetProcAddress("glGenBuffers")]
+        public partial void GenBuffers(int len, int* rv);
 
         public int GenBuffer()
         {
-            var rv = new int[1];
-            GenBuffers(1, rv);
-            return rv[0];
+            int rv;
+            GenBuffers(1, &rv);
+            return rv;
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlBindBuffer(int target, int buffer);
-        [GlEntryPoint("glBindBuffer")]
-        public GlBindBuffer BindBuffer { get; }
+        [GetProcAddress("glBindBuffer")]
+        public partial void BindBuffer(int target, int buffer);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlBufferData(int target, IntPtr size, IntPtr data, int usage);
-        [GlEntryPoint("glBufferData")]
-        public GlBufferData BufferData { get; }
+        [GetProcAddress("glBufferData")]
+        public partial void BufferData(int target, IntPtr size, IntPtr data, int usage);
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate int GlGetAttribLocation(int program, IntPtr name);
-        [GlEntryPoint("glGetAttribLocation")]
-        public GlGetAttribLocation GetAttribLocation { get; }
+        [GetProcAddress("glGetAttribLocation")]
+        public partial int GetAttribLocation(int program, IntPtr name);
 
         public int GetAttribLocationString(int program, string name)
         {
@@ -356,36 +288,24 @@ namespace Avalonia.OpenGL
                 return GetAttribLocation(program, b.DangerousGetHandle());
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlVertexAttribPointer(int index, int size, int type,
+        [GetProcAddress("glVertexAttribPointer")]
+        public partial void VertexAttribPointer(int index, int size, int type,
             int normalized, int stride, IntPtr pointer);
-        [GlEntryPoint("glVertexAttribPointer")]
-        public GlVertexAttribPointer VertexAttribPointer { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlEnableVertexAttribArray(int index);
-        [GlEntryPoint("glEnableVertexAttribArray")]
-        public GlEnableVertexAttribArray EnableVertexAttribArray { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlUseProgram(int program);
-        [GlEntryPoint("glUseProgram")]
-        public GlUseProgram UseProgram { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlDrawArrays(int mode, int first, IntPtr count);
-        [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; }
+
+        [GetProcAddress("glEnableVertexAttribArray")]
+        public partial void EnableVertexAttribArray(int index);
+
+        [GetProcAddress("glUseProgram")]
+        public partial void UseProgram(int program);
+
+        [GetProcAddress("glDrawArrays")]
+        public partial void DrawArrays(int mode, int first, IntPtr count);
+
+        [GetProcAddress("glDrawElements")]
+        public partial void DrawElements(int mode, int count, int type, IntPtr indices);
+
+        [GetProcAddress("glGetUniformLocation")]
+        public partial int GetUniformLocation(int program, IntPtr name);
 
         public int GetUniformLocationString(int program, string name)
         {
@@ -393,41 +313,65 @@ namespace Avalonia.OpenGL
                 return GetUniformLocation(program, b.DangerousGetHandle());
         }
 
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlUniform1f(int location, float falue);
-        [GlEntryPoint("glUniform1f")]
-        public GlUniform1f Uniform1f { get; }
-
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlUniformMatrix4fv(int location, int count, bool transpose, void* value);
-        [GlEntryPoint("glUniformMatrix4fv")]
-        public GlUniformMatrix4fv UniformMatrix4fv { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlEnable(int what);
-        [GlEntryPoint("glEnable")]
-        public GlEnable Enable { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlDeleteBuffers(int count, int[] buffers);
-        [GlEntryPoint("glDeleteBuffers")]
-        public GlDeleteBuffers DeleteBuffers { get; }
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        public delegate void GlDeleteProgram(int program);
-        [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; }
+        [GetProcAddress("glUniform1f")]
+        public partial void Uniform1f(int location, float falue);
+
+
+        [GetProcAddress("glUniformMatrix4fv")]
+        public partial void UniformMatrix4fv(int location, int count, bool transpose, void* value);
+
+        [GetProcAddress("glEnable")]
+        public partial void Enable(int what);
+
+        [GetProcAddress("glDeleteBuffers")]
+        public partial void DeleteBuffers(int count, int* buffers);
+
+        public void DeleteBuffer(int buffer) => DeleteBuffers(1, &buffer);
+
+        [GetProcAddress("glDeleteProgram")]
+        public partial void DeleteProgram(int program);
+
+        [GetProcAddress("glDeleteShader")]
+        public partial void DeleteShader(int shader);
+
+        [GetProcAddress("glGetRenderbufferParameteriv")]
+        public partial void GLGetRenderbufferParameteriv(int target, int name, int* value);
         // 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;
+            });
+        }
     }
-}
+}

+ 0 - 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);
-    }
-}

+ 1 - 1
src/Avalonia.X11/Avalonia.X11.csproj

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

+ 48 - 63
src/Avalonia.X11/Glx/Glx.cs

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

+ 1 - 1
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

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

+ 24 - 0
src/Shared/SourceGeneratorAttributes.cs

@@ -14,4 +14,28 @@ namespace Avalonia.SourceGenerator
         public string Namespace { 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()
+        {
+
+        }
+    }
 }

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

+ 1 - 1
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

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

+ 7 - 4
src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs

@@ -101,7 +101,7 @@ namespace Avalonia.Skia
         private bool _disposed;
         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;
             _context = context;
@@ -119,7 +119,8 @@ namespace Avalonia.Skia
                     var gl = _context.GlInterface;
                     
                     var textures = new int[2];
-                    gl.GenTextures(2, textures);
+                    fixed (int* ptex = textures)
+                        gl.GenTextures(2, ptex);
                     _texture = textures[0];
                     _frontBuffer = textures[1];
 
@@ -178,7 +179,7 @@ namespace Avalonia.Skia
             _presentCallback();
         }
 
-        public void Dispose()
+        public unsafe void Dispose()
         {
             var gl = _context.GlInterface;
             _bitmap.Present(null);
@@ -191,7 +192,9 @@ namespace Avalonia.Skia
                 if(_disposed)
                     return;
                 _disposed = true;
-                gl.DeleteTextures(2, new[] { _texture, _frontBuffer });
+                var tex = new[] { _texture, _frontBuffer };
+                fixed (int* ptex = tex)
+                    gl.DeleteTextures(2, ptex);
             }
         }
 

+ 346 - 0
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 - 0
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;
+    }
+}