Full Screen OpenGL Crashes

Member
Posts: 254
Joined: 2005.10
Post: #1
I designed an NSOpenGLView subclass to support switching to full screen rendering. I based the class on one from OSC and the one from the InkuGame project. After getting it working, I then copied the classes to a new project and hooked everything up the same in InterfaceBuilder, but when I try to go full screen in the new project my system just hangs and I have to force a restart! Anyone have any ideas as to what may be causing this? Here some possibly relevant code.

Code:
- (void)drawRect:(NSRect)rect
{
    if(isFirstFrame)
    {
        isFirstFrame = NO;
        if(isFullScreen) [fullScreenContext setFullScreen];
        else [windowedContext setView:self];
    }

    [delegate drawRect:rect];

    [[self openGLContext] flushBuffer];
}

- (IBAction) toggleFullScreen:(id)sender
{
    isFirstFrame = YES;
    CGDisplayFadeReservationToken fadeReservation;
    CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval,
                                    &fadeReservation);
    CGDisplayFade(fadeReservation, 0.5, kCGDisplayBlendNormal,
                  kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, true);

    [NSOpenGLContext clearCurrentContext];

    if(isFullScreen)
    {
        isFullScreen = NO;
        [fullScreenContext clearDrawable];
        
        CGReleaseAllDisplays();
        CGDisplaySwitchToMode(kCGDirectMainDisplay, (CFDictionaryRef)desktopMode);
        
        [self setOpenGLContext:windowedContext];
        [[self window] makeKeyAndOrderFront:self];
        
        [NSCursor unhide];
        [NSMenu setMenuBarVisible:YES];
    }
    else
    {
        isFullScreen = YES;
        isFirstFrame = YES;
        [windowedContext clearDrawable];
        
        // Store the desktop mode before we change modes.
        [desktopMode release];
        desktopMode = [(NSDictionary*)CGDisplayCurrentMode(kCGDirectMainDisplay) retain];

        CGCaptureAllDisplays();
        CGDisplaySwitchToMode(kCGDirectMainDisplay, (CFDictionaryRef)fullScreenMode);

        [fullScreenContext setFullScreen];
        [self setOpenGLContext:fullScreenContext];
        
        [NSCursor hide];
        [NSMenu setMenuBarVisible:NO];
    }
    [self display];
    
    CGDisplayFade(fadeReservation, 2.0, kCGDisplayBlendSolidColor,
                  kCGDisplayBlendNormal, 0.0, 0.0, 0.0, false);
    CGReleaseDisplayFadeReservation(fadeReservation);
}
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #2
Switching into/out of full screen can be a total pain. All I remember is that it was confusing to figure out. Wacko I don't see anything that sticks out immediately. I forgot if setOpenGLContext will make the context current as well. You might want to try calling makeCurrentContext right after setOpenGLContext in your full screen switch just to be sure, since you called clearCurrentContext earlier.
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #3
I'd also wager that you need to make the new context current. I'd also suggest using a shared context approach, unless you do already (not evident from code snippet), otherwise you have to reload all OpenGL resources, such as textures and vertex buffers, for the new context. It's also not clear from that snippet if the contexts are set up correctly.

You definitely should not be getting a kernel panic, so file a radr with Apple, but I've seen OSX KP quite a few times when an invalid OpenGL context is accessed, or with threads stepping on each other's toes.
Quote this message in a reply
Member
Posts: 245
Joined: 2005.11
Post: #4
It may not be a kernel panic. It is possible to put an OpenGL context into fullscreen mode, not make it current, and not have it attached to any other objects. Once you've done that nothing you do has any visible effect and you cannot easily get out of fullscreen mode. I have managed to set this up in such a way that even pressing command-q didn't send a terminate message to my app controller and force-quitting blind was the only way out.
It is also possible to crash the video card without crashing the OS by sending it a bad pointer, which kills the visuals without stopping any software from running (although I'm pretty sure that isn't happening here).
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #5
I haven't even been able to force quit blind. I'm not sure I have a shared context set up, so I'll check into that and also check to make sure the correct context is current. Thanks for the help.
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #6
I am using a shared context and I modified drawRect to ensure the correct context is current, but my app still crashes when switching to fullscreen.

Code:
- (void)drawRect:(NSRect)rect
{
    if(isFirstFrame)
    {
        isFirstFrame = NO;
        if(isFullScreen)
        {
            [fullScreenContext setFullScreen];
            [fullScreenContext makeCurrentContext];
        }
        else
        {
            [windowedContext setView:self];
            [windowedContext makeCurrentContext];
        }
    }

    [delegate drawRect:rect];

    [[self openGLContext] flushBuffer];
}
Quote this message in a reply
Member
Posts: 245
Joined: 2005.11
Post: #7
The OS might make other things current in between frames so you might need to make the correct context current every frame, not just on the first one.
Try this:
Code:
- (void)drawRect:(NSRect)rect
{
    if(isFirstFrame)
    {
        isFirstFrame = NO;
        if(isFullScreen)
        {
            [fullScreenContext setFullScreen];
            openGLContext  = fullScreenContext;
        }
        else
        {
            [windowedContext setView:self];
            openGLContext  = windowedContext;
        }
    }

    [openGLContext makeCurrentContext];
    [delegate drawRect:rect];

    [[self openGLContext] flushBuffer];
}
I seem to remember doing something extra in an NSApplication subclass to intercept keyboard events in fullscreen mode, but I don't have the code handy at the moment.
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #8
Good point, I fixed it so the correct context is made current every time drawRect is called. Unfortunately it doesn't fix the problem.
Code:
- (void)drawRect:(NSRect)rect
{
    if(isFirstFrame)
    {
        isFirstFrame = NO;
        if(isFullScreen) [fullScreenContext setFullScreen];
        else [windowedContext setView:self];
    }
    [[self openGLContext] makeCurrentContext];

    [delegate drawRect:rect];

    [[self openGLContext] flushBuffer];
}
Quote this message in a reply
Member
Posts: 81
Joined: 2007.05
Post: #9
Debugging fullscreen can be a pain. If you have two monitors that can make it a lot easier. You can have xcode running in one monitor with the debugger and the fullscreen going on the other monitor. Seemed to make things easier for me...
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #10
macnib Wrote:Debugging fullscreen can be a pain. If you have two monitors that can make it a lot easier. You can have xcode running in one monitor with the debugger and the fullscreen going on the other monitor. Seemed to make things easier for me...
That's a good idea, I'll have to commandeer the TV for that. I thought that when you went full screen both monitors became black, is that true? Is there anything special I need to do?
Quote this message in a reply
Member
Posts: 81
Joined: 2007.05
Post: #11
You can use CG calls like CGGetOnlineDisplayList .

Also, if you use cocoa there is :

[self enterFullScreenMode: [NSScreen mainScreen] withOptions: nil ];
[self exitFullScreenModeWithOptions: nil];
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #12
Blacktiger Wrote:That's a good idea, I'll have to commandeer the TV for that. I thought that when you went full screen both monitors became black, is that true? Is there anything special I need to do?

Hehe... You might notice in GameBase, in performToggleFullScreen:

Code:
        #ifdef DEBUG
            err = CGDisplayCapture(preferredDisplayID);
        #else
            err = CGCaptureAllDisplays();
        #endif

That is specifically there because I had such a hell of a time debugging full screen problems like this that I used two monitors. Only the captured one goes black (or at least stays black). The other one was able to mouse around and be used normally. That saved a lot of time.
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #13
Thanks for the help. As I messed around with my code, it suddenly started working again! (Well, I'm not drawing anything in full screen mode yet, but I can go in and out without problems.) The only major thing I seem to have changed is to remove the timers that I had to run drawRect at a constant frequency. I can't see how that would make a difference and maybe it didn't. Seems like this stuff should be straight forward, but for some reason it just isn't.
Quote this message in a reply
Member
Posts: 245
Joined: 2005.11
Post: #14
Does that mean you're not calling drawrect: any more? If so, don't assume that the problem is actually fixed - it may be that something in drawrect: is causing the issue (do you definitely have a valid context?).
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenGL Perspective Screen to Obj Coordinates Mapping Question WhatMeWorry 5 9,123 Feb 17, 2011 05:40 PM
Last Post: Holmes
  Cocoa: NSRectFillListWithColors crashes Lycander 0 2,008 Aug 23, 2009 10:33 PM
Last Post: Lycander
  OpenGL full screen mode leaves garbage on screen when exiting app Malarkey 5 5,379 Nov 19, 2008 12:51 PM
Last Post: Malarkey
  Changing resolution while already in full-screen mode? Malarkey 1 2,708 Jun 10, 2008 07:49 PM
Last Post: AnotherJake
  Full Screen Switching Blacktiger 3 3,683 Feb 9, 2008 03:05 PM
Last Post: Blacktiger