From 0a07902980f6675763812c7d23b2d0c689a56df2 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 6 Sep 2018 17:54:53 +0100 Subject: [PATCH] Store/create backbuffers on a per-context basis. Closes #1083 * This means we can have different context backbuffers with different formats. --- renderdoc/driver/gl/cgl_hooks.cpp | 8 +- renderdoc/driver/gl/egl_hooks.cpp | 44 +-- renderdoc/driver/gl/gl_common.cpp | 4 + renderdoc/driver/gl/gl_common.h | 2 + renderdoc/driver/gl/gl_driver.cpp | 324 +++++++++++------- renderdoc/driver/gl/gl_driver.h | 44 ++- renderdoc/driver/gl/gl_renderstate.cpp | 15 +- renderdoc/driver/gl/gl_rendertext.cpp | 27 +- renderdoc/driver/gl/gl_replay.cpp | 5 +- renderdoc/driver/gl/gl_stringise.cpp | 2 + renderdoc/driver/gl/glx_hooks.cpp | 39 ++- renderdoc/driver/gl/wgl_hooks.cpp | 14 +- .../driver/gl/wrappers/gl_buffer_funcs.cpp | 30 +- .../driver/gl/wrappers/gl_draw_funcs.cpp | 8 +- .../gl/wrappers/gl_framebuffer_funcs.cpp | 28 +- 15 files changed, 343 insertions(+), 251 deletions(-) diff --git a/renderdoc/driver/gl/cgl_hooks.cpp b/renderdoc/driver/gl/cgl_hooks.cpp index 52a42de8a..5fe609ef0 100644 --- a/renderdoc/driver/gl/cgl_hooks.cpp +++ b/renderdoc/driver/gl/cgl_hooks.cpp @@ -74,7 +74,7 @@ CGLError GL_EXPORT_NAME(CGLCreateContext)(CGLPixelFormatObj pix, CGLContextObj s init.isSRGB = value; value = 1; // GLX.glXGetConfig(dpy, vis, GLX_SAMPLES_ARB, &value); - init.isSRGB = RDCMAX(1, value); + init.multiSamples = RDCMAX(1, value); GLWindowingData data; data.wnd = NULL; @@ -125,6 +125,10 @@ CGLError GL_EXPORT_NAME(CGLSetCurrentContext)(CGLContextObj ctx) // data.cfg = NULL; cglhook.driver.ActivateContext(data); + + GLInitParams ¶ms = cglhook.driver.GetInitParams(data); + params.width = 400; + params.height = 200; } return ret; @@ -142,8 +146,6 @@ CGLError GL_EXPORT_NAME(CGLFlushDrawable)(CGLContextObj ctx) SCOPED_LOCK(glLock); - cglhook.driver.WindowSize((void *)0x4, 800, 200); - cglhook.driver.SwapBuffers((void *)0x4); return CGL.CGLFlushDrawable(ctx); diff --git a/renderdoc/driver/gl/egl_hooks.cpp b/renderdoc/driver/gl/egl_hooks.cpp index 8e8ef90bf..b92c2c95f 100644 --- a/renderdoc/driver/gl/egl_hooks.cpp +++ b/renderdoc/driver/gl/egl_hooks.cpp @@ -294,6 +294,24 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface eglhook.driver.SetDriverType(RDCDriver::OpenGLES); eglhook.driver.ActivateContext(data); + + GLInitParams ¶ms = eglhook.driver.GetInitParams(data); + + int height, width; + EGL.QuerySurface(display, draw, EGL_HEIGHT, &height); + EGL.QuerySurface(display, draw, EGL_WIDTH, &width); + + int colorspace = 0; + EGL.QuerySurface(display, draw, EGL_GL_COLORSPACE, &colorspace); + // GL_SRGB8_ALPHA8 is specified as color-renderable, unlike GL_SRGB8. + bool isSRGB = params.colorBits == 32 && colorspace == EGL_GL_COLORSPACE_SRGB; + + bool isYFlipped = eglhook.IsYFlipped(display, draw); + + params.width = width; + params.height = height; + params.isSRGB = isSRGB; + params.isYFlipped = isYFlipped; } return ret; @@ -311,20 +329,7 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface sur SCOPED_LOCK(glLock); - int height, width; - EGL.QuerySurface(dpy, surface, EGL_HEIGHT, &height); - EGL.QuerySurface(dpy, surface, EGL_WIDTH, &width); - - GLInitParams &init = eglhook.driver.GetInitParams(); - int colorspace = 0; - EGL.QuerySurface(dpy, surface, EGL_GL_COLORSPACE, &colorspace); - // GL_SRGB8_ALPHA8 is specified as color-renderable, unlike GL_SRGB8. - init.isSRGB = init.colorBits == 32 && colorspace == EGL_GL_COLORSPACE_SRGB; - - init.isYFlipped = eglhook.IsYFlipped(dpy, surface); - eglhook.driver.SetDriverType(RDCDriver::OpenGLES); - eglhook.driver.WindowSize(surface, width, height); if(!eglhook.driver.UsesVRFrameMarkers()) eglhook.driver.SwapBuffers(surface); @@ -344,20 +349,7 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface SCOPED_LOCK(glLock); - int winheight, winwidth; - EGL.QuerySurface(dpy, surface, EGL_HEIGHT, &winheight); - EGL.QuerySurface(dpy, surface, EGL_WIDTH, &winwidth); - - GLInitParams &init = eglhook.driver.GetInitParams(); - int colorspace = 0; - EGL.QuerySurface(dpy, surface, EGL_GL_COLORSPACE, &colorspace); - // GL_SRGB8_ALPHA8 is specified as color-renderable, unlike GL_SRGB8. - init.isSRGB = init.colorBits == 32 && colorspace == EGL_GL_COLORSPACE_SRGB; - - init.isYFlipped = eglhook.IsYFlipped(dpy, surface); - eglhook.driver.SetDriverType(RDCDriver::OpenGLES); - eglhook.driver.WindowSize((void *)eglhook.windows[surface], winwidth, winheight); if(!eglhook.driver.UsesVRFrameMarkers()) eglhook.driver.SwapBuffers((void *)eglhook.windows[surface]); diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 5e047bd03..ee6a76990 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -1125,6 +1125,10 @@ bool GLInitParams::IsSupportedVersion(uint64_t ver) if(ver == 0x1C) return true; + // 0x1D -> 0x1E - added new chunk for context parameters and per-context tracking of backbuffers + if(ver == 0x1D) + return true; + return false; } diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index eb6788a74..59bd9c9a8 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -2054,6 +2054,8 @@ enum class GLChunk : uint32_t glAcquireKeyedMutexWin32EXT, glReleaseKeyedMutexWin32EXT, + ContextConfiguration, + Max, }; diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 803b7fe9a..23a2aa6b1 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -580,10 +580,6 @@ WrappedOpenGL::WrappedOpenGL(GLPlatform &platform) m_ContextRecord->DataInSerialiser = false; m_ContextRecord->Length = 0; m_ContextRecord->InternalResource = true; - - // we register an ID for the backbuffer, this will be tied to the fake-created backbuffer on - // replay, and every context's FBO 0 will be pointed to it with ReplaceResource - m_FBO0_ID = ResourceIDGen::GetNewUniqueID(); } else { @@ -595,9 +591,7 @@ WrappedOpenGL::WrappedOpenGL(GLPlatform &platform) InitSPIRVCompiler(); RenderDoc::Inst().RegisterShutdownFunction(&ShutdownSPIRVCompiler); - m_FakeBB_FBO = 0; - m_FakeBB_Color = 0; - m_FakeBB_DepthStencil = 0; + m_CurrentDefaultFBO = 0; m_CurChunkOffset = 0; m_AddedDrawcall = false; @@ -607,14 +601,21 @@ WrappedOpenGL::WrappedOpenGL(GLPlatform &platform) void WrappedOpenGL::Initialise(GLInitParams ¶ms, uint64_t sectionVersion) { - // deliberately want to go through our own wrappers to set up e.g. m_Textures members + m_SectionVersion = sectionVersion; + m_GlobalInitParams = params; +} + +void WrappedOpenGL::CreateReplayBackbuffer(const GLInitParams ¶ms, ResourceId fboOrigId, + GLuint &fbo, std::string bbname) +{ + GLuint col = 0, depth = 0; + WrappedOpenGL &drv = *this; - m_InitParams = params; - m_SectionVersion = sectionVersion; + drv.glGenFramebuffers(1, &fbo); + drv.glBindFramebuffer(eGL_FRAMEBUFFER, fbo); - drv.glGenFramebuffers(1, &m_FakeBB_FBO); - drv.glBindFramebuffer(eGL_FRAMEBUFFER, m_FakeBB_FBO); + m_CurrentDefaultFBO = fbo; GLenum colfmt = eGL_RGBA8; @@ -629,27 +630,20 @@ void WrappedOpenGL::Initialise(GLInitParams ¶ms, uint64_t sectionVersion) if(params.multiSamples > 1) target = eGL_TEXTURE_2D_MULTISAMPLE; - drv.glGenTextures(1, &m_FakeBB_Color); - drv.glBindTexture(target, m_FakeBB_Color); + drv.glGenTextures(1, &col); + drv.glBindTexture(target, col); - ResourceId colorId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_Color)); - const char *name = "Backbuffer Color"; - - GetResourceManager()->SetName(colorId, name); - - // we'll add the chunk later when we re-process it. - AddResource(colorId, ResourceType::SwapchainImage, name); - GetReplay()->GetResourceDesc(colorId).initialisationChunks.clear(); - GetReplay()->GetResourceDesc(colorId).SetCustomName(name); + m_Textures[GetResourceManager()->GetID(TextureRes(GetCtx(), col))].creationFlags |= + TextureCategory::SwapBuffer; if(params.multiSamples > 1) { - drv.glTextureStorage2DMultisampleEXT(m_FakeBB_Color, target, params.multiSamples, colfmt, - params.width, params.height, true); + drv.glTextureStorage2DMultisampleEXT(col, target, params.multiSamples, colfmt, params.width, + params.height, true); } else { - drv.glTextureImage2DEXT(m_FakeBB_Color, target, 0, colfmt, params.width, params.height, 0, + drv.glTextureImage2DEXT(col, target, 0, colfmt, params.width, params.height, 0, GetBaseFormat(colfmt), GetDataType(colfmt), NULL); drv.glTexParameteri(target, eGL_TEXTURE_MAX_LEVEL, 0); drv.glTexParameteri(target, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); @@ -657,15 +651,14 @@ void WrappedOpenGL::Initialise(GLInitParams ¶ms, uint64_t sectionVersion) drv.glTexParameteri(target, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(target, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); } - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, target, m_FakeBB_Color, 0); + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, target, col, 0); drv.glViewport(0, 0, params.width, params.height); - m_FakeBB_DepthStencil = 0; if(params.depthBits > 0 || params.stencilBits > 0) { - drv.glGenTextures(1, &m_FakeBB_DepthStencil); - drv.glBindTexture(target, m_FakeBB_DepthStencil); + drv.glGenTextures(1, &depth); + drv.glBindTexture(target, depth); GLenum depthfmt = eGL_DEPTH32F_STENCIL8; bool stencil = false; @@ -696,50 +689,80 @@ void WrappedOpenGL::Initialise(GLInitParams ¶ms, uint64_t sectionVersion) else RDCERR("Unexpected # stencil bits: %d", params.stencilBits); - ResourceId depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_DepthStencil)); - name = stencil ? "Backbuffer Depth-stencil" : "Backbuffer Depth"; - - GetResourceManager()->SetName(depthId, name); - - // we'll add the chunk later when we re-process it. - AddResource(depthId, ResourceType::SwapchainImage, name); - GetReplay()->GetResourceDesc(depthId).initialisationChunks.clear(); - GetReplay()->GetResourceDesc(depthId).SetCustomName(name); + m_Textures[GetResourceManager()->GetID(TextureRes(GetCtx(), depth))].creationFlags |= + TextureCategory::SwapBuffer; if(params.multiSamples > 1) { - drv.glTextureStorage2DMultisampleEXT(m_FakeBB_DepthStencil, target, params.multiSamples, - depthfmt, params.width, params.height, true); + drv.glTextureStorage2DMultisampleEXT(depth, target, params.multiSamples, depthfmt, + params.width, params.height, true); } else { drv.glTexParameteri(target, eGL_TEXTURE_MAX_LEVEL, 0); - drv.glTextureImage2DEXT(m_FakeBB_DepthStencil, target, 0, depthfmt, params.width, - params.height, 0, GetBaseFormat(depthfmt), GetDataType(depthfmt), NULL); + drv.glTextureImage2DEXT(depth, target, 0, depthfmt, params.width, params.height, 0, + GetBaseFormat(depthfmt), GetDataType(depthfmt), NULL); } if(stencil) - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, target, - m_FakeBB_DepthStencil, 0); + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, target, depth, 0); else - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, target, - m_FakeBB_DepthStencil, 0); + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, target, depth, 0); } // give the backbuffer a default clear color - drv.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - drv.glClear(GL_COLOR_BUFFER_BIT); + float clearcol[] = {0.0f, 0.0f, 0.0f, 1.0f}; + drv.glClearBufferfv(eGL_COLOR, 0, clearcol); - if(params.depthBits > 0) + if(params.depthBits > 0 || params.stencilBits > 0) + drv.glClearBufferfi(eGL_DEPTH_STENCIL, 0, 1.0f, 0); + + GetResourceManager()->AddLiveResource(fboOrigId, FramebufferRes(GetCtx(), fbo)); + AddResource(fboOrigId, ResourceType::SwapchainImage, ""); + GetReplay()->GetResourceDesc(fboOrigId).SetCustomName(bbname + " FBO"); + + ResourceId colorId = GetResourceManager()->GetID(TextureRes(GetCtx(), col)); + std::string name = bbname + " Color"; + + GetResourceManager()->SetName(colorId, name); + + // we'll add the chunk later when we re-process it. + AddResource(colorId, ResourceType::SwapchainImage, name.c_str()); + GetReplay()->GetResourceDesc(colorId).SetCustomName(name); + + GetReplay()->GetResourceDesc(fboOrigId).derivedResources.push_back(colorId); + GetReplay()->GetResourceDesc(colorId).parentResources.push_back(fboOrigId); + + if(depth) { - drv.glClearDepthf(1.0f); - drv.glClear(GL_DEPTH_BUFFER_BIT); + ResourceId depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), depth)); + name = bbname + (params.stencilBits > 0 ? " Depth-stencil" : " Depth"); + + GetResourceManager()->SetName(depthId, name); + + // we'll add the chunk later when we re-process it. + AddResource(depthId, ResourceType::SwapchainImage, name.c_str()); + GetReplay()->GetResourceDesc(depthId).SetCustomName(name); + + GetReplay()->GetResourceDesc(fboOrigId).derivedResources.push_back(depthId); + GetReplay()->GetResourceDesc(depthId).parentResources.push_back(fboOrigId); } - if(params.stencilBits > 0) + if(fbo == m_Global_FBO0) { - drv.glClearStencil(0); - drv.glClear(GL_STENCIL_BUFFER_BIT); + GetReplay()->GetResourceDesc(fboOrigId).initialisationChunks.clear(); + GetReplay()->GetResourceDesc(fboOrigId).initialisationChunks.push_back(m_InitChunkIndex); + + GetReplay()->GetResourceDesc(colorId).initialisationChunks.clear(); + GetReplay()->GetResourceDesc(colorId).initialisationChunks.push_back(m_InitChunkIndex); + + if(depth) + { + ResourceId depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), depth)); + + GetReplay()->GetResourceDesc(depthId).initialisationChunks.clear(); + GetReplay()->GetResourceDesc(depthId).initialisationChunks.push_back(m_InitChunkIndex); + } } } @@ -753,13 +776,6 @@ std::string WrappedOpenGL::GetChunkName(uint32_t idx) WrappedOpenGL::~WrappedOpenGL() { - if(m_FakeBB_FBO) - GL.glDeleteFramebuffers(1, &m_FakeBB_FBO); - if(m_FakeBB_Color) - GL.glDeleteTextures(1, &m_FakeBB_Color); - if(m_FakeBB_DepthStencil) - GL.glDeleteTextures(1, &m_FakeBB_DepthStencil); - if(m_IndirectBuffer) GL.glDeleteBuffers(1, &m_IndirectBuffer); @@ -938,9 +954,6 @@ void WrappedOpenGL::ContextData::CreateResourceRecord(WrappedOpenGL *driver, voi void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core, bool attribsCreate) { - // TODO: support multiple GL contexts more explicitly - m_InitParams = initParams; - RDCLOG("%s context %p created %s, sharing with context %p", core ? "Core" : "Compatibility", winData.ctx, attribsCreate ? "with attribs" : "without attribs", shareContext); @@ -948,6 +961,7 @@ void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext, ctxdata.ctx = winData.ctx; ctxdata.isCore = core; ctxdata.attribsCreate = attribsCreate; + ctxdata.initParams = initParams; if(shareContext == NULL) { @@ -1001,6 +1015,48 @@ void WrappedOpenGL::RegisterReplayContext(GLWindowingData winData, void *shareCo ActivateContext(winData); } +template +bool WrappedOpenGL::Serialise_ContextConfiguration(SerialiserType &ser, void *ctx) +{ + SERIALISE_ELEMENT_LOCAL(Context, m_ContextData[ctx].m_ContextDataResourceID); + SERIALISE_ELEMENT_LOCAL(FBO, m_ContextData[ctx].m_ContextFBOID); + SERIALISE_ELEMENT_LOCAL(InitParams, m_ContextData[ctx].initParams); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + // we might encounter multiple instances of this chunk per frame, so only do work on the first + // one + if(!GetResourceManager()->HasLiveResource(FBO)) + { + std::string name; + + if(m_CurrentDefaultFBO == 0) + { + // if we haven't created a default FBO yet this is the first. Give it a nice friendly name + name = "Backbuffer"; + } + else + { + // if not, we have multiple FBOs and we want to distinguish them. Give the subsequent + // backbuffers unique names + name = StringFormat::Fmt("Context %llu Backbuffer", Context); + } + + GLuint fbo = 0; + CreateReplayBackbuffer(InitParams, FBO, fbo, name); + + // also add a simple resource descriptor for the context + AddResource(Context, ResourceType::Device, "Context"); + } + + m_CurrentDefaultFBO = GetResourceManager()->GetLiveResource(FBO).name; + } + + return true; +} + void WrappedOpenGL::ActivateContext(GLWindowingData winData) { m_ActiveContexts[Threading::GetCurrentID()] = winData; @@ -1281,31 +1337,32 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) GetResourceManager()->MarkDirtyResource(id); } - // we also do the same for FBO 0, but this is treated 'specially' as we actually only create - // one backbuffer and re-point all FBOs at it, however there may be several IDs - // corresponding to the default backbuffer. We rename them all. - GLResource fbo0 = FramebufferRes(GetCtx(), 0); + // we also do the same for FBO 0, but we must force it not to be shared as even if FBOs are + // shared the FBO0 may not be :(. + GLResource fbo0 = FramebufferRes({GetCtx().ctx, GetCtx().ctx}, 0); if(!GetResourceManager()->HasCurrentResource(fbo0)) - { - ResourceId id = GetResourceManager()->RegisterResource(fbo0); - - USE_SCRATCH_SERIALISER(); - SCOPED_SERIALISE_CHUNK(GLChunk::glContextInit); - Serialise_ContextInit(ser); - - m_DeviceRecord->AddChunk(scope.Get()); - } + ctxdata.m_ContextFBOID = GetResourceManager()->RegisterResource(fbo0); } } // if we're capturing, we need to serialise out the changed state vector if(IsActiveCapturing(m_State)) { - USE_SCRATCH_SERIALISER(); - SCOPED_SERIALISE_CHUNK(GLChunk::MakeContextCurrent); - Serialise_BeginCaptureFrame(ser); - GetContextRecord()->AddChunk(scope.Get()); + { + USE_SCRATCH_SERIALISER(); + SCOPED_SERIALISE_CHUNK(GLChunk::MakeContextCurrent); + Serialise_BeginCaptureFrame(ser); + GetContextRecord()->AddChunk(scope.Get()); + } + + // also serialise out this context's backbuffer params + { + USE_SCRATCH_SERIALISER(); + SCOPED_SERIALISE_CHUNK(GLChunk::ContextConfiguration); + Serialise_ContextConfiguration(ser, winData.ctx); + GetContextRecord()->AddChunk(scope.Get()); + } } // this is hack but GL context creation is an *utter mess*. For first-frame captures, only @@ -1316,13 +1373,6 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) } } -void WrappedOpenGL::WindowSize(void *windowHandle, uint32_t w, uint32_t h) -{ - // TODO: support multiple window handles - m_InitParams.width = w; - m_InitParams.height = h; -} - struct ReplacementSearch { bool operator()(const pair &a, ResourceId b) { return a.first < b; } @@ -1667,7 +1717,7 @@ void WrappedOpenGL::SwapBuffers(void *windowHandle) } if(!overlayText.empty()) - RenderOverlayText(0.0f, 0.0f, m_InitParams.isYFlipped, overlayText.c_str()); + RenderOverlayText(0.0f, 0.0f, overlayText.c_str()); // swallow all errors we might have inadvertantly caused. This is // better than letting an error propagate and maybe screw up the @@ -1778,6 +1828,14 @@ void WrappedOpenGL::StartFrameCapture(void *dev, void *wnd) AttemptCapture(); BeginCaptureFrame(); + // serialise out the context configuration for this current context first + { + USE_SCRATCH_SERIALISER(); + SCOPED_SERIALISE_CHUNK(GLChunk::ContextConfiguration); + Serialise_ContextConfiguration(ser, GetCtx().ctx); + GetContextRecord()->AddChunk(scope.Get()); + } + if(switchctx.ctx != prevctx.ctx) { m_Platform.MakeContextCurrent(prevctx); @@ -1869,18 +1927,23 @@ bool WrappedOpenGL::EndFrameCapture(void *dev, void *wnd) { SCOPED_SERIALISE_CHUNK(SystemChunk::DriverInit, sizeof(GLInitParams) + 16); - SERIALISE_ELEMENT(m_InitParams); + // we no longer use this one, but for ease of compatibility we still serialise it here. This + // will be immediately overridden by the actual parameters by a + // GLChunk::ContextConfiguration chunk + GLInitParams dummy; + + SERIALISE_ELEMENT(dummy); } { // remember to update this estimated chunk length if you add more parameters SCOPED_SERIALISE_CHUNK(GLChunk::DeviceInitialisation, 32); - // legacy behaviour where we had a single global VAO 0. Ignore, but preserve for easier + // legacy behaviour where we had a single global VAO/FBO 0. Ignore, but preserve for easier // compatibility with old captures - ResourceId vao; + ResourceId vao, fbo; SERIALISE_ELEMENT(vao); - SERIALISE_ELEMENT(m_FBO0_ID); + SERIALISE_ELEMENT(fbo); } RDCDEBUG("Inserting Resource Serialisers"); @@ -1970,8 +2033,7 @@ bool WrappedOpenGL::EndFrameCapture(void *dev, void *wnd) { ContextData &ctxdata = GetCtxData(); - RenderOverlayText(0.0f, 0.0f, m_InitParams.isYFlipped, "Failed to capture frame %u: %s", - m_FrameCounter, reasonString); + RenderOverlayText(0.0f, 0.0f, "Failed to capture frame %u: %s", m_FrameCounter, reasonString); // swallow all errors we might have inadvertantly caused. This is // better than letting an error propagate and maybe screw up the @@ -2071,8 +2133,10 @@ WrappedOpenGL::BackbufferImage *WrappedOpenGL::SaveBackbufferImage() GL.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0); GL.glPixelStorei(eGL_PACK_ALIGNMENT, 1); - thwidth = (uint16_t)m_InitParams.width; - thheight = (uint16_t)m_InitParams.height; + ContextData &dat = GetCtxData(); + + thwidth = (uint16_t)dat.initParams.width; + thheight = (uint16_t)dat.initParams.height; thpixels = new byte[thwidth * thheight * 4]; @@ -2091,7 +2155,7 @@ WrappedOpenGL::BackbufferImage *WrappedOpenGL::SaveBackbufferImage() } // flip the image in-place - if(!m_InitParams.isYFlipped) + if(!dat.initParams.isYFlipped) { for(uint16_t y = 0; y <= thheight / 2; y++) { @@ -2148,7 +2212,7 @@ WrappedOpenGL::BackbufferImage *WrappedOpenGL::SaveBackbufferImage() float yf = float(y) / float(thheight); byte *pixelsrc = - &src[3 * uint32_t(xf * widthf) + m_InitParams.width * 3 * uint32_t(yf * heightf)]; + &src[3 * uint32_t(xf * widthf) + dat.initParams.width * 3 * uint32_t(yf * heightf)]; memcpy(dst, pixelsrc, 3); @@ -2213,24 +2277,29 @@ bool WrappedOpenGL::Serialise_CaptureScope(SerialiserType &ser) return true; } -template -bool WrappedOpenGL::Serialise_ContextInit(SerialiserType &ser) +bool WrappedOpenGL::Serialise_ContextInit(ReadSerialiser &ser) { - SERIALISE_ELEMENT_LOCAL(FBO0_ID, GetResourceManager()->GetID(FramebufferRes(GetCtx(), 0))); + SERIALISE_ELEMENT_LOCAL(FBO0_ID, ResourceId()); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { - GetResourceManager()->ReplaceResource(FBO0_ID, m_FBO0_ID); + // this chunk has been replaced by the ContextConfiguration chunk. Previously this was used to + // register the ID of a framebuffer on another context, so it can be redirected to a single + // global FBO0. But now each context's FBO0 is unique. So if this is present, we also have the + // global FBO0 to redirect to. + ResourceId global_fbo0 = GetResourceManager()->GetID(FramebufferRes(GetCtx(), m_Global_FBO0)); + + GetResourceManager()->ReplaceResource(FBO0_ID, global_fbo0); AddResource(FBO0_ID, ResourceType::SwapchainImage, ""); GetReplay()->GetResourceDesc(FBO0_ID).SetCustomName("Window FBO"); // this is a hack, but we only support a single 'default' framebuffer so we set these // replacements up as derived resources - GetReplay()->GetResourceDesc(m_FBO0_ID).derivedResources.push_back(FBO0_ID); - GetReplay()->GetResourceDesc(FBO0_ID).parentResources.push_back(m_FBO0_ID); + GetReplay()->GetResourceDesc(global_fbo0).derivedResources.push_back(FBO0_ID); + GetReplay()->GetResourceDesc(FBO0_ID).parentResources.push_back(global_fbo0); } return true; @@ -2789,8 +2858,13 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk) draw.name = "SwapBuffers()"; draw.flags |= DrawFlags::Present; + GLuint col = 0; + GL.glGetNamedFramebufferAttachmentParameterivEXT(m_CurrentDefaultFBO, eGL_COLOR_ATTACHMENT0, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + (GLint *)&col); + draw.copyDestination = GetResourceManager()->GetOriginalID( - GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_Color))); + GetResourceManager()->GetID(TextureRes(GetCtx(), col))); AddDrawcall(draw, true); } @@ -2811,9 +2885,9 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk) { case GLChunk::DeviceInitialisation: { - ResourceId vao; + ResourceId vao, fbo; SERIALISE_ELEMENT(vao).Hidden(); - SERIALISE_ELEMENT(m_FBO0_ID).Named("FBO 0 ID"); + SERIALISE_ELEMENT(fbo).Named("FBO 0 ID"); SERIALISE_CHECK_READ_ERRORS(); @@ -2823,36 +2897,18 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk) // it can be bound and have initial contents applied to it if(vao != ResourceId()) { - glGenVertexArrays(1, &m_Fake_VAO0); - glBindVertexArray(m_Fake_VAO0); - GetResourceManager()->AddLiveResource(vao, VertexArrayRes(GetCtx(), m_Fake_VAO0)); + glGenVertexArrays(1, &m_Global_VAO0); + glBindVertexArray(m_Global_VAO0); + GetResourceManager()->AddLiveResource(vao, VertexArrayRes(GetCtx(), m_Global_VAO0)); AddResource(vao, ResourceType::StateObject, "Vertex Array"); GetReplay()->GetResourceDesc(vao).SetCustomName("Default VAO"); GetReplay()->GetResourceDesc(vao).initialisationChunks.push_back(m_InitChunkIndex); } - GetResourceManager()->AddLiveResource(m_FBO0_ID, FramebufferRes(GetCtx(), m_FakeBB_FBO)); - - AddResource(m_FBO0_ID, ResourceType::SwapchainImage, ""); - GetReplay()->GetResourceDesc(m_FBO0_ID).SetCustomName("Default FBO"); - - GetReplay()->GetResourceDesc(m_FBO0_ID).initialisationChunks.push_back(m_InitChunkIndex); - - ResourceId colorId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_Color)); - GetReplay()->GetResourceDesc(colorId).initialisationChunks.push_back(m_InitChunkIndex); - GetReplay()->GetResourceDesc(m_FBO0_ID).derivedResources.push_back(colorId); - GetReplay()->GetResourceDesc(colorId).parentResources.push_back(m_FBO0_ID); - - if(m_FakeBB_DepthStencil) - { - ResourceId depthId = - GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_DepthStencil)); - GetReplay()->GetResourceDesc(depthId).initialisationChunks.push_back(m_InitChunkIndex); - - GetReplay()->GetResourceDesc(m_FBO0_ID).derivedResources.push_back(depthId); - GetReplay()->GetResourceDesc(depthId).parentResources.push_back(m_FBO0_ID); - } + // similar behaviour for a single global FBO 0. + if(fbo != ResourceId()) + CreateReplayBackbuffer(m_GlobalInitParams, fbo, m_Global_FBO0, "Backbuffer"); } return true; @@ -3919,6 +3975,8 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk) // re-use the serialisation for beginning of the frame return Serialise_BeginCaptureFrame(ser); + case GLChunk::ContextConfiguration: return Serialise_ContextConfiguration(ser, NULL); + case GLChunk::glIndirectSubCommand: // this is a fake chunk generated at runtime as part of indirect draws. // Just in case it gets exported and imported, completely ignore it. diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 8bacd7bf8..6b678a23d 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -54,7 +54,7 @@ struct GLInitParams bool isYFlipped; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x1D; + static const uint64_t CurrentVersion = 0x1E; static bool IsSupportedVersion(uint64_t ver); }; @@ -122,8 +122,8 @@ private: GLReplay m_Replay; RDCDriver m_DriverType; - GLInitParams m_InitParams; uint64_t m_SectionVersion; + GLInitParams m_GlobalInitParams; WriteSerialiser m_ScratchSerialiser; std::set m_StringDB; @@ -257,12 +257,15 @@ private: vector> m_DependentReplacements; - GLuint m_FakeBB_FBO; - GLuint m_FakeBB_Color; - GLuint m_FakeBB_DepthStencil; - ResourceId m_FBO0_ID; + // this object is only created on old captures where VAO0 was a single global object. In new + // captures each context has its own VAO0. + GLuint m_Global_VAO0 = 0; - GLuint m_Fake_VAO0; + // Same principle here, but for FBOs. + GLuint m_Global_FBO0 = 0; + + // This tracks whatever is the FBO for the last bound context + GLuint m_CurrentDefaultFBO; GLuint m_IndirectBuffer = 0; GLsizeiptr m_IndirectBufferSize = 0; @@ -281,8 +284,7 @@ private: template bool Serialise_CaptureScope(SerialiserType &ser); - template - bool Serialise_ContextInit(SerialiserType &ser); + bool Serialise_ContextInit(ReadSerialiser &ser); bool HasSuccessfulCapture(CaptureFailReason &reason) { @@ -296,6 +298,9 @@ private: void FinishCapture(); void ContextEndFrame(); + template + bool Serialise_ContextConfiguration(SerialiserType &ser, void *ctx); + void CleanupResourceRecord(GLResourceRecord *record, bool freeParents); void CleanupCapture(); void FreeCaptureData(); @@ -337,6 +342,8 @@ private: bool attribsCreate; bool isCore; + GLInitParams initParams; + // map from window handle void* to uint64_t unix timestamp with // the last time a window was seen/associated with this context. // Decays after a few seconds since there's no good explicit @@ -390,6 +397,8 @@ private: ResourceId m_ContextDataResourceID; GLResourceRecord *m_ContextDataRecord; + + ResourceId m_ContextFBOID; }; struct ClientMemoryData @@ -443,8 +452,8 @@ private: static const int FONT_TEX_HEIGHT = 128; static const int FONT_MAX_CHARS = 256; - void RenderOverlayText(float x, float y, bool yflipped, const char *fmt, ...); - void RenderOverlayStr(float x, float y, bool yflipped, const char *str); + void RenderOverlayText(float x, float y, const char *fmt, ...); + void RenderOverlayStr(float x, float y, const char *str); struct BackbufferImage { @@ -456,6 +465,9 @@ private: uint16_t thheight; }; + void CreateReplayBackbuffer(const GLInitParams ¶ms, ResourceId fboOrigId, GLuint &fbo, + std::string bbname); + BackbufferImage *SaveBackbufferImage(); map m_BackbufferImages; @@ -488,7 +500,6 @@ public: void SetDriverType(RDCDriver type) { m_DriverType = type; } bool isGLESMode() { return m_DriverType == RDCDriver::OpenGLES; } RDCDriver GetDriverType() { return m_DriverType; } - GLInitParams &GetInitParams() { return m_InitParams; } ContextPair &GetCtx(); GLResourceRecord *GetContextRecord(); @@ -516,8 +527,8 @@ public: void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers); - GLuint GetFakeVAO0() { return m_Fake_VAO0; } - GLuint GetFakeBBFBO() { return m_FakeBB_FBO; } + GLuint GetFakeVAO0() { return m_Global_VAO0; } + GLuint GetCurrentDefaultFBO() { return m_CurrentDefaultFBO; } FrameRecord &GetFrameRecord() { return m_FrameRecord; } const APIEvent &GetEvent(uint32_t eventId); @@ -531,8 +542,11 @@ public: void RegisterReplayContext(GLWindowingData winData, void *shareContext, bool core, bool attribsCreate); void DeleteContext(void *contextHandle); + GLInitParams &GetInitParams(GLWindowingData winData) + { + return m_ContextData[winData.ctx].initParams; + } void ActivateContext(GLWindowingData winData); - void WindowSize(void *windowHandle, uint32_t w, uint32_t h); void SwapBuffers(void *windowHandle); void HandleVRFrameMarkers(const GLchar *buf, GLsizei length); bool UsesVRFrameMarkers() { return m_UsesVRMarkers; } diff --git a/renderdoc/driver/gl/gl_renderstate.cpp b/renderdoc/driver/gl/gl_renderstate.cpp index 9bfadf243..5e1dd70c1 100644 --- a/renderdoc/driver/gl/gl_renderstate.cpp +++ b/renderdoc/driver/gl/gl_renderstate.cpp @@ -1130,6 +1130,13 @@ void GLRenderState::FetchState(WrappedOpenGL *driver) GL.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&read); DrawFBO = FramebufferRes(ctx, draw); ReadFBO = FramebufferRes(ctx, read); + + // if the default FBO is bound, we must force the use of the context itself, rather than the + // sharegroup (if FBOs are normally shared). + if(draw == 0) + DrawFBO = FramebufferRes({ctx.ctx, ctx.ctx}, draw); + if(read == 0) + ReadFBO = FramebufferRes({ctx.ctx, ctx.ctx}, read); } GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, 0); @@ -1606,8 +1613,8 @@ void GLRenderState::ApplyState(WrappedOpenGL *driver) if(driver->GetReplay()->IsReplayContext(ctx.ctx)) { // apply drawbuffers/readbuffer to default framebuffer - GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, driver->GetFakeBBFBO()); - GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, driver->GetFakeBBFBO()); + GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, driver->GetCurrentDefaultFBO()); + GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, driver->GetCurrentDefaultFBO()); GL.glDrawBuffers(numDBs, DBs); // see above for reasoning for this @@ -1616,12 +1623,12 @@ void GLRenderState::ApplyState(WrappedOpenGL *driver) if(ReadFBO.name) GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO.name); else - GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, driver->GetFakeBBFBO()); + GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, driver->GetCurrentDefaultFBO()); if(DrawFBO.name) GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO.name); else - GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, driver->GetFakeBBFBO()); + GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, driver->GetCurrentDefaultFBO()); } GL.glHint(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, Hints.Derivatives); diff --git a/renderdoc/driver/gl/gl_rendertext.cpp b/renderdoc/driver/gl/gl_rendertext.cpp index d03df74ce..88d6d8c56 100644 --- a/renderdoc/driver/gl/gl_rendertext.cpp +++ b/renderdoc/driver/gl/gl_rendertext.cpp @@ -270,7 +270,7 @@ void WrappedOpenGL::ContextData::CreateDebugData() } } -void WrappedOpenGL::RenderOverlayText(float x, float y, bool yflipped, const char *fmt, ...) +void WrappedOpenGL::RenderOverlayText(float x, float y, const char *fmt, ...) { static char tmpBuf[4096]; @@ -286,18 +286,18 @@ void WrappedOpenGL::RenderOverlayText(float x, float y, bool yflipped, const cha textState.Push(ctxdata.Modern()); - RenderOverlayStr(x, y, yflipped, tmpBuf); + RenderOverlayStr(x, y, tmpBuf); textState.Pop(ctxdata.Modern()); } -void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char *text) +void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text) { if(char *t = strchr((char *)text, '\n')) { *t = 0; - RenderOverlayStr(x, y, yflipped, text); - RenderOverlayStr(x, y + 1.0f, yflipped, t + 1); + RenderOverlayStr(x, y, text); + RenderOverlayStr(x, y + 1.0f, t + 1); *t = '\n'; return; } @@ -338,8 +338,8 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char Vec2f(1.0, 0.0), Vec2f(0.0, 1.0), Vec2f(1.0, 1.0), }; - const Vec2f FontScreenAspect(ctxdata.CharAspect / RDCMAX(1.0f, float(m_InitParams.width)), - 1.0f / RDCMAX(1.0f, float(m_InitParams.height))); + const Vec2f FontScreenAspect(ctxdata.CharAspect / RDCMAX(1.0f, float(ctxdata.initParams.width)), + 1.0f / RDCMAX(1.0f, float(ctxdata.initParams.height))); float *vertexData = new float[5 * len * 6]; @@ -360,7 +360,7 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char pos.y -= 1.0f; vertexData[(i * 6 + ch) * 5 + 0] = pos.x; - vertexData[(i * 6 + ch) * 5 + 1] = yflipped ? pos.y : -pos.y; + vertexData[(i * 6 + ch) * 5 + 1] = ctxdata.initParams.isYFlipped ? pos.y : -pos.y; vertexData[(i * 6 + ch) * 5 + 2] = uv.x; vertexData[(i * 6 + ch) * 5 + 3] = uv.y; vertexData[(i * 6 + ch) * 5 + 4] = float(text[i] - FONT_FIRST_CHAR); @@ -411,12 +411,13 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char // set viewport & scissor if(HasExt[ARB_viewport_array]) { - GL.glViewportIndexedf(0, 0.0f, 0.0f, (float)m_InitParams.width, (float)m_InitParams.height); + GL.glViewportIndexedf(0, 0.0f, 0.0f, (float)ctxdata.initParams.width, + (float)ctxdata.initParams.height); GL.glDisablei(eGL_SCISSOR_TEST, 0); } else { - GL.glViewport(0, 0, m_InitParams.width, m_InitParams.height); + GL.glViewport(0, 0, ctxdata.initParams.width, ctxdata.initParams.height); GL.glDisable(eGL_SCISSOR_TEST); } @@ -473,7 +474,7 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char GL.glDisable(eGL_CULL_FACE); // set viewport & scissor - GL.glViewport(0, 0, (GLsizei)m_InitParams.width, (GLsizei)m_InitParams.height); + GL.glViewport(0, 0, (GLsizei)ctxdata.initParams.width, (GLsizei)ctxdata.initParams.height); GL.glDisable(eGL_SCISSOR_TEST); if(!IsGLES) GL.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); @@ -542,7 +543,7 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char vertices.push_back(Vec4f(maxx, miny, 0.0f, 0.0f)); vertices.push_back(Vec4f(minx, miny, 0.0f, 0.0f)); - float mul = yflipped ? -1.0f : 1.0f; + float mul = ctxdata.initParams.isYFlipped ? -1.0f : 1.0f; while(*text) { @@ -567,6 +568,6 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char ++text; } } - m_Platform.DrawQuads((float)m_InitParams.width, (float)m_InitParams.height, vertices); + m_Platform.DrawQuads((float)ctxdata.initParams.width, (float)ctxdata.initParams.height, vertices); } } diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 0f697fbb9..aed06b031 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -202,8 +202,7 @@ std::vector GLReplay::GetTextures() auto &res = m_pDriver->m_Textures[it->first]; // skip textures that aren't from the log (except the 'default backbuffer' textures) - if(res.resource.name != m_pDriver->m_FakeBB_Color && - res.resource.name != m_pDriver->m_FakeBB_DepthStencil && + if(!(res.creationFlags & TextureCategory::SwapBuffer) && m_pDriver->GetResourceManager()->GetOriginalID(it->first) == it->first) continue; @@ -489,8 +488,6 @@ void GLReplay::CacheTexture(ResourceId id) } tex.creationFlags = res.creationFlags; - if(res.resource.name == drv.m_FakeBB_Color || res.resource.name == drv.m_FakeBB_DepthStencil) - tex.creationFlags |= TextureCategory::SwapBuffer; // surely this will be the same for each level... right? that would be insane if it wasn't GLint fmt = 0; diff --git a/renderdoc/driver/gl/gl_stringise.cpp b/renderdoc/driver/gl/gl_stringise.cpp index 04717cbe4..9524e8e1a 100644 --- a/renderdoc/driver/gl/gl_stringise.cpp +++ b/renderdoc/driver/gl/gl_stringise.cpp @@ -41,6 +41,8 @@ std::string DoStringise(const GLChunk &el) STRINGISE_ENUM_CLASS(vrapi_CreateTextureSwapChain); STRINGISE_ENUM_CLASS(vrapi_CreateTextureSwapChain2); + STRINGISE_ENUM_CLASS_NAMED(ContextConfiguration, "Context Configuration"); + // re-use list of GL functions as chunks. Many of these will be aliased. This may not appear in the // same order as the definition, but that's OK. #define StringiseFunction(function, alias) STRINGISE_ENUM_CLASS_NAMED(alias, STRINGIZE(alias)); diff --git a/renderdoc/driver/gl/glx_hooks.cpp b/renderdoc/driver/gl/glx_hooks.cpp index 1984ed0de..2d00071a8 100644 --- a/renderdoc/driver/gl/glx_hooks.cpp +++ b/renderdoc/driver/gl/glx_hooks.cpp @@ -62,6 +62,26 @@ public: m_GLXWindowMap.erase(it); } + void UpdateWindowSize(GLWindowingData data, Display *dpy, GLXDrawable drawable) + { + // if we use the GLXDrawable in XGetGeometry and it's a GLXWindow, then we get + // a BadDrawable error and things go south. Instead we track GLXWindows created + // in glXCreateWindow/glXDestroyWindow and look up the source window it was + // created from to use that. + // If the drawable didn't come through there, it just passes through unscathed + // through this function + Drawable d = UnwrapGLXWindow(drawable); + + Window root; + int x, y; + unsigned int width, height, border_width, depth; + XGetGeometry(dpy, d, &root, &x, &y, &width, &height, &border_width, &depth); + + GLInitParams ¶ms = driver.GetInitParams(data); + params.width = width; + params.height = height; + } + // default to RTLD_NEXT for GLX lookups if we haven't gotten a more specific library handle void *handle = RTLD_NEXT; WrappedOpenGL driver; @@ -322,6 +342,8 @@ HOOK_EXPORT Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext c glxhook.driver.ActivateContext(data); + glxhook.UpdateWindowSize(data, dpy, drawable); + if(config) XFree(config); if(data.cfg) @@ -387,6 +409,8 @@ HOOK_EXPORT Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawab glxhook.driver.ActivateContext(data); + glxhook.UpdateWindowSize(data, dpy, draw); + if(config) XFree(config); if(data.cfg) @@ -408,21 +432,6 @@ HOOK_EXPORT void glXSwapBuffers(Display *dpy, GLXDrawable drawable) SCOPED_LOCK(glLock); - // if we use the GLXDrawable in XGetGeometry and it's a GLXWindow, then we get - // a BadDrawable error and things go south. Instead we track GLXWindows created - // in glXCreateWindow/glXDestroyWindow and look up the source window it was - // created from to use that. - // If the drawable didn't come through there, it just passes through unscathed - // through this function - Drawable d = glxhook.UnwrapGLXWindow(drawable); - - Window root; - int x, y; - unsigned int width, height, border_width, depth; - XGetGeometry(dpy, d, &root, &x, &y, &width, &height, &border_width, &depth); - - glxhook.driver.WindowSize((void *)drawable, width, height); - glxhook.driver.SwapBuffers((void *)drawable); GLX.glXSwapBuffers(dpy, drawable); diff --git a/renderdoc/driver/gl/wgl_hooks.cpp b/renderdoc/driver/gl/wgl_hooks.cpp index 4f60d895e..13d3162e3 100644 --- a/renderdoc/driver/gl/wgl_hooks.cpp +++ b/renderdoc/driver/gl/wgl_hooks.cpp @@ -145,11 +145,6 @@ void WGLHook::ProcessSwapBuffers(HDC dc) if(w != NULL && haveContextCreation && !swapRecurse) { - RECT r; - GetClientRect(w, &r); - - driver.WindowSize(w, r.right - r.left, r.bottom - r.top); - { SCOPED_LOCK(glLock); driver.SwapBuffers(w); @@ -375,7 +370,16 @@ static BOOL WINAPI wglMakeCurrent_hooked(HDC dc, HGLRC rc) data.ctx = rc; if(wglhook.haveContextCreation) + { + RECT r; + GetClientRect(data.wnd, &r); + wglhook.driver.ActivateContext(data); + + GLInitParams ¶ms = wglhook.driver.GetInitParams(data); + params.width = r.right - r.left; + params.height = r.bottom - r.top; + } } SetLastError(err); diff --git a/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp index 77be7b3ce..887e0847c 100644 --- a/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp @@ -3040,7 +3040,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribOffsetEXT( if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; // some intel drivers don't properly update query states (like GL_VERTEX_ATTRIB_ARRAY_SIZE) // unless the VAO is also bound when performing EXT_dsa functions :( @@ -3166,7 +3166,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribIOffsetEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; // some intel drivers don't properly update query states (like GL_VERTEX_ATTRIB_ARRAY_SIZE) // unless the VAO is also bound when performing EXT_dsa functions :( @@ -3292,7 +3292,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribLOffsetEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; // some intel drivers don't properly update query states (like GL_VERTEX_ATTRIB_ARRAY_SIZE) // unless the VAO is also bound when performing EXT_dsa functions :( @@ -3413,7 +3413,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribBindingEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GL.glVertexArrayVertexAttribBindingEXT(vaobj.name, attribindex, bindingindex); } @@ -3498,7 +3498,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribFormatEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GL.glVertexArrayVertexAttribFormatEXT(vaobj.name, attribindex, size, type, normalized, relativeoffset); @@ -3588,7 +3588,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribIFormatEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GL.glVertexArrayVertexAttribIFormatEXT(vaobj.name, attribindex, size, type, relativeoffset); } @@ -3675,7 +3675,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribLFormatEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GL.glVertexArrayVertexAttribLFormatEXT(vaobj.name, attribindex, size, type, relativeoffset); } @@ -3759,7 +3759,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexAttribDivisorEXT(SerialiserType if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; // at the time of writing, AMD driver seems to not have this entry point if(GL.glVertexArrayVertexAttribDivisorEXT) @@ -3849,7 +3849,7 @@ bool WrappedOpenGL::Serialise_glEnableVertexArrayAttribEXT(SerialiserType &ser, if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GLint prevVAO = 0; GL.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, &prevVAO); @@ -3932,7 +3932,7 @@ bool WrappedOpenGL::Serialise_glDisableVertexArrayAttribEXT(SerialiserType &ser, if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GLint prevVAO = 0; GL.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, &prevVAO); @@ -4131,7 +4131,7 @@ bool WrappedOpenGL::Serialise_glBindVertexArray(SerialiserType &ser, GLuint vaob if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GL.glBindVertexArray(vaobj.name); } @@ -4182,7 +4182,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayElementBuffer(SerialiserType &ser, GL if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; // might not have the live resource if this is a pre-capture chunk, and the buffer was never // referenced at all in the actual frame @@ -4253,7 +4253,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayBindVertexBufferEXT(SerialiserType &s if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; if(buffer.name) { @@ -4390,7 +4390,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexBuffers(SerialiserType &ser, GL } if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; // use ARB_direct_state_access functions here as we use EXT_direct_state_access elsewhere. If // we are running without ARB_dsa support, these functions are emulated in the obvious way. This @@ -4518,7 +4518,7 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexBindingDivisorEXT(SerialiserTyp if(IsReplayingAndReading()) { if(vaobj.name == 0) - vaobj.name = m_Fake_VAO0; + vaobj.name = m_Global_VAO0; GL.glVertexArrayVertexBindingDivisorEXT(vaobj.name, bindingindex, divisor); } diff --git a/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp index fab03e825..ccce717ef 100644 --- a/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp @@ -3321,7 +3321,7 @@ bool WrappedOpenGL::Serialise_glClearNamedFramebufferfv(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; // use ARB_direct_state_access functions here as we use EXT_direct_state_access elsewhere. If // we are running without ARB_dsa support, these functions are emulated in the obvious way. This @@ -3447,7 +3447,7 @@ bool WrappedOpenGL::Serialise_glClearNamedFramebufferiv(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; // use ARB_direct_state_access functions here as we use EXT_direct_state_access elsewhere. If // we are running without ARB_dsa support, these functions are emulated in the obvious way. This @@ -3564,7 +3564,7 @@ bool WrappedOpenGL::Serialise_glClearNamedFramebufferuiv(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; // use ARB_direct_state_access functions here as we use EXT_direct_state_access elsewhere. If // we are running without ARB_dsa support, these functions are emulated in the obvious way. This @@ -3670,7 +3670,7 @@ bool WrappedOpenGL::Serialise_glClearNamedFramebufferfi(SerialiserType &ser, GLu if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; // use ARB_direct_state_access functions here as we use EXT_direct_state_access elsewhere. If // we are running without ARB_dsa support, these functions are emulated in the obvious way. This diff --git a/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp index 2648f6fdf..e6244cf47 100644 --- a/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp @@ -164,7 +164,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferTextureEXT(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glNamedFramebufferTextureEXT(framebuffer.name, attachment, texture.name, level); @@ -305,7 +305,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferTexture1DEXT(SerialiserType &ser if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glNamedFramebufferTexture1DEXT(framebuffer.name, attachment, textarget, texture.name, level); @@ -449,7 +449,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferTexture2DEXT(SerialiserType &ser if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glNamedFramebufferTexture2DEXT(framebuffer.name, attachment, textarget, texture.name, level); @@ -594,7 +594,7 @@ bool WrappedOpenGL::Serialise_glFramebufferTexture2DMultisampleEXT( if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GLuint prevread = 0, prevdraw = 0; GL.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prevdraw); @@ -702,7 +702,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferTexture3DEXT(SerialiserType &ser if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glNamedFramebufferTexture3DEXT(framebuffer.name, attachment, textarget, texture.name, level, zoffset); @@ -850,7 +850,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferRenderbufferEXT(SerialiserType & if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glNamedFramebufferRenderbufferEXT(framebuffer.name, attachment, renderbuffertarget, renderbuffer.name); @@ -979,7 +979,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferTextureLayerEXT(SerialiserType & if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glNamedFramebufferTextureLayerEXT(framebuffer.name, attachment, texture.name, level, layer); @@ -1343,7 +1343,7 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferParameteriEXT(SerialiserType &se if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; if(framebuffer.name) GL.glNamedFramebufferParameteriEXT(framebuffer.name, pname, param); @@ -1411,7 +1411,7 @@ bool WrappedOpenGL::Serialise_glFramebufferReadBufferEXT(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; // since we are faking the default framebuffer with our own // to see the results, replace back/front/left/right with color attachment 0 @@ -1488,7 +1488,7 @@ bool WrappedOpenGL::Serialise_glBindFramebuffer(SerialiserType &ser, GLenum targ if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GL.glBindFramebuffer(target, framebuffer.name); } @@ -1532,7 +1532,7 @@ bool WrappedOpenGL::Serialise_glFramebufferDrawBufferEXT(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; // since we are faking the default framebuffer with our own // to see the results, replace back/front/left/right with color attachment 0 @@ -1611,7 +1611,7 @@ bool WrappedOpenGL::Serialise_glFramebufferDrawBuffersEXT(SerialiserType &ser, if(IsReplayingAndReading()) { if(framebuffer.name == 0) - framebuffer.name = m_FakeBB_FBO; + framebuffer.name = m_CurrentDefaultFBO; GLenum *buffers = (GLenum *)bufs; @@ -1826,9 +1826,9 @@ bool WrappedOpenGL::Serialise_glBlitNamedFramebuffer(SerialiserType &ser, if(IsReplayingAndReading()) { if(readFramebuffer.name == 0) - readFramebuffer.name = m_FakeBB_FBO; + readFramebuffer.name = m_CurrentDefaultFBO; if(drawFramebuffer.name == 0) - drawFramebuffer.name = m_FakeBB_FBO; + drawFramebuffer.name = m_CurrentDefaultFBO; // use ARB_direct_state_access functions here as we use EXT_direct_state_access elsewhere. If // we are running without ARB_dsa support, these functions are emulated in the obvious way. This // is necessary since these functions can be serialised even if ARB_dsa was not used originally,