Browse Source

Merge pull request #2205 from mstr2/opengl-error-messages

Added the option to include the OpenGL error code description when constructing OpenGlException
Nikita Tsukanov 6 years ago
parent
commit
5de3094425

+ 3 - 3
src/Avalonia.OpenGL/EglContext.cs

@@ -31,14 +31,14 @@ namespace Avalonia.OpenGL
         public void MakeCurrent()
         {
             if (!_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, Context))
-                throw new OpenGlException("eglMakeCurrent failed");
+                throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
         }
         
         public void MakeCurrent(EglSurface surface)
         {
-            var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
+            var surf = surface?.DangerousGetHandle() ?? OffscreenSurface;
             if (!_egl.MakeCurrent(_disp.Handle, surf, surf, Context))
-                throw new OpenGlException("eglMakeCurrent failed");
+                throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
         }
     }
 }

+ 8 - 9
src/Avalonia.OpenGL/EglDisplay.cs

@@ -1,5 +1,4 @@
 using System;
-using System.ComponentModel;
 using System.Runtime.InteropServices;
 using Avalonia.Platform.Interop;
 using static Avalonia.OpenGL.EglConsts;
@@ -34,11 +33,11 @@ namespace Avalonia.OpenGL
             if (_display == IntPtr.Zero)
                 _display = _egl.GetDisplay(IntPtr.Zero);
             
-            if(_display == IntPtr.Zero)
-                throw new OpenGlException("eglGetDisplay failed");
-            
+            if (_display == IntPtr.Zero)
+                throw OpenGlException.GetFormattedException("eglGetDisplay", _egl);
+
             if (!_egl.Initialize(_display, out var major, out var minor))
-                throw new OpenGlException("eglInitialize failed");
+                throw OpenGlException.GetFormattedException("eglInitialize", _egl);
 
             foreach (var cfg in new[]
             {
@@ -113,7 +112,7 @@ namespace Avalonia.OpenGL
             var shareCtx = (EglContext)share;
             var ctx = _egl.CreateContext(_display, _config, shareCtx?.Context ?? IntPtr.Zero, _contextAttributes);
             if (ctx == IntPtr.Zero)
-                throw new OpenGlException("eglCreateContext failed");
+                throw OpenGlException.GetFormattedException("eglCreateContext", _egl);
             var surf = _egl.CreatePBufferSurface(_display, _config, new[]
             {
                 EGL_WIDTH, 1,
@@ -121,7 +120,7 @@ namespace Avalonia.OpenGL
                 EGL_NONE
             });
             if (surf == IntPtr.Zero)
-                throw new OpenGlException("eglCreatePbufferSurface failed");
+                throw OpenGlException.GetFormattedException("eglCreatePBufferSurface", _egl);
             var rv = new EglContext(this, _egl, ctx, surf);
             rv.MakeCurrent(null);
             return rv;
@@ -130,14 +129,14 @@ namespace Avalonia.OpenGL
         public void ClearContext()
         {
             if (!_egl.MakeCurrent(_display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
-                throw new OpenGlException("eglMakeCurrent failed");
+                throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
         }
 
         public EglSurface CreateWindowSurface(IntPtr window)
         {
             var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
             if (s == IntPtr.Zero)
-                throw new OpenGlException("eglCreateWindowSurface failed");
+                throw OpenGlException.GetFormattedException("eglCreateWindowSurface", _egl);
             return new EglSurface(this, _egl, s);
         }
 

+ 21 - 0
src/Avalonia.OpenGL/EglErrors.cs

@@ -0,0 +1,21 @@
+namespace Avalonia.OpenGL
+{
+    public enum EglErrors
+    {
+        EGL_SUCCESS = EglConsts.EGL_SUCCESS,
+        EGL_NOT_INITIALIZED = EglConsts.EGL_NOT_INITIALIZED,
+        EGL_BAD_ACCESS = EglConsts.EGL_BAD_ACCESS,
+        EGL_BAD_ALLOC = EglConsts.EGL_BAD_ALLOC,
+        EGL_BAD_ATTRIBUTE = EglConsts.EGL_BAD_ATTRIBUTE,
+        EGL_BAD_CONTEXT = EglConsts.EGL_BAD_CONTEXT,
+        EGL_BAD_CONFIG = EglConsts.EGL_BAD_CONFIG,
+        EGL_BAD_CURRENT_SURFACE = EglConsts.EGL_BAD_CURRENT_SURFACE,
+        EGL_BAD_DISPLAY = EglConsts.EGL_BAD_DISPLAY,
+        EGL_BAD_SURFACE = EglConsts.EGL_BAD_SURFACE,
+        EGL_BAD_MATCH = EglConsts.EGL_BAD_MATCH,
+        EGL_BAD_PARAMETER = EglConsts.EGL_BAD_PARAMETER,
+        EGL_BAD_NATIVE_PIXMAP = EglConsts.EGL_BAD_NATIVE_PIXMAP,
+        EGL_BAD_NATIVE_WINDOW = EglConsts.EGL_BAD_NATIVE_WINDOW,
+        EGL_CONTEXT_LOST = EglConsts.EGL_CONTEXT_LOST
+    }
+}

+ 5 - 2
src/Avalonia.OpenGL/EglInterface.cs

@@ -1,7 +1,6 @@
 using System;
 using Avalonia.Platform;
 using Avalonia.Platform.Interop;
-using static Avalonia.OpenGL.EglConsts;
 
 namespace Avalonia.OpenGL
 {
@@ -32,8 +31,12 @@ namespace Avalonia.OpenGL
             var lib = dyn.LoadLibrary(library);
             return (s, o) => dyn.GetProcAddress(lib, s, o);
         }
-        
+
         // ReSharper disable UnassignedGetOnlyAutoProperty
+        public delegate int EglGetError();
+        [EntryPoint("eglGetError")]
+        public EglGetError GetError { get; }
+
         public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
         [EntryPoint("eglGetDisplay")]
         public EglGetDisplay GetDisplay { get; }

+ 3 - 0
src/Avalonia.OpenGL/GlConsts.cs

@@ -456,12 +456,15 @@ namespace Avalonia.OpenGL
         public const int GL_RENDERER = 0x1F01;
         public const int GL_VERSION = 0x1F02;
         public const int GL_EXTENSIONS = 0x1F03;
+        public const int GL_NO_ERROR = 0;
         public const int GL_INVALID_ENUM = 0x0500;
         public const int GL_INVALID_VALUE = 0x0501;
         public const int GL_INVALID_OPERATION = 0x0502;
         public const int GL_STACK_OVERFLOW = 0x0503;
         public const int GL_STACK_UNDERFLOW = 0x0504;
         public const int GL_OUT_OF_MEMORY = 0x0505;
+        public const int GL_INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+        public const int GL_CONTEXT_LOST = 0x0507;
         public const int GL_CURRENT_BIT = 0x00000001;
         public const int GL_POINT_BIT = 0x00000002;
         public const int GL_LINE_BIT = 0x00000004;

+ 15 - 0
src/Avalonia.OpenGL/GlErrors.cs

@@ -0,0 +1,15 @@
+namespace Avalonia.OpenGL
+{
+    public enum GlErrors
+    {
+        GL_NO_ERROR = GlConsts.GL_NO_ERROR,
+        GL_INVALID_ENUM = GlConsts.GL_INVALID_ENUM,
+        GL_INVALID_VALUE = GlConsts.GL_INVALID_VALUE,
+        GL_INVALID_OPERATION = GlConsts.GL_INVALID_OPERATION,
+        GL_INVALID_FRAMEBUFFER_OPERATION = GlConsts.GL_INVALID_FRAMEBUFFER_OPERATION,
+        GL_STACK_OVERFLOW = GlConsts.GL_STACK_OVERFLOW,
+        GL_STACK_UNDERFLOW = GlConsts.GL_STACK_UNDERFLOW,
+        GL_OUT_OF_MEMORY = GlConsts.GL_OUT_OF_MEMORY,
+        GL_CONTEXT_LOST = GlConsts.GL_CONTEXT_LOST
+    }
+}

+ 4 - 1
src/Avalonia.OpenGL/GlInterface.cs

@@ -19,7 +19,10 @@ namespace Avalonia.OpenGL
         public T GetProcAddress<T>(string proc) => Marshal.GetDelegateForFunctionPointer<T>(GetProcAddress(proc));
 
         // ReSharper disable UnassignedGetOnlyAutoProperty
-        
+        public delegate int GlGetError();
+        [EntryPoint("glGetError")]
+        public GlGetError GetError { get; }
+
         public delegate void GlClearStencil(int s);
         [EntryPoint("glClearStencil")]
         public GlClearStencil ClearStencil { get; }

+ 30 - 0
src/Avalonia.OpenGL/OpenGlException.cs

@@ -4,9 +4,39 @@ namespace Avalonia.OpenGL
 {
     public class OpenGlException : Exception
     {
+        public int? ErrorCode { get; private set; }
+
         public OpenGlException(string message) : base(message)
         {
+        }
+
+        private OpenGlException(string message, int errorCode) : base(message)
+        {
+            ErrorCode = errorCode;
+        }
+
+        public static OpenGlException GetFormattedException(string funcName, EglInterface egl)
+        {
+            return GetFormattedException(typeof(EglErrors), funcName, egl.GetError());
+        }
+
+        public static OpenGlException GetFormattedException(string funcName, GlInterface gl)
+        {
+            return GetFormattedException(typeof(GlErrors), funcName, gl.GetError());
+        }
 
+        private static OpenGlException GetFormattedException(Type consts, string funcName, int errorCode)
+        {
+            try
+            {
+                string errorName = Enum.GetName(consts, errorCode);
+                return new OpenGlException(
+                    $"{funcName} failed with error {errorName} (0x{errorCode.ToString("X")})", errorCode);
+            }
+            catch (ArgumentException)
+            {
+                return new OpenGlException($"{funcName} failed with error 0x{errorCode.ToString("X")}", errorCode);
+            }
         }
     }
 }