Browse Source

OpenGL acceleration support

pull/1977/head
Nikita Tsukanov 7 years ago
parent
commit
fad3775bde
  1. 6
      samples/ControlCatalog/Program.cs
  2. 8
      src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  3. 2
      src/Avalonia.Native.OSX/common.h
  4. 251
      src/Avalonia.Native.OSX/gl.mm
  5. 10
      src/Avalonia.Native.OSX/main.mm
  6. 85
      src/Avalonia.Native.OSX/window.mm
  7. 9
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  8. 134
      src/Avalonia.Native/GlPlatformFeature.cs
  9. 67
      src/Avalonia.Native/WindowImplBase.cs
  10. 45
      src/headers/avalonia-native.h

6
samples/ControlCatalog/Program.cs

@ -58,7 +58,11 @@ namespace ControlCatalog.NetCore
var libraryPath = Path.Combine(Directory.GetCurrentDirectory(),
"../../src/Avalonia.Native.OSX/build/Avalonia.Native.OSX/Build/Products/Debug/libAvalonia.Native.OSX.dylib");
return AppBuilder.Configure<App>().UseAvaloniaNative(libraryPath).UseSkia();
return AppBuilder.Configure<App>().UseAvaloniaNative(libraryPath, opts =>
{
opts.UseGpu = true;
opts.UseDeferredRendering = true;
}).UseSkia();
}
}

8
src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -13,6 +13,8 @@
5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; };
AB573DC4217605E400D389A2 /* gl.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB573DC3217605E400D389A2 /* gl.mm */; };
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; };
@ -29,6 +31,8 @@
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; };
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; };
AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
AB573DC3217605E400D389A2 /* gl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = gl.mm; sourceTree = "<group>"; };
AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = "<group>"; };
AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
@ -41,6 +45,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -51,6 +56,7 @@
AB661C1C2148230E00291242 /* Frameworks */ = {
isa = PBXGroup;
children = (
AB1E522B217613570091CD71 /* OpenGL.framework */,
AB661C1D2148230F00291242 /* AppKit.framework */,
);
name = Frameworks;
@ -59,6 +65,7 @@
AB7A61E62147C814003C5833 = {
isa = PBXGroup;
children = (
AB573DC3217605E400D389A2 /* gl.mm */,
5BF943652167AD1D009CAE35 /* cursor.h */,
5B21A981216530F500CEE36E /* cursor.mm */,
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */,
@ -159,6 +166,7 @@
37A517B32159597E00FBA241 /* Screens.mm in Sources */,
AB00E4F72147CA920032A60A /* main.mm in Sources */,
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */,
AB573DC4217605E400D389A2 /* gl.mm in Sources */,
AB661C202148286E00291242 /* window.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

2
src/Avalonia.Native.OSX/common.h

@ -17,6 +17,8 @@ extern IAvnSystemDialogs* CreateSystemDialogs();
extern IAvnScreens* CreateScreens();
extern IAvnClipboard* CreateClipboard();
extern IAvnCursorFactory* CreateCursorFactory();
extern IAvnGlFeature* GetGlFeature();
extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view);
extern NSPoint ToNSPoint (AvnPoint p);
extern AvnPoint ToAvnPoint (NSPoint p);

251
src/Avalonia.Native.OSX/gl.mm

@ -0,0 +1,251 @@
#include "common.h"
#include <OpenGL/gl.h>
#include <dlfcn.h>
template <typename T, size_t N> char (&ArrayCounter(T (&a)[N]))[N];
#define ARRAY_COUNT(a) (sizeof(ArrayCounter(a)))
NSOpenGLPixelFormat* CreateFormat()
{
NSOpenGLPixelFormatAttribute attribs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 32,
NSOpenGLPFAStencilSize, 8,
NSOpenGLPFADepthSize, 8,
0
};
return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
}
class AvnGlContext : public virtual ComSingleObject<IAvnGlContext, &IID_IAvnGlContext>
{
public:
FORWARD_IUNKNOWN()
NSOpenGLContext* GlContext;
GLuint Framebuffer, RenderBuffer, StencilBuffer;
AvnGlContext(NSOpenGLContext* gl, bool offscreen)
{
Framebuffer = 0;
RenderBuffer = 0;
StencilBuffer = 0;
GlContext = gl;
if(offscreen)
{
[GlContext makeCurrentContext];
glGenFramebuffersEXT(1, &Framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER, Framebuffer);
glGenRenderbuffersEXT(1, &RenderBuffer);
glGenRenderbuffersEXT(1, &StencilBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER, StencilBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, StencilBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER, RenderBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, RenderBuffer);
}
}
virtual HRESULT MakeCurrent()
{
[GlContext makeCurrentContext];/*
glBindFramebufferEXT(GL_FRAMEBUFFER, Framebuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER, RenderBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, RenderBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER, StencilBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, StencilBuffer);*/
return S_OK;
}
};
class AvnGlDisplay : public virtual ComSingleObject<IAvnGlDisplay, &IID_IAvnGlDisplay>
{
int _sampleCount, _stencilSize;
void* _libgl;
public:
FORWARD_IUNKNOWN()
AvnGlDisplay(int sampleCount, int stencilSize)
{
_sampleCount = sampleCount;
_stencilSize = stencilSize;
_libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", RTLD_LAZY);
}
virtual HRESULT GetSampleCount(int* ret)
{
*ret = _sampleCount;
return S_OK;
}
virtual HRESULT GetStencilSize(int* ret)
{
*ret = _stencilSize;
return S_OK;
}
virtual HRESULT ClearContext()
{
[NSOpenGLContext clearCurrentContext];
return S_OK;
}
virtual void* GetProcAddress(char* proc)
{
return dlsym(_libgl, proc);
}
};
class GlFeature : public virtual ComSingleObject<IAvnGlFeature, &IID_IAvnGlFeature>
{
IAvnGlDisplay* _display;
IAvnGlContext *_immediate;
public:
FORWARD_IUNKNOWN()
AvnGlContext* ViewContext;
GlFeature(IAvnGlDisplay* display, IAvnGlContext* immediate, AvnGlContext* viewContext)
{
_display = display;
_immediate = immediate;
ViewContext = viewContext;
}
virtual HRESULT ObtainDisplay(IAvnGlDisplay**retOut)
{
*retOut = _display;
_display->AddRef();
return S_OK;
}
virtual HRESULT ObtainImmediateContext(IAvnGlContext**retOut)
{
*retOut = _immediate;
_immediate->AddRef();
return S_OK;
}
};
static GlFeature* Feature;
GlFeature* CreateGlFeature()
{
auto format = CreateFormat();
if(format == nil)
{
NSLog(@"Unable to choose pixel format");
return NULL;
}
auto immediateContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
if(immediateContext == nil)
{
NSLog(@"Unable to create NSOpenGLContext");
return NULL;
}
NSOpenGLContext* viewContext = [[NSOpenGLContext alloc] initWithFormat: format shareContext: immediateContext];
if(viewContext == nil)
{
NSLog(@"Unable to create shared NSOpenGLContext");
return NULL;
}
int stencilBits = 0, sampleCount = 0;
auto fmt = CGLGetPixelFormat([immediateContext CGLContextObj]);
CGLDescribePixelFormat(fmt, 0, kCGLPFASamples, &sampleCount);
CGLDescribePixelFormat(fmt, 0, kCGLPFAStencilSize, &stencilBits);
auto offscreen = new AvnGlContext(immediateContext, true);
auto view = new AvnGlContext(viewContext, false);
auto display = new AvnGlDisplay(sampleCount, stencilBits);
return new GlFeature(display, offscreen, view);
}
static GlFeature* GetFeature()
{
if(Feature == nil)
Feature = CreateGlFeature();
return Feature;
}
extern IAvnGlFeature* GetGlFeature()
{
return GetFeature();
}
class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession>
{
NSView* _view;
NSWindow* _window;
NSOpenGLContext* _context;
public:
FORWARD_IUNKNOWN()
AvnGlRenderingSession(NSWindow*window, NSView* view, NSOpenGLContext* context)
{
_context = context;
_window = window;
_view = view;
}
virtual HRESULT GetPixelSize(AvnPixelSize* ret)
{
auto fsize = [_view convertSizeToBacking: [_view frame].size];
ret->Width = (int)fsize.width;
ret->Height = (int)fsize.height;
return S_OK;
}
virtual HRESULT GetScaling(double* ret)
{
*ret = [_window backingScaleFactor];
return S_OK;
}
virtual ~AvnGlRenderingSession()
{
glFlush();
[_context flushBuffer];
[_context setView:nil];
[_view unlockFocus];
}
};
class AvnGlRenderTarget : public ComSingleObject<IAvnGlSurfaceRenderTarget, &IID_IAvnGlSurfaceRenderTarget>
{
NSView* _view;
NSWindow* _window;
public:
FORWARD_IUNKNOWN()
AvnGlRenderTarget(NSWindow* window, NSView*view)
{
_window = window;
_view = view;
}
virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret)
{
auto f = GetFeature();
if(f == NULL)
return E_FAIL;
if(![_view lockFocusIfCanDraw])
return E_ABORT;
auto gl = f->ViewContext->GlContext;
[gl setView: _view];
[gl makeCurrentContext];
auto frame = [_view frame];
*ret = new AvnGlRenderingSession(_window, _view, gl);
return S_OK;
}
};
extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view)
{
return new AvnGlRenderTarget(window, view);
}

10
src/Avalonia.Native.OSX/main.mm

@ -123,6 +123,16 @@ public:
*ppv = ::CreateCursorFactory();
return S_OK;
}
virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv)
{
auto rv = ::GetGlFeature();
if(rv == NULL)
return E_FAIL;
rv->AddRef();
*ppv = rv;
return S_OK;
}
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()

85
src/Avalonia.Native.OSX/window.mm

@ -5,6 +5,45 @@
#include "window.h"
#include "KeyTransform.h"
#include "cursor.h"
#include <OpenGL/gl.h>
class SoftwareDrawingOperation
{
public:
void* Data = 0;
AvnFramebuffer Desc;
void Alloc(NSView* view)
{
auto logicalSize = [view frame].size;
auto pixelSize = [view convertSizeToBacking:logicalSize];
int w = pixelSize.width;
int h = pixelSize.height;
int stride = w * 4;
Data = malloc(h * stride);
Desc = {
.Data = Data,
.Stride = stride,
.Width = w,
.Height = h,
.PixelFormat = kAvnRgba8888,
.Dpi = AvnVector { .X = w / logicalSize.width * 96, .Y = h / logicalSize.height * 96}
};
}
void Dealloc()
{
if(Data != NULL)
{
free(Data);
Data = NULL;
}
}
~SoftwareDrawingOperation()
{
Dealloc();
}
};
class WindowBaseImpl : public virtual ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>, public INSWindowHolder
{
@ -22,6 +61,7 @@ public:
AvnView* View;
AvnWindow* Window;
ComPtr<IAvnWindowBaseEvents> BaseEvents;
SoftwareDrawingOperation CurrentSwDrawingOperation;
AvnPoint lastPositionSet;
NSString* _lastTitle;
@ -279,6 +319,16 @@ public:
return S_OK;
}
virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret)
{
if(![[NSThread currentThread] isMainThread])
return E_FAIL;
if(CurrentSwDrawingOperation.Data == NULL)
CurrentSwDrawingOperation.Alloc(View);
*ret = CurrentSwDrawingOperation.Desc;
return S_OK;
}
virtual HRESULT SetCursor(IAvnCursor* cursor)
{
@autoreleasepool
@ -300,6 +350,14 @@ public:
[cursor set];
}
}
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ppv)
{
if(View == NULL)
return E_FAIL;
*ppv = ::CreateGlRenderTarget(Window, View);
return S_OK;
}
protected:
virtual NSWindowStyleMask GetStyle()
@ -625,6 +683,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
-(AvnView*) initWithParent: (WindowBaseImpl*) parent
{
self = [super init];
[self setWantsBestResolutionOpenGLSurface:true];
_parent = parent;
_area = nullptr;
return self;
@ -632,7 +691,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (BOOL)isOpaque
{
return false;
return YES;
}
- (BOOL)acceptsFirstResponder
@ -706,23 +765,13 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
}
auto logicalSize = [self frame].size;
auto pixelSize = [self convertSizeToBacking:logicalSize];
int w = pixelSize.width;
int h = pixelSize.height;
int stride = w * 4;
void*ptr = malloc(h * stride);
AvnFramebuffer fb = {
.Data = ptr,
.Stride = stride,
.Width = w,
.Height = h,
.PixelFormat = kAvnRgba8888,
.Dpi = AvnVector { .X = w / logicalSize.width * 96, .Y = h / logicalSize.height * 96}
};
_parent->BaseEvents->SoftwareDraw(&fb);
[self drawFb: &fb];
free(ptr);
auto swOp = &_parent->CurrentSwDrawingOperation;
_parent->BaseEvents->Paint();
if(swOp->Data != NULL)
[self drawFb: &swOp->Desc];
swOp->Dealloc();
return;
}
-(void) redrawSelf

9
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -8,6 +8,7 @@ using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Native.Interop;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
@ -74,7 +75,9 @@ namespace Avalonia.Native
.Bind<IClipboard>().ToConstant(new ClipboardImpl(_factory.CreateClipboard()))
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<ISystemDialogImpl>().ToConstant(new SystemDialogs(_factory.CreateSystemDialogs()));
.Bind<ISystemDialogImpl>().ToConstant(new SystemDialogs(_factory.CreateSystemDialogs()))
.Bind<IWindowingPlatformGlFeature>().ToConstant(new GlPlatformFeature(_factory.ObtainGlFeature()))
.Bind<AvaloniaNativeOptions>().ToConstant(opts);
}
public IWindowImpl CreateWindow()
@ -116,7 +119,9 @@ namespace Avalonia.Native
public class AvaloniaNativeOptions
{
public AvaloniaNativeMacOptions MacOptions { get; set; }
public AvaloniaNativeMacOptions MacOptions { get; set; }
public bool UseDeferredRendering { get; set; } = true;
public bool UseGpu { get; set; } = false;
internal AvaloniaNativeOptions(IAvaloniaNativeFactory factory)
{
var mac = factory.GetMacOptions();

134
src/Avalonia.Native/GlPlatformFeature.cs

@ -0,0 +1,134 @@
using System;
using Avalonia.OpenGL;
using Avalonia.Native.Interop;
using System.Drawing;
using Avalonia.Threading;
namespace Avalonia.Native
{
class GlPlatformFeature : IWindowingPlatformGlFeature
{
public GlPlatformFeature(IAvnGlFeature feature)
{
Display = new GlDisplay(feature.ObtainDisplay());
ImmediateContext = new GlContext(Display, feature.ObtainImmediateContext());
}
public IGlContext ImmediateContext { get; }
public GlDisplay Display { get; }
}
class GlDisplay : IGlDisplay
{
private readonly IAvnGlDisplay _display;
public GlDisplay(IAvnGlDisplay display)
{
_display = display;
GlInterface = new GlInterface((name, optional) =>
{
var rv = _display.GetProcAddress(name);
if (rv == IntPtr.Zero && !optional)
throw new OpenGlException($"{name} not found in system OpenGL");
return rv;
});
}
public GlDisplayType Type => GlDisplayType.OpenGL2;
public GlInterface GlInterface { get; }
public int SampleCount => _display.GetSampleCount();
public int StencilSize => _display.GetStencilSize();
public void ClearContext() => _display.ClearContext();
}
class GlContext : IGlContext
{
public IAvnGlContext Context { get; }
public GlContext(GlDisplay display, IAvnGlContext context)
{
Display = display;
Context = context;
}
public IGlDisplay Display { get; }
public void MakeCurrent(IGlSurface surface)
{
if (surface != null)
throw new ArgumentException(nameof(surface));
Context.MakeCurrent();
}
}
class GlPlatformSurfaceRenderTarget : IGlPlatformSurfaceRenderTarget
{
private IAvnGlSurfaceRenderTarget _target;
public GlPlatformSurfaceRenderTarget(IAvnGlSurfaceRenderTarget target)
{
_target = target;
}
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var feature = (GlPlatformFeature)AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
return new GlPlatformSurfaceRenderingSession(feature.Display, _target.BeginDrawing());
}
public void Dispose()
{
_target?.Dispose();
_target = null;
}
}
class GlPlatformSurfaceRenderingSession : IGlPlatformSurfaceRenderingSession
{
private IAvnGlSurfaceRenderingSession _session;
public GlPlatformSurfaceRenderingSession(GlDisplay display, IAvnGlSurfaceRenderingSession session)
{
Display = display;
_session = session;
}
public IGlDisplay Display { get; }
public System.Drawing.Size PixelSize
{
get
{
var s = _session.GetPixelSize();
return new System.Drawing.Size(s.Width, s.Height);
}
}
public double Scaling => _session.GetScaling();
public void Dispose()
{
_session?.Dispose();
_session = null;
}
}
class GlPlatformSurface : IGlPlatformSurface
{
private readonly IAvnWindowBase _window;
public GlPlatformSurface(IAvnWindowBase window)
{
_window = window;
}
public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
return new GlPlatformSurfaceRenderTarget(_window.CreateGlRenderTarget());
}
}
}

67
src/Avalonia.Native/WindowImplBase.cs

@ -8,27 +8,42 @@ using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Native.Interop;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
namespace Avalonia.Native
{
public class WindowBaseImpl : IWindowBaseImpl, IFramebufferPlatformSurface
public class WindowBaseImpl : IWindowBaseImpl,
IFramebufferPlatformSurface
{
IInputRoot _inputRoot;
IAvnWindowBase _native;
bool _isClosed;
private object _syncRoot = new object();
private bool _deferredRendering = true;
private bool _deferredRendering = false;
private bool _gpu = false;
private readonly IMouseDevice _mouse;
private readonly IKeyboardDevice _keyboard;
private readonly IStandardCursorFactory _cursorFactory;
private Size _savedLogicalSize;
private Size _lastRenderedLogicalSize;
private double _savedScaling;
private GlPlatformSurface _glSurface;
public WindowBaseImpl()
{
var opts = AvaloniaLocator.Current.GetService<AvaloniaNativeOptions>();
// GPU is currently not compatible with DeferredRenderer
if (opts.UseGpu)
{
_gpu = true;
}
else
_deferredRendering = opts.UseDeferredRendering;
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
_mouse = AvaloniaLocator.Current.GetService<IMouseDevice>();
_cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();
@ -37,7 +52,7 @@ namespace Avalonia.Native
protected void Init(IAvnWindowBase window, IAvnScreens screens)
{
_native = window;
_glSurface = new GlPlatformSurface(window);
Screen = new ScreenImpl(screens);
_savedLogicalSize = ClientSize;
_savedScaling = Scaling;
@ -51,9 +66,12 @@ namespace Avalonia.Native
return new Size(s.Width, s.Height);
}
}
SavedFramebuffer _framebuffer;
public IEnumerable<object> Surfaces => new[] { this };
public IEnumerable<object> Surfaces => new[] {
(_gpu ? _glSurface : (object)null),
this
};
public ILockedFramebuffer Lock()
{
if(_deferredRendering)
@ -72,13 +90,9 @@ namespace Avalonia.Native
return true;
}
}, (int)w, (int)h, new Vector(dpi, dpi));
}
}
var fb = _framebuffer;
_framebuffer = null;
if (fb == null)
throw new InvalidOperationException("Lock call without corresponding Paint event");
return fb;
return new FramebufferWrapper(_native.GetSoftwareFramebuffer());
}
public Action<Rect> Paint { get; set; }
@ -87,14 +101,23 @@ namespace Avalonia.Native
public IMouseDevice MouseDevice => AvaloniaNativePlatform.MouseDevice;
class SavedFramebuffer : ILockedFramebuffer
class FramebufferWrapper : ILockedFramebuffer
{
public FramebufferWrapper(AvnFramebuffer fb)
{
Address = fb.Data;
Width = fb.Width;
Height = fb.Height;
RowBytes = fb.Stride;
Dpi = new Vector(fb.Dpi.X, fb.Dpi.Y);
Format = (PixelFormat)fb.PixelFormat;
}
public IntPtr Address { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int RowBytes {get;set;}
public Vector Dpi { get; set; }
public PixelFormat Format => PixelFormat.Rgba8888;
public PixelFormat Format { get; }
public void Dispose()
{
// Do nothing
@ -128,21 +151,11 @@ namespace Avalonia.Native
void IAvnWindowBaseEvents.Deactivated() => _parent.Deactivated?.Invoke();
void IAvnWindowBaseEvents.SoftwareDraw(ref AvnFramebuffer fb)
void IAvnWindowBaseEvents.Paint()
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
_parent._framebuffer = new SavedFramebuffer
{
Address = fb.Data,
RowBytes = fb.Stride,
Width = fb.Width,
Height = fb.Height,
Dpi = new Vector(fb.Dpi.X, fb.Dpi.Y)
};
_parent.Paint?.Invoke(new Rect(0, 0, fb.Width / (fb.Dpi.X / 96), fb.Height / (fb.Dpi.Y / 96)));
var s = _parent.ClientSize;
_parent.Paint?.Invoke(new Rect(0, 0, s.Width, s.Height));
}
void IAvnWindowBaseEvents.Resized(AvnSize size)
@ -256,7 +269,7 @@ namespace Avalonia.Native
public void Invalidate(Rect rect)
{
if (!_deferredRendering)
if (!_deferredRendering && _native != null)
_native.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y });
}

45
src/headers/avalonia-native.h

@ -17,12 +17,22 @@ struct IAvnScreens;
struct IAvnClipboard;
struct IAvnCursor;
struct IAvnCursorFactory;
struct IAvnGlFeature;
struct IAvnGlContext;
struct IAvnGlDisplay;
struct IAvnGlSurfaceRenderTarget;
struct IAvnGlSurfaceRenderingSession;
struct AvnSize
{
double Width, Height;
};
struct AvnPixelSize
{
int Width, Height;
};
struct AvnRect
{
double X, Y, Width, Height;
@ -160,6 +170,7 @@ public:
virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0;
virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) = 0;
};
AVNCOM(IAvnWindowBase, 02) : IUnknown
@ -183,6 +194,8 @@ AVNCOM(IAvnWindowBase, 02) : IUnknown
virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) = 0;
virtual HRESULT SetTopMost (bool value) = 0;
virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) = 0;
};
AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
@ -203,7 +216,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown
{
virtual HRESULT SoftwareDraw(AvnFramebuffer* fb) = 0;
virtual HRESULT Paint() = 0;
virtual void Closed() = 0;
virtual void Activated() = 0;
virtual void Deactivated() = 0;
@ -315,4 +328,34 @@ AVNCOM(IAvnCursorFactory, 11) : IUnknown
};
AVNCOM(IAvnGlFeature, 12) : IUnknown
{
virtual HRESULT ObtainDisplay(IAvnGlDisplay**retOut) = 0;
virtual HRESULT ObtainImmediateContext(IAvnGlContext**retOut) = 0;
};
AVNCOM(IAvnGlDisplay, 13) : IUnknown
{
virtual HRESULT GetSampleCount(int* ret) = 0;
virtual HRESULT GetStencilSize(int* ret) = 0;
virtual HRESULT ClearContext() = 0;
virtual void* GetProcAddress(char* proc) = 0;
};
AVNCOM(IAvnGlContext, 14) : IUnknown
{
virtual HRESULT MakeCurrent() = 0;
};
AVNCOM(IAvnGlSurfaceRenderTarget, 15) : IUnknown
{
virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret) = 0;
};
AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown
{
virtual HRESULT GetPixelSize(AvnPixelSize* ret) = 0;
virtual HRESULT GetScaling(double* ret) = 0;
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();

Loading…
Cancel
Save