141 changed files with 2659 additions and 1365 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); |
||||
|
} |
||||
@ -0,0 +1,94 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Avalonia.Utilities |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A list like struct optimized for holding zero or one items.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The type of items held in the list.</typeparam>
|
||||
|
/// <remarks>
|
||||
|
/// Once more than value has been added to this storage it will switch to using <see cref="List"/> internally.
|
||||
|
/// </remarks>
|
||||
|
public ref struct ValueSingleOrList<T> |
||||
|
{ |
||||
|
private bool _isSingleSet; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Single contained value. Only valid if <see cref="IsSingle"/> is set.
|
||||
|
/// </summary>
|
||||
|
public T Single { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// List of values.
|
||||
|
/// </summary>
|
||||
|
public List<T> List { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// If this struct is backed by a list.
|
||||
|
/// </summary>
|
||||
|
public bool HasList => List != null; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// If this struct contains only single value and storage was not promoted to a list.
|
||||
|
/// </summary>
|
||||
|
public bool IsSingle => List == null && _isSingleSet; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds a value.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">Value to add.</param>
|
||||
|
public void Add(T value) |
||||
|
{ |
||||
|
if (List != null) |
||||
|
{ |
||||
|
List.Add(value); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (!_isSingleSet) |
||||
|
{ |
||||
|
Single = value; |
||||
|
|
||||
|
_isSingleSet = true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
List = new List<T>(); |
||||
|
|
||||
|
List.Add(Single); |
||||
|
List.Add(value); |
||||
|
|
||||
|
Single = default; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes a value.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">Value to remove.</param>
|
||||
|
public bool Remove(T value) |
||||
|
{ |
||||
|
if (List != null) |
||||
|
{ |
||||
|
return List.Remove(value); |
||||
|
} |
||||
|
|
||||
|
if (!_isSingleSet) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (EqualityComparer<T>.Default.Equals(Single, value)) |
||||
|
{ |
||||
|
Single = default; |
||||
|
|
||||
|
_isSingleSet = false; |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
public static class PseudolassesExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Adds or removes a pseudoclass depending on a boolean value.
|
||||
|
/// </summary>
|
||||
|
/// <param name="classes">The pseudoclasses collection.</param>
|
||||
|
/// <param name="name">The name of the pseudoclass to set.</param>
|
||||
|
/// <param name="value">True to add the pseudoclass or false to remove.</param>
|
||||
|
public static void Set(this IPseudoClasses classes, string name, bool value) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(classes != null); |
||||
|
|
||||
|
if (value) |
||||
|
{ |
||||
|
classes.Add(name); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
classes.Remove(name); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Avalonia.LogicalTree |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a root of a logical tree.
|
||||
|
/// </summary>
|
||||
|
public interface ILogicalRoot : ILogical |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,12 +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.
|
|
||||
|
|
||||
namespace Avalonia.Styling |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Denotes the root <see cref="IStyleHost"/> in a tree.
|
|
||||
/// </summary>
|
|
||||
public interface IStyleRoot : IStyleHost |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,10 +1,15 @@ |
|||||
<Style xmlns="https://github.com/avaloniaui" Selector="ItemsControl"> |
<Style xmlns="https://github.com/avaloniaui" Selector="ItemsControl"> |
||||
<Setter Property="Template"> |
<Setter Property="Template"> |
||||
<ControlTemplate> |
<ControlTemplate> |
||||
<ItemsPresenter Name="PART_ItemsPresenter" |
<Border Background="{TemplateBinding Background}" |
||||
Items="{TemplateBinding Items}" |
BorderBrush="{TemplateBinding BorderBrush}" |
||||
ItemsPanel="{TemplateBinding ItemsPanel}" |
BorderThickness="{TemplateBinding BorderThickness}" |
||||
ItemTemplate="{TemplateBinding ItemTemplate}"/> |
Padding="{TemplateBinding Padding}"> |
||||
|
<ItemsPresenter Name="PART_ItemsPresenter" |
||||
|
Items="{TemplateBinding Items}" |
||||
|
ItemsPanel="{TemplateBinding ItemsPanel}" |
||||
|
ItemTemplate="{TemplateBinding ItemTemplate}"/> |
||||
|
</Border> |
||||
</ControlTemplate> |
</ControlTemplate> |
||||
</Setter> |
</Setter> |
||||
</Style> |
</Style> |
||||
|
|||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue