mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-12 13:00:32 +00:00
Support creating OpenGL ES contexts via WGL/GLX. Closes #1009
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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); \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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); \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user