Refactor shader editing to more reliable approach

* When we replace a shader in GL there are a few knock-ons: we need to replace
  the programs that use this shader, and then from there we need to replace the
  pipelines that use the program. We also need to beware of programs created
  with glCreateShaderProgramv which refer to themselves as both a program and a
  shader.
* Previously we'd look at the edited shader, then recurse and look at programs,
  then recurse and look at pipelines. We'd try to remember which one replaced
  which so we could undo it again.
* Now we just do this in subsequent passes since there is only a one-way
  dependency: First replace the shader as needed, then update any programs and
  either replace or remove replacement as needed, and finally update any
  pipelines.
* On Vulkan and D3D12 it's simpler as we just have shaders -> pipelines but the
  same principle applies.
This commit is contained in:
baldurk
2019-09-05 19:52:27 +01:00
parent 9627332667
commit 190cba427c
9 changed files with 499 additions and 371 deletions
+9 -2
View File
@@ -243,12 +243,18 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara
m_InitParams = params;
WrappedID3D12Resource1::m_List = NULL;
WrappedID3D12PipelineState::m_List = NULL;
if(RenderDoc::Inst().IsReplayApp())
{
m_State = CaptureState::LoadingReplaying;
if(realDevice)
{
WrappedID3D12Resource1::m_List = new std::map<ResourceId, WrappedID3D12Resource1 *>();
WrappedID3D12PipelineState::m_List = new std::vector<WrappedID3D12PipelineState *>();
}
m_FrameCaptureRecord = NULL;
@@ -258,8 +264,6 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara
{
m_State = CaptureState::BackgroundCapturing;
WrappedID3D12Resource1::m_List = NULL;
if(m_pDevice)
{
typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID, void **);
@@ -421,7 +425,10 @@ WrappedID3D12Device::~WrappedID3D12Device()
SAFE_RELEASE(m_InternalCmds.freecmds[i]);
if(!IsStructuredExporting(m_State))
{
SAFE_DELETE(WrappedID3D12Resource1::m_List);
SAFE_DELETE(WrappedID3D12PipelineState::m_List);
}
for(size_t i = 0; i < m_QueueFences.size(); i++)
{
+109 -81
View File
@@ -2849,106 +2849,134 @@ void D3D12Replay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf sourc
void D3D12Replay::ReplaceResource(ResourceId from, ResourceId to)
{
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
// replace the shader module
m_pDevice->GetResourceManager()->ReplaceResource(from, to);
// remove any previous replacement
RemoveReplacement(from);
if(rm->HasLiveResource(from))
{
ID3D12DeviceChild *resource = rm->GetLiveResource(from);
if(WrappedID3D12Shader::IsAlloc(resource))
{
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)resource;
for(size_t i = 0; i < sh->m_Pipes.size(); i++)
{
WrappedID3D12PipelineState *pipe = sh->m_Pipes[i];
ResourceId id = rm->GetOriginalID(pipe->GetResourceID());
ID3D12PipelineState *replpipe = NULL;
D3D12_SHADER_BYTECODE shDesc = rm->GetLiveAs<WrappedID3D12Shader>(to)->GetDesc();
if(pipe->graphics)
{
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC desc = *pipe->graphics;
D3D12_SHADER_BYTECODE *shaders[] = {
&desc.VS, &desc.HS, &desc.DS, &desc.GS, &desc.PS,
};
for(size_t s = 0; s < ARRAY_COUNT(shaders); s++)
{
if(shaders[s]->BytecodeLength > 0)
{
WrappedID3D12Shader *stage = (WrappedID3D12Shader *)shaders[s]->pShaderBytecode;
if(stage->GetResourceID() == from)
*shaders[s] = shDesc;
else
*shaders[s] = stage->GetDesc();
}
}
m_pDevice->CreatePipeState(desc, &replpipe);
}
else
{
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC desc = *pipe->compute;
// replace the shader
desc.CS = shDesc;
m_pDevice->CreatePipeState(desc, &replpipe);
}
rm->ReplaceResource(id, GetResID(replpipe));
}
}
rm->ReplaceResource(from, to);
}
// now update any derived resources
RefreshDerivedReplacements();
ClearPostVSCache();
}
void D3D12Replay::RemoveReplacement(ResourceId id)
{
if(m_pDevice->GetResourceManager()->HasReplacement(id))
{
m_pDevice->GetResourceManager()->RemoveReplacement(id);
RefreshDerivedReplacements();
ClearPostVSCache();
}
}
void D3D12Replay::RefreshDerivedReplacements()
{
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
rm->RemoveReplacement(id);
// we defer deletes of old replaced resources since it will invalidate elements in the vector
// we're iterating
std::vector<ID3D12PipelineState *> deletequeue;
if(rm->HasLiveResource(id))
for(WrappedID3D12PipelineState *pipe : WrappedID3D12PipelineState::GetList())
{
ID3D12DeviceChild *resource = rm->GetLiveResource(id);
ResourceId pipesrcid = pipe->GetResourceID();
ResourceId origsrcid = rm->GetOriginalID(pipesrcid);
if(WrappedID3D12Shader::IsAlloc(resource))
// only look at pipelines from the capture, no replay-time programs.
if(origsrcid == pipesrcid)
continue;
// if this pipeline has a replacement, remove it and delete the program generated for it
if(rm->HasReplacement(origsrcid))
{
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)resource;
deletequeue.push_back(rm->GetLiveAs<ID3D12PipelineState>(origsrcid));
for(size_t i = 0; i < sh->m_Pipes.size(); i++)
rm->RemoveReplacement(origsrcid);
}
bool usesReplacedShader = false;
if(pipe->IsGraphics())
{
ResourceId shaders[5];
if(pipe->VS())
shaders[0] = rm->GetOriginalID(pipe->VS()->GetResourceID());
if(pipe->HS())
shaders[1] = rm->GetOriginalID(pipe->HS()->GetResourceID());
if(pipe->DS())
shaders[2] = rm->GetOriginalID(pipe->DS()->GetResourceID());
if(pipe->GS())
shaders[3] = rm->GetOriginalID(pipe->GS()->GetResourceID());
if(pipe->PS())
shaders[4] = rm->GetOriginalID(pipe->PS()->GetResourceID());
for(size_t i = 0; i < ARRAY_COUNT(shaders); i++)
{
WrappedID3D12PipelineState *pipe = sh->m_Pipes[i];
ResourceId pipeid = rm->GetOriginalID(pipe->GetResourceID());
if(rm->HasReplacement(pipeid))
{
// if there was an active replacement, remove the dependent replaced pipelines.
ID3D12DeviceChild *replpipe = rm->GetLiveResource(pipeid);
rm->RemoveReplacement(pipeid);
SAFE_RELEASE(replpipe);
}
usesReplacedShader = rm->HasReplacement(shaders[i]);
if(usesReplacedShader)
break;
}
}
else
{
if(rm->HasReplacement(rm->GetOriginalID(pipe->CS()->GetResourceID())))
{
usesReplacedShader = true;
}
}
// if there are replaced shaders in use, create a new pipeline with any/all replaced shaders.
if(usesReplacedShader)
{
ID3D12PipelineState *newpipe = NULL;
if(pipe->IsGraphics())
{
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC desc = *pipe->graphics;
D3D12_SHADER_BYTECODE *shaders[] = {
&desc.VS, &desc.HS, &desc.DS, &desc.GS, &desc.PS,
};
for(size_t s = 0; s < ARRAY_COUNT(shaders); s++)
{
if(shaders[s]->BytecodeLength > 0)
{
WrappedID3D12Shader *stage = (WrappedID3D12Shader *)shaders[s]->pShaderBytecode;
// remap through the original ID to pick up any replacements
stage = rm->GetLiveAs<WrappedID3D12Shader>(rm->GetOriginalID(stage->GetResourceID()));
*shaders[s] = stage->GetDesc();
}
}
m_pDevice->CreatePipeState(desc, &newpipe);
}
else
{
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC desc = *pipe->compute;
WrappedID3D12Shader *stage = pipe->CS();
// remap through the original ID to pick up any replacements
stage = rm->GetLiveAs<WrappedID3D12Shader>(rm->GetOriginalID(stage->GetResourceID()));
desc.CS = stage->GetDesc();
m_pDevice->CreatePipeState(desc, &newpipe);
}
rm->ReplaceResource(origsrcid, GetResID(newpipe));
}
}
ClearPostVSCache();
for(ID3D12PipelineState *pipe : deletequeue)
{
SAFE_RELEASE(pipe);
}
}
void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
+2
View File
@@ -223,6 +223,8 @@ private:
bool CreateSOBuffers();
void RefreshDerivedReplacements();
void BuildShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry,
const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id,
std::string *errors);
@@ -30,6 +30,7 @@
GPUAddressRangeTracker WrappedID3D12Resource1::m_Addresses;
std::map<ResourceId, WrappedID3D12Resource1 *> *WrappedID3D12Resource1::m_List = NULL;
std::vector<WrappedID3D12PipelineState *> *WrappedID3D12PipelineState::m_List = NULL;
std::map<WrappedID3D12PipelineState::DXBCKey, WrappedID3D12Shader *> WrappedID3D12Shader::m_Shaders;
bool WrappedID3D12Shader::m_InternalResources = false;
+8 -6
View File
@@ -632,6 +632,9 @@ public:
}
}
static std::vector<WrappedID3D12PipelineState *> *m_List;
static std::vector<WrappedID3D12PipelineState *> &GetList() { return *m_List; }
bool IsGraphics() { return graphics != NULL; }
bool IsCompute() { return compute != NULL; }
struct DXBCKey
@@ -724,10 +727,6 @@ public:
else
shader->AddRef();
if(pipeline &&
std::find(shader->m_Pipes.begin(), shader->m_Pipes.end(), pipeline) == shader->m_Pipes.end())
shader->m_Pipes.push_back(pipeline);
return shader;
}
@@ -779,8 +778,6 @@ public:
return m_Mapping;
}
std::vector<WrappedID3D12PipelineState *> m_Pipes;
private:
ShaderEntry(const ShaderEntry &e);
void TryReplaceOriginalByteCode();
@@ -817,9 +814,14 @@ public:
WrappedID3D12PipelineState(ID3D12PipelineState *real, WrappedID3D12Device *device)
: WrappedDeviceChild12(real, device)
{
if(m_List)
m_List->push_back(this);
}
virtual ~WrappedID3D12PipelineState()
{
if(m_List)
m_List->erase(std::find(m_List->begin(), m_List->end(), this));
Shutdown();
if(graphics)
+306 -208
View File
@@ -1577,235 +1577,130 @@ struct ReplacementSearch
void WrappedOpenGL::ReplaceResource(ResourceId from, ResourceId to)
{
RemoveReplacement(from);
if(GetResourceManager()->HasLiveResource(from))
{
GLResource resource = GetResourceManager()->GetLiveResource(to);
ResourceId livefrom = GetResourceManager()->GetLiveID(from);
if(resource.Namespace == eResShader)
{
// need to replace all programs that use this shader
for(auto it = m_Programs.begin(); it != m_Programs.end(); ++it)
{
ResourceId progsrcid = it->first;
ProgramData &progdata = it->second;
PerStageReflections stages;
FillReflectionArray(it->first, stages);
// see if the shader is used
for(int i = 0; i < 6; i++)
{
if(progdata.stageShaders[i] == livefrom)
{
GLuint progsrc = GetResourceManager()->GetCurrentResource(progsrcid).name;
// make a new program
GLuint progdst = glCreateProgram();
ResourceId progdstid = GetResourceManager()->GetID(ProgramRes(GetCtx(), progdst));
// attach all but the i'th shader
for(int j = 0; j < 6; j++)
if(i != j && progdata.stageShaders[j] != ResourceId())
glAttachShader(
progdst, GetResourceManager()->GetCurrentResource(progdata.stageShaders[j]).name);
// attach the new shader
glAttachShader(progdst, resource.name);
// mark separable if previous program was separable
GLint sep = 0;
glGetProgramiv(progsrc, eGL_PROGRAM_SEPARABLE, &sep);
if(sep)
glProgramParameteri(progdst, eGL_PROGRAM_SEPARABLE, GL_TRUE);
ResourceId vs = progdata.stageShaders[0];
ResourceId fs = progdata.stageShaders[4];
if(vs != ResourceId())
CopyProgramAttribBindings(progsrc, progdst, &m_Shaders[vs].reflection);
if(fs != ResourceId())
CopyProgramFragDataBindings(progsrc, progdst, &m_Shaders[fs].reflection);
// link new program
glLinkProgram(progdst);
GLint status = 0;
glGetProgramiv(progdst, eGL_LINK_STATUS, &status);
if(status == 0)
{
GLint len = 1024;
glGetProgramiv(progdst, eGL_INFO_LOG_LENGTH, &len);
char *buffer = new char[len + 1];
glGetProgramInfoLog(progdst, len, NULL, buffer);
buffer[len] = 0;
RDCWARN(
"When making program replacement for shader, program failed to link. Skipping "
"replacement:\n%s",
buffer);
delete[] buffer;
glDeleteProgram(progdst);
}
else
{
PerStageReflections dstStages;
FillReflectionArray(progdstid, dstStages);
std::map<GLint, GLint> translate;
// copy uniforms and set up new location translation table
CopyProgramUniforms(stages, progsrc, dstStages, progdst, &translate);
// start with the original location translation table, to account for any
// capture-replay translation
m_Programs[progdstid].locationTranslate = m_Programs[progsrcid].locationTranslate;
// compose on the one from editing.
for(auto lit = m_Programs[progdstid].locationTranslate.begin();
lit != m_Programs[progdstid].locationTranslate.end(); lit++)
{
auto lit2 = translate.find(lit->second);
if(lit2 != translate.end())
lit->second = lit2->second;
else
lit->second = -1;
}
ResourceId origsrcid = GetResourceManager()->GetOriginalID(progsrcid);
// 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());
m_DependentReplacements.insert(
insertPos,
make_rdcpair(from, Replacement(origsrcid, ProgramRes(GetCtx(), progdst))));
}
break;
}
}
}
}
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,
make_rdcpair(from, Replacement(origsrcid, ProgramPipeRes(GetCtx(), pipedst))));
}
}
}
}
GLResource fromresource = GetResourceManager()->GetLiveResource(from);
GLResource toresource = GetResourceManager()->GetLiveResource(to);
// 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)
if(fromresource.Namespace == toresource.Namespace)
{
GetResourceManager()->RemoveReplacement(from);
// if they're the same type we can just replace directly
GetResourceManager()->ReplaceResource(from, to);
}
else if(fromresource.Namespace == eResProgram && resource.Namespace == eResShader)
else if(fromresource.Namespace == eResProgram && toresource.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
// if we want to replace a program with a shader, this is a glCreateShaderProgramv so we need
// to handle it specially
ResourceId progsrcid = GetResourceManager()->GetLiveID(from);
const ProgramData &progdata = m_Programs[progsrcid];
// if this program has a replacement, remove it and delete the program generated for it
if(GetResourceManager()->HasReplacement(from))
{
glDeleteProgram(GetResourceManager()->GetLiveResource(from).name);
GetResourceManager()->RemoveReplacement(from);
}
GLuint progsrc = GetResourceManager()->GetLiveResource(from).name;
// make a new program
GLuint progdst = glCreateProgram();
ResourceId progdstid = GetResourceManager()->GetID(ProgramRes(GetCtx(), progdst));
// attach the shader
glAttachShader(progdst, GetResourceManager()->GetCurrentResource(to).name);
// mark separable
glProgramParameteri(progdst, eGL_PROGRAM_SEPARABLE, GL_TRUE);
// copy VS or FS bindings as necessary
ResourceId vs = progdata.stageShaders[0];
ResourceId fs = progdata.stageShaders[4];
if(vs != ResourceId())
CopyProgramAttribBindings(progsrc, progdst, &m_Shaders[vs].reflection);
if(fs != ResourceId())
CopyProgramFragDataBindings(progsrc, progdst, &m_Shaders[fs].reflection);
// link new program
glLinkProgram(progdst);
GLint status = 0;
glGetProgramiv(progdst, eGL_LINK_STATUS, &status);
if(status == 0)
{
GLint len = 1024;
glGetProgramiv(progdst, eGL_INFO_LOG_LENGTH, &len);
char *buffer = new char[len + 1];
glGetProgramInfoLog(progdst, len, NULL, buffer);
buffer[len] = 0;
RDCWARN(
"When making program replacement for glCreateShaderProgramv shader, program failed "
"to link. Skipping replacement:\n%s",
buffer);
delete[] buffer;
glDeleteProgram(progdst);
}
else
{
PerStageReflections dstStages;
FillReflectionArray(progdstid, dstStages);
std::map<GLint, GLint> translate;
PerStageReflections stages;
FillReflectionArray(progsrcid, stages);
// copy uniforms and set up new location translation table
CopyProgramUniforms(stages, progsrc, dstStages, progdst, &translate);
// start with the original location translation table, to account for any
// capture-replay translation
m_Programs[progdstid].locationTranslate = m_Programs[progsrcid].locationTranslate;
// compose on the one from editing.
for(auto lit = m_Programs[progdstid].locationTranslate.begin();
lit != m_Programs[progdstid].locationTranslate.end(); lit++)
{
auto lit2 = translate.find(lit->second);
if(lit2 != translate.end())
lit->second = lit2->second;
else
lit->second = -1;
}
// replace the program
GetResourceManager()->ReplaceResource(from, progdstid);
}
}
else
{
RDCERR("Unsupported replacement type from type %d to type %d", fromresource.Namespace,
resource.Namespace);
toresource.Namespace);
}
RefreshDerivedReplacements();
}
}
void WrappedOpenGL::RemoveReplacement(ResourceId id)
{
// do actual removal
GetResourceManager()->RemoveReplacement(id);
std::set<ResourceId> 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();)
if(GetResourceManager()->HasReplacement(id))
{
GetResourceManager()->RemoveReplacement(it->second.id);
recurse.insert(it->second.id);
GetResourceManager()->RemoveReplacement(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;
}
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);
RefreshDerivedReplacements();
}
}
@@ -1825,6 +1720,209 @@ void WrappedOpenGL::FreeTargetResource(ResourceId id)
}
}
void WrappedOpenGL::RefreshDerivedReplacements()
{
// we defer deletes of old replaced resources since it will invalidate elements in the vector
// we're iterating
std::vector<GLuint> deletequeue;
// first go through programs and replace any that need to be updated based on whether they have
// any replaced shaders
for(auto it = m_Programs.begin(); it != m_Programs.end(); ++it)
{
ResourceId progsrcid = it->first;
const ProgramData &progdata = it->second;
ResourceId origsrcid = GetResourceManager()->GetOriginalID(progsrcid);
// only look at programs from the capture, no replay-time programs.
if(origsrcid == progsrcid)
continue;
// skip glCreateShaderProgramv programs. We handled this above and we don't want to try and
// create a dependent program or remove the replacement
if(progdata.shaderProgramUnlinkable)
continue;
// if this program has a replacement, remove it and delete the program generated for it
if(GetResourceManager()->HasReplacement(origsrcid))
{
deletequeue.push_back(GetResourceManager()->GetLiveResource(origsrcid).name);
GetResourceManager()->RemoveReplacement(origsrcid);
}
bool usesReplacedShader = false;
for(int i = 0; i < 6; i++)
{
if(GetResourceManager()->HasReplacement(
GetResourceManager()->GetOriginalID(progdata.stageShaders[i])))
{
usesReplacedShader = true;
break;
}
}
// if there are replaced shaders in use, create a new program with any/all replaced shaders.
if(usesReplacedShader)
{
GLuint progsrc = GetResourceManager()->GetCurrentResource(progsrcid).name;
// make a new program
GLuint progdst = glCreateProgram();
ResourceId progdstid = GetResourceManager()->GetID(ProgramRes(GetCtx(), progdst));
// attach shaders, going via the original ID to pick up replacements
for(int i = 0; i < 6; i++)
{
if(progdata.stageShaders[i] != ResourceId())
{
ResourceId shaderorigid = GetResourceManager()->GetOriginalID(progdata.stageShaders[i]);
glAttachShader(progdst, GetResourceManager()->GetLiveResource(shaderorigid).name);
}
}
// mark separable if previous program was separable
GLint sep = 0;
glGetProgramiv(progsrc, eGL_PROGRAM_SEPARABLE, &sep);
if(sep)
glProgramParameteri(progdst, eGL_PROGRAM_SEPARABLE, GL_TRUE);
ResourceId vs = progdata.stageShaders[0];
ResourceId fs = progdata.stageShaders[4];
if(vs != ResourceId())
CopyProgramAttribBindings(progsrc, progdst, &m_Shaders[vs].reflection);
if(fs != ResourceId())
CopyProgramFragDataBindings(progsrc, progdst, &m_Shaders[fs].reflection);
// link new program
glLinkProgram(progdst);
GLint status = 0;
glGetProgramiv(progdst, eGL_LINK_STATUS, &status);
if(status == 0)
{
GLint len = 1024;
glGetProgramiv(progdst, eGL_INFO_LOG_LENGTH, &len);
char *buffer = new char[len + 1];
glGetProgramInfoLog(progdst, len, NULL, buffer);
buffer[len] = 0;
RDCWARN(
"When making program replacement for shader, program failed to link. Skipping "
"replacement:\n%s",
buffer);
delete[] buffer;
glDeleteProgram(progdst);
}
else
{
PerStageReflections dstStages;
FillReflectionArray(progdstid, dstStages);
std::map<GLint, GLint> translate;
PerStageReflections stages;
FillReflectionArray(progsrcid, stages);
// copy uniforms and set up new location translation table
CopyProgramUniforms(stages, progsrc, dstStages, progdst, &translate);
// start with the original location translation table, to account for any
// capture-replay translation
m_Programs[progdstid].locationTranslate = m_Programs[progsrcid].locationTranslate;
// compose on the one from editing.
for(auto lit = m_Programs[progdstid].locationTranslate.begin();
lit != m_Programs[progdstid].locationTranslate.end(); lit++)
{
auto lit2 = translate.find(lit->second);
if(lit2 != translate.end())
lit->second = lit2->second;
else
lit->second = -1;
}
// replace the program
GetResourceManager()->ReplaceResource(origsrcid, progdstid);
}
}
}
for(GLuint prog : deletequeue)
glDeleteProgram(prog);
deletequeue.clear();
// then go through pipelines based on replaced programs, as above
for(auto it = m_Pipelines.begin(); it != m_Pipelines.end(); ++it)
{
ResourceId pipesrcid = it->first;
const PipelineData &pipedata = it->second;
ResourceId origsrcid = GetResourceManager()->GetOriginalID(pipesrcid);
// only look at programs from the capture, no replay-time programs.
if(origsrcid == pipesrcid)
continue;
// if this pipeline has a replacement, remove it and delete the pipeline generated for it
if(GetResourceManager()->HasReplacement(origsrcid))
{
deletequeue.push_back(GetResourceManager()->GetLiveResource(origsrcid).name);
GetResourceManager()->RemoveReplacement(origsrcid);
}
bool usesReplacedProgram = false;
for(int i = 0; i < 6; i++)
{
if(GetResourceManager()->HasReplacement(
GetResourceManager()->GetOriginalID(pipedata.stagePrograms[i])))
{
usesReplacedProgram = true;
break;
}
}
// if there are replaced shaders in use, create a new program with any/all replaced shaders.
if(usesReplacedProgram)
{
// make a new pipeline
GLuint pipedst = 0;
glGenProgramPipelines(1, &pipedst);
ResourceId pipedstid = GetResourceManager()->GetID(ProgramPipeRes(GetCtx(), pipedst));
// attach programs, going via the original ID to pick up replacements
for(int i = 0; i < 6; i++)
{
if(pipedata.stagePrograms[i] != ResourceId())
{
ResourceId progorigid = GetResourceManager()->GetOriginalID(pipedata.stagePrograms[i]);
glUseProgramStages(pipedst, ShaderBit(i),
GetResourceManager()->GetLiveResource(progorigid).name);
}
}
// replace the pipeline
GetResourceManager()->ReplaceResource(origsrcid, pipedstid);
}
}
for(GLuint prog : deletequeue)
glDeleteProgramPipelines(1, &prog);
deletequeue.clear();
}
void WrappedOpenGL::SwapBuffers(WindowingSystem winSystem, void *windowHandle)
{
if(IsBackgroundCapturing(m_State))
+1 -2
View File
@@ -264,8 +264,6 @@ private:
std::map<ResourceId, BufferData> m_Buffers;
std::vector<rdcpair<ResourceId, Replacement>> m_DependentReplacements;
// 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;
@@ -477,6 +475,7 @@ private:
void ReplaceResource(ResourceId from, ResourceId to);
void RemoveReplacement(ResourceId id);
void FreeTargetResource(ResourceId id);
void RefreshDerivedReplacements();
struct QueuedResource
{
+61 -72
View File
@@ -3927,48 +3927,89 @@ void VulkanReplay::FreeTargetResource(ResourceId id)
}
void VulkanReplay::ReplaceResource(ResourceId from, ResourceId to)
{
// replace the shader module
m_pDriver->GetResourceManager()->ReplaceResource(from, to);
// now update any derived resources
RefreshDerivedReplacements();
ClearPostVSCache();
ClearFeedbackCache();
}
void VulkanReplay::RemoveReplacement(ResourceId id)
{
if(m_pDriver->GetResourceManager()->HasReplacement(id))
{
m_pDriver->GetResourceManager()->RemoveReplacement(id);
RefreshDerivedReplacements();
ClearPostVSCache();
ClearFeedbackCache();
}
}
void VulkanReplay::RefreshDerivedReplacements()
{
VkDevice dev = m_pDriver->GetDev();
VulkanResourceManager *rm = m_pDriver->GetResourceManager();
// we're passed in the original ID but we want the live ID for comparison
ResourceId liveid = rm->GetLiveID(from);
// we defer deletes of old replaced resources since it will invalidate elements in the vector
// we're iterating
std::vector<VkPipeline> deletequeue;
VkShaderModule srcShaderModule = rm->GetCurrentHandle<VkShaderModule>(liveid);
VkShaderModule dstShaderModule = rm->GetCurrentHandle<VkShaderModule>(to);
// remake and replace any pipelines that referenced this shader
// remake and replace any pipelines that reference a replaced shader
for(auto it = m_pDriver->m_CreationInfo.m_Pipeline.begin();
it != m_pDriver->m_CreationInfo.m_Pipeline.end(); ++it)
{
bool refdShader = false;
ResourceId pipesrcid = it->first;
const VulkanCreationInfo::Pipeline &pipeInfo = it->second;
ResourceId origsrcid = rm->GetOriginalID(pipesrcid);
// only look at pipelines from the capture, no replay-time programs.
if(origsrcid == pipesrcid)
continue;
// if this pipeline has a replacement, remove it and delete the program generated for it
if(rm->HasReplacement(origsrcid))
{
deletequeue.push_back(rm->GetLiveHandle<VkPipeline>(origsrcid));
rm->RemoveReplacement(origsrcid);
}
bool usesReplacedShader = false;
for(size_t i = 0; i < ARRAY_COUNT(it->second.shaders); i++)
{
if(it->second.shaders[i].module == liveid)
if(rm->HasReplacement(rm->GetOriginalID(it->second.shaders[i].module)))
{
refdShader = true;
usesReplacedShader = true;
break;
}
}
if(refdShader)
// if there are replaced shaders in use, create a new pipeline with any/all replaced shaders.
if(usesReplacedShader)
{
VkPipeline pipe = VK_NULL_HANDLE;
const VulkanCreationInfo::Pipeline &pipeInfo = m_pDriver->m_CreationInfo.m_Pipeline[it->first];
if(pipeInfo.renderpass != ResourceId()) // check if this is a graphics or compute pipeline
{
VkGraphicsPipelineCreateInfo pipeCreateInfo;
m_pDriver->GetShaderCache()->MakeGraphicsPipelineInfo(pipeCreateInfo, it->first);
// replace the relevant module
// replace the modules by going via the live ID to pick up any replacements
for(uint32_t i = 0; i < pipeCreateInfo.stageCount; i++)
{
VkPipelineShaderStageCreateInfo &sh =
(VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[i];
if(sh.module == srcShaderModule)
sh.module = dstShaderModule;
ResourceId shadOrigId = rm->GetOriginalID(GetResID(sh.module));
sh.module = rm->GetLiveHandle<VkShaderModule>(shadOrigId);
}
// if we have pipeline executable properties, capture the data
@@ -3988,10 +4029,10 @@ void VulkanReplay::ReplaceResource(ResourceId from, ResourceId to)
VkComputePipelineCreateInfo pipeCreateInfo;
m_pDriver->GetShaderCache()->MakeComputePipelineInfo(pipeCreateInfo, it->first);
// replace the relevant module
// replace the module by going via the live ID to pick up any replacements
VkPipelineShaderStageCreateInfo &sh = pipeCreateInfo.stage;
RDCASSERT(sh.module == srcShaderModule);
sh.module = dstShaderModule;
ResourceId shadOrigId = rm->GetOriginalID(pipeInfo.shaders[5].module);
sh.module = rm->GetLiveHandle<VkShaderModule>(shadOrigId);
// if we have pipeline executable properties, capture the data
if(m_pDriver->GetExtensions(NULL).ext_KHR_pipeline_executable_properties)
@@ -4007,64 +4048,12 @@ void VulkanReplay::ReplaceResource(ResourceId from, ResourceId to)
}
// remove the replacements
rm->ReplaceResource(it->first, GetResID(pipe));
rm->ReplaceResource(rm->GetOriginalID(it->first), GetResID(pipe));
rm->ReplaceResource(origsrcid, GetResID(pipe));
}
}
// make the actual shader module replacements
rm->ReplaceResource(from, to);
rm->ReplaceResource(liveid, to);
ClearPostVSCache();
ClearFeedbackCache();
}
void VulkanReplay::RemoveReplacement(ResourceId id)
{
VkDevice dev = m_pDriver->GetDev();
VulkanResourceManager *rm = m_pDriver->GetResourceManager();
// we're passed in the original ID but we want the live ID for comparison
ResourceId liveid = rm->GetLiveID(id);
if(!rm->HasReplacement(id))
return;
// remove the actual shader module replacements
rm->RemoveReplacement(id);
rm->RemoveReplacement(liveid);
// remove any replacements on pipelines that referenced this shader
for(auto it = m_pDriver->m_CreationInfo.m_Pipeline.begin();
it != m_pDriver->m_CreationInfo.m_Pipeline.end(); ++it)
{
bool refdShader = false;
for(size_t i = 0; i < ARRAY_COUNT(it->second.shaders); i++)
{
if(it->second.shaders[i].module == liveid)
{
refdShader = true;
break;
}
}
if(refdShader)
{
VkPipeline pipe = rm->GetCurrentHandle<VkPipeline>(it->first);
// delete the replacement pipeline
m_pDriver->vkDestroyPipeline(dev, pipe, NULL);
// remove both live and original replacements, since we will have made these above
rm->RemoveReplacement(it->first);
rm->RemoveReplacement(rm->GetOriginalID(it->first));
}
}
ClearPostVSCache();
ClearFeedbackCache();
for(VkPipeline pipe : deletequeue)
m_pDriver->vkDestroyPipeline(dev, pipe, NULL);
}
ShaderDebugTrace VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
+2
View File
@@ -422,6 +422,8 @@ private:
void FetchTessGSOut(uint32_t eventId);
void ClearPostVSCache();
void RefreshDerivedReplacements();
bool RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginInfo rpbegin, int flags);
bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,