NSOpenGLView subclass does not render on Mojave

332 views Asked by At

I've encountered a very odd error when compiling with Xcode 10 against Mojave frameworks.

It turns out that the OpenGL the stops showing. It appears that it's actually somewhere there (the backing layer overlays it?) as visible when rapidly updating the visible area of the window(!) or when minimizing (the snapshot used by genie effect shows it!)

The weirdest thing is that I use almost the identical class for another project and it works fine when building for Mojave!

I see solutions with sending an update to the OpenGLContext for those who use a separate context, but this is a simple subclass to NSOpenGLView. In this case a fork off SpriteBuilder for Cocos2D.

I've tried updating the underlying context, setting the view to support high res and trying to prevent the backing layer from being created. Nothing worked so far.

The code:

@implementation CCGLView {
    NSMutableArray *_fences;
}

- (id) initWithFrame:(NSRect)frameRect
{
    self = [self initWithFrame:frameRect shareContext:nil];
    return self;
}

- (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context
{
    NSOpenGLPixelFormatAttribute attribs[] =
    {
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFADepthSize, 24,
        0
    };

    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];

    if (!pixelFormat)
        CCLOG(@"No OpenGL pixel format");

    if ((self = [super initWithFrame:frameRect pixelFormat:pixelFormat])) {

        if (context) [self setOpenGLContext:context];

    }

    return self;
}

- (void) prepareOpenGL
{
    [super prepareOpenGL];

    // Make this openGL context current to the thread
    // (i.e. all openGL on this thread calls will go to this context)
    [[self openGLContext] makeCurrentContext];

    // Synchronize buffer swaps with vertical refresh rate
    GLint swapInt = 1;
    [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];  

}

- (NSUInteger) depthFormat
{
    return 24;
}

- (void) reshape
{
    [self lockOpenGLContext];

    NSRect rect = [self convertRectToBacking:self.bounds];

    CCDirector *director = [CCDirector sharedDirector];
    [director reshapeProjection: NSSizeToCGSize(rect.size) ];

    if (director.runningScene) { 
       [director drawScene];
    }
    [self unlockOpenGLContext];
}


- (void)lockOpenGLContext
{
    NSOpenGLContext *glContext = [self openGLContext];
    NSAssert( glContext, @"FATAL: could not get openGL context");

    [glContext makeCurrentContext];
    CGLLockContext([glContext CGLContextObj]);  
}

-(void) unlockOpenGLContext
{
    NSOpenGLContext *glContext = [self openGLContext];
    NSAssert( glContext, @"FATAL: could not get openGL context");

    CGLUnlockContext([glContext CGLContextObj]);
}

// Find or make a fence that is ready to use.
-(CCGLViewFence *)getReadyFence
{
    // First checkf oldest (first in the array) fence is ready again.
    CCGLViewFence *fence = _fences.firstObject;;
    if(fence.isReady){
        // Remove the fence so it can be inserted at the end of the queue again.
        [_fences removeObjectAtIndex:0];
        return fence;
    } else {
        // No existing fences ready. Make a new one.
        return [[CCGLViewFence alloc] init];
    }
}

-(void)addFrameCompletionHandler:(dispatch_block_t)handler
{
    if(_fences == nil){
        _fences = [NSMutableArray arrayWithObject:[[CCGLViewFence alloc] init]];
    }

    CCGLViewFence *fence = _fences.lastObject;
    if(!fence.isReady){
        fence = [self getReadyFence];
        [_fences addObject:fence];
    }

    [fence.handlers addObject:handler];
}

-(void)beginFrame
{
    [self lockOpenGLContext];
}

-(void)presentFrame
{
    {
        CCGLViewFence *fence = _fences.lastObject;
        if(fence.isReady){
            // If the fence is ready to be added, insert a sync point for it.
            [fence insertFence];
        }
    }

    [self.openGLContext flushBuffer];

    // Check the fences for completion.
    for(CCGLViewFence *fence in _fences){
        if(fence.isComplete){
            for(dispatch_block_t handler in fence.handlers) handler();
            [fence.handlers removeAllObjects];
        } else {
            break;
        }
    }

    [self unlockOpenGLContext];
}

-(GLuint)fbo
{
    return 0;
}
@end    
0

There are 0 answers