1
0
Эх сурвалжийг харах

Merge pull request #3525 from AvaloniaUI/iosurf

[OSX] Use backing CALayer with offscreen-rendered IOSurface
danwalmsley 5 жил өмнө
parent
commit
1619799913

+ 11 - 17
native/Avalonia.Native/inc/avalonia-native.h

@@ -177,14 +177,14 @@ AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown
 public:
     virtual HRESULT Initialize() = 0;
     virtual IAvnMacOptions* GetMacOptions() = 0;
-    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) = 0;
-    virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnPopup** ppv) = 0;
+    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv) = 0;
+    virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv) = 0;
     virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0;
     virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0;
     virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0;
     virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
     virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
-    virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) = 0;
+    virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) = 0;
     virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) = 0;
     virtual HRESULT SetAppMenu(IAvnAppMenu* menu) = 0;
     virtual HRESULT CreateMenu (IAvnAppMenu** ppv) = 0;
@@ -219,15 +219,12 @@ AVNCOM(IAvnWindowBase, 02) : IUnknown
     virtual HRESULT SetTopMost (bool value) = 0;
     virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
     virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
-    virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) = 0;
     virtual HRESULT SetMainMenu(IAvnAppMenu* menu) = 0;
     virtual HRESULT ObtainMainMenu(IAvnAppMenu** retOut) = 0;
     virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0;
     virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0;
     virtual HRESULT ObtainNSViewHandle(void** retOut) = 0;
     virtual HRESULT ObtainNSViewHandleRetained(void** retOut) = 0;
-    virtual bool TryLock() = 0;
-    virtual void Unlock() = 0;
 };
 
 AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
@@ -360,24 +357,21 @@ AVNCOM(IAvnCursorFactory, 11) : IUnknown
     virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) = 0;
 };
 
-
-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 HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) = 0;
+    virtual void LegacyClearCurrentContext() = 0;
+    virtual HRESULT WrapContext(void* native, IAvnGlContext**ppv) = 0;
     virtual void* GetProcAddress(char* proc) = 0;
 };
 
 AVNCOM(IAvnGlContext, 14) : IUnknown
 {
-    virtual HRESULT MakeCurrent() = 0;
+    virtual HRESULT MakeCurrent(IUnknown** ppv) = 0;
+    virtual HRESULT LegacyMakeCurrent() = 0;
+    virtual int GetSampleCount() = 0;
+    virtual int GetStencilSize() = 0;
+    virtual void* GetNativeHandle() = 0;
 };
 
 AVNCOM(IAvnGlSurfaceRenderTarget, 15) : IUnknown

+ 13 - 0
native/Avalonia.Native/inc/comimpl.h

@@ -162,6 +162,19 @@ public:
         return _obj;
     }
     
+    TInterface* getRetainedReference()
+    {
+        if(_obj == NULL)
+            return NULL;
+        _obj->AddRef();
+        return _obj;
+    }
+    
+    TInterface** getPPV()
+    {
+        return &_obj;
+    }
+    
     operator TInterface*() const
     {
         return _obj;

+ 12 - 0
native/Avalonia.Native/inc/rendertarget.h

@@ -0,0 +1,12 @@
+
+@protocol IRenderTarget
+-(void) setNewLayer: (CALayer*) layer;
+-(HRESULT) setSwFrame: (AvnFramebuffer*) fb;
+-(void) resize: (AvnPixelSize) size withScale: (float) scale;
+-(AvnPixelSize) pixelSize;
+-(IAvnGlSurfaceRenderTarget*) createSurfaceRenderTarget;
+@end
+
+@interface IOSurfaceRenderTarget : NSObject<IRenderTarget>
+-(IOSurfaceRenderTarget*) initWithOpenGlContext: (IAvnGlContext*) context;
+@end

+ 16 - 4
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@@ -8,6 +8,10 @@
 
 /* Begin PBXBuildFile section */
 		1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; };
+		1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */; };
+		1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */; };
+		1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */; };
+		1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */; };
 		37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; };
 		37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
 		37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
@@ -18,7 +22,6 @@
 		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 */; };
@@ -26,6 +29,10 @@
 
 /* Begin PBXFileReference section */
 		1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = "<group>"; };
+		1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = rendertarget.mm; sourceTree = "<group>"; };
+		1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
+		1A3E5EAD23E9FB1300EDE661 /* cgl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cgl.mm; sourceTree = "<group>"; };
+		1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 		37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = "<group>"; };
 		379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; };
 		37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = "<group>"; };
@@ -41,7 +48,6 @@
 		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>"; };
@@ -54,6 +60,8 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */,
+				1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */,
 				AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
 				AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
 			);
@@ -65,6 +73,8 @@
 		AB661C1C2148230E00291242 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */,
+				1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */,
 				AB1E522B217613570091CD71 /* OpenGL.framework */,
 				AB661C1D2148230F00291242 /* AppKit.framework */,
 			);
@@ -78,7 +88,7 @@
 				37DDA9B121933371002E132B /* AvnString.h */,
 				37DDA9AF219330F8002E132B /* AvnString.mm */,
 				37A4E71A2178846A00EACBCD /* headers */,
-				AB573DC3217605E400D389A2 /* gl.mm */,
+				1A3E5EAD23E9FB1300EDE661 /* cgl.mm */,
 				5BF943652167AD1D009CAE35 /* cursor.h */,
 				5B21A981216530F500CEE36E /* cursor.mm */,
 				5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */,
@@ -91,6 +101,7 @@
 				AB00E4F62147CA920032A60A /* main.mm */,
 				37155CE3233C00EB0034DCE9 /* menu.h */,
 				520624B222973F4100C4DCEF /* menu.mm */,
+				1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */,
 				37A517B22159597E00FBA241 /* Screens.mm */,
 				37C09D8721580FE4006A6758 /* SystemDialogs.mm */,
 				AB7A61F02147C815003C5833 /* Products */,
@@ -180,12 +191,13 @@
 				5B21A982216530F500CEE36E /* cursor.mm in Sources */,
 				37DDA9B0219330F8002E132B /* AvnString.mm in Sources */,
 				AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
+				1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */,
+				1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */,
 				37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */,
 				520624B322973F4100C4DCEF /* menu.mm in Sources */,
 				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;

+ 166 - 0
native/Avalonia.Native/src/OSX/cgl.mm

@@ -0,0 +1,166 @@
+#include "common.h"
+#include <dlfcn.h>
+
+static CGLContextObj CreateCglContext(CGLContextObj share)
+{
+    int attributes[] = {
+        kCGLPFAAccelerated,
+        kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
+        kCGLPFADepthSize, 8,
+        kCGLPFAStencilSize, 8,
+        kCGLPFAColorSize, 32,
+        0
+    };
+    
+    CGLPixelFormatObj pix;
+    CGLError errorCode;
+    GLint num; // stores the number of possible pixel formats
+    errorCode = CGLChoosePixelFormat( (CGLPixelFormatAttribute*)attributes, &pix, &num );
+    if(errorCode != 0)
+        return nil;
+    CGLContextObj ctx = nil;
+    errorCode = CGLCreateContext(pix, share, &ctx );
+    CGLDestroyPixelFormat( pix );
+    if(errorCode != 0)
+        return nil;
+    return ctx;
+};
+
+
+
+class AvnGlContext : public virtual ComSingleObject<IAvnGlContext, &IID_IAvnGlContext>
+{
+    // Debug
+    int _usageCount = 0;
+public:
+    CGLContextObj Context;
+    int SampleCount = 0, StencilBits = 0;
+    FORWARD_IUNKNOWN()
+    
+    class SavedGlContext : public virtual ComUnknownObject
+    {
+        CGLContextObj _savedContext;
+        ComPtr<AvnGlContext> _parent;
+    public:
+        SavedGlContext(CGLContextObj saved, AvnGlContext* parent)
+        {
+            _savedContext = saved;
+            _parent = parent;
+            _parent->_usageCount++;
+        }
+        
+        ~SavedGlContext()
+        {
+            if(_parent->Context == CGLGetCurrentContext())
+                CGLSetCurrentContext(_savedContext);
+            _parent->_usageCount--;
+            CGLUnlockContext(_parent->Context);
+        }
+    };
+    
+    AvnGlContext(CGLContextObj context)
+    {
+        Context = context;
+        CGLPixelFormatObj fmt = CGLGetPixelFormat(context);
+        CGLDescribePixelFormat(fmt, 0, kCGLPFASamples, &SampleCount);
+        CGLDescribePixelFormat(fmt, 0, kCGLPFAStencilSize, &StencilBits);
+        
+    }
+    
+    virtual HRESULT LegacyMakeCurrent() override
+    {
+        if(CGLSetCurrentContext(Context) != 0)
+            return E_FAIL;
+        return S_OK;
+    }
+    
+    virtual HRESULT MakeCurrent(IUnknown** ppv) override
+    {
+        CGLContextObj saved = CGLGetCurrentContext();
+        CGLLockContext(Context);
+        if(CGLSetCurrentContext(Context) != 0)
+        {
+            CGLUnlockContext(Context);
+            return E_FAIL;
+        }
+        *ppv = new SavedGlContext(saved, this);
+        
+        return S_OK;
+    }
+    
+    virtual int GetSampleCount() override
+    {
+        return SampleCount;
+    }
+    
+    virtual int GetStencilSize() override
+    {
+        return StencilBits;
+    }
+    
+    virtual void* GetNativeHandle() override
+    {
+        return Context;
+    }
+    
+    ~AvnGlContext()
+    {
+        CGLReleaseContext(Context);
+    }
+};
+
+class AvnGlDisplay : public virtual ComSingleObject<IAvnGlDisplay, &IID_IAvnGlDisplay>
+{
+    void* _libgl;
+    
+public:
+    FORWARD_IUNKNOWN()
+    
+    AvnGlDisplay()
+    {
+        _libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", RTLD_LAZY);
+    }
+    
+    virtual void* GetProcAddress(char* proc)  override
+    {
+        return dlsym(_libgl, proc);
+    }
+    
+    virtual HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) override
+    {
+        CGLContextObj shareContext = nil;
+        if(share != nil)
+        {
+            AvnGlContext* shareCtx = dynamic_cast<AvnGlContext*>(share);
+            if(shareCtx != nil)
+                shareContext = shareCtx->Context;
+        }
+        CGLContextObj ctx = ::CreateCglContext(shareContext);
+        if(ctx == nil)
+            return E_FAIL;
+        *ppv = new AvnGlContext(ctx);
+        return S_OK;
+    }
+    
+    virtual HRESULT WrapContext(void* native, IAvnGlContext**ppv) override
+    {
+        if(native == nil)
+            return E_INVALIDARG;
+        *ppv = new AvnGlContext((CGLContextObj) native);
+        return S_OK;
+    }
+    
+    virtual void LegacyClearCurrentContext() override
+    {
+        CGLSetCurrentContext(nil);
+    }
+};
+
+static IAvnGlDisplay* GlDisplay = new AvnGlDisplay();
+
+
+extern IAvnGlDisplay* GetGlDisplay()
+{
+    return GlDisplay;
+};
+

+ 3 - 4
native/Avalonia.Native/src/OSX/common.h

@@ -11,14 +11,13 @@
 #include <pthread.h>
 
 extern IAvnPlatformThreadingInterface* CreatePlatformThreading();
-extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events);
-extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events);
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl);
+extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl);
 extern IAvnSystemDialogs* CreateSystemDialogs();
 extern IAvnScreens* CreateScreens();
 extern IAvnClipboard* CreateClipboard();
 extern IAvnCursorFactory* CreateCursorFactory();
-extern IAvnGlFeature* GetGlFeature();
-extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view);
+extern IAvnGlDisplay* GetGlDisplay();
 extern IAvnAppMenu* CreateAppMenu();
 extern IAvnAppMenuItem* CreateAppMenuItem();
 extern IAvnAppMenuItem* CreateAppMenuItemSeperator();

+ 0 - 261
native/Avalonia.Native/src/OSX/gl.mm

@@ -1,261 +0,0 @@
-#include "common.h"
-#include <OpenGL/gl.h>
-#include <dlfcn.h>
-#include "window.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()  override
-    {
-        [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)  override
-    {
-        *ret = _sampleCount;
-        return S_OK;
-    }
-    virtual HRESULT GetStencilSize(int* ret) override
-    {
-        *ret = _stencilSize;
-        return S_OK;
-    }
-    
-    virtual HRESULT ClearContext()  override
-    {
-        [NSOpenGLContext clearCurrentContext];
-        return S_OK;
-    }
-    
-    virtual void* GetProcAddress(char* proc)  override
-    {
-        return dlsym(_libgl, proc);
-    }
-};
-
-
-class GlFeature : public virtual ComSingleObject<IAvnGlFeature, &IID_IAvnGlFeature>
-{
-    IAvnGlDisplay* _display;
-    AvnGlContext *_immediate;
-    NSOpenGLContext* _shared;
-public:
-    FORWARD_IUNKNOWN()
-    NSOpenGLPixelFormat* _format;
-    GlFeature(IAvnGlDisplay* display, AvnGlContext* immediate, NSOpenGLPixelFormat* format)
-    {
-        _display = display;
-        _immediate = immediate;
-        _format = format;
-        _shared = [[NSOpenGLContext alloc] initWithFormat:_format shareContext:_immediate->GlContext];
-    }
-    
-    NSOpenGLContext* CreateContext()
-    {
-        return _shared;
-        //return [[NSOpenGLContext alloc] initWithFormat:_format shareContext:nil];
-    }
-    
-    virtual HRESULT ObtainDisplay(IAvnGlDisplay**retOut)  override
-    {
-        *retOut = _display;
-        _display->AddRef();
-        return S_OK;
-    }
-    
-    virtual HRESULT ObtainImmediateContext(IAvnGlContext**retOut)  override
-    {
-        *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;
-    }
-
-    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 display = new AvnGlDisplay(sampleCount, stencilBits);
-    
-    return new GlFeature(display, offscreen, format);
-}
-
-
-static GlFeature* GetFeature()
-{
-    if(Feature == nil)
-        Feature = CreateGlFeature();
-    return Feature;
-}
-
-extern IAvnGlFeature* GetGlFeature()
-{
-    return GetFeature();
-}
-
-class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession>
-{
-    AvnView* _view;
-    AvnWindow* _window;
-    NSOpenGLContext* _context;
-public:
-    FORWARD_IUNKNOWN()
-    AvnGlRenderingSession(AvnWindow*window, AvnView* view, NSOpenGLContext* context)
-    {
-        _context = context;
-        _window = window;
-        _view = view;
-    }
-    
-    virtual HRESULT GetPixelSize(AvnPixelSize* ret)  override
-    {
-        *ret = [_view getPixelSize];
-        return S_OK;
-    }
-    virtual HRESULT GetScaling(double* ret)  override
-    {
-        *ret = [_window getScaling];
-        return S_OK;
-    }
-    
-    virtual ~AvnGlRenderingSession()
-    {
-        [_context flushBuffer];
-        [NSOpenGLContext clearCurrentContext];
-        CGLUnlockContext([_context CGLContextObj]);
-        [_view unlockFocus];
-    }
-};
-
-class AvnGlRenderTarget : public ComSingleObject<IAvnGlSurfaceRenderTarget, &IID_IAvnGlSurfaceRenderTarget>
-{
-    NSView* _view;
-    NSWindow* _window;
-    NSOpenGLContext* _context;
-public:
-    FORWARD_IUNKNOWN()
-    AvnGlRenderTarget(NSWindow* window, NSView*view)
-    {
-        _window = window;
-        _view = view;
-        _context = GetFeature()->CreateContext();
-    }
-    
-    virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret)  override
-    {
-        auto f = GetFeature();
-        if(f == NULL)
-            return E_FAIL;
-        
-        @try
-        {
-            if(![_view lockFocusIfCanDraw])
-                return E_ABORT;
-        }
-        @catch(NSException* exception)
-        {
-            return E_ABORT;
-        }
-        
-        
-        auto gl = _context;
-        CGLLockContext([_context CGLContextObj]);
-        [gl setView: _view];
-        [gl update];
-        [gl makeCurrentContext];
-        *ret = new AvnGlRenderingSession(_window, _view, gl);
-        return S_OK;
-    }
-};
-
-extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view)
-{
-    return new AvnGlRenderTarget(window, view);
-}

+ 6 - 6
native/Avalonia.Native/src/OSX/main.mm

@@ -174,20 +174,20 @@ public:
         return (IAvnMacOptions*)new MacOptions();
     }
     
-    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv)  override
+    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv)  override
     {
         if(cb == nullptr || ppv == nullptr)
             return E_POINTER;
-        *ppv = CreateAvnWindow(cb);
+        *ppv = CreateAvnWindow(cb, gl);
         return S_OK;
     };
     
-    virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnPopup** ppv) override
+    virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv) override
     {
         if(cb == nullptr || ppv == nullptr)
             return E_POINTER;
         
-        *ppv = CreateAvnPopup(cb);
+        *ppv = CreateAvnPopup(cb, gl);
         return S_OK;
     }
     
@@ -221,9 +221,9 @@ public:
         return S_OK;
     }
     
-    virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) override
+    virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) override
     {
-        auto rv = ::GetGlFeature();
+        auto rv = ::GetGlDisplay();
         if(rv == NULL)
             return E_FAIL;
         rv->AddRef();

+ 284 - 0
native/Avalonia.Native/src/OSX/rendertarget.mm

@@ -0,0 +1,284 @@
+#include "common.h"
+#include "rendertarget.h"
+#import <IOSurface/IOSurface.h>
+#import <IOSurface/IOSurfaceObjC.h>
+
+#include <OpenGL/CGLIOSurface.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/glext.h>
+#include <OpenGL/gl3.h>
+#include <OpenGL/gl3ext.h>
+
+@interface IOSurfaceHolder : NSObject
+@end
+
+@implementation IOSurfaceHolder
+{
+    @public IOSurfaceRef surface;
+    @public AvnPixelSize size;
+    @public float scale;
+    ComPtr<IAvnGlContext> _context;
+    GLuint _framebuffer, _texture, _renderbuffer;
+}
+
+- (IOSurfaceHolder*) initWithSize: (AvnPixelSize) size
+                        withScale: (float)scale
+                withOpenGlContext: (IAvnGlContext*) context
+{
+    long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.Width * 4);
+    long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.Height * bytesPerRow);
+    NSDictionary* options = @{
+                              (id)kIOSurfaceWidth: @(size.Width),
+                              (id)kIOSurfaceHeight:  @(size.Height),
+                              (id)kIOSurfacePixelFormat: @((uint)'BGRA'),
+                              (id)kIOSurfaceBytesPerElement: @(4),
+                              (id)kIOSurfaceBytesPerRow: @(bytesPerRow),
+                              (id)kIOSurfaceAllocSize: @(allocSize),
+                              
+                              //(id)kIOSurfaceCacheMode: @(kIOMapWriteCombineCache),
+                              (id)kIOSurfaceElementWidth: @(1),
+                              (id)kIOSurfaceElementHeight: @(1)
+                              };
+    
+    surface = IOSurfaceCreate((CFDictionaryRef)options);
+    self->scale = scale;
+    self->size = size;
+    self->_context = context;
+    return self;
+}
+
+-(HRESULT) prepareForGlRender
+{
+    if(_context == nil)
+        return E_FAIL;
+    if(CGLGetCurrentContext() != _context->GetNativeHandle())
+        return E_FAIL;
+    if(_framebuffer == 0)
+        glGenFramebuffersEXT(1, &_framebuffer);
+    
+    
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _framebuffer);
+    if(_texture == 0)
+    {
+        glGenTextures(1, &_texture);
+    
+        glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
+        CGLError res = CGLTexImageIOSurface2D((CGLContextObj)_context->GetNativeHandle(),
+                               GL_TEXTURE_RECTANGLE_EXT, GL_RGBA8,
+                               size.Width, size.Height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface, 0);
+        glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
+        
+        if(res != 0)
+        {
+            glDeleteTextures(1, &_texture);
+            _texture = 0;
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+            return E_FAIL;
+        }
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, _texture, 0);
+    }
+    
+    if(_renderbuffer == 0)
+    {
+        glGenRenderbuffers(1, &_renderbuffer);
+        glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
+        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.Width, size.Height);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderbuffer);
+    }
+    
+    return S_OK;
+}
+
+-(void) finishDraw
+{
+    ComPtr<IUnknown> release;
+    _context->MakeCurrent(release.getPPV());
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    glFlush();
+}
+
+-(void) dealloc
+{
+    
+    if(_framebuffer != 0)
+    {
+        ComPtr<IUnknown> release;
+        _context->MakeCurrent(release.getPPV());
+        glDeleteFramebuffers(1, &_framebuffer);
+        if(_texture != 0)
+            glDeleteTextures(1, &_texture);
+        if(_renderbuffer != 0)
+            glDeleteRenderbuffers(1, &_renderbuffer);
+    }
+    IOSurfaceDecrementUseCount(surface);
+}
+@end
+
+static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* target);
+
+@implementation IOSurfaceRenderTarget
+{
+    CALayer* _layer;
+    @public IOSurfaceHolder* surface;
+    @public NSObject* lock;
+    ComPtr<IAvnGlContext> _glContext;
+}
+
+- (IOSurfaceRenderTarget*) initWithOpenGlContext: (IAvnGlContext*) context;
+{
+    self = [super init];
+    _glContext = context;
+    lock = [NSObject new];
+    surface  = nil;
+    [self resize:{1,1} withScale: 1];
+    
+    return self;
+}
+
+- (AvnPixelSize) pixelSize {
+    return {1, 1};
+}
+
+- (CALayer *)layer {
+    return _layer;
+}
+
+- (void)resize:(AvnPixelSize)size withScale: (float) scale;{
+    @synchronized (lock) {
+        if(surface == nil
+           || surface->size.Width != size.Width
+           || surface->size.Height != size.Height
+           || surface->scale != scale)
+            surface = [[IOSurfaceHolder alloc] initWithSize:size withScale:scale withOpenGlContext:_glContext.getRaw()];
+    }
+}
+
+- (void)updateLayer {
+    if ([NSThread isMainThread])
+    {
+        @synchronized (lock) {
+            if(_layer == nil)
+                return;
+            [_layer setContents: nil];
+            if(surface != nil)
+            {
+                [_layer setContentsScale: surface->scale];
+                [_layer setContents: (__bridge IOSurface*) surface->surface];
+            }
+        }
+    }
+    else
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [self updateLayer];
+        });
+}
+
+- (void) setNewLayer:(CALayer *)layer {
+    _layer = layer;
+    [self updateLayer];
+}
+
+- (HRESULT)setSwFrame:(AvnFramebuffer *)fb {
+    @synchronized (lock) {
+        if(fb->PixelFormat == AvnPixelFormat::kAvnRgb565)
+            return E_INVALIDARG;
+        if(surface == nil)
+            return E_FAIL;
+        IOSurfaceRef surf = surface->surface;
+        if(IOSurfaceLock(surf, 0, nil))
+            return E_FAIL;
+        size_t w = MIN(fb->Width, IOSurfaceGetWidth(surf));
+        size_t h = MIN(fb->Height, IOSurfaceGetHeight(surf));
+        size_t wbytes = w*4;
+        size_t sstride = IOSurfaceGetBytesPerRow(surf);
+        size_t fstride = fb->Stride;
+        char*pSurface = (char*)IOSurfaceGetBaseAddress(surf);
+        char*pFb = (char*)fb->Data;
+        for(size_t y = 0; y < h; y++)
+        {
+            memcpy(pSurface + y*sstride, pFb + y*fstride, wbytes);
+        }
+        IOSurfaceUnlock(surf, 0, nil);
+        [self updateLayer];
+        return S_OK;
+    }
+}
+
+-(IAvnGlSurfaceRenderTarget*) createSurfaceRenderTarget
+{
+    return CreateGlRenderTarget(self);
+}
+
+@end
+
+class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession>
+{
+    ComPtr<IUnknown> _releaseContext;
+    IOSurfaceRenderTarget* _target;
+    IOSurfaceHolder* _surface;
+public:
+    FORWARD_IUNKNOWN()
+    AvnGlRenderingSession(IOSurfaceRenderTarget* target, ComPtr<IUnknown> releaseContext)
+    {
+        _target = target;
+        // This happens in a synchronized block set up by AvnRenderTarget, so we take the current surface for this
+        // particular render session
+        _surface = _target->surface;
+        _releaseContext = releaseContext;
+    }
+    
+    virtual HRESULT GetPixelSize(AvnPixelSize* ret)  override
+    {
+        if(!_surface)
+            return E_FAIL;
+        *ret = _surface->size;
+        return S_OK;
+    }
+    
+    virtual HRESULT GetScaling(double* ret)  override
+    {
+        if(!_surface)
+            return E_FAIL;
+        *ret = _surface->scale;
+        return S_OK;
+    }
+    
+    virtual ~AvnGlRenderingSession()
+    {
+        [_surface finishDraw];
+        [_target updateLayer];
+        _releaseContext = nil;
+    }
+};
+
+class AvnGlRenderTarget : public ComSingleObject<IAvnGlSurfaceRenderTarget, &IID_IAvnGlSurfaceRenderTarget>
+{
+    IOSurfaceRenderTarget* _target;
+public:
+    FORWARD_IUNKNOWN()
+    AvnGlRenderTarget(IOSurfaceRenderTarget* target)
+    {
+        _target = target;
+    }
+    
+    virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret)  override
+    {
+        ComPtr<IUnknown> releaseContext;
+        @synchronized (_target->lock) {
+            if(_target->surface == nil)
+                return E_FAIL;
+            _target->_glContext->MakeCurrent(releaseContext.getPPV());
+            HRESULT res = [_target->surface prepareForGlRender];
+            if(res)
+                return res;
+            *ret = new AvnGlRenderingSession(_target, releaseContext);
+            return S_OK;
+        }
+    }
+};
+
+
+static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* target)
+{
+    return new AvnGlRenderTarget(target);
+}

+ 50 - 157
native/Avalonia.Native/src/OSX/window.mm

@@ -7,44 +7,9 @@
 #include "cursor.h"
 #include "menu.h"
 #include <OpenGL/gl.h>
+#include "rendertarget.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
 {
@@ -61,15 +26,18 @@ public:
     AvnView* View;
     AvnWindow* Window;
     ComPtr<IAvnWindowBaseEvents> BaseEvents;
-    SoftwareDrawingOperation CurrentSwDrawingOperation;
+    ComPtr<IAvnGlContext> _glContext;
+    NSObject<IRenderTarget>* renderTarget;
     AvnPoint lastPositionSet;
     NSString* _lastTitle;
     IAvnAppMenu* _mainMenu;
     
-    WindowBaseImpl(IAvnWindowBaseEvents* events)
+    WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl)
     {
         _mainMenu = nullptr;
         BaseEvents = events;
+        _glContext = gl;
+        renderTarget = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext: gl];
         View = [[AvnView alloc] initWithParent:this];
 
         Window = [[AvnWindow alloc] initWithParent:this];
@@ -291,29 +259,6 @@ public:
         return S_OK;
     }
     
-    virtual bool TryLock() override
-    {
-        @autoreleasepool
-        {
-            @try
-            {
-                return [View lockFocusIfCanDraw] == YES;
-            }
-            @catch (NSException*)
-            {
-                return NO;
-            }
-        }
-    }
-    
-    virtual void Unlock() override
-    {
-        @autoreleasepool
-        {
-            [View unlockFocus];
-        }
-    }
-    
     virtual HRESULT BeginMoveDrag () override
     {
         @autoreleasepool
@@ -408,16 +353,6 @@ public:
         return S_OK;
     }
     
-    virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) override
-    {
-        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) override
     {
         @autoreleasepool
@@ -451,8 +386,8 @@ public:
     {
         if(View == NULL)
             return E_FAIL;
-        *ppv = ::CreateGlRenderTarget(Window, View);
-        return S_OK;
+        *ppv = [renderTarget createSurfaceRenderTarget];
+        return *ppv == nil ? E_FAIL : S_OK;
     }
 
 protected:
@@ -490,7 +425,7 @@ private:
     }
     
     ComPtr<IAvnWindowEvents> WindowEvents;
-    WindowImpl(IAvnWindowEvents* events) : WindowBaseImpl(events)
+    WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl)
     {
         WindowEvents = events;
         [Window setCanBecomeKeyAndMain];
@@ -731,6 +666,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     NSEvent* _lastMouseDownEvent;
     bool _lastKeyHandled;
     AvnPixelSize _lastPixelSize;
+    NSObject<IRenderTarget>* _renderTarget;
 }
 
 - (void)onClosed
@@ -741,19 +677,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     }
 }
 
-- (BOOL)lockFocusIfCanDraw
-{
-    @synchronized (self)
-    {
-        if(_parent == nullptr)
-        {
-            return NO;
-        }
-    }
-    
-    return [super lockFocusIfCanDraw];
-}
-
 -(AvnPixelSize) getPixelSize
 {
     return _lastPixelSize;
@@ -764,18 +687,43 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     return _lastMouseDownEvent;
 }
 
+- (void) updateRenderTarget
+{
+    [_renderTarget resize:_lastPixelSize withScale: [[self window] backingScaleFactor]];
+    [self setNeedsDisplayInRect:[self frame]];
+}
+
 -(AvnView*)  initWithParent: (WindowBaseImpl*) parent
 {
     self = [super init];
-    [self setWantsBestResolutionOpenGLSurface:true];
+    _renderTarget = parent->renderTarget;
     [self setWantsLayer:YES];
+    [self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
+    
     _parent = parent;
     _area = nullptr;
     _lastPixelSize.Height = 100;
     _lastPixelSize.Width = 100;
+
     return self;
 }
 
+- (BOOL)isFlipped
+{
+    return YES;
+}
+
+- (BOOL)wantsUpdateLayer
+{
+    return YES;
+}
+
+- (void)setLayer:(CALayer *)layer
+{
+    [_renderTarget setNewLayer: layer];
+    [super setLayer: layer];
+}
+
 - (BOOL)isOpaque
 {
     return YES;
@@ -823,87 +771,32 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     auto fsize = [self convertSizeToBacking: [self frame].size];
     _lastPixelSize.Width = (int)fsize.width;
     _lastPixelSize.Height = (int)fsize.height;
-
+    [self updateRenderTarget];
     _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
 }
 
-- (void) drawFb: (AvnFramebuffer*) fb
-{
-    auto colorSpace = CGColorSpaceCreateDeviceRGB();
-    auto dataProvider = CGDataProviderCreateWithData(NULL, fb->Data, fb->Height*fb->Stride, NULL);
 
-    
-    auto image = CGImageCreate(fb->Width, fb->Height, 8, 32, fb->Stride, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast,
-                               dataProvider, nullptr, false, kCGRenderingIntentDefault);
-    
-    auto ctx = [NSGraphicsContext currentContext];
-    
-    [ctx saveGraphicsState];
-    auto cgc = [ctx CGContext];
-    
-    CGContextDrawImage(cgc, CGRect{0,0, fb->Width/(fb->Dpi.X/96), fb->Height/(fb->Dpi.Y/96)}, image);
-    CGImageRelease(image);
-    CGColorSpaceRelease(colorSpace);
-    CGDataProviderRelease(dataProvider);
-    
-    [ctx restoreGraphicsState];
-
-}
-
-- (void)drawRect:(NSRect)dirtyRect
+- (void)updateLayer
 {
     if (_parent == nullptr)
     {
         return;
     }
-        
-    _parent->BaseEvents->RunRenderPriorityJobs();
     
-    @synchronized (self) {
-        if(_swRenderedFrame != NULL)
-        {
-            [self drawFb: &_swRenderedFrameBuffer];
-            return;
-        }
-    }
-    
-    auto swOp = &_parent->CurrentSwDrawingOperation;
+    _parent->BaseEvents->RunRenderPriorityJobs();
     _parent->BaseEvents->Paint();
-    if(swOp->Data != NULL)
-        [self drawFb: &swOp->Desc];
-    
-    swOp->Dealloc();
-    return;
 }
 
--(void) redrawSelf
+- (void)drawRect:(NSRect)dirtyRect
 {
-    @autoreleasepool
-    {
-        @synchronized(self)
-        {
-            if(!_queuedDisplayFromThread)
-                return;
-            _queuedDisplayFromThread = false;
-        }
-        [self setNeedsDisplayInRect:[self frame]];
-        [self display];
-        
-    }
+    return;
 }
 
 -(void) setSwRenderedFrame: (AvnFramebuffer*) fb dispose: (IUnknown*) dispose
 {
     @autoreleasepool {
-        @synchronized (self) {
-            _swRenderedFrame = dispose;
-            _swRenderedFrameBuffer = *fb;
-            if(!_queuedDisplayFromThread)
-            {
-                _queuedDisplayFromThread = true;
-                [self performSelector:@selector(redrawSelf) onThread:[NSThread mainThread] withObject:NULL waitUntilDone:false modes: AllLoopModes];
-            }
-        }
+        [_renderTarget setSwFrame:fb];
+        dispose->Release();
     }
 }
 
@@ -928,7 +821,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     auto fsize = [self convertSizeToBacking: [self frame].size];
     _lastPixelSize.Width = (int)fsize.width;
     _lastPixelSize.Height = (int)fsize.height;
-    
+    [self updateRenderTarget];
     _parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]);
     
     [super viewDidChangeBackingProperties];
@@ -1478,7 +1371,7 @@ private:
     END_INTERFACE_MAP()
     virtual ~PopupImpl(){}
     ComPtr<IAvnWindowEvents> WindowEvents;
-    PopupImpl(IAvnWindowEvents* events) : WindowBaseImpl(events)
+    PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl)
     {
         WindowEvents = events;
         [Window setLevel:NSPopUpMenuWindowLevel];
@@ -1502,20 +1395,20 @@ protected:
     }
 };
 
-extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events)
+extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl)
 {
     @autoreleasepool
     {
-        IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events));
+        IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events, gl));
         return ptr;
     }
 }
 
-extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events)
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl)
 {
     @autoreleasepool
     {
-        IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events);
+        IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events, gl);
         return ptr;
     }
 }

+ 0 - 42
src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs

@@ -1,42 +0,0 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
-using System.Threading;
-using Avalonia.Native.Interop;
-using Avalonia.Rendering;
-
-namespace Avalonia.Native
-{
-    public class AvaloniaNativeDeferredRendererLock : IDeferredRendererLock
-    {
-        private readonly IAvnWindowBase _window;
-
-        public AvaloniaNativeDeferredRendererLock(IAvnWindowBase window)
-        {
-            _window = window;
-        }
-
-        public IDisposable TryLock()
-        {
-            if (_window.TryLock())
-                return new UnlockDisposable(_window);
-            return null;
-        }
-
-        private sealed class UnlockDisposable : IDisposable
-        {
-            private IAvnWindowBase _window;
-
-            public UnlockDisposable(IAvnWindowBase window)
-            {
-                _window = window;
-            }
-
-            public void Dispose()
-            {
-                Interlocked.Exchange(ref _window, null)?.Unlock();
-            }
-        }
-    }
-}

+ 7 - 3
src/Avalonia.Native/AvaloniaNativePlatform.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 using System;
 using System.Runtime.InteropServices;
+using System.Security.Cryptography;
 using Avalonia.Controls.Platform;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
@@ -17,6 +18,7 @@ namespace Avalonia.Native
     {
         private readonly IAvaloniaNativeFactory _factory;
         private AvaloniaNativePlatformOptions _options;
+        private GlPlatformFeature _glFeature;
 
         [DllImport("libAvaloniaNative")]
         static extern IntPtr CreateAvaloniaNative();
@@ -87,7 +89,7 @@ namespace Avalonia.Native
 
                 _factory.MacOptions.ShowInDock = macOpts?.ShowInDock != false ? 1 : 0;
             }
-
+            
             AvaloniaLocator.CurrentMutable
                 .Bind<IPlatformThreadingInterface>()
                 .ToConstant(new PlatformThreadingInterface(_factory.CreatePlatformThreadingInterface()))
@@ -100,14 +102,16 @@ namespace Avalonia.Native
                 .Bind<IRenderLoop>().ToConstant(new RenderLoop())
                 .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
                 .Bind<ISystemDialogImpl>().ToConstant(new SystemDialogs(_factory.CreateSystemDialogs()))
-                .Bind<IWindowingPlatformGlFeature>().ToConstant(new GlPlatformFeature(_factory.ObtainGlFeature()))
                 .Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Meta))
                 .Bind<IMountedVolumeInfoProvider>().ToConstant(new MacOSMountedVolumeInfoProvider());
+            if (_options.UseGpu)
+                AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>()
+                    .ToConstant(_glFeature = new GlPlatformFeature(_factory.ObtainGlDisplay()));
         }
 
         public IWindowImpl CreateWindow()
         {
-            return new WindowImpl(_factory, _options);
+            return new WindowImpl(_factory, _options, _glFeature);
         }
 
         public IEmbeddableWindowImpl CreateEmbeddableWindow()

+ 1 - 1
src/Avalonia.Native/DeferredFramebuffer.cs

@@ -21,7 +21,7 @@ namespace Avalonia.Native
             Size = new PixelSize(width, height);
             RowBytes = width * 4;
             Dpi = dpi;
-            Format = PixelFormat.Rgba8888;
+            Format = PixelFormat.Bgra8888;
         }
 
         public IntPtr Address { get; set; }

+ 21 - 10
src/Avalonia.Native/GlPlatformFeature.cs

@@ -8,24 +8,31 @@ namespace Avalonia.Native
 {
     class GlPlatformFeature : IWindowingPlatformGlFeature
     {
-
-        public GlPlatformFeature(IAvnGlFeature feature)
+        public GlPlatformFeature(IAvnGlDisplay display)
         {
-            Display = new GlDisplay(feature.ObtainDisplay());
-            ImmediateContext = new GlContext(Display, feature.ObtainImmediateContext());
+            var immediate = display.CreateContext(null);
+            var deferred = display.CreateContext(immediate);
+            GlDisplay = new GlDisplay(display, immediate.SampleCount, immediate.StencilSize);
+            
+            ImmediateContext = new GlContext(Display, immediate);
+            DeferredContext = new GlContext(Display, deferred);
         }
 
         public IGlContext ImmediateContext { get; }
-        public GlDisplay Display { get; }
+        internal GlContext DeferredContext { get; }
+        internal GlDisplay GlDisplay;
+        public GlDisplay Display => GlDisplay;
     }
 
     class GlDisplay : IGlDisplay
     {
         private readonly IAvnGlDisplay _display;
 
-        public GlDisplay(IAvnGlDisplay display)
+        public GlDisplay(IAvnGlDisplay display, int sampleCount, int stencilSize)
         {
             _display = display;
+            SampleCount = sampleCount;
+            StencilSize = stencilSize;
             GlInterface = new GlInterface((name, optional) =>
             {
                 var rv = _display.GetProcAddress(name);
@@ -39,11 +46,11 @@ namespace Avalonia.Native
 
         public GlInterface GlInterface { get; }
 
-        public int SampleCount => _display.GetSampleCount();
+        public int SampleCount { get; }
 
-        public int StencilSize => _display.GetStencilSize();
+        public int StencilSize { get; }
 
-        public void ClearContext() => _display.ClearContext();
+        public void ClearContext() => _display.LegacyClearCurrentContext();
     }
 
     class GlContext : IGlContext
@@ -60,7 +67,7 @@ namespace Avalonia.Native
 
         public void MakeCurrent()
         {
-            Context.MakeCurrent();
+            Context.LegacyMakeCurrent();
         }
     }
 
@@ -109,6 +116,9 @@ namespace Avalonia.Native
 
         public double Scaling => _session.GetScaling();
 
+
+        public bool IsYFlipped => true;
+        
         public void Dispose()
         {
             _session?.Dispose();
@@ -128,5 +138,6 @@ namespace Avalonia.Native
         {
             return new GlPlatformSurfaceRenderTarget(_window.CreateGlRenderTarget());
         }
+
     }
 }

+ 8 - 4
src/Avalonia.Native/PopupImpl.cs

@@ -8,19 +8,23 @@ using Avalonia.Platform;
 
 namespace Avalonia.Native
 {
-    public class PopupImpl : WindowBaseImpl, IPopupImpl
+    class PopupImpl : WindowBaseImpl, IPopupImpl
     {
         private readonly IAvaloniaNativeFactory _factory;
         private readonly AvaloniaNativePlatformOptions _opts;
+        private readonly GlPlatformFeature _glFeature;
+
         public PopupImpl(IAvaloniaNativeFactory factory,
             AvaloniaNativePlatformOptions opts,
-            IWindowBaseImpl parent) : base(opts)
+            GlPlatformFeature glFeature,
+            IWindowBaseImpl parent) : base(opts, glFeature)
         {
             _factory = factory;
             _opts = opts;
+            _glFeature = glFeature;
             using (var e = new PopupEvents(this))
             {
-                Init(factory.CreatePopup(e), factory.CreateScreens());
+                Init(factory.CreatePopup(e, _opts.UseGpu ? glFeature?.DeferredContext.Context : null), factory.CreateScreens());
             }
             PopupPositioner = new ManagedPopupPositioner(new OsxManagedPopupPositionerPopupImplHelper(parent, MoveResize));
         }
@@ -51,7 +55,7 @@ namespace Avalonia.Native
             }
         }
 
-        public override IPopupImpl CreatePopup() => new PopupImpl(_factory, _opts, this);
+        public override IPopupImpl CreatePopup() => new PopupImpl(_factory, _opts, _glFeature, this);
         public IPopupPositioner PopupPositioner { get; }
     }
 }

+ 7 - 3
src/Avalonia.Native/WindowImpl.cs

@@ -14,14 +14,18 @@ namespace Avalonia.Native
     {
         private readonly IAvaloniaNativeFactory _factory;
         private readonly AvaloniaNativePlatformOptions _opts;
+        private readonly GlPlatformFeature _glFeature;
         IAvnWindow _native;
-        public WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts) : base(opts)
+        internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
+            GlPlatformFeature glFeature) : base(opts, glFeature)
         {
             _factory = factory;
             _opts = opts;
+            _glFeature = glFeature;
             using (var e = new WindowEvents(this))
             {
-                Init(_native = factory.CreateWindow(e), factory.CreateScreens());
+                Init(_native = factory.CreateWindow(e,
+                    _opts.UseGpu ? glFeature?.DeferredContext.Context : null), factory.CreateScreens());
             }
 
             NativeMenuExporter = new AvaloniaNativeMenuExporter(_native, factory);
@@ -113,6 +117,6 @@ namespace Avalonia.Native
         public void Move(PixelPoint point) => Position = point;
 
         public override IPopupImpl CreatePopup() =>
-            _opts.OverlayPopups ? null : new PopupImpl(_factory, _opts, this);
+            _opts.OverlayPopups ? null : new PopupImpl(_factory, _opts, _glFeature, this);
     }
 }

+ 17 - 46
src/Avalonia.Native/WindowImplBase.cs

@@ -60,9 +60,9 @@ namespace Avalonia.Native
         private double _savedScaling;
         private GlPlatformSurface _glSurface;
 
-        public WindowBaseImpl(AvaloniaNativePlatformOptions opts)
+        internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, GlPlatformFeature glFeature)
         {
-            _gpu = opts.UseGpu;
+            _gpu = opts.UseGpu && glFeature != null;
             _deferredRendering = opts.UseDeferredRendering;
 
             _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
@@ -75,8 +75,8 @@ namespace Avalonia.Native
             _native = window;
 
             Handle = new MacOSTopLevelWindowHandle(window);
-            
-            _glSurface = new GlPlatformSurface(window);
+            if (_gpu)
+                _glSurface = new GlPlatformSurface(window);
             Screen = new ScreenImpl(screens);
             _savedLogicalSize = ClientSize;
             _savedScaling = Scaling;
@@ -103,25 +103,20 @@ namespace Avalonia.Native
 
         public ILockedFramebuffer Lock()
         {
-            if(_deferredRendering)
+            var w = _savedLogicalSize.Width * _savedScaling;
+            var h = _savedLogicalSize.Height * _savedScaling;
+            var dpi = _savedScaling * 96;
+            return new DeferredFramebuffer(cb =>
             {
-                var w = _savedLogicalSize.Width * _savedScaling;
-                var h = _savedLogicalSize.Height * _savedScaling;
-                var dpi = _savedScaling * 96;
-                return new DeferredFramebuffer(cb =>
+                lock (_syncRoot)
                 {
-                    lock (_syncRoot)
-                    {
-                        if (_native == null)
-                            return false;
-                        cb(_native);
-                        _lastRenderedLogicalSize = _savedLogicalSize;
-                        return true;
-                    }
-                }, (int)w, (int)h, new Vector(dpi, dpi));
-           }
-
-            return new FramebufferWrapper(_native.GetSoftwareFramebuffer());
+                    if (_native == null)
+                        return false;
+                    cb(_native);
+                    _lastRenderedLogicalSize = _savedLogicalSize;
+                    return true;
+                }
+            }, (int)w, (int)h, new Vector(dpi, dpi));
         }
 
         public Action<Rect> Paint { get; set; }
@@ -130,28 +125,6 @@ namespace Avalonia.Native
         public IMouseDevice MouseDevice => _mouse;
         public abstract IPopupImpl CreatePopup();
 
-
-        class FramebufferWrapper : ILockedFramebuffer
-        {
-            public FramebufferWrapper(AvnFramebuffer fb)
-            {
-                Address = fb.Data;
-                Size = new PixelSize(fb.Width, fb.Height);
-                RowBytes = fb.Stride;
-                Dpi = new Vector(fb.Dpi.X, fb.Dpi.Y);
-                Format = (PixelFormat)fb.PixelFormat;
-            }
-            public IntPtr Address { get; set; }
-            public PixelSize Size { get; set; }
-            public int RowBytes {get;set;}
-            public Vector Dpi { get; set; }
-            public PixelFormat Format { get; }
-            public void Dispose()
-            {
-                // Do nothing
-            }
-        }
-
         protected class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
         {
             private readonly WindowBaseImpl _parent;
@@ -278,9 +251,7 @@ namespace Avalonia.Native
         public IRenderer CreateRenderer(IRenderRoot root)
         {
             if (_deferredRendering)
-                return new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>(),
-                    rendererLock:
-                    _gpu ? new AvaloniaNativeDeferredRendererLock(_native) : null);
+                return new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>());
             return new ImmediateRenderer(root);
         }
 

+ 1 - 0
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@@ -107,6 +107,7 @@ namespace Avalonia.OpenGL
                 public IGlDisplay Display => _context.Display;
                 public PixelSize Size => _info.Size;
                 public double Scaling => _info.Scaling;
+                public bool IsYFlipped { get; }
             }
         }
     }

+ 1 - 0
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs

@@ -7,5 +7,6 @@ namespace Avalonia.OpenGL
         IGlDisplay Display { get; }
         PixelSize Size { get; }
         double Scaling { get; }
+        bool IsYFlipped { get; }
     }
 }

+ 1 - 0
src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs

@@ -80,6 +80,7 @@ namespace Avalonia.X11.Glx
                 public IGlDisplay Display => _context.Display;
                 public PixelSize Size => _info.Size;
                 public double Scaling => _info.Scaling;
+                public bool IsYFlipped { get; }
             }
         }
     }

+ 2 - 0
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@@ -234,6 +234,8 @@ namespace Avalonia.LinuxFramebuffer.Output
                 public PixelSize Size => _parent._mode.Resolution;
 
                 public double Scaling => _parent.Scaling;
+
+                public bool IsYFlipped { get; }
             }
 
             public IGlPlatformSurfaceRenderingSession BeginDraw()

+ 1 - 1
src/Skia/Avalonia.Skia/GlRenderTarget.cs

@@ -54,7 +54,7 @@ namespace Avalonia.Skia
                         new GRBackendRenderTarget(size.Width, size.Height, disp.SampleCount, disp.StencilSize,
                             new GRGlFramebufferInfo((uint)fb, GRPixelConfig.Rgba8888.ToGlSizedFormat()));
                     var surface = SKSurface.Create(_grContext, renderTarget,
-                        GRSurfaceOrigin.BottomLeft,
+                        session.IsYFlipped ? GRSurfaceOrigin.TopLeft : GRSurfaceOrigin.BottomLeft,
                         GRPixelConfig.Rgba8888.ToColorType());
 
                     var nfo = new DrawingContextImpl.CreateInfo

+ 1 - 0
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@@ -43,6 +43,7 @@ namespace Avalonia.Skia
                 {
                     GrContext = GRContext.Create(GRBackend.OpenGL, iface);
                 }
+                display.ClearContext();
             }
         }