diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 4bda5e218..ac84c22ed 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -1422,7 +1422,7 @@ bool WrappedOpenGL::Serialise_BeginCaptureFrame(bool applyInitialState) if(m_State >= WRITING) { - state.FetchState(); + state.FetchState(GetCtx(), this); } state.Serialise(m_State, GetCtx(), this); @@ -1430,7 +1430,7 @@ bool WrappedOpenGL::Serialise_BeginCaptureFrame(bool applyInitialState) if(m_State <= EXECUTING && applyInitialState) { m_DoStateVerify = false; - state.ApplyState(); + state.ApplyState(GetCtx(), this); m_DoStateVerify = true; } diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp index 05bff55de..e1e3e8cd8 100644 --- a/renderdoc/driver/gl/gl_manager.cpp +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -59,6 +59,12 @@ struct FeedbackInitialData uint64_t Size[4]; }; +struct FramebufferInitialData +{ + GLenum DrawBuffers[8]; + GLenum ReadBuffer; +}; + template<> void Serialiser::Serialise(const char *name, VertexAttribInitialData &el) { @@ -91,6 +97,14 @@ void Serialiser::Serialise(const char *name, FeedbackInitialData &el) Serialise<4>("Size", el.Size); } +template<> +void Serialiser::Serialise(const char *name, FramebufferInitialData &el) +{ + ScopedContext scope(this, this, name, "FramebufferInitialData", 0, true); + Serialise<8>("DrawBuffers", el.DrawBuffers); + Serialise("ReadBuffer", el.ReadBuffer); +} + struct TextureStateInitialData { int32_t baseLevel, maxLevel; @@ -280,6 +294,34 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) SetInitialContents(Id, InitialContentData(TextureRes(res.Context, tex), 0, (byte *)state)); } + else if(res.Namespace == eResFramebuffer) + { + // need to be on the right context, as feedback objects are never shared + void *oldctx = m_GL->SwitchToContext(res.Context); + + GLuint prevread = 0, prevdraw = 0; + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prevdraw); + gl.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&prevread); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, res.name); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, res.name); + + FramebufferInitialData *data = (FramebufferInitialData *)Serialiser::AllocAlignedBuffer(sizeof(FramebufferInitialData)); + RDCEraseMem(data, sizeof(FramebufferInitialData)); + + for(int i=0; i < (int)ARRAY_COUNT(data->DrawBuffers); i++) + gl.glGetIntegerv(GLenum(eGL_DRAW_BUFFER0 + i), (GLint *)&data->DrawBuffers[i]); + + gl.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&data->ReadBuffer); + + SetInitialContents(Id, InitialContentData(GLResource(MakeNullResource), 0, (byte *)data)); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, prevdraw); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevread); + + // restore the previous context + m_GL->SwitchToContext(oldctx); + } else if(res.Namespace == eResFeedback) { // need to be on the right context, as feedback objects are never shared @@ -795,6 +837,26 @@ bool GLResourceManager::Serialise_InitialState(GLResource res) gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, unpackParams[7]); } } + else if(res.Namespace == eResFramebuffer) + { + FramebufferInitialData data; + + if(m_State >= WRITING) + { + FramebufferInitialData *initialdata = (FramebufferInitialData *)GetInitialContents(Id).blob; + memcpy(&data, initialdata, sizeof(data)); + } + + m_pSerialiser->Serialise("Framebuffer object Buffers", data); + + if(m_State < WRITING) + { + byte *blob = Serialiser::AllocAlignedBuffer(sizeof(data)); + memcpy(blob, &data, sizeof(data)); + + SetInitialContents(Id, InitialContentData(GLResource(MakeNullResource), 0, blob)); + } + } else if(res.Namespace == eResFeedback) { FeedbackInitialData data; @@ -936,6 +998,25 @@ void GLResourceManager::Apply_InitialState(GLResource live, InitialContentData i { CopyProgramUniforms(gl, initial.resource.name, live.name); } + else if(live.Namespace == eResFramebuffer) + { + GLuint prevread = 0, prevdraw = 0; + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prevdraw); + gl.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&prevread); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, live.name); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, live.name); + + FramebufferInitialData *data = (FramebufferInitialData *)initial.blob; + + for(int i=0; i < (int)ARRAY_COUNT(data->DrawBuffers); i++) + gl.glDrawBuffers(ARRAY_COUNT(data->DrawBuffers), data->DrawBuffers); + + gl.glReadBuffer(data->ReadBuffer); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, prevdraw); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevread); + } else if(live.Namespace == eResFeedback) { GLuint prevfeedback = 0; diff --git a/renderdoc/driver/gl/gl_renderstate.cpp b/renderdoc/driver/gl/gl_renderstate.cpp index 70dd9a43d..2c9a52ad5 100644 --- a/renderdoc/driver/gl/gl_renderstate.cpp +++ b/renderdoc/driver/gl/gl_renderstate.cpp @@ -37,7 +37,7 @@ GLRenderState::~GLRenderState() { } -void GLRenderState::FetchState() +void GLRenderState::FetchState(void *ctx, WrappedOpenGL *gl) { GLint boolread = 0; // TODO check GL_MAX_* @@ -211,9 +211,17 @@ void GLRenderState::FetchState() m_Real->glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&DrawFBO); m_Real->glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&ReadFBO); + m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, 0); + m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0); + for(size_t i=0; i < ARRAY_COUNT(DrawBuffers); i++) m_Real->glGetIntegerv(GLenum(eGL_DRAW_BUFFER0 + i), (GLint *)&DrawBuffers[i]); + m_Real->glGetIntegerv(eGL_READ_BUFFER, (GLint *)&ReadBuffer); + + m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO); + m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO); + m_Real->glGetIntegerv(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, (GLint *)&Hints.Derivatives); m_Real->glGetIntegerv(eGL_LINE_SMOOTH_HINT, (GLint *)&Hints.LineSmooth); m_Real->glGetIntegerv(eGL_POLYGON_SMOOTH_HINT, (GLint *)&Hints.PolySmooth); @@ -287,7 +295,7 @@ void GLRenderState::FetchState() m_Real->glGetIntegerv(eGL_CULL_FACE_MODE, (GLint *)&CullFace); } -void GLRenderState::ApplyState() +void GLRenderState::ApplyState(void *ctx, WrappedOpenGL *gl) { { GLenum pnames[] = @@ -437,9 +445,6 @@ void GLRenderState::ApplyState() m_Real->glDisablei(eGL_SCISSOR_TEST, s); } - m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO); - m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO); - GLenum DBs[8] = { eGL_NONE }; uint32_t numDBs = 0; for(GLuint i=0; i < (GLuint)ARRAY_COUNT(DrawBuffers); i++) @@ -469,7 +474,17 @@ void GLRenderState::ApplyState() break; } } + + // apply drawbuffers/readbuffer to default framebuffer + m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, gl->GetFakeBBFBO()); + m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, gl->GetFakeBBFBO()); m_Real->glDrawBuffers(numDBs, DBs); + + // see above for reasoning for this + m_Real->glReadBuffer(eGL_COLOR_ATTACHMENT0); + + m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO); + m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO); m_Real->glHint(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, Hints.Derivatives); m_Real->glHint(eGL_LINE_SMOOTH_HINT, Hints.LineSmooth); @@ -565,6 +580,7 @@ void GLRenderState::Clear() RDCEraseEl(DrawFBO); RDCEraseEl(ReadFBO); RDCEraseEl(DrawBuffers); + RDCEraseEl(ReadBuffer); RDCEraseEl(PatchParams); RDCEraseEl(PolygonMode); @@ -746,7 +762,8 @@ void GLRenderState::Serialise(LogState state, void *ctx, WrappedOpenGL *gl) m_pSerialiser->Serialise("GL_SCISSOR.enabled", Scissors[i].enabled); } - m_pSerialiser->Serialise<8>("GL_DRAWBUFFERS", DrawBuffers); + m_pSerialiser->Serialise<8>("GL_DRAW_BUFFERS", DrawBuffers); + m_pSerialiser->Serialise("GL_READ_BUFFER", ReadBuffer); m_pSerialiser->Serialise("GL_FRAGMENT_SHADER_DERIVATIVE_HINT", Hints.Derivatives); m_pSerialiser->Serialise("GL_LINE_SMOOTH_HINT", Hints.LineSmooth); diff --git a/renderdoc/driver/gl/gl_renderstate.h b/renderdoc/driver/gl/gl_renderstate.h index 99a581d77..9e962de12 100644 --- a/renderdoc/driver/gl/gl_renderstate.h +++ b/renderdoc/driver/gl/gl_renderstate.h @@ -36,8 +36,8 @@ struct GLRenderState GLRenderState(const GLHookSet *funcs, Serialiser *ser, LogState state); ~GLRenderState(); - void FetchState(); - void ApplyState(); + void FetchState(void *ctx, WrappedOpenGL *gl); + void ApplyState(void *ctx, WrappedOpenGL *gl); void Clear(); void Serialise(LogState state, void *ctx, WrappedOpenGL *gl); @@ -151,12 +151,15 @@ struct GLRenderState } Scissors[16]; GLuint ReadFBO, DrawFBO; + + // these refer to the states on the default framebuffer. + // Other FBOs serialise them in their resource records. + GLenum ReadBuffer; GLenum DrawBuffers[8]; // TODO: // Image state (GL_IMAGE_BINDING_NAME) // multisampling - // provoking vertex // other misc state :) struct diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 6492f5814..78abe3617 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -820,7 +820,7 @@ void GLReplay::SavePipelineState() MakeCurrentReplayContext(&m_ReplayCtx); GLRenderState rs(&gl.GetHookset(), NULL, READING); - rs.FetchState(); + rs.FetchState(m_ReplayCtx.ctx, &gl); // Index buffer diff --git a/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp index 1acb33247..7b0d8a9f4 100644 --- a/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp @@ -728,26 +728,19 @@ void WrappedOpenGL::glReadBuffer(GLenum mode) if(m_State >= WRITING) { - SCOPED_SERIALISE_CONTEXT(READ_BUFFER); - Serialise_glReadBuffer(mode); - - if(m_State == WRITING_IDLE) + if(m_State == WRITING_CAPFRAME) { - if(GetCtxData().m_ReadFramebufferRecord) - { - Chunk *last = GetCtxData().m_ReadFramebufferRecord->GetLastChunk(); - if(last->GetChunkType() == READ_BUFFER) - { - delete last; - GetCtxData().m_ReadFramebufferRecord->PopChunk(); - } - GetCtxData().m_ReadFramebufferRecord->AddChunk(scope.Get()); - } - else - m_DeviceRecord->AddChunk(scope.Get()); + SCOPED_SERIALISE_CONTEXT(READ_BUFFER); + Serialise_glReadBuffer(mode); + + m_ContextRecord->AddChunk(scope.Get()); } else - m_ContextRecord->AddChunk(scope.Get()); + { + GLResourceRecord *readrecord = GetCtxData().m_ReadFramebufferRecord; + if(readrecord) + GetResourceManager()->MarkDirtyResource(readrecord->GetResourceID()); + } } } @@ -813,12 +806,21 @@ bool WrappedOpenGL::Serialise_glDrawBuffer(GLenum buf) void WrappedOpenGL::glDrawBuffer(GLenum buf) { - if(m_State == WRITING_CAPFRAME) + if(m_State >= WRITING) { - SCOPED_SERIALISE_CONTEXT(DRAW_BUFFER); - Serialise_glDrawBuffer(buf); - - m_ContextRecord->AddChunk(scope.Get()); + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_BUFFER); + Serialise_glDrawBuffer(buf); + + m_ContextRecord->AddChunk(scope.Get()); + } + else + { + GLResourceRecord *drawrecord = GetCtxData().m_DrawFramebufferRecord; + if(drawrecord) + GetResourceManager()->MarkDirtyResource(drawrecord->GetResourceID()); + } } m_Real.glDrawBuffer(buf); @@ -872,15 +874,24 @@ void WrappedOpenGL::glFramebufferDrawBuffersEXT(GLuint framebuffer, GLsizei n, c void WrappedOpenGL::glDrawBuffers(GLsizei n, const GLenum *bufs) { - if(m_State == WRITING_CAPFRAME) + if(m_State >= WRITING) { - SCOPED_SERIALISE_CONTEXT(DRAW_BUFFERS); - if(GetCtxData().m_DrawFramebufferRecord) - Serialise_glFramebufferDrawBuffersEXT(GetResourceManager()->GetCurrentResource(GetCtxData().m_DrawFramebufferRecord->GetResourceID()).name, n, bufs); + GLResourceRecord *drawrecord = GetCtxData().m_DrawFramebufferRecord; + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(DRAW_BUFFERS); + if(drawrecord) + Serialise_glFramebufferDrawBuffersEXT(GetResourceManager()->GetCurrentResource(drawrecord->GetResourceID()).name, n, bufs); + else + Serialise_glFramebufferDrawBuffersEXT(0, n, bufs); + + m_ContextRecord->AddChunk(scope.Get()); + } else - Serialise_glFramebufferDrawBuffersEXT(0, n, bufs); - - m_ContextRecord->AddChunk(scope.Get()); + { + if(drawrecord) + GetResourceManager()->MarkDirtyResource(drawrecord->GetResourceID()); + } } m_Real.glDrawBuffers(n, bufs);