PDA

View Full Version : Fullscreen:Nehe causes teardown and rebuild?



nickels
03-16-2010, 07:44 AM
This is a common topic I am sure, but I didn't see the answer.

I used the Nehe tutorial to enable switching back and forth from windowed to fullscreen. This amounts to destroying and recreating the app window with different parameters (and a mode change).

It works, which is a start!

What I notice is that upon teardown and releasing the wgl context, you have to recreate all your opengl objects (textures, framebuffers, vertex buffers, index buffers) else things don't work. (Delete them before teardown, recreate them after re-creating window).

Is there anyway to keep these objects around (and working) through the window destroy/create?

For instance with (--other graphics api here--) the driver handles full-screen <-> windowed without recreating any graphics objects; so it is possible at the hardware level....

ZbuffeR
03-16-2010, 08:01 AM
Something like wglShareLists works at least for display list and texture objects.

nickels
03-16-2010, 08:57 AM
Thanks a lot. wglShareLists was just the keyword I needed to find the appropriate discussions.

I found indications on the web that wglShareList does work for shaders, buffers, etc...

But there is a simpler approach for my situation:

Here is what worked for me. I am toggling between fullscreen and windowed:

At each toggle I delete the current window and create a new one (with/without border for windowed/fullscreen).

When deleting the last window I call
wglMakeCurrent(0,0);

After creating the new window I call:
hDC = GetDC(newWnd);
SetPixelFormat(hDC, pixF, 0); // pixF was creating once from the original window
wglMakeCurrent(hDC, hRC); // hRC was the original gl context created from the original window.

WHY it WORKS:
Apparently (documented) MakeCurrent doesn't require the same DC that it was created with; it only requires the same pixel format.

Works like a charm, no more tear down/rebuild.

skynet
03-16-2010, 09:58 AM
Why destroy the window at all?
Using some SetWindowLongPtr() stuff, you can enable/disable the border at runtime. SetWindowPos() lets you make it cover the whole screen.

nickels
03-16-2010, 10:59 AM
Why destroy the window at all?
Using some SetWindowLongPtr() stuff, you can enable/disable the border at runtime. SetWindowPos() lets you make it cover the whole screen.

I will try this too. Seems like a better approach if I can get it to work (I tried SetWindowPos but didn't know about SetWindowLongPtr)...

nickels
03-16-2010, 12:21 PM
Okay, the following worked without deleting/creating the windows.

I have no idea what I am doing but it at least proves the setwindowlong approach can work.

Thanks for the idea, skynet.



void GLApp::initFullScreen() {

mClientWidth = mOrigClientW; // = 800
mClientHeight = mOrigClientH; // = 600;

DEVMODE dmScreenSettings;


memset(&amp;dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = mOrigClientW;
dmScreenSettings.dmPelsHeight = mOrigClientH;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

ChangeDisplaySettings(&amp;dmScreenSettings, CDS_FULLSCREEN);

LONG dwExStyle = GetWindowLong(mhMainWnd, GWL_EXSTYLE);
LONG dwStyle = GetWindowLong(mhMainWnd, GWL_STYLE);

dwExStyle &amp;= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
dwStyle &amp;= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);

SetWindowLong(mhMainWnd,
GWL_EXSTYLE,
dwExStyle);
SetWindowLong(mhMainWnd,
GWL_STYLE,
dwStyle);

SetWindowPos(mhMainWnd,
0,
0, 0,
mOrigClientW, mOrigClientH,
SWP_NOZORDER | SWP_FRAMECHANGED);
}

void GLApp::closeFullScreen() {

ChangeDisplaySettings(NULL, 0);
ShowCursor(TRUE);

LONG dwExStyle = GetWindowLong(mhMainWnd, GWL_EXSTYLE);
LONG dwStyle = GetWindowLong(mhMainWnd, GWL_STYLE);

/* dwExStyle |= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
dwStyle |= (WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
*/

dwExStyle |= WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle |= WS_OVERLAPPEDWINDOW;

SetWindowLong(mhMainWnd,
GWL_EXSTYLE,
dwExStyle);
SetWindowLong(mhMainWnd,
GWL_STYLE,
dwStyle);

SetWindowPos(mhMainWnd,
HWND_TOP,
0, 0,
mOrigClientW, mOrigClientH,
SWP_FRAMECHANGED);

}

mark ds
03-17-2010, 05:04 AM
One thing to be aware of, is that ChangeDisplaySettings does NOT change fullscreen mode, it simply changes the current resolution and refresh rate, but without saving these settings into the registry.

if you want to use the current desktop settings just use SetWindowLong with/without a border/titlebar. No need to use ChangeDisplaySettings.

skynet
03-17-2010, 06:49 AM
More in-depth information on CDS_FULLSCREEN (which is causing common misconceptions)
http://blogs.msdn.com/oldnewthing/archive/2008/01/04/6973747.aspx

nickels
03-17-2010, 07:47 AM
One thing to be aware of, is that ChangeDisplaySettings does NOT change fullscreen mode, it simply changes the current resolution and refresh rate, but without saving these settings into the registry.

if you want to use the current desktop settings just use SetWindowLong with/without a border/titlebar. No need to use ChangeDisplaySettings.

Fair enough. I guess going into 'fullscreen mode' I am really doing TWO things':

1) making the window cover the whole screen (using setwindowlong)

but also

2) Lowering the screen resolution so my game doesn't have to play at 1920x1600 or whatever riduculous resolution I am currently running my desktop. That way I don't get hit by the fill rate so badly...