diff options
Diffstat (limited to 'src/jogl/native/macosx')
4 files changed, 1058 insertions, 571 deletions
diff --git a/src/jogl/native/macosx/MacOSXCustomCGLCode.c b/src/jogl/native/macosx/MacOSXCustomCGLCode.c index f8b7a800f..75896c3a2 100644 --- a/src/jogl/native/macosx/MacOSXCustomCGLCode.c +++ b/src/jogl/native/macosx/MacOSXCustomCGLCode.c @@ -2,7 +2,7 @@ #include <assert.h> -#include </usr/include/machine/types.h> +#include <machine/types.h> #include "macosx-window-system.h" void CGLQueryPixelFormat(CGLPixelFormatObj fmt, int* iattrs, int niattrs, int* ivalues) { diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m new file mode 100644 index 000000000..7ce8c58cf --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m @@ -0,0 +1,966 @@ +#import "MacOSXWindowSystemInterface.h" +#import <QuartzCore/QuartzCore.h> +#import <pthread.h> +#import "NativeWindowProtocols.h" +#include "timespec.h" + +#import <OpenGL/glext.h> + +/** + * Partial include of gl3.h - which we can only expect and use + * in case of a GL3 core context at runtime. + * Otherwise we would need to have 2 modules, one including GL2 + * and one inclusing GL3 headers. + */ +#ifndef GL_ARB_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +extern void glBindVertexArray (GLuint array); +extern void glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +extern void glGenVertexArrays (GLsizei n, GLuint *arrays); +extern GLboolean glIsVertexArray (GLuint array); +#endif + +// +// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient. +// Use CVDisplayLink otherwise. +// +// #define HAS_CADisplayLink 1 +// + +// lock/sync debug output +// +// #define DBG_SYNC 1 +// +#ifdef DBG_SYNC + // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define SYNC_PRINT(...) +#endif + +// fps debug output +// +// #define DBG_PERF 1 + +// #define DBG_LIFECYCLE 1 + +/** + * Capture setView(NULL), which produces a 'invalid drawable' message + * + * Also track lifecycle via DBG_PRINT messages, if VERBOSE is enabled! + */ +@interface MyNSOpenGLContext: NSOpenGLContext +{ +} +- (id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share; +- (void)setView:(NSView *)view; +- (void)update; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +#endif +- (void)dealloc; + +@end + +@implementation MyNSOpenGLContext + +- (id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share +{ + DBG_PRINT("MyNSOpenGLContext::initWithFormat.0: format %p, share %p\n", format, share); + MyNSOpenGLContext * o = [super initWithFormat:format shareContext:share]; + DBG_PRINT("MyNSOpenGLContext::initWithFormat.X: new %p\n", o); + return o; +} + +- (void)setView:(NSView *)view +{ + DBG_PRINT("MyNSOpenGLContext::setView: this.0 %p, view %p\n", self, view); + // NSLog(@"MyNSOpenGLContext::setView: %@",[NSThread callStackSymbols]); + if(NULL != view) { + [super setView:view]; + } else { + [self clearDrawable]; + } + DBG_PRINT("MyNSOpenGLContext::setView.X\n"); +} + +- (void)update +{ + DBG_PRINT("MyNSOpenGLContext::update: this.0 %p, view %p\n", self, [self view]); + [super update]; + DBG_PRINT("MyNSOpenGLContext::update.X\n"); +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyNSOpenGLContext::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLContext::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyNSOpenGLContext::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyNSOpenGLContext::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; + // DBG_PRINT("MyNSOpenGLContext::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +#endif + +#ifdef VERBOSE_ON + #define CGLRETAINCOUNT(c) (NULL!=c?(int)CGLGetContextRetainCount(c):-1) +#else + #define CGLRETAINCOUNT(c) +#endif + +- (void)dealloc +{ + /** + * The explicit CGLContext destruction below + * ensures that it is not left behind. + * Tests show that w/o these gymnastics, the CGLContext is not freed immediately after calling dealloc. + * The retain, release and dealloc ensures [super dealloc] won't message 'invalid context'. + */ + CGLContextObj cglCtx = [self CGLContextObj]; + + DBG_PRINT("MyNSOpenGLContext::dealloc.0 %p (refcnt %d) - CGL-Ctx %p\n", self, (int)[self retainCount], cglCtx, CGLRETAINCOUNT(cglCtx)); + // NSLog(@"MyNSOpenGLContext::dealloc: %@",[NSThread callStackSymbols]); + + [self clearDrawable]; + DBG_PRINT("MyNSOpenGLContext::dealloc.1 %d\n", CGLRETAINCOUNT(cglCtx)); + if( NULL != cglCtx ) { + CGLRetainContext( cglCtx ); + DBG_PRINT("MyNSOpenGLContext::dealloc.2 %d\n", CGLRETAINCOUNT(cglCtx)); + } + [super dealloc]; + DBG_PRINT("MyNSOpenGLContext::dealloc.3 %d\n", CGLRETAINCOUNT(cglCtx)); + if( NULL != cglCtx ) { + CGLReleaseContext( cglCtx ); + DBG_PRINT("MyNSOpenGLContext::dealloc.4 %d\n", CGLRETAINCOUNT(cglCtx)); + CGLDestroyContext( cglCtx ); + DBG_PRINT("MyNSOpenGLContext::dealloc.5 %d\n", CGLRETAINCOUNT(cglCtx)); + } + DBG_PRINT("MyNSOpenGLContext::dealloc.X\n"); +} + +@end + +@interface MyNSOpenGLLayer: NSOpenGLLayer <NWDedicatedFrame> +{ +@private + GLfloat gl_texCoords[8]; + NSOpenGLContext* glContext; + Bool isGLEnabled; + +@protected + GLuint gl3ShaderProgramName; + GLuint vboBufVert; + GLuint vboBufTexCoord; + GLint vertAttrLoc; + GLint texCoordAttrLoc; + NSOpenGLPixelFormat* parentPixelFmt; + int texWidth; + int texHeight; + volatile Bool dedicatedFrameSet; + volatile CGRect dedicatedFrame; + volatile NSOpenGLPixelBuffer* pbuffer; + volatile GLuint textureID; + volatile NSOpenGLPixelBuffer* newPBuffer; +#ifdef HAS_CADisplayLink + CADisplayLink* displayLink; +#else + CVDisplayLinkRef displayLink; +#endif + int tc; + struct timespec tStart; +@public + struct timespec lastWaitTime; + GLint swapInterval; + GLint swapIntervalCounter; + pthread_mutex_t renderLock; + pthread_cond_t renderSignal; + volatile Bool shallDraw; +} + +- (id) setupWithContext: (NSOpenGLContext*) parentCtx + gl3ShaderProgramName: (GLuint) gl3ShaderProgramName + pixelFormat: (NSOpenGLPixelFormat*) pfmt + pbuffer: (NSOpenGLPixelBuffer*) p + texIDArg: (GLuint) texID + opaque: (Bool) opaque + texWidth: (int) texWidth + texHeight: (int) texHeight; + +- (void)releaseLayer; +- (void)deallocPBuffer; +- (void)disableAnimation; +- (void)pauseAnimation:(Bool)pause; +- (void)setSwapInterval:(int)interval; +- (void)tick; +- (void)waitUntilRenderSignal: (long) to_micros; +- (Bool)isGLSourceValid; + +- (void) setGLEnabled: (Bool) enable; +- (Bool) validateTexSize: (CGRect) lRect; +- (void) setTextureID: (int) _texID; + +- (Bool) isSamePBuffer: (NSOpenGLPixelBuffer*) p; +- (void) setNewPBuffer: (NSOpenGLPixelBuffer*)p; +- (void) applyNewPBuffer; + +- (void)setDedicatedFrame:(CGRect)frame quirks:(int)quirks; // @NWDedicatedFrame +- (void) setFrame:(CGRect) frame; +- (id<CAAction>)actionForKey:(NSString *)key ; +- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask; +- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat; +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp; +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp; + +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +#endif +- (void)dealloc; + +@end + +#ifndef HAS_CADisplayLink + +static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext; + pthread_mutex_lock(&l->renderLock); + if( 0 < l->swapInterval ) { + l->swapIntervalCounter++; + if( l->swapIntervalCounter >= l->swapInterval ) { + SYNC_PRINT("<S %d/%d>", (int)l->swapIntervalCounter, l->swapInterval); + l->swapIntervalCounter = 0; + pthread_cond_signal(&l->renderSignal); // wake up vsync + } + } + pthread_mutex_unlock(&l->renderLock); + [pool release]; + return kCVReturnSuccess; +} + +#endif + +static const GLfloat gl_verts[] = { + -1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + 1.0, -1.0 +}; + +@implementation MyNSOpenGLLayer + +- (id) setupWithContext: (NSOpenGLContext*) parentCtx + gl3ShaderProgramName: (GLuint) _gl3ShaderProgramName + pixelFormat: (NSOpenGLPixelFormat*) _parentPixelFmt + pbuffer: (NSOpenGLPixelBuffer*) p + texIDArg: (GLuint) texID + opaque: (Bool) opaque + texWidth: (int) _texWidth + texHeight: (int) _texHeight; +{ + pthread_mutexattr_t renderLockAttr; + pthread_mutexattr_init(&renderLockAttr); + pthread_mutexattr_settype(&renderLockAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&renderLock, &renderLockAttr); // recursive + pthread_cond_init(&renderSignal, NULL); // no attribute + + { + int i; + for(i=0; i<8; i++) { + gl_texCoords[i] = 0.0f; + } + } + parentPixelFmt = [_parentPixelFmt retain]; // until destruction + glContext = [[MyNSOpenGLContext alloc] initWithFormat:parentPixelFmt shareContext:parentCtx]; + gl3ShaderProgramName = _gl3ShaderProgramName; + vboBufVert = 0; + vboBufTexCoord = 0; + vertAttrLoc = 0; + texCoordAttrLoc = 0; + swapInterval = 1; // defaults to on (as w/ new GL profiles) + swapIntervalCounter = 0; + timespec_now(&lastWaitTime); + shallDraw = NO; + isGLEnabled = YES; + dedicatedFrameSet = NO; + dedicatedFrame = CGRectMake(0, 0, _texWidth, _texHeight); + [self validateTexSize: dedicatedFrame]; + [self setTextureID: texID]; + + newPBuffer = NULL; + pbuffer = p; + if(NULL != pbuffer) { + [pbuffer retain]; + } + + { + // no animations for add/remove/swap sublayers etc + // doesn't work: [self removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] + [self removeAllAnimations]; + } + + // instantiate a deactivated displayLink +#ifdef HAS_CADisplayLink + displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain]; +#else + CVReturn cvres; + { + int allDisplaysMask = 0; + int virtualScreen, accelerated, displayMask; + for (virtualScreen = 0; virtualScreen < [parentPixelFmt numberOfVirtualScreens]; virtualScreen++) { + [parentPixelFmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen]; + [parentPixelFmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen]; + if (accelerated) { + allDisplaysMask |= displayMask; + } + } + cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + CVReturn cvres; + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.1: setup DisplayLink %p\n", displayLink); + cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [glContext CGLContextObj], [parentPixelFmt CGLPixelFormatObj]); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); + displayLink = NULL; + } + } +#endif + [self pauseAnimation: YES]; + + [self removeAllAnimations]; + [self setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [self setNeedsDisplayOnBoundsChange: YES]; + + [self setOpaque: opaque ? YES : NO]; + +#ifdef VERBOSE_ON + CGRect lRect = [self bounds]; + if(NULL != pbuffer) { + DBG_PRINT("MyNSOpenGLLayer::init (pbuffer) %p, pctx %p, pfmt %p, pbuffer %p, ctx %p, opaque %d, pbuffer %dx%d -> tex %dx%d, bounds: %lf/%lf %lfx%lf, displayLink %p (refcnt %d)\n", + self, parentCtx, parentPixelFmt, pbuffer, glContext, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, displayLink, (int)[self retainCount]); + } else { + DBG_PRINT("MyNSOpenGLLayer::init (texture) %p, pctx %p, pfmt %p, ctx %p, opaque %d, tex[id %d, %dx%d], bounds: %lf/%lf %lfx%lf, displayLink %p (refcnt %d)\n", + self, parentCtx, parentPixelFmt, glContext, opaque, (int)textureID, texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, displayLink, (int)[self retainCount]); + } +#endif + return self; +} + +- (void) setGLEnabled: (Bool) enable +{ + DBG_PRINT("MyNSOpenGLLayer::setGLEnabled: %p, %d -> %d\n", self, (int)isGLEnabled, (int)enable); + isGLEnabled = enable; +} + +- (Bool) validateTexSize: (CGRect) lRect +{ + const int lRectW = (int) (lRect.size.width + 0.5f); + const int lRectH = (int) (lRect.size.height + 0.5f); + Bool changed; + + if( lRectH != texHeight || lRectW != texWidth ) { + texWidth = lRectW; + texHeight = lRectH; + changed = YES; + + GLfloat texCoordWidth, texCoordHeight; + if(NULL != pbuffer) { + GLenum textureTarget = [pbuffer textureTarget] ; + GLsizei pwidth = [pbuffer pixelsWide]; + GLsizei pheight = [pbuffer pixelsHigh]; + if( GL_TEXTURE_2D == textureTarget ) { + texCoordWidth = (GLfloat)pwidth /(GLfloat)texWidth ; + texCoordHeight = (GLfloat)pheight/(GLfloat)texHeight ; + } else { + texCoordWidth = pwidth; + texCoordHeight = pheight; + } + } else { + texCoordWidth = (GLfloat)1.0f; + texCoordHeight = (GLfloat)1.0f; + } + gl_texCoords[3] = texCoordHeight; + gl_texCoords[5] = texCoordHeight; + gl_texCoords[4] = texCoordWidth; + gl_texCoords[6] = texCoordWidth; + #ifdef VERBOSE_ON + DBG_PRINT("MyNSOpenGLLayer::validateTexSize %p -> tex %dx%d, bounds: %lf/%lf %lfx%lf (%dx%d), dedicatedFrame set:%d %lf/%lf %lfx%lf\n", + self, texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, lRectW, lRectH, + dedicatedFrameSet, dedicatedFrame.origin.x, dedicatedFrame.origin.y, dedicatedFrame.size.width, dedicatedFrame.size.height); + #endif + } else { + changed = NO; + } + return changed; +} + +- (void) setTextureID: (int) _texID +{ + textureID = _texID; +} + +- (Bool) isSamePBuffer: (NSOpenGLPixelBuffer*) p +{ + return pbuffer == p || newPBuffer == p; +} + +- (void)setNewPBuffer: (NSOpenGLPixelBuffer*)p +{ + SYNC_PRINT("<NP-S %p -> %p>", pbuffer, p); + newPBuffer = p; + [newPBuffer retain]; +} + +- (void) applyNewPBuffer +{ + if( NULL != newPBuffer ) { // volatile OK + SYNC_PRINT("<NP-A %p -> %p>", pbuffer, newPBuffer); + + if( 0 != textureID ) { + glDeleteTextures(1, (GLuint *)&textureID); + [self setTextureID: 0]; + } + [pbuffer release]; + + pbuffer = newPBuffer; + newPBuffer = NULL; + } +} + +- (void)deallocPBuffer +{ + if(NULL != pbuffer) { + NSOpenGLContext* context = [self openGLContext]; + if(NULL!=context) { + [context makeCurrentContext]; + + DBG_PRINT("MyNSOpenGLLayer::deallocPBuffer (with ctx) %p (refcnt %d) - context %p, pbuffer %p, texID %d\n", self, (int)[self retainCount], context, pbuffer, (int)textureID); + + if( 0 != textureID ) { + glDeleteTextures(1, (GLuint *)&textureID); + [self setTextureID: 0]; + } + if(NULL != pbuffer) { + [pbuffer release]; + pbuffer = NULL; + } + if(NULL != newPBuffer) { + [newPBuffer release]; + newPBuffer = NULL; + } + + [context clearDrawable]; + } else { + DBG_PRINT("MyNSOpenGLLayer::deallocPBuffer (w/o ctx) %p (refcnt %d) - context %p, pbuffer %p, texID %d\n", self, (int)[self retainCount], context, pbuffer, (int)textureID); + } + } +} + +- (void)disableAnimation +{ + DBG_PRINT("MyNSOpenGLLayer::disableAnimation.0: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); + [self setAsynchronous: NO]; + if(NULL != displayLink) { +#ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + [displayLink release]; +#else + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); +#endif + displayLink = NULL; + } + DBG_PRINT("MyNSOpenGLLayer::disableAnimation.X: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); +} + +- (void)releaseLayer +{ + DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [self setGLEnabled: NO]; + [self disableAnimation]; + pthread_mutex_lock(&renderLock); + [self deallocPBuffer]; + if( NULL != glContext ) { + [glContext release]; + glContext = NULL; + } + if( NULL != parentPixelFmt ) { + [parentPixelFmt release]; + parentPixelFmt = NULL; + } + pthread_mutex_unlock(&renderLock); + [self release]; + DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p\n", self); +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyNSOpenGLLayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLLayer::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyNSOpenGLLayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyNSOpenGLLayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLLayer::release: %@",[NSThread callStackSymbols]); + [super release]; + // DBG_PRINT("MyNSOpenGLLayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +#endif + +- (void)dealloc +{ + DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]); + [self disableAnimation]; + pthread_mutex_lock(&renderLock); + [self deallocPBuffer]; + pthread_mutex_unlock(&renderLock); + pthread_cond_destroy(&renderSignal); + pthread_mutex_destroy(&renderLock); + [super dealloc]; + // DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); +} + +- (Bool)isGLSourceValid +{ + return NULL != pbuffer || NULL != newPBuffer || 0 != textureID ; +} + +// @NWDedicatedFrame +- (void)setDedicatedFrame:(CGRect)dFrame quirks:(int)quirks { + CGRect lRect = [self frame]; + Bool dedicatedFramePosSet = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & quirks ); + Bool dedicatedFrameSizeSet = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & quirks ); + Bool dedicatedLayoutSet = 0 != ( NW_DEDICATEDFRAME_QUIRK_LAYOUT & quirks ); + dedicatedFrameSet = dedicatedFramePosSet || dedicatedFrameSizeSet || dedicatedLayoutSet; + dedicatedFrame = dFrame; + + DBG_PRINT("MyNSOpenGLLayer::setDedicatedFrame: Quirks [%d, pos %d, size %d, lout %d], %p, texSize %dx%d, %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + quirks, dedicatedFramePosSet, dedicatedFrameSizeSet, dedicatedLayoutSet, self, texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, + dFrame.origin.x, dFrame.origin.y, dFrame.size.width, dFrame.size.height); + (void)lRect; // silence + + if( dedicatedFrameSet ) { + [super setFrame: dedicatedFrame]; + } +} + +- (void) setFrame:(CGRect) frame { + if( dedicatedFrameSet ) { + [super setFrame: dedicatedFrame]; + } else { + [super setFrame: frame]; + } +} + +- (id<CAAction>)actionForKey:(NSString *)key +{ + DBG_PRINT("MyNSOpenGLLayer::actionForKey.0 %p key %s -> NIL\n", self, [key UTF8String]); + return nil; + // return [super actionForKey: key]; +} + +- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask +{ + DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask: %p (refcnt %d) - parent-pfmt %p -> new-pfmt %p\n", + self, (int)[self retainCount], parentPixelFmt, parentPixelFmt); + // We simply take over ownership of parent PixelFormat until releaseLayer.. + return parentPixelFmt; +} + +- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat +{ + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.0: %p (refcnt %d) - pfmt %p, ctx %p, DisplayLink %p\n", + self, (int)[self retainCount], pixelFormat, glContext, displayLink); + return glContext; +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + SYNC_PRINT("<? %d, %d>", (int)shallDraw, (int)isGLEnabled); + return shallDraw && isGLEnabled; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + pthread_mutex_unlock(&renderLock); + SYNC_PRINT("<* "); + // NSLog(@"MyNSOpenGLLayer::DRAW: %@",[NSThread callStackSymbols]); + + if( isGLEnabled && shallDraw && ( NULL != pbuffer || NULL != newPBuffer || 0 != textureID ) ) { + [context makeCurrentContext]; + + if( NULL != newPBuffer ) { // volatile OK + [self applyNewPBuffer]; + } + + GLenum textureTarget; + + Bool texSizeChanged = [self validateTexSize: ( dedicatedFrameSet ? dedicatedFrame : [self bounds] ) ]; + if( texSizeChanged ) { + [context update]; + } + + if( NULL != pbuffer ) { + if( texSizeChanged && 0 != textureID ) { + glDeleteTextures(1, (GLuint *)&textureID); + [self setTextureID: 0]; + } + textureTarget = [pbuffer textureTarget]; + if( 0 != gl3ShaderProgramName ) { + glUseProgram(gl3ShaderProgramName); + glActiveTexture(GL_TEXTURE0); + } + if( 0 == textureID ) { + glGenTextures(1, (GLuint *)&textureID); + glBindTexture(textureTarget, textureID); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glBindTexture(textureTarget, textureID); + } + [context setTextureImageToPixelBuffer: (NSOpenGLPixelBuffer*) pbuffer colorBuffer: GL_FRONT]; + } else { + if( 0 != gl3ShaderProgramName ) { + glUseProgram(gl3ShaderProgramName); + glActiveTexture(GL_TEXTURE0); + } + textureTarget = GL_TEXTURE_2D; + glBindTexture(textureTarget, textureID); + } + SYNC_PRINT(" %d gl3Prog %d/%d*>", (int)textureID, (int)gl3ShaderProgramName, (int)glIsProgram (gl3ShaderProgramName)); + + if( 0 == vboBufVert ) { // Once: Init Data and Bind to Pointer + if( 0 != gl3ShaderProgramName ) { + // Install default VAO as required by GL 3.2 core! + GLuint vaoBuf = 0; + glGenVertexArrays(1, &vaoBuf); + glBindVertexArray(vaoBuf); + + // Set texture-unit 0 + GLint texUnitLoc = glGetUniformLocation (gl3ShaderProgramName, "mgl_Texture0"); + glUniform1i (texUnitLoc, 0); + } + glGenBuffers( 1, &vboBufVert ); + glBindBuffer( GL_ARRAY_BUFFER, vboBufVert ); + glBufferData( GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), gl_verts, GL_STATIC_DRAW); + if( 0 != gl3ShaderProgramName ) { + vertAttrLoc = glGetAttribLocation( gl3ShaderProgramName, "mgl_Vertex" ); + glVertexAttribPointer( vertAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL ); + } else { + glVertexPointer(2, GL_FLOAT, 0, NULL); + } + + glGenBuffers( 1, &vboBufTexCoord ); + glBindBuffer( GL_ARRAY_BUFFER, vboBufTexCoord ); + glBufferData( GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), gl_texCoords, GL_STATIC_DRAW); + if( 0 != gl3ShaderProgramName ) { + texCoordAttrLoc = glGetAttribLocation( gl3ShaderProgramName, "mgl_MultiTexCoord" ); + glVertexAttribPointer( texCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL ); + } else { + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + } + } + if( texSizeChanged ) { + glBindBuffer( GL_ARRAY_BUFFER, vboBufTexCoord ); + glBufferSubData( GL_ARRAY_BUFFER, 0, 4 * 2 * sizeof(GLfloat), gl_texCoords); + if( 0 != gl3ShaderProgramName ) { + glVertexAttribPointer( texCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL ); + } else { + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + } + } + if( 0 != gl3ShaderProgramName ) { + glEnableVertexAttribArray( vertAttrLoc ); + glEnableVertexAttribArray( texCoordAttrLoc ); + } else { + glEnable(textureTarget); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if( 0 != gl3ShaderProgramName ) { + glDisableVertexAttribArray( vertAttrLoc ); + glDisableVertexAttribArray( texCoordAttrLoc ); + glUseProgram(0); + } else { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(textureTarget); + } + + glBindTexture(textureTarget, 0); + + [context clearDrawable]; + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; + + } else { + // glClear(GL_COLOR_BUFFER_BIT); + // glBlitFramebuffer(0, 0, texWidth, texHeight, + // 0, 0, texWidth, texHeight, + // GL_COLOR_BUFFER_BIT, GL_NEAREST); + SYNC_PRINT(" 0*>"); + } + + #ifdef DBG_PERF + [self tick]; + #endif + shallDraw = NO; + + if( 0 >= swapInterval ) { + pthread_cond_signal(&renderSignal); // wake up !vsync + SYNC_PRINT("<s>"); + } + SYNC_PRINT("<$>\n"); + pthread_mutex_unlock(&renderLock); +} + +- (void)pauseAnimation:(Bool)pause +{ + DBG_PRINT("MyNSOpenGLLayer::pauseAnimation: %d\n", (int)pause); + [self setAsynchronous: NO]; + if(pause) { + if(NULL != displayLink) { + #ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + #else + CVDisplayLinkStop(displayLink); + #endif + } + } else { + if(NULL != displayLink) { + #ifdef HAS_CADisplayLink + [displayLink setPaused: NO]; + [displayLink setFrameInterval: swapInterval]; + #else + CVDisplayLinkStart(displayLink); + #endif + } + } + tc = 0; + timespec_now(&tStart); +} + +- (void)setSwapInterval:(int)interval +{ + /** + * v-sync doesn't works w/ NSOpenGLLayer's context .. well :( + * Using CVDisplayLink .. see setSwapInterval() below. + * + GLint si; + [context getValues: &si forParameter: NSOpenGLCPSwapInterval]; + if(si != swapInterval) { + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval); + [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + } + */ + + pthread_mutex_lock(&renderLock); + DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.0: %d - displayLink %p\n", interval, displayLink); + swapInterval = interval; + swapIntervalCounter = 0; + pthread_mutex_unlock(&renderLock); + + if(0 < swapInterval) { + [self pauseAnimation: NO]; + } else { + [self pauseAnimation: YES]; + } + DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.X: %d\n", interval); +} + +-(void)tick +{ + tc++; + if(tc%60==0) { + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &tStart); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n", + td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms ); + fflush(NULL); + } +} + +- (void)waitUntilRenderSignal: (long) to_micros +{ + struct timespec t0, to_until; + BOOL tooLate; + int wr; + if( 0 >= to_micros ) { + to_micros = 16666 + 1000; // defaults to 1/60s + 1ms + NSLog(@"MyNSOpenGLContext::waitUntilRenderSignal: to_micros was zero, using defaults"); + } + pthread_mutex_lock(&renderLock); + timespec_now(&t0); + to_until = lastWaitTime; + timespec_addmicros(&to_until, to_micros); + tooLate = timespec_compare(&to_until, &t0) < 0; + #ifdef DBG_SYNC + struct timespec td_until; + timespec_subtract(&td_until, &to_until, &t0); + SYNC_PRINT("{W %ld ms, to %ld ms, late %d", to_micros/1000, timespec_milliseconds(&td_until), tooLate); + #endif + if( 0 < swapInterval ) { + if( tooLate ) { + // adjust! + to_until = t0; + timespec_addmicros(&to_until, to_micros); + } + wr = pthread_cond_timedwait(&renderSignal, &renderLock, &to_until); + #ifdef DBG_SYNC + struct timespec t1, td, td2; + timespec_now(&t1); + timespec_subtract(&td, &t1, &t0); + timespec_subtract(&td2, &t1, &lastWaitTime); + fprintf(stderr, "(%ld) / (%ld) ms", timespec_milliseconds(&td), timespec_milliseconds(&td2)); + #endif + } + SYNC_PRINT("-%d-%d}\n", shallDraw, wr); + timespec_now(&lastWaitTime); + pthread_mutex_unlock(&renderLock); +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, int gl3ShaderProgramName, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, uint32_t texID, Bool opaque, int texWidth, int texHeight) { + return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx gl3ShaderProgramName: (GLuint)gl3ShaderProgramName pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID + opaque: opaque texWidth: texWidth texHeight: texHeight]; +} + +void setNSOpenGLLayerEnabled(NSOpenGLLayer* layer, Bool enable) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + [l setGLEnabled: enable]; + [pool release]; +} + +void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + [l setSwapInterval: interval]; + [pool release]; +} + +void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + [l waitUntilRenderSignal: to_micros]; + [pool release]; +} + +void setNSOpenGLLayerNeedsDisplayFBO(NSOpenGLLayer* layer, uint32_t texID) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + Bool shallDraw; + + // volatile OK + [l setTextureID: texID]; + shallDraw = [l isGLSourceValid]; + l->shallDraw = shallDraw; + + SYNC_PRINT("<! T %d>", (int)shallDraw); + if(shallDraw) { + if ( [NSThread isMainThread] == YES ) { + [l setNeedsDisplay]; + } else { + // don't wait - using doublebuffering + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; + } + } + // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; +} + +void setNSOpenGLLayerNeedsDisplayPBuffer(NSOpenGLLayer* layer, NSOpenGLPixelBuffer* p) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + Bool shallDraw; + + if( NO == [l isSamePBuffer: p] ) { + [l setNewPBuffer: p]; + } + + // volatile OK + shallDraw = [l isGLSourceValid]; + l->shallDraw = shallDraw; + + SYNC_PRINT("<! T %d>", (int)shallDraw); + if(shallDraw) { + if ( [NSThread isMainThread] == YES ) { + [l setNeedsDisplay]; + } else { + // don't wait - using doublebuffering + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; + } + } + // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* layer) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l); + [l releaseLayer]; + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l); + + [CATransaction commit]; + + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m deleted file mode 100644 index 66bd10f89..000000000 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m +++ /dev/null @@ -1,494 +0,0 @@ -#import "MacOSXWindowSystemInterface.h" -#import <QuartzCore/QuartzCore.h> -#import <pthread.h> -#include "timespec.h" - -// -// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient. -// Use CVDisplayLink otherwise. -// -// #define HAS_CADisplayLink 1 -// - -// lock/sync debug output -// -// #define DBG_SYNC 1 -// -#ifdef DBG_SYNC - // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__) - #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) -#else - #define SYNC_PRINT(...) -#endif - -// fps debug output -// -// #define DBG_PERF 1 - -@interface MyNSOpenGLLayer: NSOpenGLLayer -{ -@protected - NSOpenGLPixelBuffer* pbuffer; - int texWidth; - int texHeight; - GLuint textureID; - GLint swapInterval; - GLint swapIntervalCounter; - struct timespec lastWaitTime; -#ifdef HAS_CADisplayLink - CADisplayLink* displayLink; -#else - CVDisplayLinkRef displayLink; -#endif - int tc; - struct timespec t0; -@public - pthread_mutex_t renderLock; - pthread_cond_t renderSignal; - BOOL shallDraw; -} - -- (id) setupWithContext: (NSOpenGLContext*) ctx - pixelFormat: (NSOpenGLPixelFormat*) pfmt - pbuffer: (NSOpenGLPixelBuffer*) p - opaque: (Bool) opaque - texWidth: (int) texWidth - texHeight: (int) texHeight; - -- (void)deallocTex; -- (void)disableAnimation; -- (void)releaseLayer; -- (void)dealloc; -- (int)getSwapInterval; -- (void)setSwapInterval:(int)interval; -- (void)tick; - -@end - -#ifndef HAS_CADisplayLink - -static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink, - const CVTimeStamp *inNow, - const CVTimeStamp *inOutputTime, - CVOptionFlags flagsIn, - CVOptionFlags *flagsOut, - void *displayLinkContext) -{ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext; - pthread_mutex_lock(&l->renderLock); - #ifdef DBG_PERF - [l tick]; - #endif - if(0 < l->swapInterval) { - l->swapIntervalCounter++; - if(l->swapIntervalCounter>=l->swapInterval) { - l->swapIntervalCounter = 0; - pthread_cond_signal(&l->renderSignal); - SYNC_PRINT("S"); - } - } - pthread_mutex_unlock(&l->renderLock); - [pool release]; - return kCVReturnSuccess; -} - -#endif - -@implementation MyNSOpenGLLayer - -- (id) setupWithContext: (NSOpenGLContext*) _ctx - pixelFormat: (NSOpenGLPixelFormat*) _fmt - pbuffer: (NSOpenGLPixelBuffer*) p - opaque: (Bool) opaque - texWidth: (int) _texWidth - texHeight: (int) _texHeight; -{ - pthread_mutexattr_t renderLockAttr; - pthread_mutexattr_init(&renderLockAttr); - pthread_mutexattr_settype(&renderLockAttr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&renderLock, &renderLockAttr); // recursive - pthread_cond_init(&renderSignal, NULL); // no attribute - - textureID = 0; - swapInterval = 1; // defaults to on (as w/ new GL profiles) - swapIntervalCounter = 0; - timespec_now(&lastWaitTime); - shallDraw = NO; - texWidth = _texWidth; - texHeight = _texHeight; - pbuffer = p; - [pbuffer retain]; - - { - CGRect lRect = CGRectMake(0, 0, texWidth, texHeight); - [self setFrame:lRect]; - - // no animations for add/remove/swap sublayers etc - // doesn't work: [self removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] - [self removeAllAnimations]; - } - - // instantiate a deactivated displayLink -#ifdef HAS_CADisplayLink - displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain]; - [displayLink setPaused: YES]; -#else - CVReturn cvres; - { - int allDisplaysMask = 0; - int virtualScreen, accelerated, displayMask; - for (virtualScreen = 0; virtualScreen < [_fmt numberOfVirtualScreens]; virtualScreen++) { - [_fmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen]; - [_fmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen]; - if (accelerated) { - allDisplaysMask |= displayMask; - } - } - cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink); - if(kCVReturnSuccess != cvres) { - DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres); - displayLink = NULL; - } - } - if(NULL != displayLink) { - cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [_ctx CGLContextObj], [_fmt CGLPixelFormatObj]); - if(kCVReturnSuccess != cvres) { - DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); - displayLink = NULL; - } - } - if(NULL != displayLink) { - cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); - if(kCVReturnSuccess != cvres) { - DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); - displayLink = NULL; - } - } - if(NULL != displayLink) { - CVDisplayLinkStop(displayLink); - } -#endif - [self setAsynchronous: YES]; - - [self setNeedsDisplayOnBoundsChange: YES]; // FIXME: learn how to recreate on size change! - - [self setOpaque: opaque ? YES : NO]; - - CGRect lRect = [self frame]; - DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, frame: %lf/%lf %lfx%lf (refcnt %d)\n", - self, _ctx, _fmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, - lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]); - return self; -} - -- (void)disableAnimation -{ - DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); - pthread_mutex_lock(&renderLock); - [self setAsynchronous: NO]; - if(NULL != displayLink) { -#ifdef HAS_CADisplayLink - [displayLink setPaused: YES]; - [displayLink release]; -#else - if(NULL!=displayLink) { - CVDisplayLinkStop(displayLink); - CVDisplayLinkRelease(displayLink); - } -#endif - displayLink = NULL; - } - pthread_mutex_unlock(&renderLock); -} - -- (void)deallocTex -{ - pthread_mutex_lock(&renderLock); - NSOpenGLContext* context = [self openGLContext]; - DBG_PRINT("MyNSOpenGLLayer::deallocTex %p (refcnt %d) - context %p, pbuffer %p\n", self, (int)[self retainCount], context, pbuffer); - if(NULL != pbuffer) { - if(NULL!=context) { - [context makeCurrentContext]; - if(0 != textureID) { - glDeleteTextures(1, &textureID); - textureID = 0; - } - [context clearDrawable]; - } - [pbuffer release]; - pbuffer = NULL; - } - pthread_mutex_unlock(&renderLock); -} - -- (void)releaseLayer -{ - DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]); - pthread_mutex_lock(&renderLock); - [self disableAnimation]; - [self deallocTex]; - [self release]; - DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p (refcnt %d)\n", self, (int)[self retainCount]); - pthread_mutex_unlock(&renderLock); -} - -- (void)dealloc -{ - DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); - // NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]); - - [self disableAnimation]; - [self deallocTex]; - pthread_cond_destroy(&renderSignal); - pthread_mutex_destroy(&renderLock); - [super dealloc]; - DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); -} - -- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat - forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp -{ - // assume both methods 'canDrawInOpenGLContext' and 'drawInOpenGLContext' - // are called from the same thread subsequently - pthread_mutex_lock(&renderLock); - Bool res = NULL != pbuffer && YES == shallDraw; - if(!res) { - SYNC_PRINT("0"); - pthread_mutex_unlock(&renderLock); - } else { - SYNC_PRINT("1"); - } - return res; -} - -- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat - forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp -{ - [context makeCurrentContext]; - - /** - * v-sync doesn't works w/ NSOpenGLLayer's context .. well :( - * Using CVDisplayLink .. see setSwapInterval() below. - * - if(0 <= swapInterval) { - GLint si; - [context getValues: &si forParameter: NSOpenGLCPSwapInterval]; - if(si != swapInterval) { - DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval); - [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; - } - } */ - GLenum textureTarget = [pbuffer textureTarget]; - GLfloat tWidth, tHeight; - { - GLsizei pwidth = [pbuffer pixelsWide]; - GLsizei pheight = [pbuffer pixelsHigh]; - tWidth = textureTarget == GL_TEXTURE_2D ? (GLfloat)pwidth /(GLfloat)texWidth : pwidth; - tHeight = textureTarget == GL_TEXTURE_2D ? (GLfloat)pheight/(GLfloat)texHeight : pheight; - } - Bool texCreated = 0 == textureID; - - if(texCreated) { - glGenTextures(1, &textureID); - DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p tex %dx%d -> %fx%f 0x%X: creating texID 0x%X\n", - self, context, pixelFormat, texWidth, texHeight, tWidth, tHeight, textureTarget, textureID); - - CGRect lRect = [self frame]; - DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p frame0: %lf/%lf %lfx%lf\n", - self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); - } - - glBindTexture(textureTarget, textureID); - - /** - if(texCreated) { - // proper tex size setup - glTexImage2D(textureTarget, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - } */ - - [context setTextureImageToPixelBuffer: pbuffer colorBuffer: GL_FRONT]; - - glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glEnable(textureTarget); - - static GLfloat verts[] = { - -1.0, -1.0, - -1.0, 1.0, - 1.0, 1.0, - 1.0, -1.0 - }; - - GLfloat tex[] = { - 0.0, 0.0, - 0.0, tHeight, - tWidth, tHeight, - tWidth, 0.0 - }; - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, verts); - glTexCoordPointer(2, GL_FLOAT, 0, tex); - - glDrawArrays(GL_QUADS, 0, 4); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glDisable(textureTarget); - glBindTexture(textureTarget, 0); - - [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; - shallDraw = NO; - if(0 >= swapInterval) { - pthread_cond_signal(&renderSignal); // just to wake up - SYNC_PRINT("s"); - } - SYNC_PRINT("$"); - pthread_mutex_unlock(&renderLock); -} - -- (int)getSwapInterval -{ - return swapInterval; -} - -- (void)setSwapInterval:(int)interval -{ - DBG_PRINT("MyNSOpenGLLayer::setSwapInterval: %d\n", interval); - swapInterval = interval; - swapIntervalCounter = 0; - if(0 < swapInterval) { - tc = 0; - timespec_now(&t0); - - [self setAsynchronous: NO]; - #ifdef HAS_CADisplayLink - [displayLink setPaused: NO]; - [displayLink setFrameInterval: interval]; - #else - if(NULL!=displayLink) { - CVDisplayLinkStart(displayLink); - // FIXME: doesn't support interval .. - } - #endif - } else { - #ifdef HAS_CADisplayLink - [displayLink setPaused: YES]; - #else - if(NULL!=displayLink) { - CVDisplayLinkStop(displayLink); - } - #endif - [self setAsynchronous: YES]; - } -} - --(void)tick -{ - tc++; - if(tc%60==0) { - struct timespec t1, td; - timespec_now(&t1); - timespec_subtract(&td, &t1, &t0); - long td_ms = timespec_milliseconds(&td); - fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n", - td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms ); - fflush(NULL); - } -} - -@end - -NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, Bool opaque, int texWidth, int texHeight) { - // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ? - // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO. - // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; - - return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; -} - -void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; - pthread_mutex_lock(&l->renderLock); - [l setSwapInterval: interval]; - pthread_mutex_unlock(&l->renderLock); -} - -void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; - BOOL ready = NO; - int wr = 0; - pthread_mutex_lock(&l->renderLock); - SYNC_PRINT("{"); - do { - if([l getSwapInterval] <= 0) { - ready = !l->shallDraw; - } - if(NO == ready) { - if(0 < to_micros) { - #ifdef DBG_SYNC - struct timespec t0, t1, td, td2; - timespec_now(&t0); - #endif - struct timespec to_abs = l->lastWaitTime; - timespec_addmicros(&to_abs, to_micros); - #ifdef DBG_SYNC - timespec_subtract(&td, &to_abs, &t0); - fprintf(stderr, "(%ld) / ", timespec_milliseconds(&td)); - #endif - wr = pthread_cond_timedwait(&l->renderSignal, &l->renderLock, &to_abs); - #ifdef DBG_SYNC - timespec_now(&t1); - timespec_subtract(&td, &t1, &t0); - timespec_subtract(&td2, &t1, &l->lastWaitTime); - fprintf(stderr, "(%ld) / (%ld) ms", timespec_milliseconds(&td), timespec_milliseconds(&td2)); - #endif - } else { - pthread_cond_wait (&l->renderSignal, &l->renderLock); - } - ready = !l->shallDraw; - } - } while (NO == ready && 0 == wr) ; - SYNC_PRINT("-%d}", ready); - timespec_now(&l->lastWaitTime); - pthread_mutex_unlock(&l->renderLock); -} - -void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - pthread_mutex_lock(&l->renderLock); - l->shallDraw = YES; - if ( [NSThread isMainThread] == YES ) { - [l setNeedsDisplay]; - } else { - // can't wait, otherwise we may deadlock AWT - [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; - } - SYNC_PRINT("."); - pthread_mutex_unlock(&l->renderLock); - // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); - [pool release]; -} - -void releaseNSOpenGLLayer(NSOpenGLLayer* layer) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l); - - if ( [NSThread isMainThread] == YES ) { - [l releaseLayer]; - } else { - [l performSelectorOnMainThread:@selector(releaseLayer) withObject:nil waitUntilDone:NO]; - } - - DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l); - [pool release]; -} - diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m index 8ac9f4700..d4d3ddad9 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m @@ -446,7 +446,7 @@ NSOpenGLPixelFormat* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; // if(fmt == nil) { fallback to a [NSOpenGLView defaultPixelFormat] crashed (SIGSEGV) on 10.6.7/NV } - DBG_PRINT("createPixelFormat.X: pfmt %p\n", fmt); + DBG_PRINT("\ncreatePixelFormat.X: pfmt %p\n", fmt); [pool release]; return fmt; @@ -501,9 +501,31 @@ NSView* getNSView(NSOpenGLContext* ctx) { return view; } +static Bool lockViewIfReady(NSView *view) { + Bool viewReady = false; + + if (view != nil) { + if ([view lockFocusIfCanDraw] == NO) { + DBG_PRINT("lockViewIfReady.1 [view lockFocusIfCanDraw] failed\n"); + } else { + NSRect frame = [view frame]; + if ((frame.size.width == 0) || (frame.size.height == 0)) { + [view unlockFocus]; + DBG_PRINT("lockViewIfReady.2 view.frame size %dx%d\n", (int)frame.size.width, (int)frame.size.height); + } else { + DBG_PRINT("lockViewIfReady.X ready and locked\n"); + viewReady = true; + } + } + } else { + DBG_PRINT("lockViewIfReady.3 nil view\n"); + } + return viewReady; +} + NSOpenGLContext* createContext(NSOpenGLContext* share, NSView* view, - Bool isBackingLayerView, + Bool incompleteView, NSOpenGLPixelFormat* fmt, Bool opaque, int* viewNotReady) @@ -512,56 +534,32 @@ NSOpenGLContext* createContext(NSOpenGLContext* share, getRendererInfo(); - DBG_PRINT("createContext.0: share %p, view %p, isBackingLayer %d, pixfmt %p, opaque %d\n", - share, view, (int)isBackingLayerView, fmt, opaque); - - if (view != NULL) { - Bool viewReady = true; + DBG_PRINT("createContext.0: share %p, view %p, incompleteView %d, pixfmt %p, opaque %d\n", + share, view, (int)incompleteView, fmt, opaque); - if(!isBackingLayerView) { - if ([view lockFocusIfCanDraw] == NO) { - DBG_PRINT("createContext.1 [view lockFocusIfCanDraw] failed\n"); - viewReady = false; - } - } - if(viewReady) { - NSRect frame = [view frame]; - if ((frame.size.width == 0) || (frame.size.height == 0)) { - if(!isBackingLayerView) { - [view unlockFocus]; - } - DBG_PRINT("createContext.2 view.frame size %dx%d\n", (int)frame.size.width, (int)frame.size.height); - viewReady = false; - } - } + Bool viewReadyAndLocked = incompleteView ? false : lockViewIfReady(view); - if (!viewReady) - { - if (viewNotReady != NULL) - { - *viewNotReady = 1; - } + if (nil != viewNotReady) { + *viewNotReady = 1; + } - // the view is not ready yet - DBG_PRINT("createContext.X: view not ready yet\n"); - [pool release]; - return NULL; - } + if (nil != view && !incompleteView && !viewReadyAndLocked) { + DBG_PRINT("createContext.X: Assumed complete view not ready yet\n"); + [pool release]; + return NULL; } - + NSOpenGLContext* ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:share]; - if (ctx != nil) { - if (view != nil) { + if ( nil != ctx && nil != view ) { if(!opaque) { GLint zeroOpacity = 0; [ctx setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; } - [ctx setView:view]; - if(!isBackingLayerView) { + if( viewReadyAndLocked ) { + [ctx setView:view]; [view unlockFocus]; } - } } DBG_PRINT("createContext.X: ctx: %p\n", ctx); @@ -569,6 +567,32 @@ NSOpenGLContext* createContext(NSOpenGLContext* share, return ctx; } +void setContextView(NSOpenGLContext* ctx, NSView* view) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + if ( nil != ctx ) { + if ( nil != view ) { + Bool viewReadyAndLocked = lockViewIfReady(view); + DBG_PRINT("setContextView.0: ctx %p, view %p: setView: %d\n", ctx, view, viewReadyAndLocked); + if( viewReadyAndLocked ) { + [ctx setView:view]; + [view unlockFocus]; + } + } + DBG_PRINT("setContextView.X\n"); + } + [pool release]; +} + +void clearDrawable(NSOpenGLContext* ctx) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + if ( nil != ctx ) { + DBG_PRINT("clearDrawable.0: %p\n", ctx); + [ctx clearDrawable]; + DBG_PRINT("clearDrawable.X\n"); + } + [pool release]; +} + Bool makeCurrentContext(NSOpenGLContext* ctx) { #if 0 // we issue the CGL Lock from Java upfront! @@ -628,7 +652,12 @@ void setContextOpacity(NSOpenGLContext* ctx, int opacity) { void updateContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [ctx update]; + NSView *nsView = [ctx view]; + if(NULL != nsView) { + DBG_PRINT("updateContext.0: ctx %p, ctx.view %p\n", ctx, nsView); + [ctx update]; + DBG_PRINT("updateContext.X\n"); + } [pool release]; } @@ -638,7 +667,10 @@ void copyContext(NSOpenGLContext* dest, NSOpenGLContext* src, int mask) { void* updateContextRegister(NSOpenGLContext* ctx, NSView* view) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT("updateContextRegister.0: ctx %p, view %p\n", ctx, view); ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: ctx view: view]; + DBG_PRINT("updateContextRegister.X: ctxupd %p\n", contextUpdater); [pool release]; return contextUpdater; } @@ -658,44 +690,62 @@ void updateContextUnregister(void* updater) { ContextUpdater *contextUpdater = (ContextUpdater *)updater; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("updateContextUnregister.0: ctxupd %p\n", contextUpdater); [contextUpdater release]; + DBG_PRINT("updateContextUnregister.X\n"); [pool release]; } NSOpenGLPixelBuffer* createPBuffer(int renderTarget, int internalFormat, int width, int height) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("createPBuffer.0: renderTarget 0x%x, ifmt 0x%x, %dx%d: \n", renderTarget, internalFormat, width, height); NSOpenGLPixelBuffer* pBuffer = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:renderTarget textureInternalFormat:internalFormat textureMaxMipMapLevel:0 pixelsWide:width pixelsHigh:height]; + DBG_PRINT("createPBuffer.X: res %p\n", pBuffer); [pool release]; return pBuffer; } Bool destroyPBuffer(NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("destroyPBuffer.0: pbuffer %p\n", pBuffer); [pBuffer release]; + DBG_PRINT("destroyPBuffer.X\n"); [pool release]; return true; } void setContextPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("setContextPBuffer.0: ctx %p, pbuffer %p\n", ctx, pBuffer); [ctx setPixelBuffer: pBuffer cubeMapFace: 0 mipMapLevel: 0 currentVirtualScreen: [ctx currentVirtualScreen]]; + DBG_PRINT("setContextPBuffer.X\n"); [pool release]; } void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer, GLenum colorBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("setContextTextureImageToPBuffer.0: ctx %p, pbuffer %p, colorBuffer 0x%x\n", ctx, pBuffer, (int)colorBuffer); [ctx setTextureImageToPixelBuffer: pBuffer colorBuffer: colorBuffer]; + DBG_PRINT("setContextTextureImageToPBuffer.X\n"); [pool release]; } +Bool isNSOpenGLPixelBuffer(uint64_t object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + DBG_PRINT("isNSOpenGLPixelBuffer.0: obj %p\n", object); + Bool res = [nsObj isKindOfClass:[NSOpenGLPixelBuffer class]]; + DBG_PRINT("isNSOpenGLPixelBuffer.X: res %d\n", (int)res); + return res; +} + #include <mach-o/dyld.h> Bool imagesInitialized = false; static char libGLStr[] = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"; @@ -746,38 +796,3 @@ void resetGammaRamp() { CGDisplayRestoreColorSyncSettings(); } -/*** - * The following static functions are copied out of NEWT's OSX impl. <src/newt/native/MacWindow.m> - * May need to push code to NativeWindow, to remove duplication. - */ -static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) { - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - return (NSScreen *) [screens objectAtIndex: screen_idx]; -} -static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { - // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! - NSDictionary * dict = [screen deviceDescription]; - NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; - // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size - return (CGDirectDisplayID) [val integerValue]; -} -static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) -{ - long value = 0; - CFNumberRef numRef; - numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); - if (numRef != NULL) - CFNumberGetValue(numRef, kCFNumberLongType, &value); - return value; -} -#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate) - -int getScreenRefreshRate(int scrn_idx) { - NSScreen *screen = NewtScreen_getNSScreenByIndex(scrn_idx); - CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); - CFDictionaryRef mode = CGDisplayCurrentMode(display); - return CGDDGetModeRefreshRate(mode); -} - |