Pass bindless feedback data to UI through vulkan pipeline state

* Each binding element within an arrayed descriptor has a bool indicating if
  it's dynamically used or not (which will be set to true if the feedback isn't
  available). Each descriptor has a uint32_t indicating how many elements are
  dynamically used - which is useful for the UI to hide the root of an array
  that has no used elements, or to heuristically decide whether to expand or
  elide the contents.
This commit is contained in:
baldurk
2019-04-03 11:53:13 +01:00
parent 7f56704a92
commit f256218e17
19 changed files with 191 additions and 52 deletions
@@ -744,7 +744,8 @@ QVariantList VulkanPipelineStateViewer::makeSampler(const QString &bindset, cons
// arrange like either UVW: WRAP or UV: WRAP, W: CLAMP
for(int a = 0; a < 3; a++)
{
QString prefix = QString(QLatin1Char("UVW"[a]));
const char *uvw = "UVW";
QString prefix = QString(QLatin1Char(uvw[a]));
if(a == 0 || addr[a] == addr[a - 1])
{
@@ -937,10 +938,12 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails,
BindType bindType = BindType::Unknown;
ShaderStageMask stageBits = ShaderStageMask::Unknown;
bool pushDescriptor = false;
uint32_t dynamicallyUsedCount = 1;
if(bindset < pipe.descriptorSets.count() && bind < pipe.descriptorSets[bindset].bindings.count())
{
pushDescriptor = pipe.descriptorSets[bindset].pushDescriptor;
dynamicallyUsedCount = pipe.descriptorSets[bindset].bindings[bind].dynamicallyUsedCount;
slotBinds = &pipe.descriptorSets[bindset].bindings[bind].binds;
bindType = pipe.descriptorSets[bindset].bindings[bind].type;
stageBits = pipe.descriptorSets[bindset].bindings[bind].stageFlags;
@@ -955,7 +958,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails,
bindType = isrw ? BindType::ReadWriteImage : BindType::ReadOnlyImage;
}
bool usedSlot = bindMap != NULL && bindMap->used;
bool usedSlot = bindMap != NULL && bindMap->used && dynamicallyUsedCount > 0;
bool stageBitsIncluded = bool(stageBits & MaskForStage(stage.stage));
// skip descriptors that aren't for this shader stage
@@ -1025,8 +1028,13 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails,
{
const VKPipe::BindingElement *descriptorBind = NULL;
if(slotBinds != NULL)
{
descriptorBind = &(*slotBinds)[idx];
if(!showNode(usedSlot && descriptorBind->dynamicallyUsed, filledSlot))
continue;
}
if(arrayLength > 1)
{
if(shaderRes && !shaderRes->name.isEmpty())
@@ -1315,18 +1323,20 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta
const rdcarray<VKPipe::BindingElement> *slotBinds = NULL;
BindType bindType = BindType::ConstantBuffer;
ShaderStageMask stageBits = ShaderStageMask::Unknown;
uint32_t dynamicallyUsedCount = 1;
bool pushDescriptor = false;
if(bindset < pipe.descriptorSets.count() && bind < pipe.descriptorSets[bindset].bindings.count())
{
pushDescriptor = pipe.descriptorSets[bindset].pushDescriptor;
dynamicallyUsedCount = pipe.descriptorSets[bindset].bindings[bind].dynamicallyUsedCount;
slotBinds = &pipe.descriptorSets[bindset].bindings[bind].binds;
bindType = pipe.descriptorSets[bindset].bindings[bind].type;
stageBits = pipe.descriptorSets[bindset].bindings[bind].stageFlags;
}
bool usedSlot = bindMap != NULL && bindMap->used;
bool usedSlot = bindMap != NULL && bindMap->used && dynamicallyUsedCount > 0;
bool stageBitsIncluded = bool(stageBits & MaskForStage(stage.stage));
// skip descriptors that aren't for this shader stage
@@ -1385,8 +1395,13 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta
{
const VKPipe::BindingElement *descriptorBind = NULL;
if(slotBinds != NULL)
{
descriptorBind = &(*slotBinds)[idx];
if(!showNode(usedSlot && descriptorBind->dynamicallyUsed, filledSlot))
continue;
}
if(arrayLength > 1)
{
if(cblock != NULL && !cblock->name.isEmpty())
+20 -11
View File
@@ -2095,20 +2095,24 @@ void TextureViewer::InitStageResourcePreviews(ShaderStage stage,
const Bindpoint &key = mapping[idx];
const rdcarray<BoundResource> *resArray = NULL;
uint32_t dynamicallyUsedResCount = 1;
int residx = ResList.indexOf(key);
if(residx >= 0)
resArray = &ResList[residx].resources;
int arrayLen = resArray != NULL ? resArray->count() : 1;
// it's too expensive in bindless-type cases to create a thumbnail for every array element, so
// for now we create one just for the first element and add an array size indicator to the slot
// name
// for(int arrayIdx = 0; arrayIdx < arrayLen; arrayIdx++)
int arrayIdx = 0;
{
resArray = &ResList[residx].resources;
dynamicallyUsedResCount = ResList[residx].dynamicallyUsedCount;
}
const bool collapseArray = dynamicallyUsedResCount > 20;
const int arrayLen = resArray != NULL ? resArray->count() : 1;
for(int arrayIdx = 0; arrayIdx < arrayLen; arrayIdx++)
{
if(resArray && !resArray->at(arrayIdx).dynamicallyUsed)
continue;
ResourceId id = resArray != NULL ? resArray->at(arrayIdx).resourceId : ResourceId();
CompType typeHint = resArray != NULL ? resArray->at(arrayIdx).typeHint : CompType::Typeless;
@@ -2137,8 +2141,10 @@ void TextureViewer::InitStageResourcePreviews(ShaderStage stage,
.arg(rw ? lit("RW ") : lit(""))
.arg(idx);
if(arrayLen > 1)
if(collapseArray)
slotName += QFormatStr(" Arr[%1]").arg(arrayLen);
else
slotName += QFormatStr("[%1]").arg(arrayIdx);
if(copy)
slotName = tr("SRC");
@@ -2177,6 +2183,9 @@ void TextureViewer::InitStageResourcePreviews(ShaderStage stage,
prevIndex++;
InitResourcePreview(prev, show ? id : ResourceId(), typeHint, show, follow, bindName, slotName);
if(collapseArray)
break;
}
}
}
+19 -1
View File
@@ -232,6 +232,7 @@ struct BoundResource
BoundResource()
{
resourceId = ResourceId();
dynamicallyUsed = true;
firstMip = -1;
firstSlice = -1;
typeHint = CompType::Typeless;
@@ -239,6 +240,7 @@ struct BoundResource
BoundResource(ResourceId id)
{
resourceId = id;
dynamicallyUsed = true;
firstMip = -1;
firstSlice = -1;
typeHint = CompType::Typeless;
@@ -264,6 +266,12 @@ struct BoundResource
}
DOCUMENT("A :class:`~renderdoc.ResourceId` identifying the bound resource.");
ResourceId resourceId;
DOCUMENT(R"(``True`` if this binding element is dynamically used.
Some APIs provide fine-grained usage based on dynamic shader feedback, to support 'bindless'
scenarios where only a small sparse subset of bound resources are actually used.
)");
bool dynamicallyUsed = true;
DOCUMENT("For textures, the highest mip level available on this binding, or -1 for all mips");
int firstMip;
DOCUMENT("For textures, the first array slice available on this binding. or -1 for all slices.");
@@ -285,7 +293,10 @@ struct BoundResourceArray
BoundResourceArray() = default;
BoundResourceArray(const BoundResourceArray &) = default;
BoundResourceArray(Bindpoint b) : bindPoint(b) {}
BoundResourceArray(Bindpoint b, const rdcarray<BoundResource> &r) : bindPoint(b), resources(r) {}
BoundResourceArray(Bindpoint b, const rdcarray<BoundResource> &r) : bindPoint(b), resources(r)
{
dynamicallyUsedCount = (uint32_t)r.size();
}
// for convenience for searching the array, we compare only using the BindPoint
bool operator==(const BoundResourceArray &o) const { return bindPoint == o.bindPoint; }
bool operator!=(const BoundResourceArray &o) const { return !(bindPoint == o.bindPoint); }
@@ -295,6 +306,13 @@ struct BoundResourceArray
DOCUMENT("The resources at this bind point");
rdcarray<BoundResource> resources;
DOCUMENT(R"(Lists how many bindings in :data:`resources` are dynamically used.
Some APIs provide fine-grained usage based on dynamic shader feedback, to support 'bindless'
scenarios where only a small sparse subset of bound resources are actually used.
)");
uint32_t dynamicallyUsedCount = 0;
};
DECLARE_REFLECTION_STRUCT(BoundResourceArray);
+6
View File
@@ -1115,9 +1115,12 @@ rdcarray<BoundResourceArray> PipeState::GetReadOnlyResources(ShaderStage stage)
rdcarray<BoundResource> &val = ret.back().resources;
val.resize(bind.descriptorCount);
ret.back().dynamicallyUsedCount = bind.dynamicallyUsedCount;
for(uint32_t i = 0; i < bind.descriptorCount; i++)
{
val[i].resourceId = bind.binds[i].resourceResourceId;
val[i].dynamicallyUsed = bind.binds[i].dynamicallyUsed;
val[i].firstMip = (int)bind.binds[i].firstMip;
val[i].firstSlice = (int)bind.binds[i].firstSlice;
val[i].typeHint = bind.binds[i].viewFormat.compType;
@@ -1266,9 +1269,12 @@ rdcarray<BoundResourceArray> PipeState::GetReadWriteResources(ShaderStage stage)
rdcarray<BoundResource> &val = ret.back().resources;
val.resize(bind.descriptorCount);
ret.back().dynamicallyUsedCount = bind.dynamicallyUsedCount;
for(uint32_t i = 0; i < bind.descriptorCount; i++)
{
val[i].resourceId = bind.binds[i].resourceResourceId;
val[i].dynamicallyUsed = bind.binds[i].dynamicallyUsed;
val[i].firstMip = (int)bind.binds[i].firstMip;
val[i].firstSlice = (int)bind.binds[i].firstSlice;
val[i].typeHint = bind.binds[i].viewFormat.compType;
+33 -14
View File
@@ -37,21 +37,23 @@ struct BindingElement
bool operator==(const BindingElement &o) const
{
return viewResourceId == o.viewResourceId && resourceResourceId == o.resourceResourceId &&
samplerResourceId == o.samplerResourceId && immutableSampler == o.immutableSampler &&
viewFormat == o.viewFormat && swizzle[0] == o.swizzle[0] && swizzle[1] == o.swizzle[1] &&
swizzle[2] == o.swizzle[2] && swizzle[3] == o.swizzle[3] && firstMip == o.firstMip &&
firstSlice == o.firstSlice && numMips == o.numMips && numSlices == o.numSlices &&
byteOffset == o.byteOffset && byteSize == o.byteSize && filter == o.filter &&
addressU == o.addressU && addressV == o.addressV && addressW == o.addressW &&
mipBias == o.mipBias && maxAnisotropy == o.maxAnisotropy &&
compareFunction == o.compareFunction && minLOD == o.minLOD && maxLOD == o.maxLOD &&
borderColor[0] == o.borderColor[0] && borderColor[1] == o.borderColor[1] &&
borderColor[2] == o.borderColor[2] && borderColor[3] == o.borderColor[3] &&
unnormalized == o.unnormalized;
return dynamicallyUsed == o.dynamicallyUsed && viewResourceId == o.viewResourceId &&
resourceResourceId == o.resourceResourceId && samplerResourceId == o.samplerResourceId &&
immutableSampler == o.immutableSampler && viewFormat == o.viewFormat &&
swizzle[0] == o.swizzle[0] && swizzle[1] == o.swizzle[1] && swizzle[2] == o.swizzle[2] &&
swizzle[3] == o.swizzle[3] && firstMip == o.firstMip && firstSlice == o.firstSlice &&
numMips == o.numMips && numSlices == o.numSlices && byteOffset == o.byteOffset &&
byteSize == o.byteSize && filter == o.filter && addressU == o.addressU &&
addressV == o.addressV && addressW == o.addressW && mipBias == o.mipBias &&
maxAnisotropy == o.maxAnisotropy && compareFunction == o.compareFunction &&
minLOD == o.minLOD && maxLOD == o.maxLOD && borderColor[0] == o.borderColor[0] &&
borderColor[1] == o.borderColor[1] && borderColor[2] == o.borderColor[2] &&
borderColor[3] == o.borderColor[3] && unnormalized == o.unnormalized;
}
bool operator<(const BindingElement &o) const
{
if(!(dynamicallyUsed == o.dynamicallyUsed))
return dynamicallyUsed < o.dynamicallyUsed;
if(!(viewResourceId == o.viewResourceId))
return viewResourceId < o.viewResourceId;
if(!(resourceResourceId == o.resourceResourceId))
@@ -121,6 +123,15 @@ struct BindingElement
ResourceId samplerResourceId;
DOCUMENT("``True`` if this is an immutable sampler binding.");
bool immutableSampler = false;
DOCUMENT(R"(``True`` if this binding element is dynamically used.
If set to ``False`` this means that the binding was available to the shader but during execution it
was not referenced. The data gathered for setting this variable is conservative, meaning that only
accesses through arrays will have this calculated to reduce the required feedback bandwidth - single
non-arrayed descriptors may have this value set to ``True`` even if the shader did not use them,
since single descriptors may only be dynamically skipped by control flow.
)");
bool dynamicallyUsed = true;
DOCUMENT("The :class:`ResourceFormat` that the view uses.");
ResourceFormat viewFormat;
@@ -209,13 +220,15 @@ struct DescriptorBinding
bool operator==(const DescriptorBinding &o) const
{
return descriptorCount == o.descriptorCount && type == o.type && stageFlags == o.stageFlags &&
binds == o.binds;
return descriptorCount == o.descriptorCount && dynamicallyUsedCount == o.dynamicallyUsedCount &&
type == o.type && stageFlags == o.stageFlags && binds == o.binds;
}
bool operator<(const DescriptorBinding &o) const
{
if(!(descriptorCount == o.descriptorCount))
return descriptorCount < o.descriptorCount;
if(!(dynamicallyUsedCount == o.dynamicallyUsedCount))
return dynamicallyUsedCount < o.dynamicallyUsedCount;
if(!(type == o.type))
return type < o.type;
if(!(stageFlags == o.stageFlags))
@@ -228,6 +241,12 @@ struct DescriptorBinding
If this binding is empty/non-existant this value will be ``0``.
)");
uint32_t descriptorCount = 0;
DOCUMENT(R"(Lists how many bindings in :data:`binds` are dynamically used. Useful to avoid
redundant iteration to determine whether any bindings are present.
For more information see :data:`VKBindingElement.dynamicallyUsed`.
)");
uint32_t dynamicallyUsedCount = 0;
DOCUMENT("The :class:`BindType` of this binding.");
BindType type = BindType::Unknown;
DOCUMENT("The :class:`ShaderStageMask` where this binding is visible.");
+1 -1
View File
@@ -176,7 +176,7 @@ public:
RDCEraseEl(ret);
return ret;
}
void SavePipelineState() {}
void SavePipelineState(uint32_t eventId) {}
DriverInformation GetDriverInfo()
{
DriverInformation ret = {};
+7 -5
View File
@@ -1524,13 +1524,15 @@ ShaderDebugTrace ReplayProxy::DebugThread(uint32_t eventId, const uint32_t group
}
template <typename ParamSerialiser, typename ReturnSerialiser>
void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser &paramser, ReturnSerialiser &retser)
void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser &paramser, ReturnSerialiser &retser,
uint32_t eventId)
{
const ReplayProxyPacket expectedPacket = eReplayProxy_SavePipelineState;
ReplayProxyPacket packet = eReplayProxy_SavePipelineState;
{
BEGIN_PARAMS();
SERIALISE_ELEMENT(eventId);
END_PARAMS();
}
@@ -1538,7 +1540,7 @@ void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser &paramser, ReturnSer
REMOTE_EXECUTION();
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
{
m_Remote->SavePipelineState();
m_Remote->SavePipelineState(eventId);
if(m_APIProps.pipelineType == GraphicsAPI::D3D11)
m_D3D11PipelineState = *m_Remote->GetD3D11PipelineState();
@@ -1636,9 +1638,9 @@ void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser &paramser, ReturnSer
CheckError(packet, expectedPacket);
}
void ReplayProxy::SavePipelineState()
void ReplayProxy::SavePipelineState(uint32_t eventId)
{
PROXY_FUNCTION(SavePipelineState);
PROXY_FUNCTION(SavePipelineState, eventId);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
@@ -2581,7 +2583,7 @@ bool ReplayProxy::Tick(int type)
GetTextureData(ResourceId(), 0, 0, GetTextureDataParams(), dummy);
break;
}
case eReplayProxy_SavePipelineState: SavePipelineState(); break;
case eReplayProxy_SavePipelineState: SavePipelineState(0); break;
case eReplayProxy_GetUsage: GetUsage(ResourceId()); break;
case eReplayProxy_GetLiveID: GetLiveID(ResourceId()); break;
case eReplayProxy_GetFrameRecord: GetFrameRecord(); break;
+1 -1
View File
@@ -453,7 +453,7 @@ public:
IMPLEMENT_FUNCTION_PROXIED(std::vector<DebugMessage>, GetDebugMessages);
IMPLEMENT_FUNCTION_PROXIED(void, SavePipelineState);
IMPLEMENT_FUNCTION_PROXIED(void, SavePipelineState, uint32_t eventId);
IMPLEMENT_FUNCTION_PROXIED(void, ReplayLog, uint32_t endEventID, ReplayLogType replayType);
IMPLEMENT_FUNCTION_PROXIED(std::vector<uint32_t>, GetPassEvents, uint32_t eventId);
+1 -1
View File
@@ -638,7 +638,7 @@ std::vector<ResourceId> D3D11Replay::GetTextures()
return ret;
}
void D3D11Replay::SavePipelineState()
void D3D11Replay::SavePipelineState(uint32_t eventId)
{
D3D11RenderState *rs = m_pDevice->GetImmediateContext()->GetCurrentPipelineState();
+1 -1
View File
@@ -128,7 +128,7 @@ public:
FrameRecord GetFrameRecord();
void SavePipelineState();
void SavePipelineState(uint32_t eventId);
const D3D11Pipe::State *GetD3D11PipelineState() { return &m_CurPipelineState; }
const D3D12Pipe::State *GetD3D12PipelineState() { return NULL; }
const GLPipe::State *GetGLPipelineState() { return NULL; }
+1 -1
View File
@@ -1220,7 +1220,7 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root
}
}
void D3D12Replay::SavePipelineState()
void D3D12Replay::SavePipelineState(uint32_t eventId)
{
const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
+1 -1
View File
@@ -87,7 +87,7 @@ public:
FrameRecord GetFrameRecord();
void SavePipelineState();
void SavePipelineState(uint32_t eventId);
const D3D11Pipe::State *GetD3D11PipelineState() { return NULL; }
const D3D12Pipe::State *GetD3D12PipelineState() { return &m_PipelineState; }
const GLPipe::State *GetGLPipelineState() { return NULL; }
+1 -1
View File
@@ -757,7 +757,7 @@ string GLReplay::DisassembleShader(ResourceId pipeline, const ShaderReflection *
return StringFormat::Fmt("; Invalid disassembly target %s", target.c_str());
}
void GLReplay::SavePipelineState()
void GLReplay::SavePipelineState(uint32_t eventId)
{
GLPipe::State &pipe = m_CurPipelineState;
WrappedOpenGL &drv = *m_pDriver;
+1 -1
View File
@@ -117,7 +117,7 @@ public:
FrameRecord GetFrameRecord();
void SavePipelineState();
void SavePipelineState(uint32_t eventId);
const D3D11Pipe::State *GetD3D11PipelineState() { return NULL; }
const D3D12Pipe::State *GetD3D12PipelineState() { return NULL; }
const GLPipe::State *GetGLPipelineState() { return &m_CurPipelineState; }
+71 -1
View File
@@ -864,13 +864,19 @@ void VulkanReplay::SetDriverInformation(const VkPhysicalDeviceProperties &props)
memcpy(m_DriverInfo.version, versionString.c_str(), versionString.size());
}
void VulkanReplay::SavePipelineState()
void VulkanReplay::SavePipelineState(uint32_t eventId)
{
const VulkanRenderState &state = m_pDriver->m_RenderState;
VulkanCreationInfo &c = m_pDriver->m_CreationInfo;
VulkanResourceManager *rm = m_pDriver->GetResourceManager();
VkMarkerRegion::Begin(StringFormat::Fmt("FetchShaderFeedback for %u", eventId));
FetchShaderFeedback(eventId);
VkMarkerRegion::End();
m_VulkanPipelineState = VKPipe::State();
m_VulkanPipelineState.pushconsts.resize(state.pushConstSize);
@@ -1355,11 +1361,30 @@ void VulkanReplay::SavePipelineState()
for(size_t p = 0; p < ARRAY_COUNT(srcs); p++)
{
bool hasUsedBinds = false;
const BindIdx *usedBindsData = NULL;
size_t usedBindsSize = 0;
{
const DynamicUsedBinds &usage = m_BindlessFeedback.Usage[eventId];
bool curCompute = (p == 1);
if(usage.valid && usage.compute == curCompute)
{
hasUsedBinds = true;
usedBindsData = usage.used.data();
usedBindsSize = usage.used.size();
}
}
BindIdx curBind;
for(size_t i = 0; i < srcs[p]->size(); i++)
{
ResourceId src = (*srcs[p])[i].descSet;
VKPipe::DescriptorSet &dst = (*dsts[p])[i];
curBind.set = (uint32_t)i;
ResourceId layoutId = m_pDriver->m_DescriptorSetState[src].layout;
// push descriptors don't have a real descriptor set backing them
@@ -1381,6 +1406,8 @@ void VulkanReplay::SavePipelineState()
DescriptorSetSlot *info = m_pDriver->m_DescriptorSetState[src].currentBindings[b];
const DescSetLayout::Binding &layoutBind = c.m_DescSetLayout[layoutId].bindings[b];
curBind.bind = (uint32_t)b;
bool dynamicOffset = false;
dst.bindings[b].descriptorCount = layoutBind.descriptorCount;
@@ -1426,6 +1453,49 @@ void VulkanReplay::SavePipelineState()
dst.bindings[b].binds.resize(layoutBind.descriptorCount);
for(uint32_t a = 0; a < layoutBind.descriptorCount; a++)
{
VKPipe::BindingElement &dstel = dst.bindings[b].binds[a];
curBind.arrayidx = a;
// if we have a list of used binds, and this is an array descriptor (so would be
// expected to be in the list), check it for dynamic usage.
if(layoutBind.descriptorCount > 1 && hasUsedBinds)
{
// if we exhausted the list, all other elements are unused
if(usedBindsSize == 0)
{
dstel.dynamicallyUsed = false;
}
else
{
// we never saw the current value of usedBindsData (which is odd, we should have
// when iterating over all descriptors. This could only happen if there's some
// layout mismatch or a feedback bug that lead to an invalid entry in the list).
// Keep advancing until we get to one that is >= our current bind
while(curBind > *usedBindsData && usedBindsSize)
{
usedBindsData++;
usedBindsSize--;
}
// the next used bind is equal to this one. Mark it as dynamically used, and consume
if(curBind == *usedBindsData)
{
dstel.dynamicallyUsed = true;
usedBindsData++;
usedBindsSize--;
}
// the next used bind is after the current one, this is not used.
else if(curBind < *usedBindsData)
{
dstel.dynamicallyUsed = false;
}
}
}
if(dstel.dynamicallyUsed)
dst.bindings[b].dynamicallyUsedCount++;
if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
+1 -1
View File
@@ -254,7 +254,7 @@ public:
FrameRecord GetFrameRecord();
vector<DebugMessage> GetDebugMessages();
void SavePipelineState();
void SavePipelineState(uint32_t eventId);
const D3D11Pipe::State *GetD3D11PipelineState() { return NULL; }
const D3D12Pipe::State *GetD3D12PipelineState() { return NULL; }
const GLPipe::State *GetGLPipelineState() { return NULL; }
+5 -5
View File
@@ -226,7 +226,7 @@ void ReplayController::SetFrameEvent(uint32_t eventId, bool force)
m_pDevice->ReplayLog(eventId, eReplay_OnlyDraw);
FetchPipelineState();
FetchPipelineState(eventId);
}
}
@@ -2060,8 +2060,6 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd
if(status != ReplayStatus::Succeeded)
return status;
FetchPipelineState();
m_APIProps = m_pDevice->GetAPIProperties();
// fetch GCN ISA targets
@@ -2095,6 +2093,8 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd
m_Drawcalls.clear();
SetupDrawcallPointers(m_Drawcalls, m_FrameRecord.drawcallList);
FetchPipelineState(m_Drawcalls.back()->eventId);
return ReplayStatus::Succeeded;
}
@@ -2112,11 +2112,11 @@ APIProperties ReplayController::GetAPIProperties()
return m_pDevice->GetAPIProperties();
}
void ReplayController::FetchPipelineState()
void ReplayController::FetchPipelineState(uint32_t eventId)
{
CHECK_REPLAY_THREAD();
m_pDevice->SavePipelineState();
m_pDevice->SavePipelineState(eventId);
m_D3D11PipelineState = m_pDevice->GetD3D11PipelineState();
m_D3D12PipelineState = m_pDevice->GetD3D12PipelineState();
+2 -2
View File
@@ -139,8 +139,6 @@ public:
void SetFrameEvent(uint32_t eventId, bool force);
void FetchPipelineState();
const D3D11Pipe::State *GetD3D11PipelineState();
const D3D12Pipe::State *GetD3D12PipelineState();
const GLPipe::State *GetGLPipelineState();
@@ -215,6 +213,8 @@ public:
private:
ReplayStatus PostCreateInit(IReplayDriver *device, RDCFile *rdc);
void FetchPipelineState(uint32_t eventId);
DrawcallDescription *GetDrawcallByEID(uint32_t eventId);
bool ContainsMarker(const rdcarray<DrawcallDescription> &draws);
bool PassEquivalent(const DrawcallDescription &a, const DrawcallDescription &b);
+1 -1
View File
@@ -111,7 +111,7 @@ public:
virtual vector<EventUsage> GetUsage(ResourceId id) = 0;
virtual void SavePipelineState() = 0;
virtual void SavePipelineState(uint32_t eventId) = 0;
virtual const D3D11Pipe::State *GetD3D11PipelineState() = 0;
virtual const D3D12Pipe::State *GetD3D12PipelineState() = 0;
virtual const GLPipe::State *GetGLPipelineState() = 0;