diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 1a6c63f2a..ec6e5fadf 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -1474,8 +1474,8 @@ void WrappedOpenGL::ReplaceResource(ResourceId from, ResourceId to) ResourceId origsrcid = GetResourceManager()->GetOriginalID(progsrcid); - // replaceresource - GetResourceManager()->ReplaceResource(origsrcid, progdstid); + // recursively call to replaceresource (different type - these are programs) + ReplaceResource(origsrcid, progdstid); // insert into m_DependentReplacements auto insertPos = std::lower_bound(m_DependentReplacements.begin(), m_DependentReplacements.end(), from, ReplacementSearch()); @@ -1487,26 +1487,99 @@ void WrappedOpenGL::ReplaceResource(ResourceId from, ResourceId to) } } } - } - GetResourceManager()->ReplaceResource(from, to); + if(resource.Namespace == eResProgram) + { + // need to replace all pipelines that use this program + for(auto it=m_Pipelines.begin(); it != m_Pipelines.end(); ++it) + { + ResourceId pipesrcid = it->first; + PipelineData &pipedata = it->second; + + // see if the program is used + for(int i=0; i < 6; i++) + { + if(pipedata.stagePrograms[i] == livefrom) + { + // make a new pipeline + GLuint pipedst = 0; + glGenProgramPipelines(1, &pipedst); + + ResourceId pipedstid = GetResourceManager()->GetID(ProgramPipeRes(GetCtx(), pipedst)); + + // attach all but the i'th program + for(int j=0; j < 6; j++) + { + if(i != j && pipedata.stagePrograms[j] != ResourceId()) + { + // if this stage was provided by the program we're replacing, use that instead + if(pipedata.stagePrograms[i] == pipedata.stagePrograms[j]) + glUseProgramStages(pipedst, ShaderBit(j), resource.name); + else + glUseProgramStages(pipedst, ShaderBit(j), GetResourceManager()->GetCurrentResource(pipedata.stagePrograms[j]).name); + } + } + + // attach the new program in our stage + glUseProgramStages(pipedst, ShaderBit(i), resource.name); + + ResourceId origsrcid = GetResourceManager()->GetOriginalID(pipesrcid); + + // recursively call to replaceresource (different type - these are programs) + ReplaceResource(origsrcid, pipedstid); + + // insert into m_DependentReplacements + auto insertPos = std::lower_bound(m_DependentReplacements.begin(), m_DependentReplacements.end(), from, ReplacementSearch()); + m_DependentReplacements.insert(insertPos, std::make_pair(from, Replacement(origsrcid, ProgramPipeRes(GetCtx(), pipedst)))); + } + } + } + } + + // do actual replacement + GLResource fromresource = GetResourceManager()->GetLiveResource(from); + + // if they're the same type it's easy, but it could be we want to replace a shader + // inside a program which never had a shader (ie. glCreateShaderProgramv) + if(fromresource.Namespace == resource.Namespace) + { + GetResourceManager()->ReplaceResource(from, to); + } + else if(fromresource.Namespace == eResProgram && resource.Namespace == eResShader) + { + // if we want to replace a program with a shader, assume it's just a program with only one + // shader attached. This will have been handled above in the "programs dependent on this + // shader", so we can just skip doing anything here + } + else + { + RDCERR("Unsupported replacement type from type %d to type %d", fromresource.Namespace, resource.Namespace); + } + } } void WrappedOpenGL::RemoveReplacement(ResourceId id) { + // do actual removal GetResourceManager()->RemoveReplacement(id); + std::set recurse; + // check if there are any dependent replacements, remove if so auto it = std::lower_bound(m_DependentReplacements.begin(), m_DependentReplacements.end(), id, ReplacementSearch()); for(; it != m_DependentReplacements.end(); ) { GetResourceManager()->RemoveReplacement(it->second.id); + recurse.insert(it->second.id); switch(it->second.res.Namespace) { case eResProgram: glDeleteProgram(it->second.res.name); break; + case eResProgramPipe: + glDeleteProgramPipelines(1, &it->second.res.name); + break; default: RDCERR("Unexpected resource type to be freed"); break; @@ -1514,6 +1587,12 @@ void WrappedOpenGL::RemoveReplacement(ResourceId id) it = m_DependentReplacements.erase(it); } + + for(auto recurseit = recurse.begin(); recurseit != recurse.end(); ++recurseit) + { + // recursive call in case there are any dependents on this resource + RemoveReplacement(*recurseit); + } } void WrappedOpenGL::FreeTargetResource(ResourceId id) diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 5b30d4be9..066e316e2 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2669,16 +2669,19 @@ void GLReplay::BuildTargetShader(string source, string entry, const uint32_t com void GLReplay::ReplaceResource(ResourceId from, ResourceId to) { + MakeCurrentReplayContext(&m_ReplayCtx); m_pDriver->ReplaceResource(from, to); } void GLReplay::RemoveReplacement(ResourceId id) { + MakeCurrentReplayContext(&m_ReplayCtx); m_pDriver->RemoveReplacement(id); } void GLReplay::FreeTargetResource(ResourceId id) { + MakeCurrentReplayContext(&m_ReplayCtx); m_pDriver->FreeTargetResource(id); } diff --git a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp index ce35215ae..67959d1c0 100644 --- a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp @@ -344,6 +344,7 @@ bool WrappedOpenGL::Serialise_glCreateShaderProgramv(GLuint program, GLenum type progDetails.linked = true; progDetails.shaders.push_back(liveId); + progDetails.stageShaders[ShaderIdx(Type)] = liveId; auto &shadDetails = m_Shaders[liveId];