Win32: Use helper window to load WGL extensions

This removes window re-creation logic by performing the initial context
creation on the helper window, simplifying both window and context
creation and paving the way for attaching to existing window handles
without compromising on context or framebuffer hint support.
This commit is contained in:
Camilla Berglund 2016-06-22 20:09:07 +02:00
parent a991c01731
commit 6f313ff245
3 changed files with 107 additions and 164 deletions

View File

@ -288,8 +288,6 @@ static int extensionSupportedWGL(const char* extension)
{
const char* extensions;
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
if (_glfw.wgl.GetExtensionsStringEXT)
{
extensions = _glfw.wgl.GetExtensionsStringEXT();
@ -302,7 +300,7 @@ static int extensionSupportedWGL(const char* extension)
if (_glfw.wgl.GetExtensionsStringARB)
{
extensions = _glfw.wgl.GetExtensionsStringARB(window->context.wgl.dc);
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
if (extensions)
{
if (_glfwStringInExtensionString(extension, extensions))
@ -335,8 +333,61 @@ static void destroyContextWGL(_GLFWwindow* window)
// Initialize WGL-specific extensions
//
static void loadExtensions(void)
static void loadWGLExtensions(void)
{
int pf;
PIXELFORMATDESCRIPTOR pfd;
HDC dc;
HGLRC rc;
_glfw.wgl.extensionsLoaded = GLFW_TRUE;
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
dc = GetDC(_glfw.win32.helperWindowHandle);
pf = ChoosePixelFormat(dc, &pfd);
if (!pf)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to choose pixel format for WGL extension loading");
return;
}
if (!DescribePixelFormat(dc, pf, sizeof(pfd), &pfd))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to describe pixel format for WGL extension loading");
return;
}
if (!SetPixelFormat(dc, pf, &pfd))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to set pixel format for WGL extension loading");
return;
}
rc = wglCreateContext(dc);
if (!rc)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to create context for WGL extension loading");
return;
}
if (!wglMakeCurrent(dc, rc))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to make context current for WGL extension loading");
return;
}
// Functions for WGL_EXT_extension_string
// NOTE: These are needed by extensionSupported
_glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
@ -379,7 +430,8 @@ static void loadExtensions(void)
_glfw.wgl.ARB_context_flush_control =
extensionSupportedWGL("WGL_ARB_context_flush_control");
_glfw.wgl.extensionsLoaded = GLFW_TRUE;
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
}
@ -404,6 +456,8 @@ GLFWbool _glfwInitWGL(void)
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
_glfw.wgl.GetProcAddress = (WGLGETPROCADDRESS_T)
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
_glfw.wgl.GetCurrentDC = (WGLGETCURRENTDC_T)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
_glfw.wgl.MakeCurrent = (WGLMAKECURRENT_T)
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
_glfw.wgl.ShareLists = (WGLSHARELISTS_T)
@ -438,8 +492,8 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
PIXELFORMATDESCRIPTOR pfd;
HGLRC share = NULL;
if (ctxconfig->client == GLFW_NO_API)
return GLFW_TRUE;
if (!_glfw.wgl.extensionsLoaded)
loadWGLExtensions();
if (ctxconfig->share)
share = ctxconfig->share->context.wgl.handle;
@ -470,6 +524,40 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
{
if (!_glfw.wgl.ARB_create_context)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
return GLFW_FALSE;
}
}
if (ctxconfig->profile)
{
if (!_glfw.wgl.ARB_create_context_profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
return GLFW_FALSE;
}
}
}
else
{
if (!_glfw.wgl.ARB_create_context ||
!_glfw.wgl.ARB_create_context_profile ||
!_glfw.wgl.EXT_create_context_es2_profile)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
return GLFW_FALSE;
}
}
if (_glfw.wgl.ARB_create_context)
{
int index = 0, mask = 0, flags = 0;
@ -588,102 +676,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
#undef setWGLattrib
// Analyzes the specified context for possible recreation
//
int _glfwAnalyzeContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
GLFWbool required = GLFW_FALSE;
if (_glfw.wgl.extensionsLoaded)
return _GLFW_RECREATION_NOT_NEEDED;
makeContextCurrentWGL(window);
loadExtensions();
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
{
if (!_glfw.wgl.ARB_create_context)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
return _GLFW_RECREATION_IMPOSSIBLE;
}
required = GLFW_TRUE;
}
if (ctxconfig->profile)
{
if (!_glfw.wgl.ARB_create_context_profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
return _GLFW_RECREATION_IMPOSSIBLE;
}
required = GLFW_TRUE;
}
if (ctxconfig->release)
{
if (_glfw.wgl.ARB_context_flush_control)
required = GLFW_TRUE;
}
}
else
{
if (!_glfw.wgl.ARB_create_context ||
!_glfw.wgl.ARB_create_context_profile ||
!_glfw.wgl.EXT_create_context_es2_profile)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
return _GLFW_RECREATION_IMPOSSIBLE;
}
required = GLFW_TRUE;
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
if (_glfw.wgl.ARB_create_context)
required = GLFW_TRUE;
}
if (ctxconfig->debug)
{
if (_glfw.wgl.ARB_create_context)
required = GLFW_TRUE;
}
if (fbconfig->samples > 0)
{
// MSAA is not a hard constraint, so do nothing if it's not supported
if (_glfw.wgl.ARB_multisample && _glfw.wgl.ARB_pixel_format)
required = GLFW_TRUE;
}
if (fbconfig->sRGB)
{
// sRGB is not a hard constraint, so do nothing if it's not supported
if ((_glfw.wgl.ARB_framebuffer_sRGB ||
_glfw.wgl.EXT_framebuffer_sRGB) &&
_glfw.wgl.ARB_pixel_format)
{
required = GLFW_TRUE;
}
}
if (required)
return _GLFW_RECREATION_REQUIRED;
return _GLFW_RECREATION_NOT_NEEDED;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -82,6 +82,7 @@ typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*)
typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC);
typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC);
typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR);
typedef HDC (WINAPI * WGLGETCURRENTDC_T)(void);
typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC);
typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
@ -89,6 +90,7 @@ typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
#define wglCreateContext _glfw.wgl.CreateContext
#define wglDeleteContext _glfw.wgl.DeleteContext
#define wglGetProcAddress _glfw.wgl.GetProcAddress
#define wglGetCurrentDC _glfw.wgl.GetCurrentDC
#define wglMakeCurrent _glfw.wgl.MakeCurrent
#define wglShareLists _glfw.wgl.ShareLists
@ -118,6 +120,7 @@ typedef struct _GLFWlibraryWGL
WGLCREATECONTEXT_T CreateContext;
WGLDELETECONTEXT_T DeleteContext;
WGLGETPROCADDRESS_T GetProcAddress;
WGLGETCURRENTDC_T GetCurrentDC;
WGLMAKECURRENT_T MakeCurrent;
WGLSHARELISTS_T ShareLists;
@ -147,8 +150,5 @@ void _glfwTerminateWGL(void);
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
int _glfwAnalyzeContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
#endif // _glfw3_wgl_context_h_

View File

@ -928,21 +928,6 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig)
return GLFW_TRUE;
}
// Destroys the GLFW window and rendering context
//
static void destroyWindow(_GLFWwindow* window)
{
if (_glfw.win32.disabledCursorWindow == window)
_glfw.win32.disabledCursorWindow = NULL;
if (window->win32.handle)
{
RemovePropW(window->win32.handle, L"GLFW");
DestroyWindow(window->win32.handle);
window->win32.handle = NULL;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
@ -1001,8 +986,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
int status;
if (!createWindow(window, wndconfig))
return GLFW_FALSE;
@ -1012,46 +995,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{
if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig);
if (status == _GLFW_RECREATION_IMPOSSIBLE)
return GLFW_FALSE;
if (status == _GLFW_RECREATION_REQUIRED)
{
// Some window hints require us to re-create the context using WGL
// extensions retrieved through the current context, as we cannot
// check for WGL extensions or retrieve WGL entry points before we
// have a current context (actually until we have implicitly loaded
// the vendor ICD)
// Yes, this is strange, and yes, this is the proper way on WGL
// As Windows only allows you to set the pixel format once for
// a window, we need to destroy the current window and create a new
// one to be able to use the new pixel format
// Technically, it may be possible to keep the old window around if
// we're just creating an OpenGL 3.0+ context with the same pixel
// format, but it's not worth the added code complexity
// First we clear the current context (the one we just created)
// This is usually done by glfwDestroyWindow, but as we're not doing
// full GLFW window destruction, it's duplicated here
window->context.makeCurrent(NULL);
// Next destroy the Win32 window and WGL context (without resetting
// or destroying the GLFW window object)
window->context.destroy(window);
destroyWindow(window);
// ...and then create them again, this time with better APIs
if (!createWindow(window, wndconfig))
return GLFW_FALSE;
if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
}
else
{
@ -1081,7 +1024,15 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->context.client != GLFW_NO_API)
window->context.destroy(window);
destroyWindow(window);
if (_glfw.win32.disabledCursorWindow == window)
_glfw.win32.disabledCursorWindow = NULL;
if (window->win32.handle)
{
RemovePropW(window->win32.handle, L"GLFW");
DestroyWindow(window->win32.handle);
window->win32.handle = NULL;
}
if (window->win32.bigIcon)
DestroyIcon(window->win32.bigIcon);