From ceab482834896876a37032236246c3e03610d1fb Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sat, 30 Sep 2023 18:12:36 -0700 Subject: [PATCH] Add "EGL_ANGLE_flexible_surface_compatibility" ext check (#13080) * Add "EGL_ANGLE_flexible_surface_compatibility" ext check * Use stackalloc with CreatePBufferFromClientBuffer attributes * Fix broken API --- src/Avalonia.OpenGL/Egl/EglContext.cs | 1 + src/Avalonia.OpenGL/Egl/EglDisplay.cs | 12 +++++- src/Avalonia.OpenGL/Egl/EglInterface.cs | 7 +++- .../Angle/AngleExternalD3D11Texture2D.cs | 14 +++---- .../OpenGl/Angle/AngleWin32EglDisplay.cs | 39 ++++++++++++++----- 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/Avalonia.OpenGL/Egl/EglContext.cs b/src/Avalonia.OpenGL/Egl/EglContext.cs index 936ec06c1d..137e9a18d3 100644 --- a/src/Avalonia.OpenGL/Egl/EglContext.cs +++ b/src/Avalonia.OpenGL/Egl/EglContext.cs @@ -48,6 +48,7 @@ namespace Avalonia.OpenGL.Egl public int SampleCount { get; } public int StencilSize { get; } public EglDisplay Display => _disp; + public EglInterface EglInterface => _egl; private class RestoreContext : IDisposable { diff --git a/src/Avalonia.OpenGL/Egl/EglDisplay.cs b/src/Avalonia.OpenGL/Egl/EglDisplay.cs index db1fe56139..27a0bc065e 100644 --- a/src/Avalonia.OpenGL/Egl/EglDisplay.cs +++ b/src/Avalonia.OpenGL/Egl/EglDisplay.cs @@ -113,12 +113,20 @@ namespace Avalonia.OpenGL.Egl return new EglSurface(this, s); } } + + public unsafe EglSurface CreatePBufferFromClientBuffer(int bufferType, IntPtr handle, int[] attribs) + { + fixed (int* attrs = attribs) + { + return CreatePBufferFromClientBuffer(bufferType, handle, attrs); + } + } - public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs) + public unsafe EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int* attribs) { using (Lock()) { - var s = EglInterface.CreatePbufferFromClientBuffer(Handle, bufferType, handle, + var s = EglInterface.CreatePbufferFromClientBufferPtr(Handle, bufferType, handle, Config, attribs); if (s == IntPtr.Zero) diff --git a/src/Avalonia.OpenGL/Egl/EglInterface.cs b/src/Avalonia.OpenGL/Egl/EglInterface.cs index 4b766d0dda..5c93d2084b 100644 --- a/src/Avalonia.OpenGL/Egl/EglInterface.cs +++ b/src/Avalonia.OpenGL/Egl/EglInterface.cs @@ -122,10 +122,13 @@ 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("eglCreatePbufferFromClientBuffer")] + public partial IntPtr CreatePbufferFromClientBufferPtr(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); diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs index 6bbfde35e1..a37e178991 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs @@ -28,13 +28,13 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture InternalFormat = GL_RGBA8; - _eglSurface = _context.Display.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, texture2D.GetNativeIntPtr(), - new[] - { - EGL_WIDTH, props.Width, EGL_HEIGHT, props.Height, EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, - EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGBA, EGL_NONE, EGL_NONE, - EGL_NONE - }); + var attrs = stackalloc[] + { + EGL_WIDTH, props.Width, EGL_HEIGHT, props.Height, EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGBA, EGL_NONE, EGL_NONE, + EGL_NONE + }; + _eglSurface = _context.Display.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, texture2D.GetNativeIntPtr(), attrs); var gl = _context.GlInterface; int temp = 0; diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs index 770a27386f..c1fb757468 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Avalonia.OpenGL; using Avalonia.OpenGL.Angle; @@ -15,6 +16,8 @@ namespace Avalonia.Win32.OpenGl.Angle { internal class AngleWin32EglDisplay : EglDisplay { + private readonly bool _flexibleSurfaceSupported; + protected override bool DisplayLockIsSharedWithContexts => true; public static AngleWin32EglDisplay CreateD3D9Display(EglInterface egl) @@ -22,7 +25,7 @@ namespace Avalonia.Win32.OpenGl.Angle var display = egl.GetPlatformDisplayExt(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE }); - return new AngleWin32EglDisplay(display, new EglDisplayOptions() + return new AngleWin32EglDisplay(display, egl, new EglDisplayOptions() { Egl = egl, ContextLossIsDisplayLoss = true, @@ -35,7 +38,7 @@ namespace Avalonia.Win32.OpenGl.Angle var display = egl.GetPlatformDisplayExt(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE }); - return new AngleWin32EglDisplay(display, new EglDisplayOptions() + return new AngleWin32EglDisplay(display, egl, new EglDisplayOptions() { Egl = egl, ContextLossIsDisplayLoss = true, @@ -125,7 +128,7 @@ namespace Avalonia.Win32.OpenGl.Angle throw OpenGlException.GetFormattedException("eglGetPlatformDisplayEXT", egl); - var rv = new AngleWin32EglDisplay(display, + var rv = new AngleWin32EglDisplay(display, egl, new EglDisplayOptions { DisposeCallback = Cleanup, @@ -148,9 +151,11 @@ namespace Avalonia.Win32.OpenGl.Angle } } - private AngleWin32EglDisplay(IntPtr display, EglDisplayOptions options, AngleOptions.PlatformApi platformApi) : base(display, options) + private AngleWin32EglDisplay(IntPtr display, EglInterface egl, EglDisplayOptions options, AngleOptions.PlatformApi platformApi) : base(display, options) { PlatformApi = platformApi; + var extensions = egl.QueryString(display, EGL_EXTENSIONS); + _flexibleSurfaceSupported = extensions?.Contains("EGL_ANGLE_flexible_surface_compatibility") ?? false; } public AngleOptions.PlatformApi PlatformApi { get; } @@ -164,18 +169,32 @@ namespace Avalonia.Win32.OpenGl.Angle return d3dDeviceHandle; } - public EglSurface WrapDirect3D11Texture( IntPtr handle) + public unsafe EglSurface WrapDirect3D11Texture( IntPtr handle) { if (PlatformApi != AngleOptions.PlatformApi.DirectX11) - throw new InvalidOperationException("Current platform API is " + PlatformApi); - return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE }); + ThrowInvalidPlatformApi(); + var attrs = stackalloc[] { EGL_NONE, EGL_NONE }; + return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, attrs); } - public EglSurface WrapDirect3D11Texture(IntPtr handle, int offsetX, int offsetY, int width, int height) + public unsafe EglSurface WrapDirect3D11Texture(IntPtr handle, int offsetX, int offsetY, int width, int height) { if (PlatformApi != AngleOptions.PlatformApi.DirectX11) - throw new InvalidOperationException("Current platform API is " + PlatformApi); - return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_TRUE, EGL_TEXTURE_OFFSET_X_ANGLE, offsetX, EGL_TEXTURE_OFFSET_Y_ANGLE, offsetY, EGL_NONE }); + ThrowInvalidPlatformApi(); + var attrs = stackalloc[] + { + EGL_WIDTH, width, EGL_HEIGHT, height, EGL_TEXTURE_OFFSET_X_ANGLE, offsetX, + EGL_TEXTURE_OFFSET_Y_ANGLE, offsetY, + _flexibleSurfaceSupported ? EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE : EGL_NONE, EGL_TRUE, + EGL_NONE + }; + return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, attrs); } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void ThrowInvalidPlatformApi() + { + throw new InvalidOperationException("Current platform API is " + PlatformApi); + } } }