Browse Source

Merge pull request #10351 from MrJul/opengl-nullable

Nullable annotations for Avalonia.OpenGL
pull/10352/head
Max Katz 4 years ago
committed by GitHub
parent
commit
b75baf7a16
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  2. 5
      src/Avalonia.OpenGL/Controls/CompositionOpenGlSwapchain.cs
  3. 33
      src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
  4. 6
      src/Avalonia.OpenGL/Controls/OpenGlControlResources.cs
  5. 22
      src/Avalonia.OpenGL/Egl/EglContext.cs
  6. 11
      src/Avalonia.OpenGL/Egl/EglDisplay.cs
  7. 18
      src/Avalonia.OpenGL/Egl/EglDisplayOptions.cs
  8. 11
      src/Avalonia.OpenGL/Egl/EglDisplayUtils.cs
  9. 8
      src/Avalonia.OpenGL/Egl/EglGlPlatformSurface.cs
  10. 11
      src/Avalonia.OpenGL/Egl/EglGlPlatformSurfaceBase.cs
  11. 10
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  12. 5
      src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
  13. 43
      src/Avalonia.OpenGL/Features/ExternalObjectsOpenGlExtensionFeature.cs
  14. 16
      src/Avalonia.OpenGL/GlBasicInfoInterface.cs
  15. 18
      src/Avalonia.OpenGL/GlInterface.cs
  16. 2
      src/Avalonia.OpenGL/IGlContext.cs
  17. 3
      src/Avalonia.OpenGL/IOpenGlTextureSharingRenderInterfaceContextFeature.cs
  18. 6
      src/Avalonia.OpenGL/OpenGlException.cs

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

@ -13,6 +13,7 @@
<Import Project="..\..\build\DevAnalyzers.props" /> <Import Project="..\..\build\DevAnalyzers.props" />
<Import Project="..\..\build\SourceGenerators.props" /> <Import Project="..\..\build\SourceGenerators.props" />
<Import Project="..\..\build\TrimmingEnable.props" /> <Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\NullableEnable.props" />
<ItemGroup> <ItemGroup>
<Compile Remove="..\Shared\SourceGeneratorAttributes.cs" /> <Compile Remove="..\Shared\SourceGeneratorAttributes.cs" />

5
src/Avalonia.OpenGL/Controls/CompositionOpenGlSwapchain.cs

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
@ -22,7 +21,7 @@ internal class CompositionOpenGlSwapchain : SwapchainBase<IGlSwapchainImage>
} }
public CompositionOpenGlSwapchain(IGlContext context, ICompositionGpuInterop interop, CompositionDrawingSurface target, public CompositionOpenGlSwapchain(IGlContext context, ICompositionGpuInterop interop, CompositionDrawingSurface target,
IGlContextExternalObjectsFeature externalObjectsFeature) : base(interop, target) IGlContextExternalObjectsFeature? externalObjectsFeature) : base(interop, target)
{ {
_context = context; _context = context;
_externalObjectsFeature = externalObjectsFeature; _externalObjectsFeature = externalObjectsFeature;
@ -95,7 +94,7 @@ internal class DxgiMutexOpenGlSwapChainImage : IGlSwapchainImage
public int TextureId => _texture.TextureId; public int TextureId => _texture.TextureId;
public int InternalFormat => _texture.InternalFormat; public int InternalFormat => _texture.InternalFormat;
public PixelSize Size => new(_texture.Properties.Width, _texture.Properties.Height); public PixelSize Size => new(_texture.Properties.Width, _texture.Properties.Height);
public Task LastPresent => _lastPresent; public Task? LastPresent => _lastPresent;
public void BeginDraw() => _texture.AcquireKeyedMutex(0); public void BeginDraw() => _texture.AcquireKeyedMutex(0);
public void Present() public void Present()

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

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
@ -11,10 +12,10 @@ namespace Avalonia.OpenGL.Controls
{ {
public abstract class OpenGlControlBase : Control public abstract class OpenGlControlBase : Control
{ {
private CompositionSurfaceVisual _visual; private CompositionSurfaceVisual? _visual;
private Action _update; private readonly Action _update;
private bool _updateQueued; private bool _updateQueued;
private Task<bool> _initialization; private Task<bool>? _initialization;
private OpenGlControlBaseResources? _resources; private OpenGlControlBaseResources? _resources;
private Compositor? _compositor; private Compositor? _compositor;
protected GlVersion GlVersion => _resources?.Context.Version ?? default; protected GlVersion GlVersion => _resources?.Context.Version ?? default;
@ -24,7 +25,7 @@ namespace Avalonia.OpenGL.Controls
_update = Update; _update = Update;
} }
void DoCleanup() private void DoCleanup()
{ {
if (_initialization is { Status: TaskStatus.RanToCompletion } && _resources != null) if (_initialization is { Status: TaskStatus.RanToCompletion } && _resources != null)
{ {
@ -63,14 +64,14 @@ namespace Avalonia.OpenGL.Controls
RequestNextFrameRendering(); RequestNextFrameRendering();
} }
[MemberNotNullWhen(true, nameof(_resources))]
private bool EnsureInitializedCore( private bool EnsureInitializedCore(
ICompositionGpuInterop interop, ICompositionGpuInterop interop,
IOpenGlTextureSharingRenderInterfaceContextFeature contextSharingFeature) IOpenGlTextureSharingRenderInterfaceContextFeature? contextSharingFeature)
{ {
var surface = _compositor.CreateDrawingSurface(); var surface = _compositor!.CreateDrawingSurface();
IGlContext ctx = null; IGlContext? ctx = null;
var contextFactory = AvaloniaLocator.Current.GetService<IPlatformGraphicsOpenGlContextFactory>();
try try
{ {
if (contextSharingFeature?.CanCreateSharedContext == true) if (contextSharingFeature?.CanCreateSharedContext == true)
@ -78,6 +79,7 @@ namespace Avalonia.OpenGL.Controls
if(_resources == null) if(_resources == null)
{ {
var contextFactory = AvaloniaLocator.Current.GetRequiredService<IPlatformGraphicsOpenGlContextFactory>();
ctx = contextFactory.CreateContext(null); ctx = contextFactory.CreateContext(null);
if (ctx.TryGetFeature<IGlContextExternalObjectsFeature>(out var externalObjects)) if (ctx.TryGetFeature<IGlContextExternalObjectsFeature>(out var externalObjects))
_resources = OpenGlControlBaseResources.TryCreate(ctx, surface, interop, externalObjects); _resources = OpenGlControlBaseResources.TryCreate(ctx, surface, interop, externalObjects);
@ -121,13 +123,14 @@ namespace Avalonia.OpenGL.Controls
base.OnPropertyChanged(change); base.OnPropertyChanged(change);
} }
void ContextLost() private void ContextLost()
{ {
_initialization = null; _initialization = null;
_resources?.DisposeAsync(); _resources?.DisposeAsync();
OnOpenGlLost(); OnOpenGlLost();
} }
[MemberNotNullWhen(true, nameof(_resources))]
private bool EnsureInitialized() private bool EnsureInitialized()
{ {
if (_initialization != null) if (_initialization != null)
@ -170,11 +173,11 @@ namespace Avalonia.OpenGL.Controls
private void Update() private void Update()
{ {
_updateQueued = false; _updateQueued = false;
if (VisualRoot == null) if (VisualRoot is not { } visualRoot)
return; return;
if(!EnsureInitialized()) if(!EnsureInitialized())
return; return;
using (_resources.BeginDraw(GetPixelSize())) using (_resources.BeginDraw(GetPixelSize(visualRoot)))
OnOpenGlRender(_resources.Context.GlInterface, _resources.Fbo); OnOpenGlRender(_resources.Context.GlInterface, _resources.Fbo);
} }
@ -190,7 +193,7 @@ namespace Avalonia.OpenGL.Controls
var gpuInteropTask = _compositor.TryGetCompositionGpuInterop(); var gpuInteropTask = _compositor.TryGetCompositionGpuInterop();
var contextSharingFeature = var contextSharingFeature =
(IOpenGlTextureSharingRenderInterfaceContextFeature) (IOpenGlTextureSharingRenderInterfaceContextFeature?)
await _compositor.TryGetRenderInterfaceFeature( await _compositor.TryGetRenderInterfaceFeature(
typeof(IOpenGlTextureSharingRenderInterfaceContextFeature)); typeof(IOpenGlTextureSharingRenderInterfaceContextFeature));
var interop = await gpuInteropTask; var interop = await gpuInteropTask;
@ -208,7 +211,7 @@ namespace Avalonia.OpenGL.Controls
return false; return false;
} }
using (_resources!.Context.MakeCurrent()) using (_resources.Context.MakeCurrent())
OnOpenGlInit(_resources.Context.GlInterface); OnOpenGlInit(_resources.Context.GlInterface);
return true; return true;
@ -228,9 +231,9 @@ namespace Avalonia.OpenGL.Controls
} }
} }
private PixelSize GetPixelSize() private PixelSize GetPixelSize(IRenderRoot visualRoot)
{ {
var scaling = VisualRoot!.RenderScaling; var scaling = visualRoot.RenderScaling;
return new PixelSize(Math.Max(1, (int)(Bounds.Width * scaling)), return new PixelSize(Math.Max(1, (int)(Bounds.Width * scaling)),
Math.Max(1, (int)(Bounds.Height * scaling))); Math.Max(1, (int)(Bounds.Height * scaling)));
} }

6
src/Avalonia.OpenGL/Controls/OpenGlControlResources.cs

@ -14,14 +14,14 @@ internal class OpenGlControlBaseResources : IAsyncDisposable
public int Fbo { get; private set; } public int Fbo { get; private set; }
private PixelSize _depthBufferSize; private PixelSize _depthBufferSize;
public CompositionDrawingSurface Surface { get; } public CompositionDrawingSurface Surface { get; }
public CompositionOpenGlSwapchain _swapchain; private readonly CompositionOpenGlSwapchain _swapchain;
public IGlContext Context { get; private set; } public IGlContext Context { get; private set; }
public static OpenGlControlBaseResources? TryCreate(CompositionDrawingSurface surface, public static OpenGlControlBaseResources? TryCreate(CompositionDrawingSurface surface,
ICompositionGpuInterop interop, ICompositionGpuInterop interop,
IOpenGlTextureSharingRenderInterfaceContextFeature feature) IOpenGlTextureSharingRenderInterfaceContextFeature feature)
{ {
IGlContext context; IGlContext? context;
try try
{ {
context = feature.CreateSharedContext(); context = feature.CreateSharedContext();
@ -71,7 +71,7 @@ internal class OpenGlControlBaseResources : IAsyncDisposable
new CompositionOpenGlSwapchain(context, interop, Surface, externalObjects); new CompositionOpenGlSwapchain(context, interop, Surface, externalObjects);
} }
void UpdateDepthRenderbuffer(PixelSize size) private void UpdateDepthRenderbuffer(PixelSize size)
{ {
if (size == _depthBufferSize && _depthBuffer != 0) if (size == _depthBufferSize && _depthBuffer != 0)
return; return;

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

@ -12,15 +12,15 @@ namespace Avalonia.OpenGL.Egl
{ {
private readonly EglDisplay _disp; private readonly EglDisplay _disp;
private readonly EglInterface _egl; private readonly EglInterface _egl;
private readonly EglContext _sharedWith; private readonly EglContext? _sharedWith;
private bool _isLost; private bool _isLost;
private IntPtr _context; private IntPtr _context;
private readonly Action _disposeCallback; private readonly Action? _disposeCallback;
private readonly Dictionary<Type, object> _features; private readonly Dictionary<Type, object> _features;
private readonly object _lock; private readonly object _lock;
internal EglContext(EglDisplay display, EglInterface egl, EglContext sharedWith, IntPtr ctx, EglSurface offscreenSurface, internal EglContext(EglDisplay display, EglInterface egl, EglContext? sharedWith, IntPtr ctx, EglSurface? offscreenSurface,
GlVersion version, int sampleCount, int stencilSize, Action disposeCallback, GlVersion version, int sampleCount, int stencilSize, Action? disposeCallback,
Dictionary<Type, Func<EglContext, object>> features) Dictionary<Type, Func<EglContext, object>> features)
{ {
_disp = display; _disp = display;
@ -42,19 +42,19 @@ namespace Avalonia.OpenGL.Egl
public IntPtr Context => public IntPtr Context =>
_context == IntPtr.Zero ? throw new ObjectDisposedException(nameof(EglContext)) : _context; _context == IntPtr.Zero ? throw new ObjectDisposedException(nameof(EglContext)) : _context;
public EglSurface OffscreenSurface { get; } public EglSurface? OffscreenSurface { get; }
public GlVersion Version { get; } public GlVersion Version { get; }
public GlInterface GlInterface { get; } public GlInterface GlInterface { get; }
public int SampleCount { get; } public int SampleCount { get; }
public int StencilSize { get; } public int StencilSize { get; }
public EglDisplay Display => _disp; public EglDisplay Display => _disp;
class RestoreContext : IDisposable private class RestoreContext : IDisposable
{ {
private readonly EglInterface _egl; private readonly EglInterface _egl;
private readonly object _l; private readonly object _l;
private readonly IntPtr _display; private readonly IntPtr _display;
public IntPtr _context, _read, _draw; private readonly IntPtr _context, _read, _draw;
public RestoreContext(EglInterface egl, IntPtr defDisplay, object l) public RestoreContext(EglInterface egl, IntPtr defDisplay, object l)
{ {
@ -78,7 +78,7 @@ namespace Avalonia.OpenGL.Egl
public IDisposable MakeCurrent() => MakeCurrent(OffscreenSurface); public IDisposable MakeCurrent() => MakeCurrent(OffscreenSurface);
public IDisposable MakeCurrent(EglSurface surface) public IDisposable MakeCurrent(EglSurface? surface)
{ {
if (IsLost) if (IsLost)
throw new PlatformGraphicsContextLostException(); throw new PlatformGraphicsContextLostException();
@ -147,7 +147,7 @@ namespace Avalonia.OpenGL.Egl
public bool CanCreateSharedContext => _disp.SupportsSharing; public bool CanCreateSharedContext => _disp.SupportsSharing;
public IGlContext CreateSharedContext(IEnumerable<GlVersion> preferredVersions = null) => public IGlContext CreateSharedContext(IEnumerable<GlVersion>? preferredVersions = null) =>
_disp.CreateContext(new EglContextOptions _disp.CreateContext(new EglContextOptions
{ {
ShareWith = _sharedWith ?? this ShareWith = _sharedWith ?? this
@ -174,9 +174,9 @@ namespace Avalonia.OpenGL.Egl
_disposeCallback?.Invoke(); _disposeCallback?.Invoke();
} }
public object TryGetFeature(Type featureType) public object? TryGetFeature(Type featureType)
{ {
if (_features?.TryGetValue(featureType, out var feature) == true) if (_features.TryGetValue(featureType, out var feature))
return feature; return feature;
return null; return null;
} }

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

@ -14,14 +14,14 @@ namespace Avalonia.OpenGL.Egl
private readonly EglDisplayOptions _options; private readonly EglDisplayOptions _options;
private EglConfigInfo _config; private EglConfigInfo _config;
private bool _isLost; private bool _isLost;
private object _lock = new(); private readonly object _lock = new();
public bool SupportsSharing { get; } public bool SupportsSharing { get; }
public IntPtr Handle => _display; public IntPtr Handle => _display;
public IntPtr Config => _config.Config; public IntPtr Config => _config.Config;
internal bool SingleContext => !_options.SupportsMultipleContexts; internal bool SingleContext => !_options.SupportsMultipleContexts;
private List<EglContext> _contexts = new(); private readonly List<EglContext> _contexts = new();
public EglDisplay() : this(new EglDisplayCreationOptions public EglDisplay() : this(new EglDisplayCreationOptions
{ {
@ -38,7 +38,7 @@ namespace Avalonia.OpenGL.Egl
public EglDisplay(IntPtr display, EglDisplayOptions options) public EglDisplay(IntPtr display, EglDisplayOptions options)
{ {
_egl = options.Egl; _egl = options.Egl ?? new EglInterface();
SupportsSharing = options.SupportsContextSharing; SupportsSharing = options.SupportsContextSharing;
_display = display; _display = display;
_options = options; _options = options;
@ -49,7 +49,7 @@ namespace Avalonia.OpenGL.Egl
} }
public EglInterface EglInterface => _egl; public EglInterface EglInterface => _egl;
public EglContext CreateContext(EglContextOptions options) public EglContext CreateContext(EglContextOptions? options)
{ {
if (SingleContext && _contexts.Any()) if (SingleContext && _contexts.Any())
throw new OpenGlException("This EGLDisplay can only have one active context"); throw new OpenGlException("This EGLDisplay can only have one active context");
@ -129,7 +129,7 @@ namespace Avalonia.OpenGL.Egl
protected virtual bool DisplayLockIsSharedWithContexts => false; protected virtual bool DisplayLockIsSharedWithContexts => false;
internal object ContextSharedSyncRoot => DisplayLockIsSharedWithContexts ? _lock : null; internal object? ContextSharedSyncRoot => DisplayLockIsSharedWithContexts ? _lock : null;
internal void OnContextLost(EglContext context) internal void OnContextLost(EglContext context)
{ {
@ -171,7 +171,6 @@ namespace Avalonia.OpenGL.Egl
if (_display != IntPtr.Zero) if (_display != IntPtr.Zero)
_egl.Terminate(_display); _egl.Terminate(_display);
_display = IntPtr.Zero; _display = IntPtr.Zero;
_config = null;
_options.DisposeCallback?.Invoke(); _options.DisposeCallback?.Invoke();
} }
} }

18
src/Avalonia.OpenGL/Egl/EglDisplayOptions.cs

@ -5,26 +5,26 @@ namespace Avalonia.OpenGL.Egl;
public class EglDisplayOptions public class EglDisplayOptions
{ {
public EglInterface Egl { get; set; } public EglInterface? Egl { get; set; }
public bool SupportsContextSharing { get; set; } public bool SupportsContextSharing { get; set; }
public bool SupportsMultipleContexts { get; set; } public bool SupportsMultipleContexts { get; set; }
public bool ContextLossIsDisplayLoss { get; set; } public bool ContextLossIsDisplayLoss { get; set; }
public Func<bool> DeviceLostCheckCallback { get; set; } public Func<bool>? DeviceLostCheckCallback { get; set; }
public Action DisposeCallback { get; set; } public Action? DisposeCallback { get; set; }
public IEnumerable<GlVersion> GlVersions { get; set; } public IEnumerable<GlVersion>? GlVersions { get; set; }
} }
public class EglContextOptions public class EglContextOptions
{ {
public EglContext ShareWith { get; set; } public EglContext? ShareWith { get; set; }
public EglSurface OffscreenSurface { get; set; } public EglSurface? OffscreenSurface { get; set; }
public Action DisposeCallback { get; set; } public Action? DisposeCallback { get; set; }
public Dictionary<Type, Func<EglContext, object>> ExtraFeatures { get; set; } public Dictionary<Type, Func<EglContext, object>>? ExtraFeatures { get; set; }
} }
public class EglDisplayCreationOptions : EglDisplayOptions public class EglDisplayCreationOptions : EglDisplayOptions
{ {
public int? PlatformType { get; set; } public int? PlatformType { get; set; }
public IntPtr PlatformDisplay { get; set; } public IntPtr PlatformDisplay { get; set; }
public int[] PlatformDisplayAttrs { get; set; } public int[]? PlatformDisplayAttrs { get; set; }
} }

11
src/Avalonia.OpenGL/Egl/EglDisplayUtils.cs

@ -1,15 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using static Avalonia.OpenGL.Egl.EglConsts; using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL.Egl; namespace Avalonia.OpenGL.Egl;
static class EglDisplayUtils internal static class EglDisplayUtils
{ {
public static IntPtr CreateDisplay(EglDisplayCreationOptions options) public static IntPtr CreateDisplay(EglDisplayCreationOptions options)
{ {
var egl = options.Egl; var egl = options.Egl ?? new EglInterface();
var display = IntPtr.Zero; var display = IntPtr.Zero;
if (options.PlatformType == null) if (options.PlatformType == null)
{ {
@ -30,9 +29,9 @@ static class EglDisplayUtils
return display; return display;
} }
public static EglConfigInfo InitializeAndGetConfig(EglInterface egl, IntPtr display, IEnumerable<GlVersion> versions) public static EglConfigInfo InitializeAndGetConfig(EglInterface egl, IntPtr display, IEnumerable<GlVersion>? versions)
{ {
if (!egl.Initialize(display, out var major, out var minor)) if (!egl.Initialize(display, out _, out _))
throw OpenGlException.GetFormattedException("eglInitialize", egl); throw OpenGlException.GetFormattedException("eglInitialize", egl);
// TODO: AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles // TODO: AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles
@ -112,7 +111,7 @@ static class EglDisplayUtils
} }
class EglConfigInfo internal class EglConfigInfo
{ {
public IntPtr Config { get; } public IntPtr Config { get; }
public GlVersion Version { get; } public GlVersion Version { get; }

8
src/Avalonia.OpenGL/Egl/EglGlPlatformSurface.cs

@ -27,9 +27,9 @@ namespace Avalonia.OpenGL.Egl
return new RenderTarget(glSurface, eglContext, _info); return new RenderTarget(glSurface, eglContext, _info);
} }
class RenderTarget : EglPlatformSurfaceRenderTargetBase private class RenderTarget : EglPlatformSurfaceRenderTargetBase
{ {
private EglSurface _glSurface; private EglSurface? _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info; private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _currentSize; private PixelSize _currentSize;
private readonly IntPtr _handle; private readonly IntPtr _handle;
@ -42,12 +42,12 @@ namespace Avalonia.OpenGL.Egl
_handle = _info.Handle; _handle = _info.Handle;
} }
public override void Dispose() => _glSurface.Dispose(); public override void Dispose() => _glSurface?.Dispose();
public override IGlPlatformSurfaceRenderingSession BeginDrawCore() public override IGlPlatformSurfaceRenderingSession BeginDrawCore()
{ {
if (_info.Size != _currentSize if (_info.Size != _currentSize
|| _handle != _info.Handle || _handle != _info.Handle
|| _glSurface == null) || _glSurface == null)
{ {
_glSurface?.Dispose(); _glSurface?.Dispose();

11
src/Avalonia.OpenGL/Egl/EglGlPlatformSurfaceBase.cs

@ -33,7 +33,7 @@ namespace Avalonia.OpenGL.Egl
public abstract IGlPlatformSurfaceRenderingSession BeginDrawCore(); public abstract IGlPlatformSurfaceRenderingSession BeginDrawCore();
protected IGlPlatformSurfaceRenderingSession BeginDraw(EglSurface surface, protected IGlPlatformSurfaceRenderingSession BeginDraw(EglSurface surface,
PixelSize size, double scaling, Action onFinish = null, bool isYFlipped = false) PixelSize size, double scaling, Action? onFinish = null, bool isYFlipped = false)
{ {
var restoreContext = Context.MakeCurrent(surface); var restoreContext = Context.MakeCurrent(surface);
@ -56,19 +56,18 @@ namespace Avalonia.OpenGL.Egl
restoreContext.Dispose(); restoreContext.Dispose();
} }
} }
class Session : IGlPlatformSurfaceRenderingSession private class Session : IGlPlatformSurfaceRenderingSession
{ {
private readonly EglContext _context; private readonly EglContext _context;
private readonly EglSurface _glSurface; private readonly EglSurface _glSurface;
private readonly EglDisplay _display; private readonly EglDisplay _display;
private readonly IDisposable _restoreContext; private readonly IDisposable _restoreContext;
private readonly Action _onFinish; private readonly Action? _onFinish;
public Session(EglDisplay display, EglContext context, public Session(EglDisplay display, EglContext context,
EglSurface glSurface, PixelSize size, double scaling, EglSurface glSurface, PixelSize size, double scaling,
IDisposable restoreContext, Action onFinish, bool isYFlipped) IDisposable restoreContext, Action? onFinish, bool isYFlipped)
{ {
Size = size; Size = size;
Scaling = scaling; Scaling = scaling;

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

@ -49,7 +49,7 @@ namespace Avalonia.OpenGL.Egl
public partial IntPtr GetDisplay(IntPtr nativeDisplay); public partial IntPtr GetDisplay(IntPtr nativeDisplay);
[GetProcAddress("eglGetPlatformDisplayEXT", true)] [GetProcAddress("eglGetPlatformDisplayEXT", true)]
public partial IntPtr GetPlatformDisplayExt(int platform, IntPtr nativeDisplay, int[] attrs); public partial IntPtr GetPlatformDisplayExt(int platform, IntPtr nativeDisplay, int[]? attrs);
[GetProcAddress("eglInitialize")] [GetProcAddress("eglInitialize")]
public partial bool Initialize(IntPtr display, out int major, out int minor); public partial bool Initialize(IntPtr display, out int major, out int minor);
@ -75,7 +75,7 @@ namespace Avalonia.OpenGL.Egl
public partial bool DestroyContext(IntPtr display, IntPtr context); public partial bool DestroyContext(IntPtr display, IntPtr context);
[GetProcAddress("eglCreatePbufferSurface")] [GetProcAddress("eglCreatePbufferSurface")]
public partial IntPtr CreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs); public partial IntPtr CreatePBufferSurface(IntPtr display, IntPtr config, int[]? attrs);
[GetProcAddress("eglMakeCurrent")] [GetProcAddress("eglMakeCurrent")]
public partial bool MakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context); public partial bool MakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
@ -96,7 +96,7 @@ namespace Avalonia.OpenGL.Egl
public partial void SwapBuffers(IntPtr display, IntPtr surface); public partial void SwapBuffers(IntPtr display, IntPtr surface);
[GetProcAddress("eglCreateWindowSurface")] [GetProcAddress("eglCreateWindowSurface")]
public partial IntPtr CreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs); public partial IntPtr CreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[]? attrs);
[GetProcAddress("eglBindTexImage")] [GetProcAddress("eglBindTexImage")]
public partial int BindTexImage(IntPtr display, IntPtr surface, int buffer); public partial int BindTexImage(IntPtr display, IntPtr surface, int buffer);
@ -116,7 +116,7 @@ namespace Avalonia.OpenGL.Egl
[GetProcAddress("eglQueryString")] [GetProcAddress("eglQueryString")]
public partial IntPtr QueryStringNative(IntPtr display, int i); public partial IntPtr QueryStringNative(IntPtr display, int i);
public string QueryString(IntPtr display, int i) public string? QueryString(IntPtr display, int i)
{ {
var rv = QueryStringNative(display, i); var rv = QueryStringNative(display, i);
if (rv == IntPtr.Zero) if (rv == IntPtr.Zero)
@ -125,7 +125,7 @@ namespace Avalonia.OpenGL.Egl
} }
[GetProcAddress("eglCreatePbufferFromClientBuffer")] [GetProcAddress("eglCreatePbufferFromClientBuffer")]
public partial IntPtr CreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[] attrib_list); public partial IntPtr CreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[]? attrib_list);
[GetProcAddress("eglQueryDisplayAttribEXT", true)] [GetProcAddress("eglQueryDisplayAttribEXT", true)]
public partial bool QueryDisplayAttribExt(IntPtr display, int attr, out IntPtr res); public partial bool QueryDisplayAttribExt(IntPtr display, int attr, out IntPtr res);

5
src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs

@ -1,7 +1,6 @@
using System; using System;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Platform; using Avalonia.Platform;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL.Egl namespace Avalonia.OpenGL.Egl
{ {
@ -24,7 +23,7 @@ namespace Avalonia.OpenGL.Egl
AvaloniaLocator.CurrentMutable.Bind<IPlatformGraphics>().ToConstant(feature); AvaloniaLocator.CurrentMutable.Bind<IPlatformGraphics>().ToConstant(feature);
} }
public static EglPlatformGraphics TryCreate() => TryCreate(() => new EglDisplay(new EglDisplayCreationOptions public static EglPlatformGraphics? TryCreate() => TryCreate(() => new EglDisplay(new EglDisplayCreationOptions
{ {
Egl = new EglInterface(), Egl = new EglInterface(),
// Those are expected to be supported by most EGL implementations // Those are expected to be supported by most EGL implementations
@ -32,7 +31,7 @@ namespace Avalonia.OpenGL.Egl
SupportsContextSharing = true SupportsContextSharing = true
})); }));
public static EglPlatformGraphics TryCreate(Func<EglDisplay> displayFactory) public static EglPlatformGraphics? TryCreate(Func<EglDisplay> displayFactory)
{ {
try try
{ {

43
src/Avalonia.OpenGL/Features/ExternalObjectsOpenGlExtensionFeature.cs

@ -63,10 +63,10 @@ public class ExternalObjectsOpenGlExtensionFeature : IGlContextExternalObjectsFe
{ {
private readonly IGlContext _context; private readonly IGlContext _context;
private readonly ExternalObjectsInterface _ext; private readonly ExternalObjectsInterface _ext;
private List<string> _imageTypes = new(); private readonly List<string> _imageTypes = new();
private List<string> _semaphoreTypes = new(); private readonly List<string> _semaphoreTypes = new();
public static ExternalObjectsOpenGlExtensionFeature TryCreate(IGlContext context) public static ExternalObjectsOpenGlExtensionFeature? TryCreate(IGlContext context)
{ {
var extensions = context.GlInterface.GetExtensions(); var extensions = context.GlInterface.GetExtensions();
if (extensions.Contains("GL_EXT_memory_object") && extensions.Contains("GL_EXT_semaphore")) if (extensions.Contains("GL_EXT_memory_object") && extensions.Contains("GL_EXT_semaphore"))
@ -142,10 +142,15 @@ public class ExternalObjectsOpenGlExtensionFeature : IGlContextExternalObjectsFe
public IGlExternalImageTexture ImportImage(IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties) public IGlExternalImageTexture ImportImage(IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties)
{ {
if(!_imageTypes.Contains(handle.HandleDescriptor)) var handleDescriptor = handle.HandleDescriptor;
throw new ArgumentException(handle.HandleDescriptor + " is not supported");
if (string.IsNullOrEmpty(handleDescriptor))
if (handle.HandleDescriptor == KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor) throw new ArgumentException("The handle must have a descriptor", nameof(handle));
if (!_imageTypes.Contains(handleDescriptor))
throw new ArgumentException(handleDescriptor + " is not supported", nameof(handle));
if (handleDescriptor == KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor)
{ {
while (_context.GlInterface.GetError() != 0) while (_context.GlInterface.GetError() != 0)
{ {
@ -174,23 +179,27 @@ public class ExternalObjectsOpenGlExtensionFeature : IGlContextExternalObjectsFe
return new ExternalImageTexture(_context, properties, _ext, memoryObject, texture); return new ExternalImageTexture(_context, properties, _ext, memoryObject, texture);
} }
throw new ArgumentException(handle.HandleDescriptor + " is not supported"); throw new ArgumentException(handleDescriptor + " is not supported", nameof(handle));
} }
public IGlExternalSemaphore ImportSemaphore(IPlatformHandle handle) public IGlExternalSemaphore ImportSemaphore(IPlatformHandle handle)
{ {
if(!_semaphoreTypes.Contains(handle.HandleDescriptor)) var handleDescriptor = handle.HandleDescriptor;
throw new ArgumentException(handle.HandleDescriptor + " is not supported");
if (string.IsNullOrEmpty(handleDescriptor))
throw new ArgumentException("The handle must have a descriptor", nameof(handle));
if (!_semaphoreTypes.Contains(handleDescriptor))
throw new ArgumentException(handleDescriptor + " is not supported");
if (handle.HandleDescriptor == if (handleDescriptor == KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor)
KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor)
{ {
_ext.GenSemaphoresEXT(1, out var semaphore); _ext.GenSemaphoresEXT(1, out var semaphore);
_ext.ImportSemaphoreFdEXT(semaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT, handle.Handle.ToInt32()); _ext.ImportSemaphoreFdEXT(semaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT, handle.Handle.ToInt32());
return new ExternalSemaphore(_context, _ext, semaphore); return new ExternalSemaphore(_context, _ext, semaphore);
} }
throw new ArgumentException(handle.HandleDescriptor + " is not supported"); throw new ArgumentException(handleDescriptor + " is not supported", nameof(handle));
} }
public CompositionGpuImportedImageSynchronizationCapabilities GetSynchronizationCapabilities(string imageHandleType) public CompositionGpuImportedImageSynchronizationCapabilities GetSynchronizationCapabilities(string imageHandleType)
@ -200,10 +209,10 @@ public class ExternalObjectsOpenGlExtensionFeature : IGlContextExternalObjectsFe
return default; return default;
} }
public byte[] DeviceLuid { get; } public byte[]? DeviceLuid { get; }
public byte[] DeviceUuid { get; } public byte[]? DeviceUuid { get; }
unsafe class ExternalSemaphore : IGlExternalSemaphore private unsafe class ExternalSemaphore : IGlExternalSemaphore
{ {
private readonly IGlContext _context; private readonly IGlContext _context;
private readonly ExternalObjectsInterface _ext; private readonly ExternalObjectsInterface _ext;
@ -242,7 +251,7 @@ public class ExternalObjectsOpenGlExtensionFeature : IGlContextExternalObjectsFe
} }
} }
class ExternalImageTexture : IGlExternalImageTexture private class ExternalImageTexture : IGlExternalImageTexture
{ {
private readonly IGlContext _context; private readonly IGlContext _context;
private readonly ExternalObjectsInterface _ext; private readonly ExternalObjectsInterface _ext;

16
src/Avalonia.OpenGL/GlBasicInfoInterface.cs

@ -2,14 +2,14 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
using Avalonia.SourceGenerator; using Avalonia.SourceGenerator;
namespace Avalonia.OpenGL namespace Avalonia.OpenGL
{ {
public unsafe partial class GlBasicInfoInterface public unsafe partial class GlBasicInfoInterface
{ {
public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress){ public GlBasicInfoInterface(Func<string, IntPtr> getProcAddress)
{
Initialize(getProcAddress); Initialize(getProcAddress);
} }
@ -22,7 +22,7 @@ namespace Avalonia.OpenGL
[GetProcAddress("glGetStringi")] [GetProcAddress("glGetStringi")]
public partial IntPtr GetStringiNative(int v, int v1); public partial IntPtr GetStringiNative(int v, int v1);
public string GetString(int v) public string? GetString(int v)
{ {
var ptr = GetStringNative(v); var ptr = GetStringNative(v);
if (ptr != IntPtr.Zero) if (ptr != IntPtr.Zero)
@ -30,7 +30,7 @@ namespace Avalonia.OpenGL
return null; return null;
} }
public string GetString(int v, int index) public string? GetString(int v, int index)
{ {
var ptr = GetStringiNative(v, index); var ptr = GetStringiNative(v, index);
if (ptr != IntPtr.Zero) if (ptr != IntPtr.Zero)
@ -46,7 +46,13 @@ namespace Avalonia.OpenGL
GetIntegerv(GlConsts.GL_NUM_EXTENSIONS, out int count); GetIntegerv(GlConsts.GL_NUM_EXTENSIONS, out int count);
var rv = new List<string>(count); var rv = new List<string>(count);
for (var c = 0; c < count; c++) for (var c = 0; c < count; c++)
rv.Add(GetString(GlConsts.GL_EXTENSIONS, c)); {
if (GetString(GlConsts.GL_EXTENSIONS, c) is { } extension)
{
rv.Add(extension);
}
}
return rv; return rv;
} }
} }

18
src/Avalonia.OpenGL/GlInterface.cs

@ -11,9 +11,9 @@ namespace Avalonia.OpenGL
public unsafe partial class GlInterface : GlBasicInfoInterface public unsafe partial class GlInterface : GlBasicInfoInterface
{ {
private readonly Func<string, IntPtr> _getProcAddress; private readonly Func<string, IntPtr> _getProcAddress;
public string Version { get; } public string? Version { get; }
public string Vendor { get; } public string? Vendor { get; }
public string Renderer { get; } public string? Renderer { get; }
public GlContextInfo ContextInfo { get; } public GlContextInfo ContextInfo { get; }
public class GlContextInfo public class GlContextInfo
@ -39,9 +39,9 @@ namespace Avalonia.OpenGL
{ {
_getProcAddress = getProcAddress; _getProcAddress = getProcAddress;
ContextInfo = info; ContextInfo = info;
Version = GetString(GlConsts.GL_VERSION); Version = GetString(GL_VERSION);
Renderer = GetString(GlConsts.GL_RENDERER); Renderer = GetString(GL_RENDERER);
Vendor = GetString(GlConsts.GL_VENDOR); Vendor = GetString(GL_VENDOR);
Initialize(getProcAddress, ContextInfo); Initialize(getProcAddress, ContextInfo);
} }
@ -203,7 +203,7 @@ namespace Avalonia.OpenGL
[GetProcAddress("glGetShaderInfoLog")] [GetProcAddress("glGetShaderInfoLog")]
public partial void GetShaderInfoLog(int shader, int maxLength, out int length, void* infoLog); public partial void GetShaderInfoLog(int shader, int maxLength, out int length, void* infoLog);
public unsafe string CompileShaderAndGetError(int shader, string source) public unsafe string? CompileShaderAndGetError(int shader, string source)
{ {
ShaderSourceString(shader, source); ShaderSourceString(shader, source);
CompileShader(shader); CompileShader(shader);
@ -238,7 +238,7 @@ namespace Avalonia.OpenGL
[GetProcAddress("glGetProgramInfoLog")] [GetProcAddress("glGetProgramInfoLog")]
public partial void GetProgramInfoLog(int program, int maxLength, out int len, void* infoLog); public partial void GetProgramInfoLog(int program, int maxLength, out int len, void* infoLog);
public unsafe string LinkProgramAndGetError(int program) public unsafe string? LinkProgramAndGetError(int program)
{ {
LinkProgram(program); LinkProgram(program);
int compiled; int compiled;
@ -374,4 +374,4 @@ namespace Avalonia.OpenGL
}); });
} }
} }
} }

2
src/Avalonia.OpenGL/IGlContext.cs

@ -15,7 +15,7 @@ namespace Avalonia.OpenGL
IDisposable EnsureCurrent(); IDisposable EnsureCurrent();
bool IsSharedWith(IGlContext context); bool IsSharedWith(IGlContext context);
bool CanCreateSharedContext { get; } bool CanCreateSharedContext { get; }
IGlContext CreateSharedContext(IEnumerable<GlVersion> preferredVersions = null); IGlContext? CreateSharedContext(IEnumerable<GlVersion>? preferredVersions = null);
} }
public interface IGlPlatformSurfaceRenderTargetFactory public interface IGlPlatformSurfaceRenderTargetFactory

3
src/Avalonia.OpenGL/IOpenGlTextureSharingRenderInterfaceContextFeature.cs

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
@ -7,7 +6,7 @@ namespace Avalonia.OpenGL
public interface IOpenGlTextureSharingRenderInterfaceContextFeature public interface IOpenGlTextureSharingRenderInterfaceContextFeature
{ {
bool CanCreateSharedContext { get; } bool CanCreateSharedContext { get; }
IGlContext CreateSharedContext(IEnumerable<GlVersion> preferredVersions = null); IGlContext? CreateSharedContext(IEnumerable<GlVersion>? preferredVersions = null);
ICompositionImportableOpenGlSharedTexture CreateSharedTextureForComposition(IGlContext context, PixelSize size); ICompositionImportableOpenGlSharedTexture CreateSharedTextureForComposition(IGlContext context, PixelSize size);
} }

6
src/Avalonia.OpenGL/OpenGlException.cs

@ -5,13 +5,13 @@ namespace Avalonia.OpenGL
{ {
public class OpenGlException : Exception public class OpenGlException : Exception
{ {
public int? ErrorCode { get; private set; } public int? ErrorCode { get; }
public OpenGlException(string message) : base(message) public OpenGlException(string? message) : base(message)
{ {
} }
private OpenGlException(string message, int errorCode) : base(message) private OpenGlException(string? message, int errorCode) : base(message)
{ {
ErrorCode = errorCode; ErrorCode = errorCode;
} }

Loading…
Cancel
Save