diff --git a/modules/graphics/src/main/native-glass/mac/GlassEmbeddedWindow+Overrides.m b/modules/graphics/src/main/native-glass/mac/GlassEmbeddedWindow+Overrides.m --- a/modules/graphics/src/main/native-glass/mac/GlassEmbeddedWindow+Overrides.m +++ b/modules/graphics/src/main/native-glass/mac/GlassEmbeddedWindow+Overrides.m @@ -70,7 +70,7 @@ if ([layer isKindOfClass:[GlassLayer3D class]] == YES) { - GlassOffscreen *offscreen = [((GlassLayer3D*)layer) getOffscreen]; + GlassOffscreen *offscreen = [((GlassLayer3D*)layer) getGlassOffscreen]; layer = [self->parent->gWindow->view layer]; if ([layer isKindOfClass:[GlassLayer3D class]] == YES) diff --git a/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.h b/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.h --- a/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.h +++ b/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.h @@ -40,6 +40,7 @@ GLuint _fboToRestore; } +- (void)blitFromFBO:(GlassFrameBufferObject*)other_fbo; - (GLuint)texture; - (GLuint)fbo; diff --git a/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.m b/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.m --- a/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.m +++ b/modules/graphics/src/main/native-glass/mac/GlassFrameBufferObject.m @@ -303,6 +303,18 @@ } } +- (void)blitFromFBO:(GlassFrameBufferObject*)other_fbo +{ + [self _createFboIfNeededForWidth:other_fbo->_width andHeight:other_fbo->_height]; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self->_fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, other_fbo->_fbo); + glBlitFramebuffer(0,0, other_fbo->_width, other_fbo->_height, + 0,0, self->_width, self->_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +} + + - (GLuint)texture { return self->_texture; diff --git a/modules/graphics/src/main/native-glass/mac/GlassLayer3D.h b/modules/graphics/src/main/native-glass/mac/GlassLayer3D.h --- a/modules/graphics/src/main/native-glass/mac/GlassLayer3D.h +++ b/modules/graphics/src/main/native-glass/mac/GlassLayer3D.h @@ -34,20 +34,23 @@ CALayer *_remoteLayer; uint32_t _remoteLayerID; - CGLContextObj _ctx; - CGLPixelFormatObj _format; - GlassOffscreen *_offscreen; + GlassOffscreen *_glassOffscreen; + GlassOffscreen *_painterOffscreen; BOOL isHiDPIAware; } -- (id)initWithSharedContext:(CGLContextObj)ctx withHiDPIAware:(BOOL)HiDPIAware; +- (id)initWithSharedContext:(CGLContextObj)ctx + andClientContext:(CGLContextObj)clCtx + withHiDPIAware:(BOOL)HiDPIAware; - (uint32_t)getRemoteLayerIdForServer:(NSString*)serverName; - (void)hostRemoteLayerId:(uint32_t)layerId; -- (GlassOffscreen*)getOffscreen; +- (GlassOffscreen*)getPainterOffscreen; +- (GlassOffscreen*)getGlassOffscreen; - (void)hostOffscreen:(GlassOffscreen*)offscreen; +- (void)flush; - (void)notifyScaleFactorChanged:(CGFloat)scale; diff --git a/modules/graphics/src/main/native-glass/mac/GlassLayer3D.m b/modules/graphics/src/main/native-glass/mac/GlassLayer3D.m --- a/modules/graphics/src/main/native-glass/mac/GlassLayer3D.m +++ b/modules/graphics/src/main/native-glass/mac/GlassLayer3D.m @@ -38,6 +38,8 @@ @implementation GlassLayer3D +static NSArray *allModes = nil; + - (void)_connectToRemoteServer:(NSString*)serverName { // SAK: Note that RemoteLayerGetServerPort can return 0/MACH_PORT_NULL. This is @@ -62,41 +64,10 @@ NSLog(@"RemoteLayer ERROR: nil remoteLayer for serverName:%@", serverName); } } -- (CGLPixelFormatObj)_createPixelFormat -{ - CGLPixelFormatObj pix = NULL; - { - const CGLPixelFormatAttribute attributes[] = - { - kCGLPFAAccelerated, - kCGLPFAColorSize, 32, - (CGLPixelFormatAttribute)0 - }; - GLint npix = 0; - CGLError err = CGLChoosePixelFormat(attributes, &pix, &npix); - if (err != kCGLNoError) - { - NSLog(@"CGLChoosePixelFormat error: %d", err); - } - } - return pix; -} -- (CGLContextObj)_createContextWithShared:(CGLContextObj)share withFormat:(CGLPixelFormatObj)format -{ - CGLContextObj ctx = NULL; - { - //NSLog(@"ALLOC"); - CGLError err = CGLCreateContext(format, share, &ctx); - if (err != kCGLNoError) - { - NSLog(@"CGLCreateContext error: %d", err); - } - } - return ctx; -} - -- (id)initWithSharedContext:(CGLContextObj)ctx withHiDPIAware:(BOOL)HiDPIAware +- (id)initWithSharedContext:(CGLContextObj)ctx + andClientContext:(CGLContextObj)clCtx + withHiDPIAware:(BOOL)HiDPIAware { LOG("GlassLayer3D initWithSharedContext]"); self = [super init]; @@ -106,14 +77,14 @@ self->_remoteLayer = nil; self->_remoteLayerID = 0; - self->_format = [self _createPixelFormat]; - self->_ctx = [self _createContextWithShared:ctx withFormat:self->_format]; - self->_offscreen = nil; - LOG(" GlassLayer3D context: %p", self->_ctx); + self->_painterOffscreen = [[GlassOffscreen alloc] initWithContext:clCtx]; + self->_glassOffscreen = [[GlassOffscreen alloc] initWithContext:ctx]; + [self->_glassOffscreen setLayer:self]; + LOG(" GlassLayer3D context: %p", ctx); self->isHiDPIAware = HiDPIAware; - [self setAsynchronous:YES]; // allow the layer to check for dirty flag and repaint if needed + [self setAsynchronous:NO]; [self setAutoresizingMask:(kCALayerWidthSizable|kCALayerHeightSizable)]; [self setContentsGravity:kCAGravityTopLeft]; @@ -125,18 +96,23 @@ [self setMasksToBounds:YES]; [self setNeedsDisplayOnBoundsChange:YES]; [self setAnchorPoint:CGPointMake(0.0f, 0.0f)]; + + if (allModes == nil) { + allModes = [[NSArray arrayWithObjects:NSDefaultRunLoopMode, + NSModalPanelRunLoopMode, + NSModalPanelRunLoopMode, nil] retain]; + } } return self; } - (void)dealloc { - //NSLog(@"FREE"); - CGLDestroyContext( self->_ctx ); - self->_ctx = NULL; + [self->_glassOffscreen release]; + self->_glassOffscreen = nil; - [self->_offscreen dealloc]; - self->_offscreen = nil; + [self->_painterOffscreen release]; + self->_painterOffscreen = nil; [self->_remoteLayer dealloc]; self->_remoteLayer = nil; @@ -161,54 +137,60 @@ - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - //return YES; - return (([self needsDisplay] == YES) || ([self->_offscreen isDirty] == YES)); + return [self->_glassOffscreen isDirty]; } - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { - return CGLRetainContext(self->_ctx); + return CGLRetainContext([self->_glassOffscreen getContext]); } - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { - return CGLRetainPixelFormat(self->_format); + return CGLRetainPixelFormat(CGLGetPixelFormat([self->_glassOffscreen getContext])); } - (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - [self->_offscreen lock]; + // glContext is already set as current by now and locked by Quartz internaly + LOG("GlassLayer3D drawInCGLContext]"); + LOG(" current context: %p", CGLGetCurrentContext()); +#ifdef VERBOSE { - LOG("GlassLayer3D drawInCGLContext]"); - LOG(" current context: %p", CGLGetCurrentContext()); -#ifdef VERBOSE - { - GLint fbo = 0; // default to screen - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, (GLint*)&fbo); - LOG(" fbo: %d", fbo); - } + GLint fbo = 0; // default to screen + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, (GLint*)&fbo); + LOG(" fbo: %d", fbo); + } #endif - // the viewport is already set for us here, so just blit - + // the viewport is already set for us here, so just blit + #if 0 - // this will stretch the offscreen to cover all the surface - // ie., live resizing "appears" better, but the blit area is not at 1:1 scale - [self->_offscreen blit]; + // this will stretch the offscreen to cover all the surface + // ie., live resizing "appears" better, but the blit area is not at 1:1 scale + [self->_glassOffscreen blit]; #else - // we blit only in the area we rendered in - GLint params[] = { 0, 0, 0, 0 }; - glGetIntegerv(GL_VIEWPORT, params); - if ((params[2] > 0) && ((params[3] > 0))) - { - [self->_offscreen blitForWidth:(GLuint)params[2] andHeight:(GLuint)params[3]]; - } + // we blit only in the area we rendered in + GLint params[] = { 0, 0, 0, 0 }; + glGetIntegerv(GL_VIEWPORT, params); + if ((params[2] > 0) && ((params[3] > 0))) + { + [self->_glassOffscreen blitForWidth:(GLuint)params[2] andHeight:(GLuint)params[3]]; + } #endif - - // the default implementation of the method flushes the context. - [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; - LOG("\n"); - } - [self->_offscreen unlock]; + + // the default implementation of the method flushes the context. + [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; + LOG("\n"); +} + +- (void)flush +{ + [(GlassOffscreen*)_glassOffscreen blitFromOffscreen:(GlassOffscreen*)_painterOffscreen]; + [[NSRunLoop mainRunLoop] performSelector:@selector(setNeedsDisplay) + target:[self->_glassOffscreen getLayer] + argument:nil + order:0 + modes:allModes]; } - (uint32_t)getRemoteLayerIdForServer:(NSString*)serverName @@ -241,16 +223,24 @@ } } -- (GlassOffscreen*)getOffscreen +- (GlassOffscreen*)getPainterOffscreen { - return self->_offscreen; + return self->_painterOffscreen; +} + +- (GlassOffscreen*)getGlassOffscreen +{ + return self->_glassOffscreen; } - (void)hostOffscreen:(GlassOffscreen*)offscreen { - [self->_offscreen release]; - self->_offscreen = nil; - self->_offscreen = [offscreen retain]; + [self->_glassOffscreen release]; + self->_glassOffscreen = [offscreen retain]; + [self->_glassOffscreen setLayer:self]; + // We are now hosting an offscreen from another layer + // Self painter offscreen would never be needed. + [self->_painterOffscreen release]; } @end diff --git a/modules/graphics/src/main/native-glass/mac/GlassOffscreen.h b/modules/graphics/src/main/native-glass/mac/GlassOffscreen.h --- a/modules/graphics/src/main/native-glass/mac/GlassOffscreen.h +++ b/modules/graphics/src/main/native-glass/mac/GlassOffscreen.h @@ -45,9 +45,7 @@ @interface GlassOffscreen : NSObject { - NSRecursiveLock *_lock; CGLContextObj _ctx; - CGLContextObj _ctxToRestore; id _offscreen; @@ -57,6 +55,8 @@ GLfloat _backgroundG; GLfloat _backgroundB; GLfloat _backgroundA; + + CAOpenGLLayer* _layer; } - (id)initWithContext:(CGLContextObj)ctx; @@ -67,10 +67,11 @@ - (void)blit; - (GLuint)texture; -// need locks to set contexts, which may differ for OffscreenProtocol bind/unbind and blit -- (void)lock; -- (void)unlock; +- (CAOpenGLLayer*)getLayer; +- (void)setLayer:(CAOpenGLLayer*)new_layer; - (GLboolean)isDirty; +- (void)blitFromOffscreen:(GlassOffscreen*) other_offscreen; + @end diff --git a/modules/graphics/src/main/native-glass/mac/GlassOffscreen.m b/modules/graphics/src/main/native-glass/mac/GlassOffscreen.m --- a/modules/graphics/src/main/native-glass/mac/GlassOffscreen.m +++ b/modules/graphics/src/main/native-glass/mac/GlassOffscreen.m @@ -42,7 +42,6 @@ self = [super init]; if (self != nil) { - self->_lock = [[NSRecursiveLock alloc] init]; self->_ctx = CGLRetainContext(ctx); self->_backgroundR = 1.0f; @@ -50,9 +49,8 @@ self->_backgroundB = 1.0f; self->_backgroundA = 1.0f; - self->_ctxToRestore = CGLGetCurrentContext(); + [self setContext]; { - CGLSetCurrentContext(self->_ctx); self->_offscreen = [[GlassFrameBufferObject alloc] init]; if (self->_offscreen == nil) { @@ -60,8 +58,7 @@ //self->_offscreen = [[GlassPBuffer alloc] init]; } } - CGLSetCurrentContext(self->_ctxToRestore); - self->_ctxToRestore = NULL; + [self unsetContext]; } return self; } @@ -73,12 +70,16 @@ - (void)dealloc { - [self->_lock release]; - self->_lock = nil; - + [self setContext]; + { + [(NSObject*)self->_offscreen release]; + self->_offscreen = NULL; + } + [self unsetContext]; + CGLReleaseContext(self->_ctx); self->_ctx = NULL; - + [super dealloc]; } @@ -90,16 +91,6 @@ self->_backgroundA = (GLfloat)[color alphaComponent]; } -- (void)lock -{ - [self->_lock lock]; -} - -- (void)unlock; -{ - [self->_lock unlock]; -} - - (GLuint)width { return [self->_offscreen width]; @@ -110,43 +101,45 @@ return [self->_offscreen height]; } +- (CAOpenGLLayer*)getLayer +{ + return _layer; +} + +- (void)setLayer:(CAOpenGLLayer*)new_layer +{ + //Set a weak reference as layer owns offscreen + self->_layer = new_layer; +} + +- (void)setContext +{ + CGLLockContext(self->_ctx); + CGLSetCurrentContext(self->_ctx); +} + +- (void)unsetContext +{ + CGLSetCurrentContext(NULL); + CGLUnlockContext(self->_ctx); +} + - (void)bindForWidth:(GLuint)width andHeight:(GLuint)height { - [self lock]; - { - self->_ctxToRestore = CGLGetCurrentContext(); - { - CGLSetCurrentContext(self->_ctx); - - [self->_offscreen bindForWidth:width andHeight:height]; - self->_dirty = GL_TRUE; - } - } - // will be unlocked later by [GlassOffscreen unbind] + [self setContext]; + [self->_offscreen bindForWidth:width andHeight:height]; } - (void)unbind { - // already locked earlier by [GlassOffscreen bindForWidth:andHeight]; - { - assert(CGLGetCurrentContext() == self->_ctx); - { - self->_dirty = GL_TRUE; - [self->_offscreen unbind]; - } - CGLSetCurrentContext(self->_ctxToRestore); - self->_ctxToRestore = NULL; - } - [self unlock]; + assert(CGLGetCurrentContext() == self->_ctx); + [self->_offscreen unbind]; + [self unsetContext]; } - (void)blit { - [self lock]; - { - [self blitForWidth:[self->_offscreen width] andHeight:[self->_offscreen height]]; - } - [self unlock]; + [self blitForWidth:[self->_offscreen width] andHeight:[self->_offscreen height]]; } - (GLuint)texture @@ -156,7 +149,6 @@ - (void)blitForWidth:(GLuint)width andHeight:(GLuint)height { - [self lock]; { #if 1 glClearColor(self->_backgroundR, self->_backgroundG, self->_backgroundB, self->_backgroundA); @@ -183,13 +175,11 @@ break; } glClear(GL_COLOR_BUFFER_BIT); -#endif - +#endif [self->_offscreen blitForWidth:width andHeight:height]; self->_dirty = GL_FALSE; } - [self unlock]; } - (GLboolean)isDirty @@ -197,4 +187,14 @@ return self->_dirty; } +- (void)blitFromOffscreen:(GlassOffscreen*) other_offscreen +{ + [self setContext]; + { + [(GlassFrameBufferObject*)self->_offscreen blitFromFBO:(GlassFrameBufferObject*)other_offscreen->_offscreen]; + self->_dirty = GL_TRUE; + } + [self unsetContext]; +} + @end diff --git a/modules/graphics/src/main/native-glass/mac/GlassView3D.m b/modules/graphics/src/main/native-glass/mac/GlassView3D.m --- a/modules/graphics/src/main/native-glass/mac/GlassView3D.m +++ b/modules/graphics/src/main/native-glass/mac/GlassView3D.m @@ -142,7 +142,6 @@ { NSOpenGLContext *sharedContextNS = (NSOpenGLContext*)jlong_to_ptr(jsharedContextPtr); sharedCGL = [sharedContextNS CGLContextObj]; - CGLSetCurrentContext(sharedCGL); } } } @@ -172,10 +171,7 @@ // this can happen in Rain or clients other than Prism (ie. device details do not have the shared context set) sharedCGL = clientCGL; } - - // the offscreen is the buffered context (ex. Fbo) that the client can draw into at any time - GlassOffscreen *offscreen = [[GlassOffscreen alloc] initWithContext:clientCGL]; - + self->isHiDPIAware = NO; if (jproperties != NULL) { @@ -187,9 +183,8 @@ } } - GlassLayer3D *layer = [[GlassLayer3D alloc] initWithSharedContext:sharedCGL withHiDPIAware:self->isHiDPIAware]; - [layer hostOffscreen:offscreen]; - + GlassLayer3D *layer = [[GlassLayer3D alloc] initWithSharedContext:sharedCGL andClientContext:clientCGL withHiDPIAware:self->isHiDPIAware]; + // https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/nsview_Class/Reference/NSView.html#//apple_ref/occ/instm/NSView/setWantsLayer: // the order of the following 2 calls is important: here we indicate we want a layer-hosting view { @@ -226,11 +221,11 @@ if (self->_texture != 0) { GlassLayer3D *layer = (GlassLayer3D*)[self layer]; - [[layer getOffscreen] bindForWidth:(GLuint)[self bounds].size.width andHeight:(GLuint)[self bounds].size.height]; + [[layer getPainterOffscreen] bindForWidth:(GLuint)[self bounds].size.width andHeight:(GLuint)[self bounds].size.height]; { glDeleteTextures(1, &self->_texture); } - [[layer getOffscreen] unbind]; + [[layer getPainterOffscreen] unbind]; } [[self layer] release]; @@ -295,9 +290,9 @@ if ([self window] != nil) { GlassLayer3D *layer = (GlassLayer3D*)[self layer]; - [[layer getOffscreen] setBackgroundColor:[[[self window] backgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]]; + [[layer getPainterOffscreen] setBackgroundColor:[[[self window] backgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]]; } - + [self->_delegate viewDidMoveToWindow]; } @@ -555,7 +550,7 @@ GlassLayer3D *layer = (GlassLayer3D*)[self layer]; NSRect bounds = (self->isHiDPIAware && [self respondsToSelector:@selector(convertRectToBacking:)]) ? [self convertRectToBacking:[self bounds]] : [self bounds]; - [[layer getOffscreen] bindForWidth:(GLuint)bounds.size.width andHeight:(GLuint)bounds.size.height]; + [[layer getPainterOffscreen] bindForWidth:(GLuint)bounds.size.width andHeight:(GLuint)bounds.size.height]; } self->_drawCounter++; } @@ -568,7 +563,8 @@ if (self->_drawCounter == 0) { GlassLayer3D *layer = (GlassLayer3D*)[self layer]; - [[layer getOffscreen] unbind]; + [[layer getPainterOffscreen] unbind]; + [layer flush]; } LOG("end:%d", flush); }