Trouble with fullscreen switching

codeman9
Unregistered
 
Post: #1
Hi all, I apologize if this horse has been beaten to death, but I can't seem to find the answer to the problem I am having and I'm sure it is something simple. I have code that displays a simple white triangle in a window and a menu item that switches to fullscreen mode. I do the normal make context, capture display, etc. from what I have seen in samples and such, but for some reason, I either get nothing but a black screen or I get a bunch of garbage, then I switch out of fullscreen and there is my nice window with the white triangle. I have tried starting the app in fullscreen mode and the same thing happens. Here is the relevant code:


- (void)setWindowedMode
{
[fullScreenContext clearDrawable];

CGReleaseAllDisplays();

[windowedContext makeCurrentContext];

isFullScreen = NO;
}

- (void)setFullScreenMode
{

NSOpenGLPixelFormatAttribute fullScreenAttrs[] = {
NSOpenGLPFAFullScreen,
NSOpenGLPFAScreenMask, CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
NSOpenGLPFASingleRenderer,
NSOpenGLPFANoRecovery,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 32,
NSOpenGLPFADepthSize, 16,
0
};

NSOpenGLPixelFormat *fullScreenPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:fullScreenAttrs];

fullScreenContext = [[NSOpenGLContext alloc] initWithFormat:fullScreenPixelFormat shareContext:windowedContext];
[fullScreenPixelFormat release];
fullScreenPixelFormat = nil;

[windowedContext clearDrawable];

CGDisplayErr err = CGCaptureAllDisplays();
if (err != CGDisplayNoErr) {
[fullScreenContext release];
fullScreenContext = nil;
return;
}

[fullScreenContext setFullScreen];
[fullScreenContext makeCurrentContext];

isFullScreen = YES;
}

- (void)toggleFullScreen
{
[NSOpenGLContext clearCurrentContext];

if (isFullScreen) {
[self setWindowedMode];
[self setNeedsDisplay:YES];
} else {
[self setFullScreenMode];
[self setNeedsDisplay:YES];
//[fullScreenContext flushBuffer]; // Uncomment this line and I get
// garbage on the screen after
// fullscreen is entered.
}
}

At the end of drawRect I have [[self openGLContext] flushBuffer]. The custom view was created in a nib file and hooked up in the normal way. I cannot seem to figure out what is wrong with this. If anyone can help, that would be great. Also, if you need more info, I would be happy to supply it.

Thanks!
Cody
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
Are you getting "Invalid drawable" or "Invalid share context" printed to the Console?

The full-screen and windowed pixel format attribute lists should be identical save the NSOpenGLPFAFullScreen attribute.

Working code here: http://onesadcookie.is-a-geek.net/svn/repos/GameShell/
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #3
If you've specified a display mask for the fullscreen renderer, and you want to share it with the windowed context, then you must also specify a display mask there. Otherwise, in systems with two video cards, you could get a context on each one.

More working code: Shoot Things
Quote this message in a reply
srcleaves
Unregistered
 
Post: #4
The code you post looks very similar to that in the NSOpenGL Fullscreen demo code from Apple...

http://developer.apple.com/samplecode/NS...creen.html

I have recently started working through these examples...

http://gametutorials.com/Tutorials/openg...GL_Pg1.htm

And of course they all must be converted to Obj-C and in my case using NSOpenGLView. My first crack at this left out the full screen support. I have done fullscreen stuff successfully without involving OpenGL though. I am planning to add full screen support though. My question about Apple's demo code is why do they set up their own event handling loop once they enter full screen? What would be the benefit of doing this over continuing with the animation timer that they already use for the windowed version? My guess is that since they are full screen they are trying to increase the frame rate but I didn't know if there was some other reason for them to do this?
Quote this message in a reply
codeman9
Unregistered
 
Post: #5
I do not get any errors printed to the console. The windowedContext is exactly the same as the fullScreenContext as far as attributes save the NSOpenGLPFAFullScreen. Yes, this code is a lot like Apple's example, as that is the first one I looked at, but I have looked at the GameShell and many others trying their various techniques, but to no avail. When I print out the [self openGLContext] in drawRect, it never changes. I'm thinking that this may be the problem, but I don't know. I'm just confused. The reason I changed what I saw in Apple's example is because of that weird event loop in the goFullScreen method, I did not want that. Hope that clears up some things. I've been staring at it for the longest time now.

Thanks,
Cody
Quote this message in a reply
nabobnick
Unregistered
 
Post: #6
I'll offer another example that might help. I've written a basic shell that uses it's own event loop to control rendering and input, should be able to switch between full screen and windowed on the fly (though nothing is in there now to switch while it's running) and it uses by hand created windows (there are no windows in the .nib file). It also does not use Cocoa based rendering (i.e. drawRect) and I think this last part is helpful when rendering in windows and fullscreen without doing something different for each case.

One important part of this example is that the code to switch between fullscreen and windowed is written in separate methods that helps show the steps involved in each while the rendering code is exactly the same for each.

The code is at: http://www.nutzy.net/NutzyGLEngine2.tar.gz

A more recent version, but one that will not run for you since you do not have the data files it uses is at: http://www.nutzy.net/NutzyEngine.tar.gz

This second version includes code for reading data files, translating those files into textures and (if I uploaded a version recently which I can't remember) also includes reading in 3d objects and displaying them. The only downside is the file format it uses is from a proprietary PC game, Asheron's Call.

Both sets of code pretty much use Cocoa and Objective-C exclusively (no porting gonna be done to this code, at least not easily).
Quote this message in a reply
Member
Posts: 72
Joined: 2006.10
Post: #7
Well, if it helps you, here's how I do it:
Here

HTH

EDIT: There's a lot of stuff in there you don't need, you should look at the
initializeWithConfigurationFile: , setupWindowed, setupFullscreen and toggleFullscreen methods.

- Sohta
Quote this message in a reply
codeman9
Unregistered
 
Post: #8
Well, I tried adding:
CGDisplaySwitchToMode(kCGDirectMainDisplay, (CFDictionaryRef)fullMode);

right before:
[fullScreenContext setFullScreen];

with fullMode being the current display mode chosen in initWithFrame: and I now get an invalid drawable message on the console. The error happens somewhere in the
[fullScreenContext setFullScreen]; line, I have deduced. Maybe this is the problem. When does the view become a valid drawable? When I try and [windowedContext setView:self]; in the initWithFrame, I also get an invalid drawable message in the console, but I still get my triangle.

Thanks,
Cody
Quote this message in a reply
codeman9
Unregistered
 
Post: #9
Some more updates: I added a few lines concerning the view and its context; mainly [self setOpenGLContext:windowedContext]; in the setWindowedMode method and [self setOpenGLContext:fullScreenContext]; in the setFullScreenMode method. In drawRect I print out [self openGLContext]; and it looks like it is now changing to the correct mode as that matches the printout of fullScreenContext and windowedContext separately. But, now I am getting the invalid drawable when switching to full screen mode. The windowed mode works fine, and also, if I comment out [fullScreenContext setFullScreen]; I still get into full screen mode, ie an all black screen.

Edit: Well, the black screen is due to the CGCaptureAllDisplays(); function call...

Here are the new methods:

- (void)setFullScreenMode
{
[windowedContext clearDrawable];

NSOpenGLPixelFormatAttribute fullScreenAttrs[] = {
NSOpenGLPFAFullScreen,
NSOpenGLPFAScreenMask, CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
NSOpenGLPFANoRecovery,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 32,
NSOpenGLPFADepthSize, 16,
0
};

NSOpenGLPixelFormat *fullScreenPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:fullScreenAttrs];

fullScreenContext = [[NSOpenGLContext alloc] initWithFormat:fullScreenPixelFormat shareContext:windowedContext];
[fullScreenPixelFormat release];
fullScreenPixelFormat = nil;
CGDisplayErr err = CGCaptureAllDisplays();
if (err != CGDisplayNoErr) {
[fullScreenContext release];
fullScreenContext = nil;
return;
}

[fullScreenContext makeCurrentContext];
//[fullScreenContext setFullScreen];
[self setOpenGLContext:fullScreenContext];

NSLog(@"setFullScreenMode context = %@", [self openGLContext]);

[self setViewportRect:NSMakeRect(0, 0, CGDisplayPixelsWide(kCGDirectMainDisplay), CGDisplayPixelsHigh(kCGDirectMainDisplay))];

isFullScreen = YES;
}


- (void)setWindowedMode
{
[fullScreenContext clearDrawable];

CGReleaseAllDisplays();

[windowedContext makeCurrentContext];
[self setOpenGLContext:windowedContext];
NSLog(@"setWindowedMode context = %@", [self openGLContext]);

isFullScreen = NO;
}

- (void)drawRect:(NSRect)aRect
{
// Clear the screen and depth buffer
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity(); // Reset the current modelview matrix

glTranslatef(0.0, 0.0, -6.0); // Into screen 6.0

glBegin( GL_TRIANGLES ); // Draw a triangle
glVertex3f( 0.0, 1.0, 0.0); // Top
glVertex3f( -1.0, -1.0, 0.0); // Bottom left
glVertex3f( 1.0, -1.0, 0.0); // Bottom right
glEnd();

NSLog(@"drawRect openGLContext = %@", [self openGLContext]);
[[self openGLContext] flushBuffer];
}

any ideas?

Thanks,
Cody
Quote this message in a reply
srcleaves
Unregistered
 
Post: #10
I believe I can shed light on the original problem. Does the garbage look like lots of little bits of windows and other Aqua controls? I added my own toggle code and was able to reproduce this type of garbage. I think I also understand why Apple uses their own event loop in their code.

If you switch to fullscreen you may think that by calling makeCurrentContext that all future OpenGL drawing will go there. The documentation says as much. But if you wait until the drawRect method to perform the drawing you will find that the context is no longer the fullscreen context but is instead the context associated with the NSOpenGLView. I'm guessing NSOpenGLView does this for you to allow you to very simply issue OpenGL commands in the drawRect without worrying about the context creation. No doubt it even says this somewhere but it is not in the API docs. The upshot of this is that when you do flushBuffer you really are just pushing out garbage because you haven't drawn to that context.

So the reason the Apple demo uses its own event loop in full screen mode is so they do continue to draw into that full screen context. You'll notice they call [scene render] directly. They have very intelligently isolated the rendering code from the NSOpenGLView subclass so they can use it from both that subclass and the full screen loop.

I haven't had a chance to look at the other examples provided in this thread but look forward to doing so. I hope my explanation is correct and helpful.

[edit]OneSadCookie's GSOpenGLView gives a good example of how to fix the problem. In his drawRect he is explicitly calling makeCurrentContext depending on whether he is in full screen or windowed mode. Then all subsequent drawing does in fact go to the context you want. Is there any major overhead associated with calling makeCurrentContext so frequently?[edit]
Quote this message in a reply
codeman9
Unregistered
 
Post: #11
Quote:If you switch to fullscreen you may think that by calling makeCurrentContext that all future OpenGL drawing will go there. The documentation says as much. But if you wait until the drawRect method to perform the drawing you will find that the context is no longer the fullscreen context but is instead the context associated with the NSOpenGLView. I'm guessing NSOpenGLView does this for you to allow you to very simply issue OpenGL commands in the drawRect without worrying about the context creation. No doubt it even says this somewhere but it is not in the API docs. The upshot of this is that when you do flushBuffer you really are just pushing out garbage because you haven't drawn to that context.

You are correct! I just noticed this when I was printing out the [self openGLContext] in drawRect. It was always the same as the windowedContext. I have figured out that by using the [self setOpenGLContext:insertcontexthere] message, the openGLContext represented in drawRect changes to that context, at least when printed out to the console. This has sufficiently removed the garbage to the screen when the [fullScreenContext flushBuffer] is called, but I still get no white triangle and now an invalid drawable error prints out in the console.

Edit: From what I gathered in OneSadCookie's code was that the makeCurrentContext call was only called once, if _firstFrame was YES. Otherwise it wasn't invoked in the drawRect method.

Thanks,
Cody
Quote this message in a reply
srcleaves
Unregistered
 
Post: #12
codeman9 Wrote:Edit: From what I gathered in OneSadCookie's code was that the makeCurrentContext call was only called once, if _firstFrame was YES. Otherwise it wasn't invoked in the drawRect method.

Ah good point. I haven't looked that in depth yet but he must set _firstFrame when he switches between window and full and vice versa.
Quote this message in a reply
codeman9
Unregistered
 
Post: #13
_firstFrame is only YES in the init method. After that it is always NO.

Cody
Quote this message in a reply
codeman9
Unregistered
 
Post: #14
Straight from Apple's docs:

Invalid drawable. This error occurs when you attempt to attach a second, incompatible, context to a drawable. For more information about incompatible contexts, see the discussion section of the function CGLCreateContext. This error also occurs when you attempt to attach a context to a full-screen drawable, and the color depth of the drawable is different than that specified by the pixel format used to create the context. The kCGLPFAColorSize attribute, described in the section ìPixel Format Attribute Constantsî, specifies the pixel formatís color depth.

So either I am attaching an incompatible context or the color depth of the drawable mysteriously changes.

Cody
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #15
Changing the context once per frame has negligible overhead. If your app requires multiple contexts (i.e. render-to-texture), you have to do this anyway.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  switching screen resolution NelsonMandella 3 3,417 Apr 25, 2010 01:33 PM
Last Post: SethWillits
  Mac OS X. Switching between fullscreen and windowed mode. e40pud 2 4,190 Jan 25, 2010 12:01 PM
Last Post: OneSadCookie
  Full Screen Switching Blacktiger 3 3,570 Feb 9, 2008 03:05 PM
Last Post: Blacktiger
  opengl bitmap font question: switching to fullscreen moon_magic 2 3,019 Jul 8, 2006 03:39 PM
Last Post: OneSadCookie
  Cocoa OpenGL - Switching to/from fullscreen Indie Mac 5 3,944 Jan 28, 2005 12:40 AM
Last Post: OneSadCookie