Windows GL Multisample Tutorial(ish)
Posted: Tue May 21, 2013 4:30 am
Quick and dirty "mostly a tutorial" on implementing multisample in Windows/OpenGL.
Step 1: Use the "Starting Quake Dialog". Multisample requires restarting the OpenGL window (and doing a DestroyWindow too, to the best of my knowledge). This is annoying and causes the screen to flash. Since I do not want that, I have the "Starting Quake" window create a GL context and check for multisample there.
sys_win.c
Step 2: Kill multiple bitsperpixel support in your engine and instead ALWAYS use the desktop resolution. This is going to be 32 bits per pixel for 99.999999% and it won't the 5 people that use 16 bits per pixel.
Grabbing desktop bpp =
Step 3: When you are closing the starting Quake dialog, take the time to get available pixel format info and check wgl extensions and poke around for multisample. If you find it, you'll get an "int" value of the pixel format you want, which you will use instead of querying the pfd.
4. My modified PFD function looks like this:
5. The function to check for multisample availability, mostly from NeHe and modified some while looking at FTE's implementation.
Multisample gets rid of the "jaggies" but with some performance cost. Barnes pointed out in another thread there are better and more refined versions to do this that emerged, these look like they require shaders and for now the moment I'm sticking with the OpenGL 1.x level feature-set.
Step 1: Use the "Starting Quake Dialog". Multisample requires restarting the OpenGL window (and doing a DestroyWindow too, to the best of my knowledge). This is annoying and causes the screen to flash. Since I do not want that, I have the "Starting Quake" window create a GL context and check for multisample there.
sys_win.c
Code: Select all
#if 1 //johnfitz -- 0 to supress the 'starting quake' dialog
if (!isDedicated)
{
wplat.hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
if (wplat.hwnd_dialog)
{
RECT rect;
GetWindowRect (wplat.hwnd_dialog, &rect);
WIN_AdjustRectToCenterScreen (&rect);
SetWindowPos
(
wplat.hwnd_dialog,
NULL,
rect.left,
rect.top,
0,
0,
SWP_NOZORDER | SWP_NOSIZE
);
ShowWindow (wplat.hwnd_dialog, SW_SHOWDEFAULT);
UpdateWindow (wplat.hwnd_dialog);
SetForegroundWindow (wplat.hwnd_dialog);
}
}
#endifGrabbing desktop bpp =
Code: Select all
vmode_t VID_Local_GetDesktopProperties (void)
{
DEVMODE devmode;
vmode_t desktop = {0};
if (!EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &devmode))
{
Sys_Error ("VID_UpdateDesktopProperties: EnumDisplaySettings failed\n");
return desktop;
}
desktop.type = MODE_FULLSCREEN;
desktop.width = devmode.dmPelsWidth;
desktop.height = devmode.dmPelsHeight;
desktop.bpp = devmode.dmBitsPerPel;
return desktop;
}Code: Select all
if (wplat.hwnd_dialog)
{
if (vid_multisample.value)
{
// Poke into it for the PFD
HDC hdc = GetDC(wplat.hwnd_dialog);
int unused = WIN_SetupPixelFormat (hdc);
HGLRC wglHRC = wglCreateContext( hdc );
HDC wglHDC = wglGetCurrentDC();
int unused2 = wglMakeCurrent( hdc, wglHRC);
int ask_samples = (int)vid_multisample.value;
if (ask_samples != 2 && ask_samples != 4 && ask_samples != 8)
{
Con_Warning ("Multisamples requested \"%i\" is invalid, trying 4\n", ask_samples);
ask_samples = 4;
}
// Do it. We already have desktop properties
wplat.multisamples = WIN_InitMultisample (wplat.hInstance, wplat.hwnd_dialog, wplat.pfd, ask_samples, &wplat.forcePixelFormat);
// Your mission is complete. You may leave now ...
wglMakeCurrent(NULL, NULL);
wglDeleteContext(wglHRC);
ReleaseDC(wplat.hwnd_dialog, wglHDC);
ReleaseDC(wplat.hwnd_dialog, hdc);
if (wplat.multisamples)
Con_Printf ("Multisample x %i Enabled (Requested %i, Received %i).\n", wplat.multisamples, ask_samples, wplat.multisamples);
else Con_Warning ("Multisample: Requested but not available.\n");
} else Con_Printf ("Note: Multisample not requested\n");
// Post teardown
DestroyWindow (wplat.hwnd_dialog);
wplat.hwnd_dialog = NULL;
}Code: Select all
BOOL WIN_SetupPixelFormat (HDC hDC)
{
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32-bit z-buffer
8, // 8-bit stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat;
PIXELFORMATDESCRIPTOR test; //johnfitz
#ifdef SUPPORTS_MULTISAMPLE // Baker change
if (!wplat.multisamples)
{
#endif // Baker change + #ifdef SUPPORTS_MULTISAMPLE // Baker change
if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
{
Sys_Error ("Video: ChoosePixelFormat failed");
return FALSE;
}
#ifdef SUPPORTS_MULTISAMPLE // Baker change
} else pixelformat = wplat.forcePixelFormat; // Multisample overrride
#endif // Baker change + #ifdef SUPPORTS_MULTISAMPLE // Baker change
DescribePixelFormat(hDC, pixelformat, sizeof(PIXELFORMATDESCRIPTOR), &test);
if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE)
{
Sys_Error ("SetPixelFormat failed");
return FALSE;
}
#ifdef SUPPORTS_MULTISAMPLE // Baker change
memcpy (&wplat.pfd, &pfd, sizeof(pfd) );
#endif // Baker change + #ifdef SUPPORTS_MULTISAMPLE // Baker change
return TRUE;
}Code: Select all
#include "vid_wglext.h" //WGL extensions
int arbMultisampleSupported = false;
int arbMultisampleFormat = 0;
// WGLisExtensionSupported: This Is A Form Of The Extension For WGL
int WGLisExtensionSupported(const char *extension)
{
const size_t extlen = strlen(extension);
const char *supported = NULL;
const char* p;
// Try To Use wglGetExtensionStringARB On Current DC, If Possible
PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
if (wglGetExtString)
supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());
// If That Failed, Try Standard Opengl Extensions String
if (supported == NULL)
supported = (char*)glGetString(GL_EXTENSIONS);
// If That Failed Too, Must Be No Extensions Supported
if (supported == NULL)
return false;
// Begin Examination At Start Of String, Increment By 1 On False Match
for (p = supported; ; p++)
{
// Advance p Up To The Next Possible Match
p = strstr(p, extension);
if (p == NULL)
return false; // No Match
// Make Sure That Match Is At The Start Of The String Or That
// The Previous Char Is A Space, Or Else We Could Accidentally
// Match "wglFunkywglExtension" With "wglExtension"
// Also, Make Sure That The Following Character Is Space Or NULL
// Or Else "wglExtensionTwo" Might Match "wglExtension"
if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
return true; // Match
}
}
// InitMultisample: Used To Query The Multisample Frequencies
int WIN_InitMultisample (HINSTANCE hInstance,HWND hWnd,PIXELFORMATDESCRIPTOR pfd, int ask_samples, int* pixelForceFormat)
{
// See If The String Exists In WGL!
if (!WGLisExtensionSupported("WGL_ARB_multisample"))
{
arbMultisampleSupported=false;
return false;
}
{
// Get Our Pixel Format
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
if (!wglChoosePixelFormatARB)
{
arbMultisampleSupported=false;
return false;
}
{
// Get Our Current Device Context
HDC hDC = GetDC(hWnd);
int pixelFormat;
int valid;
UINT numFormats;
float fAttributes[] = {0,0};
// These Attributes Are The Bits We Want To Test For In Our Sample
// Everything Is Pretty Standard, The Only One We Want To
// Really Focus On Is The SAMPLE BUFFERS ARB And WGL SAMPLES
// These Two Are Going To Do The Main Testing For Whether Or Not
// We Support Multisampling On This Hardware.
int iAttributes[] =
{
WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, 24 /*currentbpp? Nah */, // Baker: Mirror current bpp color depth?
WGL_ALPHA_BITS_ARB,8,
WGL_DEPTH_BITS_ARB,16,
WGL_STENCIL_BITS_ARB,8, // Baker: Stencil bits
WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
WGL_SAMPLES_ARB, ask_samples /*multisample bits*/,
0,0
};
while (ask_samples == 8 || ask_samples == 4 || ask_samples == 2)
{
iAttributes[19] = ask_samples;
// First We Check To See If We Can Get A Pixel Format For 4 Samples
valid = wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
// If We Returned True, And Our Format Count Is Greater Than 1
if (valid && numFormats >= 1)
{
*pixelForceFormat = arbMultisampleFormat = pixelFormat;
return (arbMultisampleSupported = ask_samples);
}
ask_samples >>= 1; // Divide by 2
}
// Return Fail
return (arbMultisampleSupported = 0);
}
}
}