Browse Source

Merge branch 'master' into fix-4733-property-accessor

pull/4746/head
Dariusz Komosiński 6 years ago
committed by GitHub
parent
commit
3c20202706
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  2. 9
      src/Avalonia.Controls/IconElement.cs
  3. 21
      src/Avalonia.Controls/PathIcon.cs
  4. 8
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  5. 41
      src/Avalonia.Native/AvaloniaNativePlatformOpenGlInterface.cs
  6. 6
      src/Avalonia.Native/PopupImpl.cs
  7. 6
      src/Avalonia.Native/WindowImpl.cs
  8. 2
      src/Avalonia.Native/WindowImplBase.cs
  9. 1
      src/Avalonia.OpenGL/Angle/AngleEglInterface.cs
  10. 10
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  11. 192
      src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
  12. 2
      src/Avalonia.OpenGL/Egl/EglConsts.cs
  13. 69
      src/Avalonia.OpenGL/Egl/EglContext.cs
  14. 53
      src/Avalonia.OpenGL/Egl/EglDisplay.cs
  15. 2
      src/Avalonia.OpenGL/Egl/EglErrors.cs
  16. 54
      src/Avalonia.OpenGL/Egl/EglGlPlatformSurface.cs
  17. 47
      src/Avalonia.OpenGL/Egl/EglGlPlatformSurfaceBase.cs
  18. 2
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  19. 72
      src/Avalonia.OpenGL/Egl/EglPlatformOpenGlInterface.cs
  20. 11
      src/Avalonia.OpenGL/Egl/EglSurface.cs
  21. 43
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  22. 51
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  23. 13
      src/Avalonia.OpenGL/GlInterface.cs
  24. 2
      src/Avalonia.OpenGL/IGlContext.cs
  25. 2
      src/Avalonia.OpenGL/IOpenGlAwarePlatformRenderInterface.cs
  26. 13
      src/Avalonia.OpenGL/IPlatformOpenGlInterface.cs
  27. 8
      src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs
  28. 17
      src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs
  29. 13
      src/Avalonia.OpenGL/Imaging/IOpenGlTextureBitmapImpl.cs
  30. 34
      src/Avalonia.OpenGL/Imaging/OpenGlBitmap.cs
  31. 1
      src/Avalonia.OpenGL/OpenGlException.cs
  32. 2
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurface.cs
  33. 2
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs
  34. 2
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderingSession.cs
  35. 3
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  36. 3
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  37. 3
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  38. 17
      src/Avalonia.Themes.Default/PathIcon.xaml
  39. 2
      src/Avalonia.Themes.Fluent/Accents/Base.xaml
  40. 3
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  41. 25
      src/Avalonia.Themes.Fluent/PathIcon.xaml
  42. 53
      src/Avalonia.X11/Glx/GlxContext.cs
  43. 8
      src/Avalonia.X11/Glx/GlxDisplay.cs
  44. 25
      src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
  45. 13
      src/Avalonia.X11/Glx/GlxPlatformFeature.cs
  46. 5
      src/Avalonia.X11/X11Platform.cs
  47. 9
      src/Avalonia.X11/X11Window.cs
  48. 4
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  49. 18
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  50. 9
      src/Linux/Avalonia.LinuxFramebuffer/Output/IGlOutputBackend.cs
  51. 2
      src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
  52. 1
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
  53. 9
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs
  54. 207
      src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs
  55. 81
      src/Skia/Avalonia.Skia/Gpu/OpenGlTextureBitmapImpl.cs
  56. 6
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  57. 10
      src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
  58. 9
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  59. 6
      src/Windows/Avalonia.Win32/WindowImpl.cs
  60. 20
      src/iOS/Avalonia.iOS/EaglDisplay.cs
  61. 3
      src/iOS/Avalonia.iOS/EaglLayerSurface.cs
  62. 2
      src/iOS/Avalonia.iOS/Platform.cs

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

@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Controls;
using Avalonia.Platform.Interop;
using Avalonia.Threading;
using static Avalonia.OpenGL.GlConsts;

9
src/Avalonia.Controls/IconElement.cs

@ -0,0 +1,9 @@
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
{
public abstract class IconElement : TemplatedControl
{
}
}

21
src/Avalonia.Controls/PathIcon.cs

@ -0,0 +1,21 @@
using Avalonia.Media;
namespace Avalonia.Controls
{
public class PathIcon : IconElement
{
static PathIcon()
{
AffectsRender<PathIcon>(DataProperty);
}
public static readonly StyledProperty<Geometry> DataProperty =
AvaloniaProperty.Register<PathIcon, Geometry>(nameof(Data));
public Geometry Data
{
get { return GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
}
}

8
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -16,7 +16,7 @@ namespace Avalonia.Native
{
private readonly IAvaloniaNativeFactory _factory;
private AvaloniaNativePlatformOptions _options;
private GlPlatformFeature _glFeature;
private AvaloniaNativePlatformOpenGlInterface _platformGl;
[DllImport("libAvaloniaNative")]
static extern IntPtr CreateAvaloniaNative();
@ -116,8 +116,8 @@ namespace Avalonia.Native
{
try
{
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>()
.ToConstant(_glFeature = new GlPlatformFeature(_factory.ObtainGlDisplay()));
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>()
.ToConstant(_platformGl = new AvaloniaNativePlatformOpenGlInterface(_factory.ObtainGlDisplay()));
}
catch (Exception)
{
@ -128,7 +128,7 @@ namespace Avalonia.Native
public IWindowImpl CreateWindow()
{
return new WindowImpl(_factory, _options, _glFeature);
return new WindowImpl(_factory, _options, _platformGl);
}
public IWindowImpl CreateEmbeddableWindow()

41
src/Avalonia.Native/GlPlatformFeature.cs → src/Avalonia.Native/AvaloniaNativePlatformOpenGlInterface.cs

@ -2,21 +2,20 @@
using Avalonia.OpenGL;
using Avalonia.Native.Interop;
using System.Drawing;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Threading;
namespace Avalonia.Native
{
class GlPlatformFeature : IWindowingPlatformGlFeature
class AvaloniaNativePlatformOpenGlInterface : IPlatformOpenGlInterface
{
private readonly IAvnGlDisplay _display;
public GlPlatformFeature(IAvnGlDisplay display)
public AvaloniaNativePlatformOpenGlInterface(IAvnGlDisplay display)
{
_display = display;
var immediate = display.CreateContext(null);
var deferred = display.CreateContext(immediate);
int major, minor;
GlInterface glInterface;
using (immediate.MakeCurrent())
@ -33,19 +32,22 @@ namespace Avalonia.Native
}
GlDisplay = new GlDisplay(display, glInterface, immediate.SampleCount, immediate.StencilSize);
ImmediateContext = new GlContext(GlDisplay, immediate, _version);
DeferredContext = new GlContext(GlDisplay, deferred, _version);
MainContext = new GlContext(GlDisplay, null, immediate, _version);
}
internal IGlContext ImmediateContext { get; }
public IGlContext MainContext => DeferredContext;
internal GlContext DeferredContext { get; }
internal GlContext MainContext { get; }
public IGlContext PrimaryContext => MainContext;
public bool CanShareContexts => true;
public bool CanCreateContexts => true;
internal GlDisplay GlDisplay;
private readonly GlVersion _version;
public IGlContext CreateSharedContext() => new GlContext(GlDisplay,
MainContext, _display.CreateContext(MainContext.Context), _version);
public IGlContext CreateContext() => new GlContext(GlDisplay,
_display.CreateContext(((GlContext)ImmediateContext).Context), _version);
null, _display.CreateContext(null), _version);
}
class GlDisplay
@ -72,11 +74,13 @@ namespace Avalonia.Native
class GlContext : IGlContext
{
private readonly GlDisplay _display;
private readonly GlContext _sharedWith;
public IAvnGlContext Context { get; private set; }
public GlContext(GlDisplay display, IAvnGlContext context, GlVersion version)
public GlContext(GlDisplay display, GlContext sharedWith, IAvnGlContext context, GlVersion version)
{
_display = display;
_sharedWith = sharedWith;
Context = context;
Version = version;
}
@ -86,6 +90,17 @@ namespace Avalonia.Native
public int SampleCount => _display.SampleCount;
public int StencilSize => _display.StencilSize;
public IDisposable MakeCurrent() => Context.MakeCurrent();
public IDisposable EnsureCurrent() => MakeCurrent();
public bool IsSharedWith(IGlContext context)
{
var c = (GlContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
public void Dispose()
{
@ -108,7 +123,7 @@ namespace Avalonia.Native
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var feature = (GlPlatformFeature)AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
var feature = (AvaloniaNativePlatformOpenGlInterface)AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
return new GlPlatformSurfaceRenderingSession(_context, _target.BeginDrawing());
}

6
src/Avalonia.Native/PopupImpl.cs

@ -9,12 +9,12 @@ namespace Avalonia.Native
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
private readonly GlPlatformFeature _glFeature;
private readonly AvaloniaNativePlatformOpenGlInterface _glFeature;
private readonly IWindowBaseImpl _parent;
public PopupImpl(IAvaloniaNativeFactory factory,
AvaloniaNativePlatformOptions opts,
GlPlatformFeature glFeature,
AvaloniaNativePlatformOpenGlInterface glFeature,
IWindowBaseImpl parent) : base(opts, glFeature)
{
_factory = factory;
@ -23,7 +23,7 @@ namespace Avalonia.Native
_parent = parent;
using (var e = new PopupEvents(this))
{
var context = _opts.UseGpu ? glFeature?.DeferredContext : null;
var context = _opts.UseGpu ? glFeature?.MainContext : null;
Init(factory.CreatePopup(e, context?.Context), factory.CreateScreens(), context);
}
PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(parent, MoveResize));

6
src/Avalonia.Native/WindowImpl.cs

@ -14,19 +14,19 @@ namespace Avalonia.Native
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
private readonly GlPlatformFeature _glFeature;
private readonly AvaloniaNativePlatformOpenGlInterface _glFeature;
IAvnWindow _native;
private double _extendTitleBarHeight = -1;
internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
GlPlatformFeature glFeature) : base(opts, glFeature)
AvaloniaNativePlatformOpenGlInterface glFeature) : base(opts, glFeature)
{
_factory = factory;
_opts = opts;
_glFeature = glFeature;
using (var e = new WindowEvents(this))
{
var context = _opts.UseGpu ? glFeature?.DeferredContext : null;
var context = _opts.UseGpu ? glFeature?.MainContext : null;
Init(_native = factory.CreateWindow(e, context?.Context), factory.CreateScreens(), context);
}

2
src/Avalonia.Native/WindowImplBase.cs

@ -61,7 +61,7 @@ namespace Avalonia.Native
private NativeControlHostImpl _nativeControlHost;
private IGlContext _glContext;
internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, GlPlatformFeature glFeature)
internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, AvaloniaNativePlatformOpenGlInterface glFeature)
{
_gpu = opts.UseGpu && glFeature != null;
_deferredRendering = opts.UseDeferredRendering;

1
src/Avalonia.OpenGL/Angle/AngleEglInterface.cs

@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Platform.Interop;

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

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using static Avalonia.OpenGL.EglConsts;
using Avalonia.OpenGL.Egl;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL.Angle
{
@ -52,7 +52,7 @@ namespace Avalonia.OpenGL.Angle
}
}
private AngleWin32EglDisplay(EglInterface egl, AngleInfo info) : base(egl, info.Display)
private AngleWin32EglDisplay(EglInterface egl, AngleInfo info) : base(egl, false, info.Display)
{
PlatformApi = info.PlatformApi;
}
@ -78,11 +78,11 @@ namespace Avalonia.OpenGL.Angle
return d3dDeviceHandle;
}
public EglSurface WrapDirect3D11Texture(IntPtr handle)
public EglSurface WrapDirect3D11Texture(EglPlatformOpenGlInterface egl, 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 });
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
}
}
}

192
src/Avalonia.OpenGL/OpenGlControlBase.cs → src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

@ -3,44 +3,83 @@ using Avalonia.Controls;
using Avalonia.Logging;
using Avalonia.Media;
using Avalonia.OpenGL.Imaging;
using Avalonia.Rendering;
using Avalonia.VisualTree;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Controls
{
public abstract class OpenGlControlBase : Control
{
private IGlContext _context;
private int _fb, _texture, _renderBuffer;
private OpenGlTextureBitmap _bitmap;
private PixelSize _oldSize;
private int _fb, _depthBuffer;
private OpenGlBitmap _bitmap;
private IOpenGlBitmapAttachment _attachment;
private PixelSize _depthBufferSize;
private bool _glFailed;
private bool _initialized;
protected GlVersion GlVersion { get; private set; }
public sealed override void Render(DrawingContext context)
{
if(!EnsureInitialized())
return;
using (_context.MakeCurrent())
{
using (_bitmap.Lock())
{
var gl = _context.GlInterface;
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
if (_oldSize != GetPixelSize())
ResizeTexture(gl);
OnOpenGlRender(gl, _fb);
gl.Flush();
}
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, _fb);
EnsureTextureAttachment();
EnsureDepthBufferAttachment(_context.GlInterface);
if(!CheckFramebufferStatus(_context.GlInterface))
return;
OnOpenGlRender(_context.GlInterface, _fb);
_attachment.Present();
}
context.DrawImage(_bitmap, new Rect(_bitmap.Size), Bounds);
base.Render(context);
}
private void CheckError(GlInterface gl)
{
int err;
while ((err = gl.GetError()) != GL_NO_ERROR)
Console.WriteLine(err);
}
void EnsureTextureAttachment()
{
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, _fb);
if (_bitmap == null || _attachment == null || _bitmap.PixelSize != GetPixelSize())
{
_attachment?.Dispose();
_attachment = null;
_bitmap?.Dispose();
_bitmap = null;
_bitmap = new OpenGlBitmap(GetPixelSize(), new Vector(96, 96));
_attachment = _bitmap.CreateFramebufferAttachment(_context);
}
}
void EnsureDepthBufferAttachment(GlInterface gl)
{
var size = GetPixelSize();
if (size == _depthBufferSize && _depthBuffer != 0)
return;
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer);
if (_depthBuffer != 0) gl.DeleteRenderbuffers(1, new[] { _depthBuffer });
var oneArr = new int[1];
gl.GenRenderbuffers(1, oneArr);
_depthBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
size.Width, size.Height);
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
}
void DoCleanup(bool callUserDeinit)
void DoCleanup()
{
if (_context != null)
{
@ -50,16 +89,19 @@ namespace Avalonia.OpenGL
gl.BindTexture(GL_TEXTURE_2D, 0);
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
gl.DeleteFramebuffers(1, new[] { _fb });
using (_bitmap.Lock())
_bitmap.SetTexture(0, 0, new PixelSize(1, 1), 1);
gl.DeleteTextures(1, new[] { _texture });
gl.DeleteRenderbuffers(1, new[] { _renderBuffer });
_bitmap.Dispose();
gl.DeleteRenderbuffers(1, new[] { _depthBuffer });
_attachment?.Dispose();
_attachment = null;
_bitmap?.Dispose();
_bitmap = null;
try
{
if (callUserDeinit)
if (_initialized)
{
_initialized = false;
OnOpenGlDeinit(_context.GlInterface, _fb);
}
}
finally
{
@ -72,11 +114,11 @@ namespace Avalonia.OpenGL
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
DoCleanup(true);
DoCleanup();
base.OnDetachedFromVisualTree(e);
}
bool EnsureInitialized()
private bool EnsureInitializedCore()
{
if (_context != null)
return true;
@ -84,34 +126,43 @@ namespace Avalonia.OpenGL
if (_glFailed)
return false;
var feature = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
var feature = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
if (feature == null)
return false;
if (!feature.CanShareContexts)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: current platform does not support multithreaded context sharing");
return false;
}
try
{
_context = feature.CreateContext();
_context = feature.CreateSharedContext();
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: unable to create additional OpenGL context: {exception}", e);
_glFailed = true;
return false;
}
GlVersion = _context.Version;
try
{
_bitmap = new OpenGlTextureBitmap();
_bitmap = new OpenGlBitmap(GetPixelSize(), new Vector(96, 96));
if (!_bitmap.SupportsContext(_context))
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: unable to create OpenGlBitmap: OpenGL context is not compatible");
return false;
}
}
catch (Exception e)
{
_context.Dispose();
_context = null;
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL: unable to create OpenGlTextureBitmap: {exception}", e);
_glFailed = true;
"Unable to initialize OpenGL: unable to create OpenGlBitmap: {exception}", e);
return false;
}
@ -119,80 +170,55 @@ namespace Avalonia.OpenGL
{
try
{
_oldSize = GetPixelSize();
_depthBufferSize = GetPixelSize();
var gl = _context.GlInterface;
var oneArr = new int[1];
gl.GenFramebuffers(1, oneArr);
_fb = oneArr[0];
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
gl.GenTextures(1, oneArr);
_texture = oneArr[0];
ResizeTexture(gl);
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
EnsureDepthBufferAttachment(gl);
EnsureTextureAttachment();
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
int code;
while ((code = gl.GetError()) != 0)
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL FBO: {code}", code);
_glFailed = true;
return false;
}
return CheckFramebufferStatus(gl);
}
catch(Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL FBO: {exception}", e);
_glFailed = true;
return false;
}
if (!_glFailed)
OnOpenGlInit(_context.GlInterface, _fb);
}
}
if (_glFailed)
private bool CheckFramebufferStatus(GlInterface gl)
{
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
DoCleanup(false);
int code;
while ((code = gl.GetError()) != 0)
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("OpenGlControlBase",
"Unable to initialize OpenGL FBO: {code}", code);
return false;
}
return true;
}
void ResizeTexture(GlInterface gl)
private bool EnsureInitialized()
{
var size = GetPixelSize();
gl.GetIntegerv( GL_TEXTURE_BINDING_2D, out var oldTexture);
gl.BindTexture(GL_TEXTURE_2D, _texture);
gl.TexImage2D(GL_TEXTURE_2D, 0,
GlVersion.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8,
size.Width, size.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.BindTexture(GL_TEXTURE_2D, oldTexture);
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer);
gl.DeleteRenderbuffers(1, new[] { _renderBuffer });
var oneArr = new int[1];
gl.GenRenderbuffers(1, oneArr);
_renderBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
size.Width, size.Height);
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer);
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
using (_bitmap.Lock())
_bitmap.SetTexture(_texture, GL_RGBA8, size, 1);
if (_initialized)
return true;
_glFailed = !(_initialized = EnsureInitializedCore());
if (_glFailed)
return false;
using (_context.MakeCurrent())
OnOpenGlInit(_context.GlInterface, _fb);
return true;
}
PixelSize GetPixelSize()
private PixelSize GetPixelSize()
{
var scaling = VisualRoot.RenderScaling;
return new PixelSize(Math.Max(1, (int)(Bounds.Width * scaling)),

2
src/Avalonia.OpenGL/EglConsts.cs → src/Avalonia.OpenGL/Egl/EglConsts.cs

@ -1,6 +1,6 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable IdentifierTypo
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public static class EglConsts
{

69
src/Avalonia.OpenGL/EglContext.cs → src/Avalonia.OpenGL/Egl/EglContext.cs

@ -1,23 +1,25 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
using static Avalonia.OpenGL.EglConsts;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglContext : IGlContext
{
private readonly EglDisplay _disp;
private readonly EglInterface _egl;
private readonly EglContext _sharedWith;
private readonly object _lock = new object();
public EglContext(EglDisplay display, EglInterface egl, IntPtr ctx, EglSurface offscreenSurface,
public EglContext(EglDisplay display, EglInterface egl, EglContext sharedWith, IntPtr ctx, Func<EglContext, EglSurface> offscreenSurface,
GlVersion version, int sampleCount, int stencilSize)
{
_disp = display;
_egl = egl;
_sharedWith = sharedWith;
Context = ctx;
OffscreenSurface = offscreenSurface;
OffscreenSurface = offscreenSurface(this);
Version = version;
SampleCount = sampleCount;
StencilSize = stencilSize;
@ -33,21 +35,17 @@ namespace Avalonia.OpenGL
public int StencilSize { get; }
public EglDisplay Display => _disp;
public IDisposable Lock()
{
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
class RestoreContext : IDisposable
{
private readonly EglInterface _egl;
private readonly object _l;
private readonly IntPtr _display;
private IntPtr _context, _read, _draw;
public RestoreContext(EglInterface egl, IntPtr defDisplay)
public RestoreContext(EglInterface egl, IntPtr defDisplay, object l)
{
_egl = egl;
_l = l;
_display = _egl.GetCurrentDisplay();
if (_display == IntPtr.Zero)
_display = defDisplay;
@ -59,29 +57,52 @@ namespace Avalonia.OpenGL
public void Dispose()
{
_egl.MakeCurrent(_display, _draw, _read, _context);
Monitor.Exit(_l);
}
}
public IDisposable MakeCurrent()
public IDisposable MakeCurrent() => MakeCurrent(OffscreenSurface);
public IDisposable MakeCurrent(EglSurface surface)
{
var old = new RestoreContext(_egl, _disp.Handle);
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, Context))
throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
return old;
Monitor.Enter(_lock);
var success = false;
try
{
var old = new RestoreContext(_egl, _disp.Handle, _lock);
var surf = surface ?? OffscreenSurface;
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, surf.DangerousGetHandle(), surf.DangerousGetHandle(), Context))
throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
success = true;
return old;
}
finally
{
if(!success)
Monitor.Enter(_lock);
}
}
public IDisposable MakeCurrent(EglSurface surface)
public IDisposable EnsureCurrent()
{
var old = new RestoreContext(_egl, _disp.Handle);
var surf = surface ?? OffscreenSurface;
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, surf.DangerousGetHandle(), surf.DangerousGetHandle(), Context))
throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
return old;
if(IsCurrent)
return Disposable.Empty;
return MakeCurrent();
}
public bool IsSharedWith(IGlContext context)
{
var c = (EglContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
public bool IsCurrent => _egl.GetCurrentDisplay() == _disp.Handle && _egl.GetCurrentContext() == Context;
public void Dispose()
{
_egl.DestroyContext(_disp.Handle, Context);

53
src/Avalonia.OpenGL/EglDisplay.cs → src/Avalonia.OpenGL/Egl/EglDisplay.cs

@ -1,26 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.EglConsts;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglDisplay
{
private readonly EglInterface _egl;
public bool SupportsSharing { get; }
private readonly IntPtr _display;
private readonly IntPtr _config;
private readonly int[] _contextAttributes;
private readonly int _surfaceType;
public IntPtr Handle => _display;
public IntPtr Config => _config;
private int _sampleCount;
private int _stencilSize;
private GlVersion _version;
public EglDisplay(EglInterface egl) : this(egl, -1, IntPtr.Zero, null)
public EglDisplay(EglInterface egl, bool supportsSharing) : this(egl, supportsSharing, -1, IntPtr.Zero, null)
{
}
@ -45,15 +44,16 @@ namespace Avalonia.OpenGL
return display;
}
public EglDisplay(EglInterface egl, int platformType, IntPtr platformDisplay, int[] attrs)
: this(egl, CreateDisplay(egl, platformType, platformDisplay, attrs))
public EglDisplay(EglInterface egl, bool supportsSharing, int platformType, IntPtr platformDisplay, int[] attrs)
: this(egl, supportsSharing, CreateDisplay(egl, platformType, platformDisplay, attrs))
{
}
public EglDisplay(EglInterface egl, IntPtr display)
public EglDisplay(EglInterface egl, bool supportsSharing, IntPtr display)
{
_egl = egl;
SupportsSharing = supportsSharing;
_display = display;
if(_display == IntPtr.Zero)
throw new ArgumentException();
@ -136,7 +136,12 @@ namespace Avalonia.OpenGL
throw new OpenGlException("No suitable EGL config was found");
}
public EglDisplay() : this(new EglInterface())
public EglDisplay() : this(false)
{
}
public EglDisplay(bool supportsSharing) : this(new EglInterface(), supportsSharing)
{
}
@ -144,6 +149,9 @@ namespace Avalonia.OpenGL
public EglInterface EglInterface => _egl;
public EglContext CreateContext(IGlContext share)
{
if (share != null && !SupportsSharing)
throw new NotSupportedException("Context sharing is not supported by this display");
if((_surfaceType|EGL_PBUFFER_BIT) == 0)
throw new InvalidOperationException("Platform doesn't support PBUFFER surfaces");
var shareCtx = (EglContext)share;
@ -158,37 +166,22 @@ namespace Avalonia.OpenGL
});
if (surf == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePBufferSurface", _egl);
var rv = new EglContext(this, _egl, ctx, new EglSurface(this, _egl, surf),
var rv = new EglContext(this, _egl, shareCtx, ctx, context => new EglSurface(this, context, surf),
_version, _sampleCount, _stencilSize);
return rv;
}
public EglContext CreateContext(EglContext share, EglSurface offscreenSurface)
{
if (share != null && !SupportsSharing)
throw new NotSupportedException("Context sharing is not supported by this display");
var ctx = _egl.CreateContext(_display, _config, share?.Context ?? IntPtr.Zero, _contextAttributes);
if (ctx == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateContext", _egl);
var rv = new EglContext(this, _egl, ctx, offscreenSurface, _version, _sampleCount, _stencilSize);
var rv = new EglContext(this, _egl, share, ctx, _ => offscreenSurface, _version, _sampleCount, _stencilSize);
rv.MakeCurrent(null);
return rv;
}
public EglSurface CreateWindowSurface(IntPtr window)
{
var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", _egl);
return new EglSurface(this, _egl, s);
}
public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs)
{
var s = _egl.CreatePbufferFromClientBuffer(_display, bufferType, handle,
_config, attribs);
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePbufferFromClientBuffer", _egl);
return new EglSurface(this, _egl, s);
}
}
}

2
src/Avalonia.OpenGL/EglErrors.cs → src/Avalonia.OpenGL/Egl/EglErrors.cs

@ -1,4 +1,4 @@
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public enum EglErrors
{

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

@ -0,0 +1,54 @@
using Avalonia.OpenGL.Surfaces;
namespace Avalonia.OpenGL.Egl
{
public class EglGlPlatformSurface : EglGlPlatformSurfaceBase
{
private readonly EglPlatformOpenGlInterface _egl;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) : base()
{
_egl = egl;
_info = info;
}
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
var glSurface = _egl.CreateWindowSurface(_info.Handle);
return new RenderTarget(_egl, glSurface, _info);
}
class RenderTarget : EglPlatformSurfaceRenderTargetBase
{
private readonly EglPlatformOpenGlInterface _egl;
private EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _currentSize;
public RenderTarget(EglPlatformOpenGlInterface egl,
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) : base(egl)
{
_egl = egl;
_glSurface = glSurface;
_info = info;
_currentSize = info.Size;
}
public override void Dispose() => _glSurface.Dispose();
public override IGlPlatformSurfaceRenderingSession BeginDraw()
{
if (_info.Size != _currentSize || _glSurface == null)
{
_glSurface?.Dispose();
_glSurface = null;
_glSurface = _egl.CreateWindowSurface(_info.Handle);
_currentSize = _info.Size;
}
return base.BeginDraw(_glSurface, _info);
}
}
}
}

47
src/Avalonia.OpenGL/EglGlPlatformSurfaceBase.cs → src/Avalonia.OpenGL/Egl/EglGlPlatformSurfaceBase.cs

@ -1,6 +1,7 @@
using System;
using Avalonia.OpenGL.Surfaces;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public abstract class EglGlPlatformSurfaceBase : IGlPlatformSurface
{
@ -14,19 +15,15 @@ namespace Avalonia.OpenGL
public abstract IGlPlatformSurfaceRenderTarget CreateGlRenderTarget();
}
public abstract class EglPlatformSurfaceRenderTargetBase : IGlPlatformSurfaceRenderTargetWithCorruptionInfo
public abstract class EglPlatformSurfaceRenderTargetBase : IGlPlatformSurfaceRenderTarget
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglPlatformOpenGlInterface _egl;
protected EglPlatformSurfaceRenderTargetBase(EglDisplay display, EglContext context)
protected EglPlatformSurfaceRenderTargetBase(EglPlatformOpenGlInterface egl)
{
_display = display;
_context = context;
_egl = egl;
}
public abstract bool IsCorrupted { get; }
public virtual void Dispose()
{
@ -37,22 +34,25 @@ namespace Avalonia.OpenGL
protected IGlPlatformSurfaceRenderingSession BeginDraw(EglSurface surface,
EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info, Action onFinish = null, bool isYFlipped = false)
{
var l = _context.Lock();
var restoreContext = _egl.PrimaryEglContext.MakeCurrent(surface);
var success = false;
try
{
if (IsCorrupted)
throw new RenderTargetCorruptedException();
var restoreContext = _context.MakeCurrent(surface);
_display.EglInterface.WaitClient();
_display.EglInterface.WaitGL();
_display.EglInterface.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE);
return new Session(_display, _context, surface, info, l, restoreContext, onFinish, isYFlipped);
var egli = _egl.Display.EglInterface;
egli.WaitClient();
egli.WaitGL();
egli.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE);
_egl.PrimaryContext.GlInterface.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
success = true;
return new Session(_egl.Display, _egl.PrimaryEglContext, surface, info, restoreContext, onFinish, isYFlipped);
}
catch
finally
{
l.Dispose();
throw;
if(!success)
restoreContext.Dispose();
}
}
@ -62,21 +62,19 @@ namespace Avalonia.OpenGL
private readonly EglSurface _glSurface;
private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info;
private readonly EglDisplay _display;
private readonly IDisposable _lock;
private readonly IDisposable _restoreContext;
private readonly Action _onFinish;
public Session(EglDisplay display, EglContext context,
EglSurface glSurface, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock, IDisposable restoreContext, Action onFinish, bool isYFlipped)
IDisposable restoreContext, Action onFinish, bool isYFlipped)
{
IsYFlipped = isYFlipped;
_context = context;
_display = display;
_glSurface = glSurface;
_info = info;
_lock = @lock;
_restoreContext = restoreContext;
_onFinish = onFinish;
}
@ -90,7 +88,6 @@ namespace Avalonia.OpenGL
_display.EglInterface.WaitGL();
_display.EglInterface.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE);
_restoreContext.Dispose();
_lock.Dispose();
_onFinish?.Invoke();
}

2
src/Avalonia.OpenGL/EglInterface.cs → src/Avalonia.OpenGL/Egl/EglInterface.cs

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglInterface : GlInterfaceBase
{

72
src/Avalonia.OpenGL/Egl/EglPlatformOpenGlInterface.cs

@ -0,0 +1,72 @@
using System;
using Avalonia.Logging;
using static Avalonia.OpenGL.Egl.EglConsts;
namespace Avalonia.OpenGL.Egl
{
public class EglPlatformOpenGlInterface : IPlatformOpenGlInterface
{
public EglDisplay Display { get; private set; }
public bool CanCreateContexts => true;
public bool CanShareContexts => Display.SupportsSharing;
public EglContext PrimaryEglContext { get; }
public IGlContext PrimaryContext => PrimaryEglContext;
public EglPlatformOpenGlInterface(EglDisplay display)
{
Display = display;
PrimaryEglContext = display.CreateContext(null);
}
public static void TryInitialize()
{
var feature = TryCreate();
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToConstant(feature);
}
public static EglPlatformOpenGlInterface TryCreate() => TryCreate(() => new EglDisplay());
public static EglPlatformOpenGlInterface TryCreate(Func<EglDisplay> displayFactory)
{
try
{
return new EglPlatformOpenGlInterface(displayFactory());
}
catch(Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log(null, "Unable to initialize EGL-based rendering: {0}", e);
return null;
}
}
public IGlContext CreateContext() => Display.CreateContext(null);
public IGlContext CreateSharedContext() => Display.CreateContext(PrimaryEglContext);
public EglSurface CreateWindowSurface(IntPtr window)
{
using (PrimaryContext.MakeCurrent())
{
var s = Display.EglInterface.CreateWindowSurface(Display.Handle, Display.Config, window,
new[] { EGL_NONE, EGL_NONE });
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", Display.EglInterface);
return new EglSurface(Display, PrimaryEglContext, s);
}
}
public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs)
{
using (PrimaryContext.MakeCurrent())
{
var s = Display.EglInterface.CreatePbufferFromClientBuffer(Display.Handle, bufferType, handle,
Display.Config, attribs);
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePbufferFromClientBuffer", Display.EglInterface);
return new EglSurface(Display, PrimaryEglContext, s);
}
}
}
}

11
src/Avalonia.OpenGL/EglSurface.cs → src/Avalonia.OpenGL/Egl/EglSurface.cs

@ -1,22 +1,25 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Egl
{
public class EglSurface : SafeHandle
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglInterface _egl;
public EglSurface(EglDisplay display, EglInterface egl, IntPtr surface) : base(surface, true)
public EglSurface(EglDisplay display, EglContext context, IntPtr surface) : base(surface, true)
{
_display = display;
_egl = egl;
_context = context;
_egl = display.EglInterface;
}
protected override bool ReleaseHandle()
{
_egl.DestroySurface(_display.Handle, handle);
using (_context.MakeCurrent())
_egl.DestroySurface(_display.Handle, handle);
return true;
}

43
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -1,43 +0,0 @@
using System;
using Avalonia.Logging;
namespace Avalonia.OpenGL
{
public class EglGlPlatformFeature : IWindowingPlatformGlFeature
{
private EglDisplay _display;
public EglDisplay Display => _display;
public IGlContext CreateContext()
{
return _display.CreateContext(DeferredContext);
}
public EglContext DeferredContext { get; private set; }
public IGlContext MainContext => DeferredContext;
public static void TryInitialize()
{
var feature = TryCreate();
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
}
public static EglGlPlatformFeature TryCreate() => TryCreate(() => new EglDisplay());
public static EglGlPlatformFeature TryCreate(Func<EglDisplay> displayFactory)
{
try
{
var disp = displayFactory();
return new EglGlPlatformFeature
{
_display = disp,
DeferredContext = disp.CreateContext(null)
};
}
catch(Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log(null, "Unable to initialize EGL-based rendering: {0}", e);
return null;
}
}
}
}

51
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -1,51 +0,0 @@
using System;
using System.Threading;
namespace Avalonia.OpenGL
{
public class EglGlPlatformSurface : EglGlPlatformSurfaceBase
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglContext context, IEglWindowGlPlatformSurfaceInfo info) : base()
{
_display = context.Display;
_context = context;
_info = info;
}
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
var glSurface = _display.CreateWindowSurface(_info.Handle);
return new RenderTarget(_display, _context, glSurface, _info);
}
class RenderTarget : EglPlatformSurfaceRenderTargetBase
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _initialSize;
public RenderTarget(EglDisplay display, EglContext context,
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) : base(display, context)
{
_display = display;
_context = context;
_glSurface = glSurface;
_info = info;
_initialSize = info.Size;
}
public override void Dispose() => _glSurface.Dispose();
public override bool IsCorrupted => _initialSize != _info.Size;
public override IGlPlatformSurfaceRenderingSession BeginDraw() => base.BeginDraw(_glSurface, _info);
}
}
}

13
src/Avalonia.OpenGL/GlInterface.cs

@ -82,6 +82,9 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glFlush")]
public Action Flush { get; }
[GlEntryPoint("glFinish")]
public Action Finish { get; }
public delegate IntPtr GlGetString(int v);
[GlEntryPoint("glGetString")]
@ -144,6 +147,10 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glBindTexture")]
public GlBindTexture BindTexture { get; }
public delegate void GlActiveTexture(int texture);
[GlEntryPoint("glActiveTexture")]
public GlActiveTexture ActiveTexture { get; }
public delegate void GlDeleteTextures(int count, int[] textures);
[GlEntryPoint("glDeleteTextures")]
public GlDeleteTextures DeleteTextures { get; }
@ -154,6 +161,12 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glTexImage2D")]
public GlTexImage2D TexImage2D { get; }
public delegate void GlCopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y,
int width, int height);
[GlEntryPoint("glCopyTexSubImage2D")]
public GlCopyTexSubImage2D CopyTexSubImage2D { get; }
public delegate void GlTexParameteri(int target, int name, int value);
[GlEntryPoint("glTexParameteri")]
public GlTexParameteri TexParameteri { get; }

2
src/Avalonia.OpenGL/IGlContext.cs

@ -9,5 +9,7 @@ namespace Avalonia.OpenGL
int SampleCount { get; }
int StencilSize { get; }
IDisposable MakeCurrent();
IDisposable EnsureCurrent();
bool IsSharedWith(IGlContext context);
}
}

2
src/Avalonia.OpenGL/IOpenGlAwarePlatformRenderInterface.cs

@ -4,6 +4,6 @@ namespace Avalonia.OpenGL
{
public interface IOpenGlAwarePlatformRenderInterface
{
IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap();
IOpenGlBitmapImpl CreateOpenGlBitmap(PixelSize size, Vector dpi);
}
}

13
src/Avalonia.OpenGL/IPlatformOpenGlInterface.cs

@ -0,0 +1,13 @@
namespace Avalonia.OpenGL
{
public interface IPlatformOpenGlInterface
{
IGlContext PrimaryContext { get; }
IGlContext CreateSharedContext();
bool CanShareContexts { get; }
bool CanCreateContexts { get; }
IGlContext CreateContext();
/*IGlContext TryCreateContext(GlVersion version);
*/
}
}

8
src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs

@ -1,8 +0,0 @@
namespace Avalonia.OpenGL
{
public interface IWindowingPlatformGlFeature
{
IGlContext CreateContext();
IGlContext MainContext { get; }
}
}

17
src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs

@ -0,0 +1,17 @@
using System;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace Avalonia.OpenGL.Imaging
{
public interface IOpenGlBitmapImpl : IBitmapImpl
{
IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context, Action presentCallback);
bool SupportsContext(IGlContext context);
}
public interface IOpenGlBitmapAttachment : IDisposable
{
void Present();
}
}

13
src/Avalonia.OpenGL/Imaging/IOpenGlTextureBitmapImpl.cs

@ -1,13 +0,0 @@
using System;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace Avalonia.OpenGL.Imaging
{
public interface IOpenGlTextureBitmapImpl : IBitmapImpl
{
IDisposable Lock();
void SetBackBuffer(int textureId, int internalFormat, PixelSize pixelSize, double dpiScaling);
void SetDirty();
}
}

34
src/Avalonia.OpenGL/Imaging/OpenGlTextureBitmap.cs → src/Avalonia.OpenGL/Imaging/OpenGlBitmap.cs

@ -6,32 +6,30 @@ using Avalonia.Threading;
namespace Avalonia.OpenGL.Imaging
{
public class OpenGlTextureBitmap : Bitmap, IAffectsRender
public class OpenGlBitmap : Bitmap, IAffectsRender
{
private IOpenGlTextureBitmapImpl _impl;
static IOpenGlTextureBitmapImpl CreateOrThrow()
private IOpenGlBitmapImpl _impl;
public OpenGlBitmap(PixelSize size, Vector dpi)
: base(CreateOrThrow(size, dpi))
{
if (!(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() is IOpenGlAwarePlatformRenderInterface
glAware))
throw new PlatformNotSupportedException("Rendering platform does not support OpenGL integration");
return glAware.CreateOpenGlTextureBitmap();
_impl = (IOpenGlBitmapImpl)PlatformImpl.Item;
}
public OpenGlTextureBitmap()
: base(CreateOrThrow())
static IOpenGlBitmapImpl CreateOrThrow(PixelSize size, Vector dpi)
{
_impl = (IOpenGlTextureBitmapImpl)PlatformImpl.Item;
if (!(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() is IOpenGlAwarePlatformRenderInterface
glAware))
throw new PlatformNotSupportedException("Rendering platform does not support OpenGL integration");
return glAware.CreateOpenGlBitmap(size, dpi);
}
public IDisposable Lock() => _impl.Lock();
public IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context) =>
_impl.CreateFramebufferAttachment(context, SetIsDirty);
public void SetTexture(int textureId, int internalFormat, PixelSize size, double dpiScaling)
{
_impl.SetBackBuffer(textureId, internalFormat, size, dpiScaling);
SetIsDirty();
}
public void SetIsDirty()
public bool SupportsContext(IGlContext context) => _impl.SupportsContext(context);
void SetIsDirty()
{
if (Dispatcher.UIThread.CheckAccess())
CallInvalidated();

1
src/Avalonia.OpenGL/OpenGlException.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.OpenGL.Egl;
namespace Avalonia.OpenGL
{

2
src/Avalonia.OpenGL/IGlPlatformSurface.cs → src/Avalonia.OpenGL/Surfaces/IGlPlatformSurface.cs

@ -1,4 +1,4 @@
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Surfaces
{
public interface IGlPlatformSurface
{

2
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderTarget.cs → src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs

@ -1,6 +1,6 @@
using System;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Surfaces
{
public interface IGlPlatformSurfaceRenderTarget : IDisposable
{

2
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs → src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderingSession.cs

@ -1,6 +1,6 @@
using System;
namespace Avalonia.OpenGL
namespace Avalonia.OpenGL.Surfaces
{
public interface IGlPlatformSurfaceRenderingSession : IDisposable
{

3
src/Avalonia.Themes.Default/Accents/BaseDark.xaml

@ -72,5 +72,8 @@
<sys:Double x:Key="ScrollBarThickness">18</sys:Double>
<sys:Double x:Key="ScrollBarThumbThickness">8</sys:Double>
<sys:Double x:Key="IconElementThemeHeight">20</sys:Double>
<sys:Double x:Key="IconElementThemeWidth">20</sys:Double>
</Style.Resources>
</Style>

3
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@ -75,5 +75,8 @@
<sys:Double x:Key="ScrollBarThickness">18</sys:Double>
<sys:Double x:Key="ScrollBarThumbThickness">8</sys:Double>
<sys:Double x:Key="IconElementThemeHeight">20</sys:Double>
<sys:Double x:Key="IconElementThemeWidth">20</sys:Double>
</Style.Resources>
</Style>

3
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -12,7 +12,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.CaptionButtons.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ComboBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ComboBoxItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ContentControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ContentControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.GridSplitter.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ItemsControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ListBox.xaml?assembly=Avalonia.Themes.Default"/>
@ -21,6 +21,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.ContextMenu.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.MenuItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.OverlayPopupHost.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.PathIcon.xaml?assembly=Avalonia.Themes.Default" />
<StyleInclude Source="resm:Avalonia.Themes.Default.PopupRoot.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ProgressBar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.RadioButton.xaml?assembly=Avalonia.Themes.Default"/>

17
src/Avalonia.Themes.Default/PathIcon.xaml

@ -0,0 +1,17 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="PathIcon">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
<Setter Property="Height" Value="16" />
<Setter Property="Width" Value="16" />
<Setter Property="Template">
<ControlTemplate>
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}" />
</Viewbox>
</ControlTemplate>
</Setter>
</Style>
</Styles>

2
src/Avalonia.Themes.Fluent/Accents/Base.xaml

@ -20,5 +20,7 @@
<Thickness x:Key="TextControlBorderThemeThickness">1</Thickness>
<Thickness x:Key="TextControlBorderThemeThicknessFocused">2</Thickness>
<Thickness x:Key="TextControlThemePadding">10,6,6,5</Thickness>
<sys:Double x:Key="IconElementThemeHeight">20</sys:Double>
<sys:Double x:Key="IconElementThemeWidth">20</sys:Double>
</Style.Resources>
</Style>

3
src/Avalonia.Themes.Fluent/FluentTheme.xaml

@ -11,7 +11,7 @@
<StyleInclude Source="avares://Avalonia.Themes.Fluent/CheckBox.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ComboBox.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ComboBoxItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ContentControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ContentControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/GridSplitter.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ItemsControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ListBox.xaml"/>
@ -20,6 +20,7 @@
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ContextMenu.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/MenuItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/OverlayPopupHost.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/PathIcon.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Fluent/PopupRoot.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/ProgressBar.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/RadioButton.xaml"/>

25
src/Avalonia.Themes.Fluent/PathIcon.xaml

@ -0,0 +1,25 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<StackPanel>
<StackPanel.Resources>
<StreamGeometry x:Key="settings_regular">M14 9.50006C11.5147 9.50006 9.5 11.5148 9.5 14.0001C9.5 16.4853 11.5147 18.5001 14 18.5001C15.3488 18.5001 16.559 17.9066 17.3838 16.9666C18.0787 16.1746 18.5 15.1365 18.5 14.0001C18.5 13.5401 18.431 13.0963 18.3028 12.6784C17.7382 10.8381 16.0253 9.50006 14 9.50006ZM11 14.0001C11 12.3432 12.3431 11.0001 14 11.0001C15.6569 11.0001 17 12.3432 17 14.0001C17 15.6569 15.6569 17.0001 14 17.0001C12.3431 17.0001 11 15.6569 11 14.0001Z M21.7093 22.3948L19.9818 21.6364C19.4876 21.4197 18.9071 21.4515 18.44 21.7219C17.9729 21.9924 17.675 22.4693 17.6157 23.0066L17.408 24.8855C17.3651 25.273 17.084 25.5917 16.7055 25.682C14.9263 26.1061 13.0725 26.1061 11.2933 25.682C10.9148 25.5917 10.6336 25.273 10.5908 24.8855L10.3834 23.0093C10.3225 22.4731 10.0112 21.9976 9.54452 21.7281C9.07783 21.4586 8.51117 21.4269 8.01859 21.6424L6.29071 22.4009C5.93281 22.558 5.51493 22.4718 5.24806 22.1859C4.00474 20.8536 3.07924 19.2561 2.54122 17.5137C2.42533 17.1384 2.55922 16.7307 2.8749 16.4977L4.40219 15.3703C4.83721 15.0501 5.09414 14.5415 5.09414 14.0007C5.09414 13.4598 4.83721 12.9512 4.40162 12.6306L2.87529 11.5051C2.55914 11.272 2.42513 10.8638 2.54142 10.4882C3.08038 8.74734 4.00637 7.15163 5.24971 5.82114C5.51684 5.53528 5.93492 5.44941 6.29276 5.60691L8.01296 6.36404C8.50793 6.58168 9.07696 6.54881 9.54617 6.27415C10.0133 6.00264 10.3244 5.52527 10.3844 4.98794L10.5933 3.11017C10.637 2.71803 10.9245 2.39704 11.3089 2.31138C12.19 2.11504 13.0891 2.01071 14.0131 2.00006C14.9147 2.01047 15.8128 2.11485 16.6928 2.31149C17.077 2.39734 17.3643 2.71823 17.4079 3.11017L17.617 4.98937C17.7116 5.85221 18.4387 6.50572 19.3055 6.50663C19.5385 6.507 19.769 6.45838 19.9843 6.36294L21.7048 5.60568C22.0626 5.44818 22.4807 5.53405 22.7478 5.81991C23.9912 7.1504 24.9172 8.74611 25.4561 10.487C25.5723 10.8623 25.4386 11.2703 25.1228 11.5035L23.5978 12.6297C23.1628 12.95 22.9 13.4586 22.9 13.9994C22.9 14.5403 23.1628 15.0489 23.5988 15.3698L25.1251 16.4965C25.441 16.7296 25.5748 17.1376 25.4586 17.5131C24.9198 19.2536 23.9944 20.8492 22.7517 22.1799C22.4849 22.4657 22.0671 22.5518 21.7093 22.3948ZM16.263 22.1966C16.4982 21.4685 16.9889 20.8288 17.6884 20.4238C18.5702 19.9132 19.6536 19.8547 20.5841 20.2627L21.9281 20.8526C22.791 19.8538 23.4593 18.7013 23.8981 17.4552L22.7095 16.5778L22.7086 16.5771C21.898 15.98 21.4 15.0277 21.4 13.9994C21.4 12.9719 21.8974 12.0195 22.7073 11.4227L22.7085 11.4218L23.8957 10.545C23.4567 9.2988 22.7881 8.14636 21.9248 7.1477L20.5922 7.73425L20.5899 7.73527C20.1844 7.91463 19.7472 8.00722 19.3039 8.00663C17.6715 8.00453 16.3046 6.77431 16.1261 5.15465L16.1259 5.15291L15.9635 3.69304C15.3202 3.57328 14.6677 3.50872 14.013 3.50017C13.3389 3.50891 12.6821 3.57367 12.0377 3.69328L11.8751 5.15452C11.7625 6.16272 11.1793 7.05909 10.3019 7.56986C9.41937 8.0856 8.34453 8.14844 7.40869 7.73694L6.07273 7.14893C5.20949 8.14751 4.54092 9.29983 4.10196 10.5459L5.29181 11.4233C6.11115 12.0269 6.59414 12.9837 6.59414 14.0007C6.59414 15.0173 6.11142 15.9742 5.29237 16.5776L4.10161 17.4566C4.54002 18.7044 5.2085 19.8585 6.07205 20.8587L7.41742 20.2682C8.34745 19.8613 9.41573 19.9215 10.2947 20.4292C11.174 20.937 11.7593 21.832 11.8738 22.84L11.8744 22.8445L12.0362 24.3088C13.3326 24.5638 14.6662 24.5638 15.9626 24.3088L16.1247 22.8418C16.1491 22.6217 16.1955 22.4055 16.263 22.1966Z</StreamGeometry>
</StackPanel.Resources>
<PathIcon Data="{StaticResource settings_regular}" />
</StackPanel>
</Design.PreviewWith>
<Style Selector="PathIcon">
<Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
<Setter Property="Height" Value="16" />
<Setter Property="Width" Value="16" />
<Setter Property="Template">
<ControlTemplate>
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}" />
</Viewbox>
</ControlTemplate>
</Setter>
</Style>
</Styles>

53
src/Avalonia.X11/Glx/GlxContext.cs

@ -8,18 +8,21 @@ namespace Avalonia.X11.Glx
{
public IntPtr Handle { get; }
public GlxInterface Glx { get; }
private readonly GlxContext _sharedWith;
private readonly X11Info _x11;
private readonly IntPtr _defaultXid;
private readonly bool _ownsPBuffer;
private readonly object _lock = new object();
public GlxContext(GlxInterface glx, IntPtr handle, GlxDisplay display,
public GlxContext(GlxInterface glx, IntPtr handle, GlxDisplay display,
GlxContext sharedWith,
GlVersion version, int sampleCount, int stencilSize,
X11Info x11, IntPtr defaultXid,
bool ownsPBuffer)
{
Handle = handle;
Glx = glx;
_sharedWith = sharedWith;
_x11 = x11;
_defaultXid = defaultXid;
_ownsPBuffer = ownsPBuffer;
@ -37,25 +40,21 @@ namespace Avalonia.X11.Glx
public int SampleCount { get; }
public int StencilSize { get; }
public IDisposable Lock()
{
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
class RestoreContext : IDisposable
{
private GlxInterface _glx;
private IntPtr _defaultDisplay;
private readonly object _l;
private IntPtr _display;
private IntPtr _context;
private IntPtr _read;
private IntPtr _draw;
public RestoreContext(GlxInterface glx, IntPtr defaultDisplay)
public RestoreContext(GlxInterface glx, IntPtr defaultDisplay, object l)
{
_glx = glx;
_defaultDisplay = defaultDisplay;
_l = l;
_display = _glx.GetCurrentDisplay();
_context = _glx.GetCurrentContext();
_read = _glx.GetCurrentReadDrawable();
@ -66,19 +65,49 @@ namespace Avalonia.X11.Glx
{
var disp = _display == IntPtr.Zero ? _defaultDisplay : _display;
_glx.MakeContextCurrent(disp, _draw, _read, _context);
Monitor.Exit(_l);
}
}
public IDisposable MakeCurrent() => MakeCurrent(_defaultXid);
public IDisposable EnsureCurrent()
{
if(IsCurrent)
return Disposable.Empty;
return MakeCurrent();
}
public bool IsSharedWith(IGlContext context)
{
var c = (GlxContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
public IDisposable MakeCurrent(IntPtr xid)
{
var old = new RestoreContext(Glx, _x11.Display);
if (!Glx.MakeContextCurrent(_x11.Display, xid, xid, Handle))
throw new OpenGlException("glXMakeContextCurrent failed ");
return old;
Monitor.Enter(_lock);
var success = false;
try
{
var old = new RestoreContext(Glx, _x11.Display, _lock);
if (!Glx.MakeContextCurrent(_x11.Display, xid, xid, Handle))
throw new OpenGlException("glXMakeContextCurrent failed ");
success = true;
return old;
}
finally
{
if (!success)
Monitor.Exit(_lock);
}
}
public bool IsCurrent => Glx.GetCurrentContext() == Handle;
public void Dispose()
{
Glx.DestroyContext(_x11.Display, Handle);

8
src/Avalonia.X11/Glx/GlxDisplay.cs

@ -113,9 +113,9 @@ namespace Avalonia.X11.Glx
}
public GlxContext CreateContext() => CreateContext(DeferredContext);
GlxContext CreateContext(IGlContext share) => CreateContext(CreatePBuffer(), share,
public GlxContext CreateContext() => CreateContext();
public GlxContext CreateContext(IGlContext share) => CreateContext(CreatePBuffer(), share,
share.SampleCount, share.StencilSize, true);
GlxContext CreateContext(IntPtr defaultXid, IGlContext share,
@ -144,7 +144,7 @@ namespace Avalonia.X11.Glx
if (handle != IntPtr.Zero)
{
_version = profile;
return new GlxContext(new GlxInterface(), handle, this, profile,
return new GlxContext(new GlxInterface(), handle, this, (GlxContext)share, profile,
sampleCount, stencilSize, _x11, defaultXid, ownsPBuffer);
}

25
src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs

@ -1,5 +1,8 @@
using System;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.X11.Glx
{
@ -40,33 +43,26 @@ namespace Avalonia.X11.Glx
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var l = _context.Lock();
try
{
return new Session(_context, _info, l, _context.MakeCurrent(_info.Handle));
}
catch
{
l.Dispose();
throw;
}
var oldContext = _context.MakeCurrent(_info.Handle);
// Reset to default FBO first
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, 0);
return new Session(_context, _info, oldContext);
}
class Session : IGlPlatformSurfaceRenderingSession
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private IDisposable _lock;
private readonly IDisposable _clearContext;
public IGlContext Context => _context;
public Session(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock, IDisposable clearContext)
IDisposable clearContext)
{
_context = context;
_info = info;
_lock = @lock;
_clearContext = clearContext;
}
@ -77,7 +73,6 @@ namespace Avalonia.X11.Glx
_context.Display.SwapBuffers(_info.Handle);
_context.Glx.WaitX();
_clearContext.Dispose();
_lock.Dispose();
}
public PixelSize Size => _info.Size;

13
src/Avalonia.X11/Glx/GlxPlatformFeature.cs

@ -5,31 +5,34 @@ using Avalonia.OpenGL;
namespace Avalonia.X11.Glx
{
class GlxGlPlatformFeature : IWindowingPlatformGlFeature
class GlxPlatformOpenGlInterface : IPlatformOpenGlInterface
{
public GlxDisplay Display { get; private set; }
public bool CanCreateContexts => true;
public bool CanShareContexts => true;
public IGlContext CreateContext() => Display.CreateContext();
public IGlContext CreateSharedContext() => Display.CreateContext(PrimaryContext);
public GlxContext DeferredContext { get; private set; }
public IGlContext MainContext => DeferredContext;
public IGlContext PrimaryContext => DeferredContext;
public static bool TryInitialize(X11Info x11, IList<GlVersion> glProfiles)
{
var feature = TryCreate(x11, glProfiles);
if (feature != null)
{
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToConstant(feature);
return true;
}
return false;
}
public static GlxGlPlatformFeature TryCreate(X11Info x11, IList<GlVersion> glProfiles)
public static GlxPlatformOpenGlInterface TryCreate(X11Info x11, IList<GlVersion> glProfiles)
{
try
{
var disp = new GlxDisplay(x11, glProfiles);
return new GlxGlPlatformFeature
return new GlxPlatformOpenGlInterface
{
Display = disp,
DeferredContext = disp.DeferredContext

5
src/Avalonia.X11/X11Platform.cs

@ -7,6 +7,7 @@ using Avalonia.FreeDesktop;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.X11;
@ -70,9 +71,9 @@ namespace Avalonia.X11
if (options.UseGpu)
{
if (options.UseEGL)
EglGlPlatformFeature.TryInitialize();
EglPlatformOpenGlInterface.TryInitialize();
else
GlxGlPlatformFeature.TryInitialize(Info, Options.GlProfiles);
GlxPlatformOpenGlInterface.TryInitialize(Info, Options.GlProfiles);
}

9
src/Avalonia.X11/X11Window.cs

@ -12,6 +12,7 @@ using Avalonia.FreeDesktop;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
@ -65,7 +66,7 @@ namespace Avalonia.X11
_touch = new TouchDevice();
_keyboard = platform.KeyboardDevice;
var glfeature = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
var glfeature = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
XSetWindowAttributes attr = new XSetWindowAttributes();
var valueMask = default(SetWindowValuemask);
@ -87,13 +88,13 @@ namespace Avalonia.X11
// OpenGL seems to be do weird things to it's current window which breaks resize sometimes
_useRenderWindow = glfeature != null;
var glx = glfeature as GlxGlPlatformFeature;
var glx = glfeature as GlxPlatformOpenGlInterface;
if (glx != null)
visualInfo = *glx.Display.VisualInfo;
else if (glfeature == null)
visualInfo = _x11.TransparentVisualInfo;
var egl = glfeature as EglGlPlatformFeature;
var egl = glfeature as EglPlatformOpenGlInterface;
var visual = IntPtr.Zero;
var depth = 24;
@ -168,7 +169,7 @@ namespace Avalonia.X11
if (egl != null)
surfaces.Insert(0,
new EglGlPlatformSurface(egl.DeferredContext,
new EglGlPlatformSurface(egl,
new SurfaceInfo(this, _x11.DeferredDisplay, _handle, _renderHandle)));
if (glx != null)
surfaces.Insert(0, new GlxGlPlatformSurface(glx.Display, glx.DeferredContext,

4
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -32,8 +32,8 @@ namespace Avalonia.LinuxFramebuffer
void Initialize()
{
Threading = new InternalPlatformThreadingInterface();
if (_fb is IWindowingPlatformGlFeature glFeature)
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(glFeature);
if (_fb is IGlOutputBackend gl)
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToConstant(gl.PlatformOpenGlInterface);
AvaloniaLocator.CurrentMutable
.Bind<IPlatformThreadingInterface>().ToConstant(Threading)
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))

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

@ -4,6 +4,8 @@ using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform.Interop;
using static Avalonia.LinuxFramebuffer.NativeUnsafeMethods;
using static Avalonia.LinuxFramebuffer.Output.LibDrm;
@ -11,13 +13,16 @@ using static Avalonia.LinuxFramebuffer.Output.LibDrm.GbmColorFormats;
namespace Avalonia.LinuxFramebuffer.Output
{
public unsafe class DrmOutput : IOutputBackend, IGlPlatformSurface, IWindowingPlatformGlFeature
public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface
{
private DrmCard _card;
private readonly EglGlPlatformSurface _eglPlatformSurface;
public PixelSize PixelSize => _mode.Resolution;
public double Scaling { get; set; }
public IGlContext MainContext => _deferredContext;
public IGlContext PrimaryContext => _deferredContext;
private EglPlatformOpenGlInterface _platformGl;
public IPlatformOpenGlInterface PlatformOpenGlInterface => _platformGl;
public DrmOutput(string path = null)
{
@ -132,10 +137,9 @@ namespace Avalonia.LinuxFramebuffer.Output
if(_gbmTargetSurface == null)
throw new InvalidOperationException("Unable to create GBM surface");
_eglDisplay = new EglDisplay(new EglInterface(eglGetProcAddress), 0x31D7, device, null);
_eglSurface = _eglDisplay.CreateWindowSurface(_gbmTargetSurface);
_eglDisplay = new EglDisplay(new EglInterface(eglGetProcAddress), false, 0x31D7, device, null);
_platformGl = new EglPlatformOpenGlInterface(_eglDisplay);
_eglSurface = _platformGl.CreateWindowSurface(_gbmTargetSurface);
EglContext CreateContext(EglContext share)
@ -144,7 +148,7 @@ namespace Avalonia.LinuxFramebuffer.Output
GbmBoFlags.GBM_BO_USE_RENDERING);
if (offSurf == null)
throw new InvalidOperationException("Unable to create 1x1 sized GBM surface");
return _eglDisplay.CreateContext(share, _eglDisplay.CreateWindowSurface(offSurf));
return _eglDisplay.CreateContext(share, _platformGl.CreateWindowSurface(offSurf));
}
_deferredContext = CreateContext(null);

9
src/Linux/Avalonia.LinuxFramebuffer/Output/IGlOutputBackend.cs

@ -0,0 +1,9 @@
using Avalonia.OpenGL;
namespace Avalonia.LinuxFramebuffer.Output
{
public interface IGlOutputBackend : IOutputBackend
{
public IPlatformOpenGlInterface PlatformOpenGlInterface { get; }
}
}

2
src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs

@ -19,6 +19,6 @@ namespace Avalonia.Skia
public interface IOpenGlAwareSkiaGpu : ISkiaGpu
{
IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap();
IOpenGlBitmapImpl CreateOpenGlBitmap(PixelSize size, Vector dpi);
}
}

1
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs

@ -1,6 +1,7 @@
using System;
using System.Reactive.Disposables;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform;
using Avalonia.Rendering;
using SkiaSharp;

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

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Imaging;
using Avalonia.OpenGL.Surfaces;
using SkiaSharp;
namespace Avalonia.Skia
@ -8,10 +9,12 @@ namespace Avalonia.Skia
class GlSkiaGpu : IOpenGlAwareSkiaGpu
{
private GRContext _grContext;
private IGlContext _glContext;
public GlSkiaGpu(IWindowingPlatformGlFeature gl, long? maxResourceBytes)
public GlSkiaGpu(IPlatformOpenGlInterface openGl, long? maxResourceBytes)
{
var context = gl.MainContext;
var context = openGl.PrimaryContext;
_glContext = context;
using (context.MakeCurrent())
{
using (var iface = context.Version.Type == GlProfileType.OpenGL ?
@ -40,6 +43,6 @@ namespace Avalonia.Skia
return null;
}
public IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap() => new OpenGlTextureBitmapImpl();
public IOpenGlBitmapImpl CreateOpenGlBitmap(PixelSize size, Vector dpi) => new GlOpenGlBitmapImpl(_glContext, size, dpi);
}
}

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

@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Imaging;
using Avalonia.Utilities;
using SkiaSharp;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.Skia
{
class GlOpenGlBitmapImpl : IOpenGlBitmapImpl, IDrawableBitmapImpl
{
private readonly IGlContext _context;
private readonly object _lock = new object();
private IGlPresentableOpenGlSurface _surface;
public GlOpenGlBitmapImpl(IGlContext context, PixelSize pixelSize, Vector dpi)
{
_context = context;
PixelSize = pixelSize;
Dpi = dpi;
}
public Vector Dpi { get; }
public PixelSize PixelSize { get; }
public int Version { get; private set; }
public void Save(string fileName) => throw new NotSupportedException();
public void Save(Stream stream) => throw new NotSupportedException();
public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint)
{
lock (_lock)
{
if (_surface == null)
return;
using (_surface.Lock())
{
using (var backendTexture = new GRBackendTexture(PixelSize.Width, PixelSize.Height, false,
new GRGlTextureInfo(
GlConsts.GL_TEXTURE_2D, (uint)_surface.GetTextureId(),
(uint)_surface.InternalFormat)))
using (var surface = SKSurface.Create(context.GrContext, backendTexture, GRSurfaceOrigin.TopLeft,
SKColorType.Rgba8888))
{
// Again, silently ignore, if something went wrong it's not our fault
if (surface == null)
return;
using (var snapshot = surface.Snapshot())
context.Canvas.DrawImage(snapshot, sourceRect, destRect, paint);
}
}
}
}
public IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context, Action presentCallback)
{
if (!SupportsContext(context))
throw new OpenGlException("Context is not supported for texture sharing");
return new SharedOpenGlBitmapAttachment(this, context, presentCallback);
}
public bool SupportsContext(IGlContext context)
{
// TODO: negotiated platform surface sharing
return _context.IsSharedWith(context);
}
public void Dispose()
{
}
internal void Present(IGlPresentableOpenGlSurface surface)
{
lock (_lock)
{
_surface = surface;
}
}
}
interface IGlPresentableOpenGlSurface : IDisposable
{
int GetTextureId();
int InternalFormat { get; }
IDisposable Lock();
}
class SharedOpenGlBitmapAttachment : IOpenGlBitmapAttachment, IGlPresentableOpenGlSurface
{
private readonly GlOpenGlBitmapImpl _bitmap;
private readonly IGlContext _context;
private readonly Action _presentCallback;
private readonly int _fbo;
private readonly int _texture;
private readonly int _frontBuffer;
private bool _disposed;
private readonly DisposableLock _lock = new DisposableLock();
public SharedOpenGlBitmapAttachment(GlOpenGlBitmapImpl bitmap, IGlContext context, Action presentCallback)
{
_bitmap = bitmap;
_context = context;
_presentCallback = presentCallback;
using (_context.EnsureCurrent())
{
var glVersion = _context.Version;
InternalFormat = glVersion.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8;
_context.GlInterface.GetIntegerv(GL_FRAMEBUFFER_BINDING, out _fbo);
if (_fbo == 0)
throw new OpenGlException("Current FBO is 0");
{
var gl = _context.GlInterface;
var textures = new int[2];
gl.GenTextures(2, textures);
_texture = textures[0];
_frontBuffer = textures[1];
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture);
foreach (var t in textures)
{
gl.BindTexture(GL_TEXTURE_2D, t);
gl.TexImage2D(GL_TEXTURE_2D, 0,
InternalFormat,
_bitmap.PixelSize.Width, _bitmap.PixelSize.Height,
0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
gl.BindTexture(GL_TEXTURE_2D, oldTexture);
}
}
}
public void Present()
{
using (_context.MakeCurrent())
{
if (_disposed)
throw new ObjectDisposedException(nameof(SharedOpenGlBitmapAttachment));
var gl = _context.GlInterface;
gl.Finish();
using (Lock())
{
gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var oldFbo);
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture);
gl.GetIntegerv(GL_ACTIVE_TEXTURE, out var oldActive);
gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo);
gl.BindTexture(GL_TEXTURE_2D, _frontBuffer);
gl.ActiveTexture(GL_TEXTURE0);
gl.CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _bitmap.PixelSize.Width,
_bitmap.PixelSize.Height);
gl.BindFramebuffer(GL_FRAMEBUFFER, oldFbo);
gl.BindTexture(GL_TEXTURE_2D, oldTexture);
gl.ActiveTexture(oldActive);
gl.Finish();
}
}
_bitmap.Present(this);
_presentCallback();
}
public void Dispose()
{
var gl = _context.GlInterface;
_bitmap.Present(null);
if(_disposed)
return;
using (_context.MakeCurrent())
using (Lock())
{
if(_disposed)
return;
_disposed = true;
gl.DeleteTextures(2, new[] { _texture, _frontBuffer });
}
}
int IGlPresentableOpenGlSurface.GetTextureId()
{
return _frontBuffer;
}
public int InternalFormat { get; }
public IDisposable Lock() => _lock.Lock();
}
}

81
src/Skia/Avalonia.Skia/Gpu/OpenGlTextureBitmapImpl.cs

@ -1,81 +0,0 @@
using System;
using System.IO;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Imaging;
using Avalonia.Skia.Helpers;
using Avalonia.Utilities;
using SkiaSharp;
namespace Avalonia.Skia
{
class OpenGlTextureBitmapImpl : IOpenGlTextureBitmapImpl, IDrawableBitmapImpl
{
private DisposableLock _lock = new DisposableLock();
private int _textureId;
private int _internalFormat;
public void Dispose()
{
using (Lock())
{
_textureId = 0;
PixelSize = new PixelSize(1, 1);
Version++;
}
}
public Vector Dpi { get; private set; } = new Vector(96, 96);
public PixelSize PixelSize { get; private set; } = new PixelSize(1, 1);
public int Version { get; private set; } = 0;
public void Save(string fileName) => throw new System.NotSupportedException();
public void Save(Stream stream) => throw new System.NotSupportedException();
public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint)
{
// For now silently ignore
if (context.GrContext == null)
return;
using (Lock())
{
if (_textureId == 0)
return;
using (var backendTexture = new GRBackendTexture(PixelSize.Width, PixelSize.Height, false,
new GRGlTextureInfo(
GlConsts.GL_TEXTURE_2D, (uint)_textureId,
(uint)_internalFormat)))
using (var surface = SKSurface.Create(context.GrContext, backendTexture, GRSurfaceOrigin.TopLeft,
SKColorType.Rgba8888))
{
// Again, silently ignore, if something went wrong it's not our fault
if (surface == null)
return;
using (var snapshot = surface.Snapshot())
context.Canvas.DrawImage(snapshot, sourceRect, destRect, paint);
}
}
}
public IDisposable Lock() => _lock.Lock();
public void SetBackBuffer(int textureId, int internalFormat, PixelSize pixelSize, double dpiScaling)
{
using (_lock.Lock())
{
_textureId = textureId;
_internalFormat = internalFormat;
PixelSize = pixelSize;
Dpi = new Vector(96 * dpiScaling, 96 * dpiScaling);
Version++;
}
}
public void SetDirty()
{
using (_lock.Lock())
Version++;
}
}
}

6
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -30,7 +30,7 @@ namespace Avalonia.Skia
return;
}
var gl = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
var gl = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
if (gl != null)
_skiaGpu = new GlSkiaGpu(gl, maxResourceBytes);
}
@ -256,10 +256,10 @@ namespace Avalonia.Skia
}
public IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap()
public IOpenGlBitmapImpl CreateOpenGlBitmap(PixelSize size, Vector dpi)
{
if (_skiaGpu is IOpenGlAwareSkiaGpu glAware)
return glAware.CreateOpenGlTextureBitmap();
return glAware.CreateOpenGlBitmap(size, dpi);
if (_skiaGpu == null)
throw new PlatformNotSupportedException("GPU acceleration is not available");
throw new PlatformNotSupportedException(

10
src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs

@ -109,10 +109,16 @@ namespace Avalonia.Skia
/// <inheritdoc />
public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint)
{
using (var image = SnapshotImage())
if (sourceRect.Left == 0 && sourceRect.Top == 0 && sourceRect.Size == destRect.Size)
{
context.Canvas.DrawImage(image, sourceRect, destRect, paint);
_surface.Canvas.Flush();
_surface.Draw(context.Canvas, destRect.Left, destRect.Top, paint);
}
else
using (var image = SnapshotImage())
{
context.Canvas.DrawImage(image, sourceRect, destRect, paint);
}
}
/// <summary>

9
src/Windows/Avalonia.Win32/Win32GlManager.cs

@ -1,26 +1,27 @@
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
namespace Avalonia.Win32
{
static class Win32GlManager
{
/// <summary>This property is initialized if drawing platform requests OpenGL support</summary>
public static EglGlPlatformFeature EglFeature { get; private set; }
public static EglPlatformOpenGlInterface EglPlatformInterface { get; private set; }
private static bool s_attemptedToInitialize;
public static void Initialize()
{
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToFunc(() =>
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToFunc(() =>
{
if (!s_attemptedToInitialize)
{
EglFeature = EglGlPlatformFeature.TryCreate(() => new AngleWin32EglDisplay());
EglPlatformInterface = EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
s_attemptedToInitialize = true;
}
return EglFeature;
return EglPlatformInterface;
});
}
}

6
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -7,6 +7,8 @@ using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Win32.Input;
@ -103,8 +105,8 @@ namespace Avalonia.Win32
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
if (Win32GlManager.EglFeature != null)
_gl = new EglGlPlatformSurface(Win32GlManager.EglFeature.DeferredContext, this);
if (Win32GlManager.EglPlatformInterface != null)
_gl = new EglGlPlatformSurface(Win32GlManager.EglPlatformInterface, this);
Screen = new ScreenImpl();

20
src/iOS/Avalonia.iOS/EaglDisplay.cs

@ -1,15 +1,18 @@
using System;
using System.Reactive.Disposables;
using Avalonia.OpenGL;
using OpenGLES;
using OpenTK.Graphics.ES30;
namespace Avalonia.iOS
{
class EaglFeature : IWindowingPlatformGlFeature
class EaglFeature : IPlatformOpenGlInterface
{
public IGlContext PrimaryContext => Context;
public IGlContext CreateSharedContext() => throw new NotSupportedException();
public bool CanShareContexts => false;
public bool CanCreateContexts => false;
public IGlContext CreateContext() => throw new System.NotSupportedException();
public IGlContext MainContext => Context;
public GlContext Context { get; } = new GlContext();
}
@ -61,9 +64,18 @@ namespace Avalonia.iOS
return new ResetContext(old);
}
public IDisposable EnsureCurrent()
{
if(EAGLContext.CurrentContext == Context)
return Disposable.Empty;
return MakeCurrent();
}
public bool IsSharedWith(IGlContext context) => false;
public GlVersion Version { get; } = new GlVersion(GlProfileType.OpenGLES, 3, 0);
public GlInterface GlInterface { get; }
public int SampleCount { get; } = 0;
public int StencilSize { get; } = 9;
}
}
}

3
src/iOS/Avalonia.iOS/EaglLayerSurface.cs

@ -2,6 +2,7 @@
using System;
using System.Threading;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Surfaces;
using CoreAnimation;
using OpenTK.Graphics.ES30;
@ -91,4 +92,4 @@ namespace Avalonia.iOS
}
}
}
}
}

2
src/iOS/Avalonia.iOS/Platform.cs

@ -26,7 +26,7 @@ namespace Avalonia.iOS
var keyboard = new KeyboardDevice();
var softKeyboard = new SoftKeyboardHelper();
AvaloniaLocator.CurrentMutable
.Bind<IWindowingPlatformGlFeature>().ToConstant(GlFeature)
.Bind<IPlatformOpenGlInterface>().ToConstant(GlFeature)
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactoryStub())
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformStub())
.Bind<IClipboard>().ToConstant(new ClipboardImpl())

Loading…
Cancel
Save