Browse Source
[OSX] Use backing CALayer with offscreen-rendered IOSurface # Conflicts: # native/Avalonia.Native/src/OSX/window.mm # src/Avalonia.Native/AvaloniaNativePlatform.csforeign-embed-squash
committed by
Dan Walmsley
23 changed files with 630 additions and 559 deletions
@ -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 |
|||
@ -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; |
|||
}; |
|||
|
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue