Support creating OpenGL ES contexts via WGL/GLX. Closes #1009

This commit is contained in:
baldurk
2018-07-04 18:54:46 +01:00
parent 4299c29c8b
commit d0ca83bf6c
10 changed files with 323 additions and 134 deletions
+2 -1
View File
@@ -45,8 +45,9 @@ class CGLPlatform : public GLPlatform
}
void *GetReplayFunction(const char *funcname) { return NULL; }
bool CanCreateGLESContext() { return false; }
bool PopulateForReplay() { return false; }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext)
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
{
return ReplayStatus::APIUnsupported;
}
+15 -12
View File
@@ -179,18 +179,12 @@ class EGLPlatform : public GLPlatform
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
EGL_NONE};
struct
{
int major;
int minor;
} versions[] = {
{3, 2}, {3, 1}, {3, 0},
};
std::vector<GLVersion> versions = GetReplayVersions(RDCDriver::OpenGLES);
for(size_t v = 0; v < ARRAY_COUNT(versions); v++)
for(GLVersion v : versions)
{
verAttribs[1] = versions[v].major;
verAttribs[3] = versions[v].minor;
verAttribs[1] = v.major;
verAttribs[3] = v.minor;
ctx = EGL.CreateContext(eglDisplay, config, share_ctx, verAttribs);
if(ctx)
@@ -236,9 +230,18 @@ class EGLPlatform : public GLPlatform
return ret;
}
bool PopulateForReplay() { return EGL.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext)
bool CanCreateGLESContext()
{
// as long as we can get libEGL we're fine
return GetEGLHandle() != NULL;
}
bool PopulateForReplay() { return EGL.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
{
// we only support replaying GLES through EGL
RDCASSERT(api == RDCDriver::OpenGLES);
EGL.BindAPI(EGL_OPENGL_ES_API);
EGLDisplay eglDisplay = EGL.GetDisplay(EGL_DEFAULT_DISPLAY);
+11 -1
View File
@@ -26,6 +26,7 @@
#pragma once
#include "common/common.h"
#include "core/core.h"
#include "maths/vec.h"
// typed enum so that templates will pick up specialisations
@@ -259,11 +260,20 @@ struct GLPlatform
virtual void DrawQuads(float width, float height, const std::vector<Vec4f> &vertices) = 0;
// for initialisation at replay time
virtual bool CanCreateGLESContext() = 0;
virtual bool PopulateForReplay() = 0;
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext) = 0;
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api) = 0;
virtual void *GetReplayFunction(const char *funcname) = 0;
};
struct GLVersion
{
int major;
int minor;
};
std::vector<GLVersion> GetReplayVersions(RDCDriver api);
#if defined(RENDERDOC_SUPPORT_GL)
// platform specific (WGL, GLX, etc)
+58 -8
View File
@@ -3241,7 +3241,7 @@ ReplayStatus CreateReplayDevice(RDCFile *rdc, GLPlatform &platform, IReplayDrive
GLWindowingData data = {};
ReplayStatus status = platform.InitialiseAPI(data);
ReplayStatus status = platform.InitialiseAPI(data, rdc->GetDriver());
// any errors will be already printed, just pass the error up
if(status != ReplayStatus::Succeeded)
@@ -3312,8 +3312,9 @@ class GLDummyPlatform : public GLPlatform
virtual void DrawQuads(float width, float height, const std::vector<Vec4f> &vertices) {}
virtual void *GetReplayFunction(const char *funcname) { return NULL; }
// for initialisation at replay time
virtual bool CanCreateGLESContext() { return true; }
virtual bool PopulateForReplay() { return true; }
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext)
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
{
return ReplayStatus::Succeeded;
}
@@ -3340,6 +3341,24 @@ static StructuredProcessRegistration GLProcessRegistration(RDCDriver::OpenGL, &G
static StructuredProcessRegistration GLESProcessRegistration(RDCDriver::OpenGLES,
&GL_ProcessStructured);
std::vector<GLVersion> GetReplayVersions(RDCDriver api)
{
// try to create all versions from highest down to lowest in order to get the highest versioned
// context we can
if(api == RDCDriver::OpenGLES)
{
return {
{3, 2}, {3, 1}, {3, 0},
};
}
else
{
return {
{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2},
};
}
}
#if defined(RENDERDOC_SUPPORT_GL)
ReplayStatus GL_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
@@ -3367,15 +3386,46 @@ ReplayStatus GLES_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
{
RDCDEBUG("Creating an OpenGL ES replay device");
bool load_ok = GetEGLPlatform().PopulateForReplay();
if(!load_ok)
// for GLES replay, we try to use EGL if it's available. If it's not available, we look to see if
// we can create an OpenGL ES context via the platform GL functions
if(GetEGLPlatform().CanCreateGLESContext())
{
RDCERR("Couldn't find required EGL function addresses");
return ReplayStatus::APIInitFailed;
bool load_ok = GetEGLPlatform().PopulateForReplay();
if(!load_ok)
{
RDCERR("Couldn't find required EGL function addresses");
return ReplayStatus::APIInitFailed;
}
return CreateReplayDevice(rdc, GetEGLPlatform(), driver);
}
#if defined(RENDERDOC_SUPPORT_GL)
else if(GetGLPlatform().CanCreateGLESContext())
{
RDCDEBUG("libEGL is not available, falling back to EXT_create_context_es2_profile");
bool load_ok = GetGLPlatform().PopulateForReplay();
if(!load_ok)
{
RDCERR("Couldn't find required GLX function addresses");
return ReplayStatus::APIInitFailed;
}
return CreateReplayDevice(rdc, GetGLPlatform(), driver);
}
return CreateReplayDevice(rdc, GetEGLPlatform(), driver);
RDCERR(
"libEGL not available, and GL cannot initialise or doesn't support "
"EXT_create_context_es2_profile");
return ReplayStatus::APIInitFailed;
#else
// no GL support, no fallback apart from EGL
RDCERR("libEGL is not available");
return ReplayStatus::APIInitFailed;
#endif
}
static DriverRegistration GLESDriverRegistration(RDCDriver::OpenGLES, &GLES_CreateReplayDevice);
+2
View File
@@ -36,6 +36,7 @@ typedef int (*PFN_glXGetConfig)(Display *dpy, XVisualInfo *vis, int attrib, int
typedef Bool (*PFN_glXIsDirect)(Display *dpy, GLXContext ctx);
typedef __GLXextFuncPtr (*PFN_glXGetProcAddress)(const GLubyte *);
typedef __GLXextFuncPtr (*PFN_glXGetProcAddressARB)(const GLubyte *);
typedef const char *(*PFN_glXQueryExtensionsString)(Display *dpy, int screen);
typedef PFNGLXGETVISUALFROMFBCONFIGPROC PFN_glXGetVisualFromFBConfig;
typedef PFNGLXMAKECONTEXTCURRENTPROC PFN_glXMakeContextCurrent;
typedef PFNGLXCREATEWINDOWPROC PFN_glXCreateWindow;
@@ -78,6 +79,7 @@ typedef void (*PFN_glEnd)();
FUNC(glXChooseFBConfig); \
FUNC(glXGetFBConfigAttrib); \
FUNC(glXQueryDrawable); \
FUNC(glXQueryExtensionsString); \
FUNC(glXCreatePbuffer); \
FUNC(glXDestroyPbuffer); \
FUNC(glGetIntegerv); \
+11 -2
View File
@@ -197,7 +197,7 @@ HOOK_EXPORT GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig conf
RDCDEBUG("glXCreateContextAttribsARB:");
bool core = false;
bool core = false, es = false;
int *a = (int *)attribs;
while(*a)
@@ -205,11 +205,20 @@ HOOK_EXPORT GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig conf
RDCDEBUG("%x: %d", a[0], a[1]);
if(a[0] == GLX_CONTEXT_PROFILE_MASK_ARB)
core = (a[1] & GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
{
core = (a[1] & GLX_CONTEXT_CORE_PROFILE_BIT_ARB) != 0;
es = (a[1] & (GLX_CONTEXT_ES_PROFILE_BIT_EXT | GLX_CONTEXT_ES2_PROFILE_BIT_EXT)) != 0;
}
a += 2;
}
if(es)
{
glxhook.driver.SetDriverType(RDCDriver::OpenGLES);
core = true;
}
GLXContext ret = GLX.glXCreateContextAttribsARB(dpy, config, shareList, direct, attribs);
// don't continue if context creation failed
+32 -16
View File
@@ -296,9 +296,32 @@ class GLXPlatform : public GLPlatform
return ret;
}
bool PopulateForReplay() { return GLX.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext)
bool CanCreateGLESContext()
{
bool success = GLX.PopulateForReplay();
// if we can't populate our functions we bail now.
if(!success)
return false;
// we need to check for the presence of EXT_create_context_es2_profile
Display *dpy = RenderDoc::Inst().GetGlobalEnvironment().xlibDisplay;
const char *exts = GLX.glXQueryExtensionsString(dpy, DefaultScreen(dpy));
bool ret = (strstr(exts, "EXT_create_context_es2_profile") != NULL);
RDCDEBUG("%s find EXT_create_context_es2_profile to create GLES context",
ret ? "Could" : "Couldn't");
return ret;
}
bool PopulateForReplay() { return GLX.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
{
RDCASSERT(api == RDCDriver::OpenGL || api == RDCDriver::OpenGLES);
int attribs[64] = {0};
int i = 0;
@@ -315,7 +338,8 @@ class GLXPlatform : public GLPlatform
attribs[i++] = 0;
#endif
attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
attribs[i++] = api == RDCDriver::OpenGLES ? GLX_CONTEXT_ES2_PROFILE_BIT_EXT
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
Display *dpy = RenderDoc::Inst().GetGlobalEnvironment().xlibDisplay;
@@ -339,25 +363,17 @@ class GLXPlatform : public GLPlatform
GLXContext ctx = NULL;
// try to create all versions from 4.6 down to 3.2 in order to get the
// highest versioned context we can
struct
{
int major;
int minor;
} versions[] = {
{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2},
};
{
X11ErrorHandler prev = XSetErrorHandler(&NonFatalX11ErrorHandler);
for(size_t v = 0; v < ARRAY_COUNT(versions); v++)
std::vector<GLVersion> versions = GetReplayVersions(api);
for(GLVersion v : versions)
{
X11ErrorSeen = false;
major = versions[v].major;
minor = versions[v].minor;
major = v.major;
minor = v.minor;
ctx = GLX.glXCreateContextAttribsARB(dpy, fbcfg[0], 0, true, attribs);
if(ctx && !X11ErrorSeen)
+4 -2
View File
@@ -40,9 +40,9 @@ typedef HDC(WINAPI *PFN_wglGetCurrentDC)();
// wgl extensions
typedef PFNWGLCREATECONTEXTATTRIBSARBPROC PFN_wglCreateContextAttribsARB;
typedef PFNWGLCHOOSEPIXELFORMATARBPROC PFN_wglChoosePixelFormatARB;
typedef PFNWGLGETPIXELFORMATATTRIBIVARBPROC PFN_wglGetPixelFormatAttribivARB;
typedef PFNWGLGETPIXELFORMATATTRIBFVARBPROC PFN_wglGetPixelFormatAttribfvARB;
typedef PFNWGLGETEXTENSIONSSTRINGEXTPROC PFN_wglGetExtensionsStringEXT;
typedef PFNWGLGETEXTENSIONSSTRINGARBPROC PFN_wglGetExtensionsStringARB;
// gl functions (used for quad rendering on legacy contexts)
typedef PFNGLGETINTEGERVPROC PFN_glGetIntegerv;
@@ -83,6 +83,8 @@ typedef LONG(WINAPI *PFN_ChangeDisplaySettingsExW)(LPCWSTR, DEVMODEW *, HWND, DW
FUNC("opengl32.dll", wglGetCurrentContext); \
FUNC("opengl32.dll", wglGetCurrentDC); \
FUNC("", wglGetPixelFormatAttribivARB); \
FUNC("", wglGetExtensionsStringEXT); \
FUNC("", wglGetExtensionsStringARB); \
FUNC("opengl32.dll", glGetIntegerv); \
FUNC("opengl32.dll", glPushMatrix); \
FUNC("opengl32.dll", glLoadIdentity); \
+19 -2
View File
@@ -73,6 +73,14 @@ void WGLHook::PopulateFromContext(HDC dc, HGLRC rc)
WGL.wglGetPixelFormatAttribivARB =
(PFN_wglGetPixelFormatAttribivARB)WGL.wglGetProcAddress("wglGetPixelFormatAttribivARB");
if(!WGL.wglGetExtensionsStringEXT)
WGL.wglGetExtensionsStringEXT =
(PFN_wglGetExtensionsStringEXT)WGL.wglGetProcAddress("wglGetExtensionsStringEXT");
if(!WGL.wglGetExtensionsStringARB)
WGL.wglGetExtensionsStringARB =
(PFN_wglGetExtensionsStringARB)WGL.wglGetProcAddress("wglGetExtensionsStringARB");
GL.PopulateWithCallback([](const char *funcName) {
ScopedSuppressHooking suppress;
return (void *)WGL.wglGetProcAddress(funcName);
@@ -279,7 +287,7 @@ static HGLRC WINAPI wglCreateContextAttribsARB_hooked(HDC dc, HGLRC hShareContex
RDCDEBUG("wglCreateContextAttribsARB:");
bool core = false;
bool core = false, es = false;
int *a = (int *)attribs;
while(*a)
@@ -287,11 +295,20 @@ static HGLRC WINAPI wglCreateContextAttribsARB_hooked(HDC dc, HGLRC hShareContex
RDCDEBUG("%x: %d", a[0], a[1]);
if(a[0] == WGL_CONTEXT_PROFILE_MASK_ARB)
core = (a[1] & WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
{
core = (a[1] & WGL_CONTEXT_CORE_PROFILE_BIT_ARB) != 0;
es = (a[1] & (WGL_CONTEXT_ES_PROFILE_BIT_EXT | WGL_CONTEXT_ES2_PROFILE_BIT_EXT)) != 0;
}
a += 2;
}
if(es)
{
wglhook.driver.SetDriverType(RDCDriver::OpenGLES);
core = true;
}
SetLastError(0);
HGLRC ret = WGL.wglCreateContextAttribsARB(dc, hShareContext, attribs);
+169 -90
View File
@@ -25,6 +25,8 @@
#include "driver/gl/gl_common.h"
#include "driver/gl/wgl_dispatch_table.h"
#define WINDOW_CLASS_NAME L"renderdocGLclass"
class WGLPlatform : public GLPlatform
{
bool MakeContextCurrent(GLWindowingData data)
@@ -108,7 +110,7 @@ class WGLPlatform : public GLPlatform
HWND w = window.win32.window;
if(w == NULL)
w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW,
w = CreateWindowEx(WS_EX_CLIENTEDGE, WINDOW_CLASS_NAME, L"", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
GetModuleHandle(NULL), NULL);
@@ -237,88 +239,69 @@ class WGLPlatform : public GLPlatform
return Process::GetFunctionAddress(Process::LoadModule("opengl32.dll"), funcname);
}
bool PopulateForReplay() { return WGL.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext)
bool CanCreateGLESContext()
{
WNDCLASSEX wc = {};
wc.style = CS_OWNDC;
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"renderdocGLclass";
bool success = WGL.PopulateForReplay();
WNDCLASSEX dummyCheck = {};
// if we can't populate our functions we bail now.
if(!success)
return false;
// if the class isn't already registered, then register it.
if(!GetClassInfoExW(wc.hInstance, wc.lpszClassName, &dummyCheck))
{
if(!RegisterClassEx(&wc))
{
RDCERR("Couldn't register GL window class");
return ReplayStatus::APIInitFailed;
}
}
// we need to check for the presence of EXT_create_context_es2_profile.
// Unfortunately on windows this means creating a trampoline context
success = RegisterClass();
PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 0;
if(!success)
return false;
HWND w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
GetModuleHandle(NULL), NULL);
HWND w = NULL;
HDC dc = NULL;
HGLRC rc = NULL;
HDC dc = GetDC(w);
success = CreateTrampolineContext(w, dc, rc);
int pf = ::ChoosePixelFormat(dc, &pfd);
if(pf == 0)
{
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't choose pixel format");
if(!success)
return false;
const char *exts = NULL;
if(WGL.wglGetExtensionsStringARB)
exts = WGL.wglGetExtensionsStringARB(dc);
if(!exts && WGL.wglGetExtensionsStringEXT)
exts = WGL.wglGetExtensionsStringEXT();
if(!exts)
RDCERR("Couldn't get WGL extension string");
bool ret = (exts && strstr(exts, "EXT_create_context_es2_profile") != NULL);
WGL.wglMakeCurrent(NULL, NULL);
WGL.wglDeleteContext(rc);
ReleaseDC(w, dc);
DestroyWindow(w);
return ret;
}
bool PopulateForReplay() { return WGL.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
{
RDCASSERT(api == RDCDriver::OpenGL || api == RDCDriver::OpenGLES);
bool success = RegisterClass();
if(!success)
return ReplayStatus::APIInitFailed;
}
BOOL res = ::SetPixelFormat(dc, pf, &pfd);
if(res == FALSE)
{
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't set pixel format");
HWND w = NULL;
HDC dc = NULL;
HGLRC rc = NULL;
success = CreateTrampolineContext(w, dc, rc);
if(!success)
return ReplayStatus::APIInitFailed;
}
HGLRC rc = WGL.wglCreateContext(dc);
if(rc == NULL)
{
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't create simple RC");
return ReplayStatus::APIInitFailed;
}
res = WGL.wglMakeCurrent(dc, rc);
if(res == FALSE)
{
WGL.wglMakeCurrent(NULL, NULL);
WGL.wglDeleteContext(rc);
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't make simple RC current");
return ReplayStatus::APIInitFailed;
}
// now we can fetch the extension functions we need and fill out WGL
WGL.wglCreateContextAttribsARB =
(PFN_wglCreateContextAttribsARB)WGL.wglGetProcAddress("wglCreateContextAttribsARB");
WGL.wglGetPixelFormatAttribivARB =
(PFN_wglGetPixelFormatAttribivARB)WGL.wglGetProcAddress("wglGetPixelFormatAttribivARB");
if(!WGL.wglCreateContextAttribsARB || !WGL.wglGetPixelFormatAttribivARB)
{
@@ -337,18 +320,23 @@ class WGLPlatform : public GLPlatform
// we don't use the default framebuffer (backbuffer) for anything, so we make it
// tiny and with no depth/stencil bits
PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 0;
pfd.cStencilBits = 0;
w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"RenderDoc replay window",
w = CreateWindowEx(WS_EX_CLIENTEDGE, WINDOW_CLASS_NAME, L"RenderDoc replay window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 32, 32, NULL, NULL,
GetModuleHandle(NULL), NULL);
dc = GetDC(w);
pf = ChoosePixelFormat(dc, &pfd);
int pf = ChoosePixelFormat(dc, &pfd);
if(pf == 0)
{
RDCERR("Couldn't choose pixel format");
@@ -357,7 +345,7 @@ class WGLPlatform : public GLPlatform
return ReplayStatus::APIInitFailed;
}
res = SetPixelFormat(dc, pf, &pfd);
BOOL res = SetPixelFormat(dc, pf, &pfd);
if(res == FALSE)
{
RDCERR("Couldn't set pixel format");
@@ -382,24 +370,17 @@ class WGLPlatform : public GLPlatform
attribs[i++] = 0;
#endif
attribs[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
attribs[i++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
// try to create all versions from 4.6 down to 3.2 in order to get the
// highest versioned context we can
struct
{
int major;
int minor;
} versions[] = {
{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2},
};
attribs[i++] = api == RDCDriver::OpenGLES ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT
: WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
rc = NULL;
for(size_t v = 0; v < ARRAY_COUNT(versions); v++)
std::vector<GLVersion> versions = GetReplayVersions(api);
for(GLVersion v : versions)
{
major = versions[v].major;
minor = versions[v].minor;
major = v.major;
minor = v.minor;
rc = WGL.wglCreateContextAttribsARB(dc, NULL, attribs);
if(rc)
@@ -434,6 +415,104 @@ class WGLPlatform : public GLPlatform
return ReplayStatus::Succeeded;
}
bool CreateTrampolineContext(HWND &w, HDC &dc, HGLRC &rc)
{
PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 0;
pfd.cStencilBits = 0;
w = CreateWindowEx(WS_EX_CLIENTEDGE, WINDOW_CLASS_NAME, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
GetModuleHandle(NULL), NULL);
dc = GetDC(w);
int pf = ::ChoosePixelFormat(dc, &pfd);
if(pf == 0)
{
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't choose pixel format");
return false;
}
BOOL res = ::SetPixelFormat(dc, pf, &pfd);
if(res == FALSE)
{
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't set pixel format");
return false;
}
rc = WGL.wglCreateContext(dc);
if(rc == NULL)
{
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't create trampoline context");
return false;
}
res = WGL.wglMakeCurrent(dc, rc);
if(res == FALSE)
{
WGL.wglMakeCurrent(NULL, NULL);
WGL.wglDeleteContext(rc);
ReleaseDC(w, dc);
DestroyWindow(w);
RDCERR("Couldn't make trampoline context current");
return false;
}
// now we can fetch the extension functions we need and fill out WGL
if(!WGL.wglCreateContextAttribsARB)
WGL.wglCreateContextAttribsARB =
(PFN_wglCreateContextAttribsARB)WGL.wglGetProcAddress("wglCreateContextAttribsARB");
if(!WGL.wglGetPixelFormatAttribivARB)
WGL.wglGetPixelFormatAttribivARB =
(PFN_wglGetPixelFormatAttribivARB)WGL.wglGetProcAddress("wglGetPixelFormatAttribivARB");
if(!WGL.wglGetExtensionsStringEXT)
WGL.wglGetExtensionsStringEXT =
(PFN_wglGetExtensionsStringEXT)WGL.wglGetProcAddress("wglGetExtensionsStringEXT");
if(!WGL.wglGetExtensionsStringARB)
WGL.wglGetExtensionsStringARB =
(PFN_wglGetExtensionsStringARB)WGL.wglGetProcAddress("wglGetExtensionsStringARB");
return true;
}
bool RegisterClass()
{
WNDCLASSEX wc = {};
wc.style = CS_OWNDC;
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = WINDOW_CLASS_NAME;
WNDCLASSEX dummyCheck = {};
// if the class isn't already registered, then register it.
if(!GetClassInfoExW(wc.hInstance, wc.lpszClassName, &dummyCheck))
{
if(!RegisterClassEx(&wc))
{
RDCERR("Couldn't register GL window class");
return false;
}
}
return true;
}
void DrawQuads(float width, float height, const std::vector<Vec4f> &vertices)
{
::DrawQuads(WGL, width, height, vertices);