ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver) { RDCDEBUG("Creating an OpenGL replay device"); HMODULE lib = NULL; lib = LoadLibraryA("opengl32.dll"); if(lib == NULL) { RDCERR("Failed to load opengl32.dll"); return eReplayCreate_APIInitFailed; } GLInitParams initParams; RDCDriver driverType = RDC_OpenGL; string driverName = "OpenGL"; uint64_t machineIdent = 0; if(logfile) { auto status = RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, machineIdent, (RDCInitParams *)&initParams); if(status != eReplayCreate_Success) return status; } PIXELFORMATDESCRIPTOR pfd = {0}; if(wglGetProc == NULL) { wglGetProc = (WGLGETPROCADDRESSPROC)GetProcAddress(lib, "wglGetProcAddress"); wglCreateRC = (WGLCREATECONTEXTPROC)GetProcAddress(lib, "wglCreateContext"); wglMakeCurrentProc = (WGLMAKECURRENTPROC)GetProcAddress(lib, "wglMakeCurrent"); wglDeleteRC = (WGLDELETECONTEXTPROC)GetProcAddress(lib, "wglDeleteContext"); if(wglGetProc == NULL || wglCreateRC == NULL || wglMakeCurrentProc == NULL || wglDeleteRC == NULL) { RDCERR("Couldn't get wgl function addresses"); return eReplayCreate_APIInitFailed; } WNDCLASSEX wc; RDCEraseEl(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"; if(!RegisterClassEx(&wc)) { RDCERR("Couldn't register GL window class"); return eReplayCreate_APIInitFailed; } RDCEraseEl(pfd); 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; } HWND w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL); HDC dc = GetDC(w); int pf = ChoosePixelFormat(dc, &pfd); if(pf == 0) { RDCERR("Couldn't choose pixel format"); return eReplayCreate_APIInitFailed; } BOOL res = SetPixelFormat(dc, pf, &pfd); if(res == FALSE) { RDCERR("Couldn't set pixel format"); return eReplayCreate_APIInitFailed; } HGLRC rc = wglCreateRC(dc); if(rc == NULL) { RDCERR("Couldn't create simple RC"); return eReplayCreate_APIInitFailed; } res = wglMakeCurrentProc(dc, rc); if(res == FALSE) { RDCERR("Couldn't make simple RC current"); return eReplayCreate_APIInitFailed; } createContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProc("wglCreateContextAttribsARB"); getPixelFormatAttrib = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProc("wglGetPixelFormatAttribivARB"); if(createContextAttribs == NULL || getPixelFormatAttrib == NULL) { RDCERR("RenderDoc requires WGL_ARB_create_context and WGL_ARB_pixel_format"); return eReplayCreate_APIHardwareUnsupported; } wglMakeCurrentProc(NULL, NULL); wglDeleteRC(rc); ReleaseDC(w, dc); DestroyWindow(w); GLReplay::PreContextInitCounters(); // we don't use the default framebuffer (backbuffer) for anything, so we make it // tiny and with no depth/stencil bits 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", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 32, 32, NULL, NULL, GetModuleHandle(NULL), NULL); dc = GetDC(w); pf = ChoosePixelFormat(dc, &pfd); if(pf == 0) { RDCERR("Couldn't choose pixel format"); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } res = SetPixelFormat(dc, pf, &pfd); if(res == FALSE) { RDCERR("Couldn't set pixel format"); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } int attribs[64] = {0}; int i = 0; attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; int &major = attribs[i]; attribs[i++] = 0; attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; int &minor = attribs[i]; attribs[i++] = 0; attribs[i++] = WGL_CONTEXT_FLAGS_ARB; #if ENABLED(RDOC_DEVEL) attribs[i++] = WGL_CONTEXT_DEBUG_BIT_ARB; #else 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.5 down to 3.2 in order to get the // highest versioned context we can struct { int major; int minor; } versions[] = { {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}, }; rc = NULL; for(size_t v = 0; v < ARRAY_COUNT(versions); v++) { major = versions[v].major; minor = versions[v].minor; rc = createContextAttribs(dc, NULL, attribs); if(rc) break; } if(rc == NULL) { RDCERR("Couldn't create 3.2 RC - RenderDoc requires OpenGL 3.2 availability"); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIHardwareUnsupported; } GLCoreVersion = major * 10 + minor; res = wglMakeCurrentProc(dc, rc); if(res == FALSE) { RDCERR("Couldn't make 3.2 RC current"); wglMakeCurrentProc(NULL, NULL); wglDeleteRC(rc); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } PFNGLGETINTEGERVPROC getInt = (PFNGLGETINTEGERVPROC)GetProcAddress(lib, "glGetIntegerv"); PFNGLGETSTRINGPROC getStr = (PFNGLGETSTRINGPROC)GetProcAddress(lib, "glGetString"); PFNGLGETSTRINGIPROC getStri = (PFNGLGETSTRINGIPROC)wglGetProc("glGetStringi"); if(getInt == NULL || getStr == NULL || getStri == NULL) { RDCERR("Couldn't get glGetIntegerv (%p), glGetString (%p) or glGetStringi (%p) entry points", getInt, getStr, getStri); wglMakeCurrentProc(NULL, NULL); wglDeleteRC(rc); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } bool missingExt = CheckReplayContext(getStr, getInt, getStri); if(missingExt) { wglMakeCurrentProc(NULL, NULL); wglDeleteRC(rc); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } const GLHookSet &real = GetRealGLFunctions(); bool extensionsValidated = ValidateFunctionPointers(real); if(!extensionsValidated) { wglMakeCurrentProc(NULL, NULL); wglDeleteRC(rc); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } WrappedOpenGL *gl = new WrappedOpenGL(logfile, real, GetGLPlatform()); gl->Initialise(initParams); if(gl->GetSerialiser()->HasError()) { delete gl; return eReplayCreate_FileIOFailed; } RDCLOG("Created device."); GLReplay *replay = gl->GetReplay(); replay->SetProxy(logfile == NULL); GLWindowingData data; data.DC = dc; data.ctx = rc; data.wnd = w; replay->SetReplayData(data); *driver = (IReplayDriver *)replay; return eReplayCreate_Success; }
ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver) { RDCDEBUG("Creating an OpenGL replay device"); if(glXCreateContextAttribsProc == NULL) { glXGetFuncProc = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress"); glXDestroyCtxProc = (PFNGLXDESTROYCONTEXTPROC)dlsym(RTLD_NEXT, "glXDestroyContext"); glXSwapProc = (PFNGLXSWAPBUFFERSPROC)dlsym(RTLD_NEXT, "glXSwapBuffers"); glXChooseFBConfigProc = (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig"); glXCreatePbufferProc = (PFNGLXCREATEPBUFFERPROC)dlsym(RTLD_NEXT, "glXCreatePbuffer"); glXDestroyPbufferProc = (PFNGLXDESTROYPBUFFERPROC)dlsym(RTLD_NEXT, "glXDestroyPbuffer"); glXQueryDrawableProc = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable"); if(glXGetFuncProc == NULL || glXDestroyCtxProc == NULL || glXSwapProc == NULL || glXChooseFBConfigProc == NULL || glXCreatePbufferProc == NULL || glXDestroyPbufferProc == NULL || glXQueryDrawableProc == NULL) { RDCERR("Couldn't find required entry points, glXGetProcAddress glXDestroyContext glXSwapBuffers"); return eReplayCreate_APIInitFailed; } glXCreateContextAttribsProc = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetFuncProc((const GLubyte*)"glXCreateContextAttribsARB"); glXMakeContextCurrentProc = (PFNGLXMAKECONTEXTCURRENTPROC)glXGetFuncProc((const GLubyte*)"glXMakeContextCurrent"); if(glXCreateContextAttribsProc == NULL || glXMakeContextCurrentProc == NULL) { RDCERR("Couldn't get glx function addresses, glXCreateContextAttribsARB glXMakeContextCurrent"); return eReplayCreate_APIInitFailed; } } GLInitParams initParams; RDCDriver driverType = RDC_OpenGL; string driverName = "OpenGL"; if(logfile) RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, (RDCInitParams *)&initParams); if(initParams.SerialiseVersion != GLInitParams::GL_SERIALISE_VERSION) { RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GLInitParams::GL_SERIALISE_VERSION, initParams.SerialiseVersion); return eReplayCreate_APIIncompatibleVersion; } int attribs[64] = {0}; int i=0; GLReplay::PreContextInitCounters(); attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; attribs[i++] = 4; attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; attribs[i++] = 3; attribs[i++] = GLX_CONTEXT_FLAGS_ARB; attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB; attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; Display *dpy = XOpenDisplay(NULL); if(dpy == NULL) { RDCERR("Couldn't open default X display"); return eReplayCreate_APIInitFailed; } // don't need to care about the fb config as we won't be using the default framebuffer (backbuffer) static int visAttribs[] = { 0 }; int numCfgs = 0; GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); if(fbcfg == NULL) { XCloseDisplay(dpy); GLReplay::PostContextShutdownCounters(); RDCERR("Couldn't choose default framebuffer config"); return eReplayCreate_APIInitFailed; } GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs); if(ctx == NULL) { XFree(fbcfg); XCloseDisplay(dpy); GLReplay::PostContextShutdownCounters(); RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability"); return eReplayCreate_APIHardwareUnsupported; } // don't care about pbuffer properties for same reason as backbuffer int pbAttribs[] = { GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0 }; GLXPbuffer pbuffer = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs); XFree(fbcfg); Bool res = glXMakeContextCurrentProc(dpy, pbuffer, pbuffer, ctx); if(!res) { glXDestroyPbufferProc(dpy, pbuffer); glXDestroyCtxProc(dpy, ctx); XFree(fbcfg); XCloseDisplay(dpy); GLReplay::PostContextShutdownCounters(); RDCERR("Couldn't make pbuffer & context current"); return eReplayCreate_APIInitFailed; } PFNGLGETINTEGERVPROC getInt = (PFNGLGETINTEGERVPROC)glXGetFuncProc((const GLubyte *)"glGetIntegerv"); PFNGLGETSTRINGIPROC getStr = (PFNGLGETSTRINGIPROC)glXGetFuncProc((const GLubyte *)"glGetStringi"); if(getInt == NULL || getStr == NULL) { RDCERR("Couldn't get glGetIntegerv (%p) or glGetStringi (%p) entry points", getInt, getStr); glXDestroyPbufferProc(dpy, pbuffer); glXDestroyCtxProc(dpy, ctx); XFree(fbcfg); XCloseDisplay(dpy); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } else { // eventually we want to emulate EXT_dsa on replay if it isn't present, but for // now we just require it. bool dsa = false; bool bufstorage = false; if(getStr) RDCLOG("Running GL replay on: %s / %s / %s", getStr(eGL_VENDOR), getStr(eGL_RENDERER), getStr(eGL_VERSION)); GLint numExts = 0; getInt(eGL_NUM_EXTENSIONS, &numExts); for(GLint e=0; e < numExts; e++) { const char *ext = (const char *)getStri(eGL_EXTENSIONS, (GLuint)e); RDCLOG("Extension % 3d: %s", e, ext); if(!strcmp(ext, "GL_EXT_direct_state_access")) dsa = true; if(!strcmp(ext, "GL_ARB_buffer_storage")) bufstorage = true; } if(!dsa) RDCERR("RenderDoc requires EXT_direct_state_access availability, and it is not reported. Try updating your drivers."); if(!bufstorage) RDCERR("RenderDoc requires ARB_buffer_storage availability, and it is not reported. Try updating your drivers."); if(!dsa || !bufstorage) { glXDestroyPbufferProc(dpy, pbuffer); glXDestroyCtxProc(dpy, ctx); XFree(fbcfg); XCloseDisplay(dpy); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIHardwareUnsupported; } } WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealGLFunctions()); gl->Initialise(initParams); RDCLOG("Created device."); GLReplay *replay = gl->GetReplay(); replay->SetProxy(logfile == NULL); GLWindowingData data; data.dpy = dpy; data.ctx = ctx; data.wnd = pbuffer; replay->SetReplayData(data); *driver = (IReplayDriver *)replay; return eReplayCreate_Success; }
ReplayCreateStatus GL_CreateReplayDevice(const wchar_t *logfile, IReplayDriver **driver) { RDCDEBUG("Creating an OpenGL replay device"); if(glXCreateContextAttribsProc == NULL) { glXGetFuncProc = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress"); glXDestroyCtxProc = (PFNGLXDESTROYCONTEXTPROC)dlsym(RTLD_NEXT, "glXDestroyContext"); glXSwapProc = (PFNGLXSWAPBUFFERSPROC)dlsym(RTLD_NEXT, "glXSwapBuffers"); glXChooseFBConfigProc = (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig"); glXCreatePbufferProc = (PFNGLXCREATEPBUFFERPROC)dlsym(RTLD_NEXT, "glXCreatePbuffer"); glXDestroyPbufferProc = (PFNGLXDESTROYPBUFFERPROC)dlsym(RTLD_NEXT, "glXDestroyPbuffer"); glXQueryDrawableProc = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable"); if(glXGetFuncProc == NULL || glXDestroyCtxProc == NULL || glXSwapProc == NULL || glXChooseFBConfigProc == NULL || glXCreatePbufferProc == NULL || glXDestroyPbufferProc == NULL || glXQueryDrawableProc == NULL) { RDCERR("Couldn't find required entry points, glXGetProcAddress glXDestroyContext glXSwapBuffers"); return eReplayCreate_APIInitFailed; } glXCreateContextAttribsProc = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetFuncProc((const GLubyte*)"glXCreateContextAttribsARB"); glXMakeContextCurrentProc = (PFNGLXMAKECONTEXTCURRENTPROC)glXGetFuncProc((const GLubyte*)"glXMakeContextCurrent"); if(glXCreateContextAttribsProc == NULL || glXMakeContextCurrentProc == NULL) { RDCERR("Couldn't get glx function addresses, glXCreateContextAttribsARB glXMakeContextCurrent"); return eReplayCreate_APIInitFailed; } } GLInitParams initParams; RDCDriver driverType = RDC_OpenGL; wstring driverName = L"OpenGL"; if(logfile) RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, (RDCInitParams *)&initParams); if(initParams.SerialiseVersion != GLInitParams::GL_SERIALISE_VERSION) { RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GLInitParams::GL_SERIALISE_VERSION, initParams.SerialiseVersion); return eReplayCreate_APIIncompatibleVersion; } int attribs[64] = {0}; int i=0; attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; attribs[i++] = 4; attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; attribs[i++] = 3; attribs[i++] = GLX_CONTEXT_FLAGS_ARB; attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; Display *dpy = XOpenDisplay(NULL); if(dpy == NULL) { RDCERR("Couldn't open default X display"); return eReplayCreate_APIInitFailed; } // don't need to care about the fb config as we won't be using the default framebuffer (backbuffer) static int visAttribs[] = { 0 }; int numCfgs = 0; GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); if(fbcfg == NULL) { XCloseDisplay(dpy); RDCERR("Couldn't choose default framebuffer config"); return eReplayCreate_APIInitFailed; } GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs); if(ctx == NULL) { XCloseDisplay(dpy); RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability"); return eReplayCreate_APIHardwareUnsupported; } // don't care about pbuffer properties for same reason as backbuffer int pbAttribs[] = { GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0 }; GLXPbuffer pbuffer = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs); XFree(fbcfg); Bool res = glXMakeContextCurrentProc(dpy, pbuffer, pbuffer, ctx); if(!res) { glXDestroyPbufferProc(dpy, pbuffer); glXDestroyCtxProc(dpy, ctx); XCloseDisplay(dpy); RDCERR("Couldn't make pbuffer & context current"); return eReplayCreate_APIInitFailed; } WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealFunctions()); gl->Initialise(initParams); RDCLOG("Created device."); GLReplay *replay = gl->GetReplay(); replay->SetProxy(logfile == NULL); GLWindowingData data; data.dpy = dpy; data.ctx = ctx; data.wnd = pbuffer; replay->SetReplayData(data); *driver = (IReplayDriver *)replay; return eReplayCreate_Success; }