diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bcdd544b..bfcd19704 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ if(ANDROID) message(STATUS "Disabling GL driver on android and enabling GLES") endif() set(ENABLE_GL OFF CACHE BOOL "" FORCE) - set(ENABLE_GLES ON CACHE BOOL "" FORCE) + set(ENABLE_GLES OFF CACHE BOOL "" FORCE) # Android doesn't support the Qt UI for obvious reasons message(STATUS "Disabling qrenderdoc for android build") diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 28f91e87a..9f85f0d40 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -161,12 +161,20 @@ struct GLWindowingData #error "Unknown platform" #endif +#include "api/replay/renderdoc_replay.h" + struct GLPlatform { // simple wrapper for OS functions to make/delete a context virtual GLWindowingData MakeContext(GLWindowingData share) = 0; virtual void DeleteContext(GLWindowingData context) = 0; + virtual void DeleteReplayContext(GLWindowingData context) = 0; virtual void MakeContextCurrent(GLWindowingData data) = 0; + virtual void SwapBuffers(GLWindowingData context) = 0; + virtual void GetOutputWindowDimensions(GLWindowingData context, int32_t &w, int32_t &h) = 0; + virtual bool IsOutputWindowVisible(GLWindowingData context) = 0; + virtual GLWindowingData MakeOutputWindow(WindowingSystem system, void *data, bool depth, + GLWindowingData share_context) = 0; // for 'backwards compatible' overlay rendering virtual bool DrawQuads(float width, float height, const std::vector &vertices) = 0; diff --git a/renderdoc/driver/gl/gl_hooks_apple.cpp b/renderdoc/driver/gl/gl_hooks_apple.cpp index 509d14406..10557c0ce 100644 --- a/renderdoc/driver/gl/gl_hooks_apple.cpp +++ b/renderdoc/driver/gl/gl_hooks_apple.cpp @@ -49,7 +49,28 @@ public: return GLWindowingData(); } virtual void DeleteContext(GLWindowingData context) { RDCUNIMPLEMENTED("DeleteContext"); } + virtual void DeleteReplayContext(GLWindowingData context) + { + RDCUNIMPLEMENTED("DeleteReplayContext"); + } virtual void MakeContextCurrent(GLWindowingData data) { RDCUNIMPLEMENTED("MakeContextCurrent"); } + virtual void SwapBuffers(GLWindowingData context) { RDCUNIMPLEMENTED("SwapBuffers"); } + virtual void GetOutputWindowDimensions(GLWindowingData context, int32_t &w, int32_t &h) + { + RDCUNIMPLEMENTED("GetOutputWindowDimensions"); + } + virtual bool IsOutputWindowVisible(GLWindowingData context) + { + RDCUNIMPLEMENTED("IsOutputWindowVisible"); + return true; + } + virtual GLWindowingData MakeOutputWindow(WindowingSystem system, void *data, bool depth, + GLWindowingData share_context) + { + RDCUNIMPLEMENTED("MakeOutputWindow"); + return GLWindowingData(); + } + virtual bool DrawQuads(float width, float height, const std::vector &vertices) { RDCUNIMPLEMENTED("DrawQuads"); diff --git a/renderdoc/driver/gl/gl_hooks_egl.cpp b/renderdoc/driver/gl/gl_hooks_egl.cpp index 8fefb091b..6d7be206b 100644 --- a/renderdoc/driver/gl/gl_hooks_egl.cpp +++ b/renderdoc/driver/gl/gl_hooks_egl.cpp @@ -41,6 +41,8 @@ typedef EGLContext (*PFN_eglCreateContext)(EGLDisplay dpy, EGLConfig config, typedef EGLBoolean (*PFN_eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); typedef EGLSurface (*PFN_eglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +typedef EGLSurface (*PFN_eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, const EGLint *attrib_list); typedef EGLBoolean (*PFN_eglQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); typedef EGLBoolean (*PFN_eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); @@ -174,6 +176,110 @@ public: eglDestroyContext_real(context.egl_dpy, context.egl_ctx); } + void DeleteReplayContext(GLWindowingData context) + { + if(eglDestroyContext_real) + { + eglMakeCurrent_real(context.egl_dpy, 0L, 0L, NULL); + eglDestroyContext_real(context.egl_dpy, context.egl_ctx); + } + } + + void SwapBuffers(GLWindowingData context) + { + eglSwapBuffers_real(context.egl_dpy, context.egl_wnd); + } + + void GetOutputWindowDimensions(GLWindowingData context, int32_t &w, int32_t &h) + { + eglQuerySurface_real(context.egl_dpy, context.egl_wnd, EGL_WIDTH, &w); + eglQuerySurface_real(context.egl_dpy, context.egl_wnd, EGL_HEIGHT, &h); + } + + bool IsOutputWindowVisible(GLWindowingData context) { return true; } + GLWindowingData MakeOutputWindow(WindowingSystem system, void *data, bool depth, + GLWindowingData share_context) + { + GLWindowingData ret; + EGLNativeWindowType window = 0; + + if(system == eWindowingSystem_Xlib) + { + XlibWindowData *xlib = (XlibWindowData *)data; + window = (EGLNativeWindowType)xlib->window; + } + else if(system == eWindowingSystem_Unknown) + { + // allow undefined so that internally we can create a window-less context + Display *dpy = XOpenDisplay(NULL); + + if(dpy == NULL) + return ret; + } + else + { + RDCERR("Unexpected window system %u", system); + } + + EGLDisplay eglDisplay = eglGetDisplay_real(EGL_DEFAULT_DISPLAY); + RDCASSERT(eglDisplay); + + static const EGLint configAttribs[] = {EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES3_BIT, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT | EGL_WINDOW_BIT, + EGL_NONE}; + + PFN_eglChooseConfig eglChooseConfig = (PFN_eglChooseConfig)dlsym(RTLD_NEXT, "eglChooseConfig"); + PFN_eglCreateWindowSurface eglCreateWindowSurface = + (PFN_eglCreateWindowSurface)dlsym(RTLD_NEXT, "eglCreateWindowSurfaceProc"); + PFN_eglCreatePbufferSurface eglCreatePbufferSurface = + (PFN_eglCreatePbufferSurface)dlsym(RTLD_NEXT, "eglCreatePbufferSurface"); + + EGLint numConfigs; + EGLConfig config; + if(!eglChooseConfig(eglDisplay, configAttribs, &config, 1, &numConfigs)) + { + RDCERR("Couldn't find a suitable EGL config"); + return ret; + } + + static const EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR, + EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL_NONE}; + + EGLContext ctx = eglCreateContext_real(eglDisplay, config, EGL_NO_CONTEXT, ctxAttribs); + + if(ctx == NULL) + { + RDCERR("Couldn't create GL ES context"); + return ret; + } + + EGLSurface surface = 0; + + if(window != 0) + { + surface = eglCreateWindowSurface(eglDisplay, config, window, NULL); + } + else + { + static const EGLint pbAttribs[] = {EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE}; + surface = eglCreatePbufferSurface(eglDisplay, config, pbAttribs); + } + + ret.egl_dpy = eglDisplay; + ret.egl_ctx = ctx; + ret.egl_wnd = surface; + + return ret; + } + bool DrawQuads(float width, float height, const std::vector &vertices); WrappedOpenGL *GetDriver() diff --git a/renderdoc/driver/gl/gl_hooks_linux.cpp b/renderdoc/driver/gl/gl_hooks_linux.cpp index d06f46e47..637554781 100644 --- a/renderdoc/driver/gl/gl_hooks_linux.cpp +++ b/renderdoc/driver/gl/gl_hooks_linux.cpp @@ -153,22 +153,20 @@ public: bool is_direct = false; PFNGLXISDIRECTPROC glXIsDirectProc = (PFNGLXISDIRECTPROC)dlsym(RTLD_NEXT, "glXIsDirect"); - PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfigProc = - (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig"); PFNGLXCREATEPBUFFERPROC glXCreatePbufferProc = (PFNGLXCREATEPBUFFERPROC)dlsym(RTLD_NEXT, "glXCreatePbuffer"); if(glXIsDirectProc) is_direct = glXIsDirectProc(share.dpy, share.ctx); - if(glXChooseFBConfigProc && glXCreatePbufferProc) + if(glXChooseFBConfig_real && glXCreatePbufferProc) { // don't need to care about the fb config as we won't be using the default framebuffer // (backbuffer) int visAttribs[] = {0}; int numCfgs = 0; GLXFBConfig *fbcfg = - glXChooseFBConfigProc(share.dpy, DefaultScreen(share.dpy), visAttribs, &numCfgs); + glXChooseFBConfig_real(share.dpy, DefaultScreen(share.dpy), visAttribs, &numCfgs); // don't care about pbuffer properties as we won't render directly to this int pbAttribs[] = {GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0}; @@ -197,6 +195,157 @@ public: glXDestroyContext_real(context.dpy, context.ctx); } + void DeleteReplayContext(GLWindowingData context) + { + if(glXDestroyContext_real) + { + glXMakeContextCurrent_real(context.dpy, 0L, 0L, NULL); + glXDestroyContext_real(context.dpy, context.ctx); + } + } + + void SwapBuffers(GLWindowingData context) { glXSwapBuffers_real(context.dpy, context.wnd); } + void GetOutputWindowDimensions(GLWindowingData context, int32_t &w, int32_t &h) + { + glXQueryDrawable_real(context.dpy, context.wnd, GLX_WIDTH, (unsigned int *)&w); + glXQueryDrawable_real(context.dpy, context.wnd, GLX_HEIGHT, (unsigned int *)&h); + } + + bool IsOutputWindowVisible(GLWindowingData context) + { + GLNOTIMP("Optimisation missing - output window always returning true"); + + return true; + } + + GLWindowingData MakeOutputWindow(WindowingSystem system, void *data, bool depth, + GLWindowingData share_context) + { + GLWindowingData ret; + + Display *dpy = NULL; + Drawable draw = 0; + + if(system == eWindowingSystem_Xlib) + { +#if ENABLED(RDOC_XLIB) + XlibWindowData *xlib = (XlibWindowData *)data; + + dpy = xlib->display; + draw = xlib->window; +#else + RDCERR( + "Xlib windowing system data passed in, but support is not compiled in. GL must have xlib " + "support compiled in"); +#endif + } + else if(system == eWindowingSystem_Unknown) + { + // allow undefined so that internally we can create a window-less context + dpy = XOpenDisplay(NULL); + + if(dpy == NULL) + return ret; + } + else + { + RDCERR("Unexpected window system %u", system); + } + + static int visAttribs[] = {GLX_X_RENDERABLE, + True, + GLX_DRAWABLE_TYPE, + GLX_WINDOW_BIT, + GLX_RENDER_TYPE, + GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE, + GLX_TRUE_COLOR, + GLX_RED_SIZE, + 8, + GLX_GREEN_SIZE, + 8, + GLX_BLUE_SIZE, + 8, + GLX_DOUBLEBUFFER, + True, + GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, + True, + 0}; + int numCfgs = 0; + GLXFBConfig *fbcfg = glXChooseFBConfig_real(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + + if(fbcfg == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't choose default framebuffer config"); + return ret; + } + + if(draw != 0) + { + // Choose FB config with a GLX_VISUAL_ID that matches the X screen. + VisualID visualid_correct = DefaultVisual(dpy, DefaultScreen(dpy))->visualid; + for(int i = 0; i < numCfgs; i++) + { + int visualid; + glXGetFBConfigAttrib(dpy, fbcfg[i], GLX_VISUAL_ID, &visualid); + if((VisualID)visualid == visualid_correct) + { + fbcfg[0] = fbcfg[i]; + break; + } + } + } + + int attribs[64] = {0}; + int i = 0; + + attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = GLCoreVersion / 10; + attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = GLCoreVersion % 10; + attribs[i++] = GLX_CONTEXT_FLAGS_ARB; +#if ENABLED(RDOC_DEVEL) + attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; +#else + attribs[i++] = 0; +#endif + attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB; + attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + + GLXContext ctx = glXCreateContextAttribsARB_real(dpy, fbcfg[0], share_context.ctx, true, attribs); + + if(ctx == NULL) + { + XCloseDisplay(dpy); + RDCERR("Couldn't create %d.%d context - something changed since creation", GLCoreVersion / 10, + GLCoreVersion % 10); + return ret; + } + + GLXDrawable wnd = 0; + + if(draw == 0) + { + // don't care about pbuffer properties as we won't render directly to this + int pbAttribs[] = {GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0}; + + wnd = glXCreatePbuffer(dpy, fbcfg[0], pbAttribs); + } + else + { + wnd = glXCreateWindow(dpy, fbcfg[0], draw, 0); + } + + XFree(fbcfg); + + ret.dpy = dpy; + ret.ctx = ctx; + ret.wnd = wnd; + + return ret; + } + bool DrawQuads(float width, float height, const std::vector &vertices); WrappedOpenGL *GetDriver() @@ -218,6 +367,8 @@ public: PFNGLXGETVISUALFROMFBCONFIGPROC glXGetVisualFromFBConfig_real; PFNGLXCREATEWINDOWPROC glXCreateWindow_real; PFNGLXDESTROYWINDOWPROC glXDestroyWindow_real; + PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig_real; + PFNGLXQUERYDRAWABLEPROC glXQueryDrawable_real; set m_Contexts; @@ -258,6 +409,11 @@ public: glXCreateWindow_real = (PFNGLXCREATEWINDOWPROC)dlsym(libGLdlsymHandle, "glXCreateWindow"); if(glXDestroyWindow_real == NULL) glXDestroyWindow_real = (PFNGLXDESTROYWINDOWPROC)dlsym(libGLdlsymHandle, "glXDestroyWindow"); + if(glXChooseFBConfig_real == NULL) + glXChooseFBConfig_real = + (PFNGLXCHOOSEFBCONFIGPROC)dlsym(libGLdlsymHandle, "glXChooseFBConfig"); + if(glXQueryDrawable_real == NULL) + glXQueryDrawable_real = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable"); return success; } diff --git a/renderdoc/driver/gl/gl_hooks_win32.cpp b/renderdoc/driver/gl/gl_hooks_win32.cpp index e24758136..02e2fdfe6 100644 --- a/renderdoc/driver/gl/gl_hooks_win32.cpp +++ b/renderdoc/driver/gl/gl_hooks_win32.cpp @@ -305,6 +305,9 @@ Threading::CriticalSection glLock; +extern PFNWGLCREATECONTEXTATTRIBSARBPROC createContextAttribs; +extern PFNWGLGETPIXELFORMATATTRIBIVARBPROC getPixelFormatAttrib; + class OpenGLHook : LibraryHook, public GLPlatform { public: @@ -391,6 +394,159 @@ public: wglDeleteContext_hook()(context.ctx); } + void DeleteReplayContext(GLWindowingData context) + { + if(wglDeleteContext_hook()) + { + wglMakeCurrent_hook()(NULL, NULL); + wglDeleteContext_hook()(context.ctx); + ReleaseDC(context.wnd, context.DC); + ::DestroyWindow(context.wnd); + } + } + + void SwapBuffers(GLWindowingData context) { ::SwapBuffers(context.DC); } + void GetOutputWindowDimensions(GLWindowingData context, int32_t &w, int32_t &h) + { + RECT rect = {0}; + GetClientRect(context.wnd, &rect); + w = rect.right - rect.left; + h = rect.bottom - rect.top; + } + + bool IsOutputWindowVisible(GLWindowingData context) + { + return (IsWindowVisible(context.wnd) == TRUE); + } + + GLWindowingData GLPlatform::MakeOutputWindow(WindowingSystem system, void *data, bool depth, + GLWindowingData share_context) + { + GLWindowingData ret; + + RDCASSERT(system == eWindowingSystem_Win32 || system == eWindowingSystem_Unknown, system); + + HWND w = (HWND)data; + + if(w == NULL) + 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); + + PIXELFORMATDESCRIPTOR pfd = {0}; + + int attrib = eWGL_NUMBER_PIXEL_FORMATS_ARB; + int value = 1; + + getPixelFormatAttrib(DC, 1, 0, 1, &attrib, &value); + + int pf = 0; + + int numpfs = value; + for(int i = 1; i <= numpfs; i++) + { + // verify that we have the properties we want + attrib = eWGL_DRAW_TO_WINDOW_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value == 0) + continue; + + attrib = eWGL_ACCELERATION_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value == eWGL_NO_ACCELERATION_ARB) + continue; + + attrib = eWGL_SUPPORT_OPENGL_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value == 0) + continue; + + attrib = eWGL_DOUBLE_BUFFER_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value == 0) + continue; + + attrib = eWGL_PIXEL_TYPE_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value != eWGL_TYPE_RGBA_ARB) + continue; + + // we have an opengl-capable accelerated RGBA context. + // we use internal framebuffers to do almost all rendering, so we just need + // RGB (color bits > 24) and SRGB buffer. + + attrib = eWGL_COLOR_BITS_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value < 24) + continue; + + attrib = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; + getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); + if(value == 0) + continue; + + // this one suits our needs, choose it + pf = i; + break; + } + + if(pf == 0) + { + ReleaseDC(w, DC); + RDCERR("Couldn't choose pixel format"); + return ret; + } + + BOOL res = DescribePixelFormat(DC, pf, sizeof(pfd), &pfd); + if(res == FALSE) + { + ReleaseDC(w, DC); + RDCERR("Couldn't describe pixel format"); + return ret; + } + + res = SetPixelFormat(DC, pf, &pfd); + if(res == FALSE) + { + ReleaseDC(w, DC); + RDCERR("Couldn't set pixel format"); + return ret; + } + + int attribs[64] = {0}; + int i = 0; + + attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = GLCoreVersion / 10; + attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = GLCoreVersion % 10; + 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; + + HGLRC rc = createContextAttribs(DC, share_context.ctx, attribs); + if(rc == NULL) + { + ReleaseDC(w, DC); + RDCERR("Couldn't create %d.%d context - something changed since creation", GLCoreVersion / 10, + GLCoreVersion % 10); + return ret; + } + + ret.DC = DC; + ret.ctx = rc; + ret.wnd = w; + + return ret; + } + bool DrawQuads(float width, float height, const std::vector &vertices); private: diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 5b00eca6e..0406c0227 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -3203,6 +3203,83 @@ ShaderDebugTrace GLReplay::DebugThread(uint32_t eventID, uint32_t groupid[3], ui return ShaderDebugTrace(); } +void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) +{ + static GLWindowingData *prev = NULL; + + if(ctx && ctx != prev) + { + m_pDriver->m_Platform.MakeContextCurrent(*ctx); + prev = ctx; + m_pDriver->ActivateContext(*ctx); + } +} + +void GLReplay::SwapBuffers(GLWindowingData *ctx) +{ + m_pDriver->m_Platform.SwapBuffers(*ctx); +} + +void GLReplay::CloseReplayContext() +{ + m_pDriver->m_Platform.DeleteReplayContext(m_ReplayCtx); +} + +uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) +{ + OutputWindow win = m_pDriver->m_Platform.MakeOutputWindow(system, data, depth, m_ReplayCtx); + if(!win.wnd) + return eReplayCreate_APIInitFailed; + + m_pDriver->m_Platform.GetOutputWindowDimensions(win, win.width, win.height); + + MakeCurrentReplayContext(&win); + InitOutputWindow(win); + CreateOutputWindowBackbuffer(win, depth); + + uint64_t ret = m_OutputWindowID++; + + m_OutputWindows[ret] = win; + + return ret; +} + +void GLReplay::DestroyOutputWindow(uint64_t id) +{ + auto it = m_OutputWindows.find(id); + if(id == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + MakeCurrentReplayContext(&outw); + + WrappedOpenGL &gl = *m_pDriver; + gl.glDeleteFramebuffers(1, &outw.BlitData.readFBO); + + m_pDriver->m_Platform.DeleteReplayContext(outw); + + m_OutputWindows.erase(it); +} + +void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return; + + OutputWindow &outw = m_OutputWindows[id]; + + m_pDriver->m_Platform.GetOutputWindowDimensions(outw, w, h); +} + +bool GLReplay::IsOutputWindowVisible(uint64_t id) +{ + if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) + return false; + + return m_pDriver->m_Platform.IsOutputWindowVisible(m_OutputWindows[id]); +} + #if defined(RENDERDOC_SUPPORT_GL) // defined in gl_replay_.cpp diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 5a4ffbdb4..fef887e0d 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -243,6 +243,8 @@ private: struct OutputWindow : public GLWindowingData { + OutputWindow(const GLWindowingData &data) : GLWindowingData(data) {} + OutputWindow() {} struct { // used to blit from defined FBO (VAOs not shared) diff --git a/renderdoc/driver/gl/gl_replay_apple.cpp b/renderdoc/driver/gl/gl_replay_apple.cpp index 8d475aceb..955726f49 100644 --- a/renderdoc/driver/gl/gl_replay_apple.cpp +++ b/renderdoc/driver/gl/gl_replay_apple.cpp @@ -26,43 +26,6 @@ #include "gl_driver.h" #include "gl_resources.h" -void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) -{ - RDCUNIMPLEMENTED("GLReplay::MakeCurrentReplayContext"); -} - -void GLReplay::SwapBuffers(GLWindowingData *ctx) -{ - RDCUNIMPLEMENTED("GLReplay::SwapBuffers"); -} - -void GLReplay::CloseReplayContext() -{ - RDCUNIMPLEMENTED("GLReplay::CloseReplayContext"); -} - -uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) -{ - RDCUNIMPLEMENTED("GLReplay::MakeOutputWindow"); - return 0; -} - -void GLReplay::DestroyOutputWindow(uint64_t id) -{ - RDCUNIMPLEMENTED("GLReplay::DestroyOutputWindow"); -} - -void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) -{ - RDCUNIMPLEMENTED("GLReplay::GetOutputWindowDimensions"); -} - -bool GLReplay::IsOutputWindowVisible(uint64_t id) -{ - RDCUNIMPLEMENTED("GLReplay::IsOutputWindowVisible"); - return false; -} - ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver) { RDCUNIMPLEMENTED("GL_CreateReplayDevice"); diff --git a/renderdoc/driver/gl/gl_replay_egl.cpp b/renderdoc/driver/gl/gl_replay_egl.cpp index 573ad2fe2..526f0e2fd 100644 --- a/renderdoc/driver/gl/gl_replay_egl.cpp +++ b/renderdoc/driver/gl/gl_replay_egl.cpp @@ -61,161 +61,6 @@ PFN_eglCreateWindowSurface eglCreateWindowSurfaceProc = NULL; PFN_eglChooseConfig eglChooseConfigProc = NULL; PFN_eglGetProcAddress eglGetProcAddressProc = NULL; -void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) -{ - static GLWindowingData *prev = NULL; - - if(eglMakeCurrentProc && ctx && ctx != prev) - { - prev = ctx; - eglMakeCurrentProc(ctx->egl_dpy, ctx->egl_wnd, ctx->egl_wnd, ctx->egl_ctx); - m_pDriver->ActivateContext(*ctx); - } -} - -void GLReplay::SwapBuffers(GLWindowingData *ctx) -{ - eglSwapBuffersProc(ctx->egl_dpy, ctx->egl_wnd); -} - -void GLReplay::CloseReplayContext() -{ - if(eglDestroyContextProc) - { - eglMakeCurrentProc(m_ReplayCtx.egl_dpy, 0L, 0L, NULL); - eglDestroyContextProc(m_ReplayCtx.egl_dpy, m_ReplayCtx.egl_ctx); - } -} - -uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) -{ - EGLNativeWindowType window = 0; - - if(system == eWindowingSystem_Xlib) - { - XlibWindowData *xlib = (XlibWindowData *)data; - window = (EGLNativeWindowType)xlib->window; - } - else if(system == eWindowingSystem_Unknown) - { - // allow undefined so that internally we can create a window-less context - Display *dpy = XOpenDisplay(NULL); - - if(dpy == NULL) - return 0; - } - else - { - RDCERR("Unexpected window system %u", system); - } - - EGLDisplay eglDisplay = eglGetDisplayProc(EGL_DEFAULT_DISPLAY); - RDCASSERT(eglDisplay); - - static const EGLint configAttribs[] = {EGL_RED_SIZE, - 8, - EGL_GREEN_SIZE, - 8, - EGL_BLUE_SIZE, - 8, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES3_BIT, - EGL_SURFACE_TYPE, - EGL_PBUFFER_BIT | EGL_WINDOW_BIT, - EGL_NONE}; - EGLint numConfigs; - EGLConfig config; - - if(!eglChooseConfigProc(eglDisplay, configAttribs, &config, 1, &numConfigs)) - { - RDCERR("Couldn't find a suitable EGL config"); - return 0; - } - - static const EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR, - EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL_NONE}; - - EGLContext ctx = eglCreateContextProc(eglDisplay, config, EGL_NO_CONTEXT, ctxAttribs); - - if(ctx == NULL) - { - RDCERR("Couldn't create GL ES context"); - return 0; - } - - EGLSurface surface = 0; - - if(window != 0) - { - surface = eglCreateWindowSurfaceProc(eglDisplay, config, window, NULL); - } - else - { - static const EGLint pbAttribs[] = {EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE}; - surface = eglCreatePbufferSurfaceProc(eglDisplay, config, pbAttribs); - } - - RDCASSERT(surface != NULL); - - OutputWindow win; - win.egl_dpy = eglDisplay; - win.egl_ctx = ctx; - win.egl_wnd = surface; - - eglQuerySurfaceProc(eglDisplay, surface, EGL_WIDTH, &win.width); - eglQuerySurfaceProc(eglDisplay, surface, EGL_HEIGHT, &win.height); - - MakeCurrentReplayContext(&win); - InitOutputWindow(win); - CreateOutputWindowBackbuffer(win, depth); - - uint64_t ret = m_OutputWindowID++; - - m_OutputWindows[ret] = win; - - return ret; -} - -void GLReplay::DestroyOutputWindow(uint64_t id) -{ - auto it = m_OutputWindows.find(id); - if(id == 0 || it == m_OutputWindows.end()) - return; - - OutputWindow &outw = it->second; - - MakeCurrentReplayContext(&outw); - - WrappedOpenGL &gl = *m_pDriver; - gl.glDeleteFramebuffers(1, &outw.BlitData.readFBO); - - eglMakeCurrentProc(outw.egl_dpy, 0L, 0L, NULL); - eglDestroyContextProc(outw.egl_dpy, outw.egl_ctx); - - m_OutputWindows.erase(it); -} - -void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) -{ - if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) - return; - - OutputWindow &outw = m_OutputWindows[id]; - - eglQuerySurfaceProc(outw.egl_dpy, outw.egl_wnd, EGL_WIDTH, &w); - eglQuerySurfaceProc(outw.egl_dpy, outw.egl_wnd, EGL_HEIGHT, &h); -} - -bool GLReplay::IsOutputWindowVisible(uint64_t id) -{ - if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) - return false; - - GLNOTIMP("Optimisation missing - output window always returning true"); - - return true; -} - const GLHookSet &GetRealGLFunctionsEGL(); GLPlatform &GetGLPlatformEGL(); diff --git a/renderdoc/driver/gl/gl_replay_linux.cpp b/renderdoc/driver/gl/gl_replay_linux.cpp index eb270530b..fcdd0db55 100644 --- a/renderdoc/driver/gl/gl_replay_linux.cpp +++ b/renderdoc/driver/gl/gl_replay_linux.cpp @@ -42,215 +42,6 @@ PFNGLXQUERYDRAWABLEPROC glXQueryDrawableProc = NULL; PFNGLXDESTROYCONTEXTPROC glXDestroyCtxProc = NULL; PFNGLXSWAPBUFFERSPROC glXSwapProc = NULL; -void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) -{ - static GLWindowingData *prev = NULL; - - if(glXMakeContextCurrentProc && ctx && ctx != prev) - { - prev = ctx; - glXMakeContextCurrentProc(ctx->dpy, ctx->wnd, ctx->wnd, ctx->ctx); - m_pDriver->ActivateContext(*ctx); - } -} - -void GLReplay::SwapBuffers(GLWindowingData *ctx) -{ - glXSwapProc(ctx->dpy, ctx->wnd); -} - -void GLReplay::CloseReplayContext() -{ - if(glXDestroyCtxProc) - { - glXMakeContextCurrentProc(m_ReplayCtx.dpy, 0L, 0L, NULL); - glXDestroyCtxProc(m_ReplayCtx.dpy, m_ReplayCtx.ctx); - } -} - -uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) -{ - Display *dpy = NULL; - Drawable draw = 0; - - if(system == eWindowingSystem_Xlib) - { -#if ENABLED(RDOC_XLIB) - XlibWindowData *xlib = (XlibWindowData *)data; - - dpy = xlib->display; - draw = xlib->window; -#else - RDCERR( - "Xlib windowing system data passed in, but support is not compiled in. GL must have xlib " - "support compiled in"); -#endif - } - else if(system == eWindowingSystem_Unknown) - { - // allow undefined so that internally we can create a window-less context - dpy = XOpenDisplay(NULL); - - if(dpy == NULL) - return 0; - } - else - { - RDCERR("Unexpected window system %u", system); - } - - static int visAttribs[] = {GLX_X_RENDERABLE, - True, - GLX_DRAWABLE_TYPE, - GLX_WINDOW_BIT, - GLX_RENDER_TYPE, - GLX_RGBA_BIT, - GLX_X_VISUAL_TYPE, - GLX_TRUE_COLOR, - GLX_RED_SIZE, - 8, - GLX_GREEN_SIZE, - 8, - GLX_BLUE_SIZE, - 8, - GLX_DOUBLEBUFFER, - True, - GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, - True, - 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; - } - - if(draw != 0) - { - // Choose FB config with a GLX_VISUAL_ID that matches the X screen. - VisualID visualid_correct = DefaultVisual(dpy, DefaultScreen(dpy))->visualid; - for(int i = 0; i < numCfgs; i++) - { - int visualid; - glXGetFBConfigAttrib(dpy, fbcfg[i], GLX_VISUAL_ID, &visualid); - if((VisualID)visualid == visualid_correct) - { - fbcfg[0] = fbcfg[i]; - break; - } - } - } - - int attribs[64] = {0}; - int i = 0; - - attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; - attribs[i++] = GLCoreVersion / 10; - attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; - attribs[i++] = GLCoreVersion % 10; - attribs[i++] = GLX_CONTEXT_FLAGS_ARB; -#if ENABLED(RDOC_DEVEL) - attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; -#else - attribs[i++] = 0; -#endif - attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB; - attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - - GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], m_ReplayCtx.ctx, true, attribs); - - if(ctx == NULL) - { - XCloseDisplay(dpy); - RDCERR("Couldn't create %d.%d context - something changed since creation", GLCoreVersion / 10, - GLCoreVersion % 10); - return 0; - } - - GLXDrawable wnd = 0; - - if(draw == 0) - { - // don't care about pbuffer properties as we won't render directly to this - int pbAttribs[] = {GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0}; - - wnd = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs); - } - else - { - // on NV and AMD creating this window causes problems rendering to any widgets in Qt, with the - // width/height queries failing to return any values and the framebuffer blitting not working. - // For the moment, we use the passed-in drawable directly as this works in testing on - // renderdoccmd and qrenderdoc - wnd = draw; - // glXCreateWindow(dpy, fbcfg[0], draw, 0); - } - - XFree(fbcfg); - - OutputWindow win; - win.dpy = dpy; - win.ctx = ctx; - win.wnd = wnd; - - glXQueryDrawableProc(dpy, wnd, GLX_WIDTH, (unsigned int *)&win.width); - glXQueryDrawableProc(dpy, wnd, GLX_HEIGHT, (unsigned int *)&win.height); - - MakeCurrentReplayContext(&win); - - InitOutputWindow(win); - CreateOutputWindowBackbuffer(win, depth); - - uint64_t ret = m_OutputWindowID++; - - m_OutputWindows[ret] = win; - - return ret; -} - -void GLReplay::DestroyOutputWindow(uint64_t id) -{ - auto it = m_OutputWindows.find(id); - if(id == 0 || it == m_OutputWindows.end()) - return; - - OutputWindow &outw = it->second; - - MakeCurrentReplayContext(&outw); - - WrappedOpenGL &gl = *m_pDriver; - gl.glDeleteFramebuffers(1, &outw.BlitData.readFBO); - - glXMakeContextCurrentProc(outw.dpy, 0L, 0L, NULL); - glXDestroyCtxProc(outw.dpy, outw.ctx); - - m_OutputWindows.erase(it); -} - -void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) -{ - if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) - return; - - OutputWindow &outw = m_OutputWindows[id]; - - glXQueryDrawableProc(outw.dpy, outw.wnd, GLX_WIDTH, (unsigned int *)&w); - glXQueryDrawableProc(outw.dpy, outw.wnd, GLX_HEIGHT, (unsigned int *)&h); -} - -bool GLReplay::IsOutputWindowVisible(uint64_t id) -{ - if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) - return false; - - GLNOTIMP("Optimisation missing - output window always returning true"); - - return true; -} - static bool X11ErrorSeen = false; int NonFatalX11ErrorHandler(Display *display, XErrorEvent *error) diff --git a/renderdoc/driver/gl/gl_replay_win32.cpp b/renderdoc/driver/gl/gl_replay_win32.cpp index af13db63c..e2a778005 100644 --- a/renderdoc/driver/gl/gl_replay_win32.cpp +++ b/renderdoc/driver/gl/gl_replay_win32.cpp @@ -40,215 +40,6 @@ WGLCREATECONTEXTPROC wglCreateRC = NULL; WGLMAKECURRENTPROC wglMakeCurrentProc = NULL; WGLDELETECONTEXTPROC wglDeleteRC = NULL; -void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx) -{ - static GLWindowingData *prev = NULL; - - if(wglMakeCurrentProc && ctx && ctx != prev) - { - prev = ctx; - wglMakeCurrentProc(ctx->DC, ctx->ctx); - m_pDriver->ActivateContext(*ctx); - } -} - -void GLReplay::SwapBuffers(GLWindowingData *ctx) -{ - ::SwapBuffers(ctx->DC); -} - -void GLReplay::CloseReplayContext() -{ - if(wglDeleteRC) - { - wglMakeCurrentProc(NULL, NULL); - wglDeleteRC(m_ReplayCtx.ctx); - ReleaseDC(m_ReplayCtx.wnd, m_ReplayCtx.DC); - ::DestroyWindow(m_ReplayCtx.wnd); - } -} - -uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) -{ - RDCASSERT(system == eWindowingSystem_Win32 || system == eWindowingSystem_Unknown, system); - - HWND w = (HWND)data; - - if(w == NULL) - 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); - - PIXELFORMATDESCRIPTOR pfd = {0}; - - int attrib = eWGL_NUMBER_PIXEL_FORMATS_ARB; - int value = 1; - - getPixelFormatAttrib(DC, 1, 0, 1, &attrib, &value); - - int pf = 0; - - int numpfs = value; - for(int i = 1; i <= numpfs; i++) - { - // verify that we have the properties we want - attrib = eWGL_DRAW_TO_WINDOW_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value == 0) - continue; - - attrib = eWGL_ACCELERATION_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value == eWGL_NO_ACCELERATION_ARB) - continue; - - attrib = eWGL_SUPPORT_OPENGL_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value == 0) - continue; - - attrib = eWGL_DOUBLE_BUFFER_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value == 0) - continue; - - attrib = eWGL_PIXEL_TYPE_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value != eWGL_TYPE_RGBA_ARB) - continue; - - // we have an opengl-capable accelerated RGBA context. - // we use internal framebuffers to do almost all rendering, so we just need - // RGB (color bits > 24) and SRGB buffer. - - attrib = eWGL_COLOR_BITS_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value < 24) - continue; - - attrib = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; - getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value); - if(value == 0) - continue; - - // this one suits our needs, choose it - pf = i; - break; - } - - if(pf == 0) - { - ReleaseDC(w, DC); - RDCERR("Couldn't choose pixel format"); - return NULL; - } - - BOOL res = DescribePixelFormat(DC, pf, sizeof(pfd), &pfd); - if(res == FALSE) - { - ReleaseDC(w, DC); - RDCERR("Couldn't describe pixel format"); - return NULL; - } - - res = SetPixelFormat(DC, pf, &pfd); - if(res == FALSE) - { - ReleaseDC(w, DC); - RDCERR("Couldn't set pixel format"); - return NULL; - } - - int attribs[64] = {0}; - int i = 0; - - attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; - attribs[i++] = GLCoreVersion / 10; - attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; - attribs[i++] = GLCoreVersion % 10; - 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; - - HGLRC rc = createContextAttribs(DC, m_ReplayCtx.ctx, attribs); - if(rc == NULL) - { - ReleaseDC(w, DC); - RDCERR("Couldn't create %d.%d context - something changed since creation", GLCoreVersion / 10, - GLCoreVersion % 10); - return 0; - } - - OutputWindow win; - win.DC = DC; - win.ctx = rc; - win.wnd = w; - - RECT rect = {0}; - GetClientRect(w, &rect); - win.width = rect.right - rect.left; - win.height = rect.bottom - rect.top; - - m_pDriver->RegisterContext(win, m_ReplayCtx.ctx, true, true); - - InitOutputWindow(win); - CreateOutputWindowBackbuffer(win, depth); - - uint64_t ret = m_OutputWindowID++; - - m_OutputWindows[ret] = win; - - return ret; -} - -void GLReplay::DestroyOutputWindow(uint64_t id) -{ - auto it = m_OutputWindows.find(id); - if(id == 0 || it == m_OutputWindows.end()) - return; - - OutputWindow &outw = it->second; - - MakeCurrentReplayContext(&outw); - - WrappedOpenGL &gl = *m_pDriver; - gl.glDeleteFramebuffers(1, &outw.BlitData.readFBO); - - wglMakeCurrentProc(NULL, NULL); - wglDeleteRC(outw.ctx); - ReleaseDC(outw.wnd, outw.DC); - - m_OutputWindows.erase(it); -} - -void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) -{ - if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) - return; - - OutputWindow &outw = m_OutputWindows[id]; - - RECT rect = {0}; - GetClientRect(outw.wnd, &rect); - w = rect.right - rect.left; - h = rect.bottom - rect.top; -} - -bool GLReplay::IsOutputWindowVisible(uint64_t id) -{ - if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) - return false; - - return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE); -} - ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver) { RDCDEBUG("Creating an OpenGL replay device"); diff --git a/renderdoccmd/renderdoccmd_linux.cpp b/renderdoccmd/renderdoccmd_linux.cpp index 6f221d4b2..aa99816f7 100644 --- a/renderdoccmd/renderdoccmd_linux.cpp +++ b/renderdoccmd/renderdoccmd_linux.cpp @@ -389,10 +389,10 @@ void sig_handler(int signo) int main(int argc, char *argv[]) { setlocale(LC_CTYPE, ""); + volatile bool never_run = false; #if defined(RENDERDOC_SUPPORT_GL) - volatile bool never_run = false; if(never_run) glXWaitX(); @@ -400,7 +400,6 @@ int main(int argc, char *argv[]) #if defined(RENDERDOC_SUPPORT_GLES) - volatile bool never_run = false; if(never_run) eglWaitGL();