From f718e72ac95534b8d7fa917965b8d0fb7bde5d9e Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 19 Mar 2024 16:44:42 +0000 Subject: [PATCH] Update texture viewer to use new pipeline helpers --- qrenderdoc/Windows/TextureViewer.cpp | 401 +++++++++++++-------------- qrenderdoc/Windows/TextureViewer.h | 44 +-- 2 files changed, 223 insertions(+), 222 deletions(-) diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index a08ab62dc..2db3da76d 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -87,6 +87,26 @@ static inline uint32_t BaseCoordFromMip(uint32_t coord, const uint32_t mip, cons return uint32_t(dim * (coordf + 1e-6f)); } +static Descriptor MakeDescriptor(ResourceId res, Subresource sub = Subresource()) +{ + Descriptor ret; + ret.type = DescriptorType::ReadWriteImage; + ret.resource = res; + ret.firstMip = sub.mip; + ret.firstSlice = sub.slice; + return ret; +} + +static UsedDescriptor MakeUsedDescriptor(ResourceId res, Subresource sub = Subresource()) +{ + UsedDescriptor ret; + ret.descriptor = MakeDescriptor(res, sub); + ret.access.type = ret.descriptor.type; + ret.access.index = DescriptorAccess::NoShaderBinding; + ret.access.byteSize = 1; + return ret; +} + static QMap encodingExtensions = { {lit("hlsl"), ShaderEncoding::HLSL}, {lit("glsl"), ShaderEncoding::GLSL}, @@ -98,12 +118,10 @@ static QMap encodingExtensions = { Q_DECLARE_METATYPE(Following); -Following::Following(const TextureViewer &tex, FollowType t, ShaderStage s, int i, int a) : tex(tex) +Following::Following(const TextureViewer &tex, FollowType type, ShaderStage stage, uint32_t index, + uint32_t arrayElement) + : tex(tex), Type(type), Stage(stage), index(index), arrayEl(arrayElement) { - Type = t; - Stage = s; - index = i; - arrayEl = a; } Following::Following(const Following &other) : tex(other.tex) @@ -160,31 +178,31 @@ void Following::GetActionContext(ICaptureContext &ctx, bool ©, bool &clear, int Following::GetHighestMip(ICaptureContext &ctx) { - return GetBoundResource(ctx, arrayEl).firstMip; + return GetDescriptor(ctx, arrayEl).firstMip; } int Following::GetFirstArraySlice(ICaptureContext &ctx) { - return GetBoundResource(ctx, arrayEl).firstSlice; + return GetDescriptor(ctx, arrayEl).firstSlice; } CompType Following::GetTypeHint(ICaptureContext &ctx) { - return GetBoundResource(ctx, arrayEl).typeCast; + return GetDescriptor(ctx, arrayEl).format.compType; } ResourceId Following::GetResourceId(ICaptureContext &ctx) { - return GetBoundResource(ctx, arrayEl).resourceId; + return GetDescriptor(ctx, arrayEl).resource; } -BoundResource Following::GetBoundResource(ICaptureContext &ctx, int arrayIdx) +Descriptor Following::GetDescriptor(ICaptureContext &ctx, uint32_t arrayIdx) { - BoundResource ret; + Descriptor ret; if(Type == FollowType::OutputColor) { - rdcarray outputs = GetOutputTargets(ctx); + rdcarray outputs = GetOutputTargets(ctx); if(index < outputs.count()) ret = outputs[index]; @@ -199,41 +217,25 @@ BoundResource Following::GetBoundResource(ICaptureContext &ctx, int arrayIdx) } else if(Type == FollowType::ReadWrite) { - const rdcarray &rw = tex.m_ReadWriteResources[(int)Stage]; + const rdcarray &rw = tex.m_ReadWriteResources[(int)Stage]; - ShaderBindpointMapping mapping = GetMapping(ctx); - - if(index < mapping.readWriteResources.count()) + for(const UsedDescriptor &d : rw) { - Bindpoint &key = mapping.readWriteResources[index]; - - int residx = rw.indexOf(key); - if(residx >= 0) + if(d.access.index == index && d.access.arrayElement == arrayIdx) { - const BoundResourceArray &resArray = rw[residx]; - if(arrayIdx >= resArray.firstIndex && - arrayIdx - resArray.firstIndex < resArray.resources.count()) - ret = resArray.resources[arrayIdx - resArray.firstIndex]; + return d.descriptor; } } } else if(Type == FollowType::ReadOnly) { - const rdcarray &ro = tex.m_ReadOnlyResources[(int)Stage]; + const rdcarray &ro = tex.m_ReadOnlyResources[(int)Stage]; - ShaderBindpointMapping mapping = GetMapping(ctx); - - if(index < mapping.readOnlyResources.count()) + for(const UsedDescriptor &d : ro) { - Bindpoint &key = mapping.readOnlyResources[index]; - - int residx = ro.indexOf(key); - if(residx >= 0) + if(d.access.index == index && d.access.arrayElement == arrayIdx) { - const BoundResourceArray &resArray = ro[residx]; - if(arrayIdx >= resArray.firstIndex && - arrayIdx - resArray.firstIndex < resArray.resources.count()) - ret = resArray.resources[arrayIdx - resArray.firstIndex]; + return d.descriptor; } } } @@ -241,7 +243,7 @@ BoundResource Following::GetBoundResource(ICaptureContext &ctx, int arrayIdx) return ret; } -rdcarray Following::GetOutputTargets(ICaptureContext &ctx) +rdcarray Following::GetOutputTargets(ICaptureContext &ctx) { const ActionDescription *curAction = ctx.CurAction(); bool copy = false, clear = false, compute = false; @@ -249,7 +251,7 @@ rdcarray Following::GetOutputTargets(ICaptureContext &ctx) if(copy || clear) { - return {BoundResource(curAction->copyDestination, curAction->copyDestinationSubresource)}; + return {MakeDescriptor(curAction->copyDestination, curAction->copyDestinationSubresource)}; } else if(compute) { @@ -257,17 +259,17 @@ rdcarray Following::GetOutputTargets(ICaptureContext &ctx) } else { - rdcarray ret = ctx.CurPipelineState().GetOutputTargets(); + rdcarray ret = ctx.CurPipelineState().GetOutputTargetDescriptors(); if(ret.isEmpty() && curAction != NULL && (curAction->flags & ActionFlags::Present)) { if(curAction->copyDestination != ResourceId()) - return {BoundResource(curAction->copyDestination, curAction->copyDestinationSubresource)}; + return {MakeDescriptor(curAction->copyDestination, curAction->copyDestinationSubresource)}; for(const TextureDescription &tex : ctx.GetTextures()) { if(tex.creationFlags & TextureCategory::SwapBuffer) - return {BoundResource(tex.resourceId)}; + return {MakeDescriptor(tex.resourceId)}; } } @@ -275,54 +277,54 @@ rdcarray Following::GetOutputTargets(ICaptureContext &ctx) } } -BoundResource Following::GetDepthTarget(ICaptureContext &ctx) +Descriptor Following::GetDepthTarget(ICaptureContext &ctx) { bool copy = false, clear = false, compute = false; GetActionContext(ctx, copy, clear, compute); if(copy || clear || compute) - return BoundResource(ResourceId()); + return Descriptor(); else - return ctx.CurPipelineState().GetDepthTarget(); + return ctx.CurPipelineState().GetDepthTargetDescriptor(); } -BoundResource Following::GetDepthResolveTarget(ICaptureContext &ctx) +Descriptor Following::GetDepthResolveTarget(ICaptureContext &ctx) { bool copy = false, clear = false, compute = false; GetActionContext(ctx, copy, clear, compute); if(copy || clear || compute) - return BoundResource(ResourceId()); + return Descriptor(); else - return ctx.CurPipelineState().GetDepthResolveTarget(); + return ctx.CurPipelineState().GetDepthResolveTargetDescriptor(); } -rdcarray Following::GetReadWriteResources(ICaptureContext &ctx, - ShaderStage stage, bool onlyUsed) +rdcarray Following::GetReadWriteResources(ICaptureContext &ctx, ShaderStage stage, + bool onlyUsed) { bool copy = false, clear = false, compute = false; GetActionContext(ctx, copy, clear, compute); if(copy || clear) { - return rdcarray(); + return rdcarray(); } else if(compute) { // only return compute resources for one stage - if(stage == ShaderStage::Pixel || stage == ShaderStage::Compute) - return ctx.CurPipelineState().GetReadWriteResources(ShaderStage::Compute, onlyUsed); - else - return rdcarray(); + if(stage != ShaderStage::Pixel && stage != ShaderStage::Compute) + return rdcarray(); + + return ctx.CurPipelineState().GetReadWriteDescriptors(ShaderStage::Compute, onlyUsed); } else { - return ctx.CurPipelineState().GetReadWriteResources(stage, onlyUsed); + return ctx.CurPipelineState().GetReadWriteDescriptors(stage, onlyUsed); } } -rdcarray Following::GetReadOnlyResources(ICaptureContext &ctx, - ShaderStage stage, bool onlyUsed) +rdcarray Following::GetReadOnlyResources(ICaptureContext &ctx, ShaderStage stage, + bool onlyUsed) { const ActionDescription *curAction = ctx.CurAction(); bool copy = false, clear = false, compute = false; @@ -330,26 +332,25 @@ rdcarray Following::GetReadOnlyResources(ICaptureContext &ct if(copy || clear) { - rdcarray ret; + rdcarray ret; // only return copy source for one stage if(copy && stage == ShaderStage::Pixel) - ret.push_back(BoundResourceArray( - Bindpoint(0, 0), {BoundResource(curAction->copySource, curAction->copySourceSubresource)})); + ret.push_back(MakeUsedDescriptor(curAction->copySource, curAction->copySourceSubresource)); return ret; } else if(compute) { // only return compute resources for one stage - if(stage == ShaderStage::Pixel || stage == ShaderStage::Compute) - return ctx.CurPipelineState().GetReadOnlyResources(ShaderStage::Compute, onlyUsed); - else - return rdcarray(); + if(stage != ShaderStage::Pixel && stage != ShaderStage::Compute) + return rdcarray(); + + return ctx.CurPipelineState().GetReadOnlyDescriptors(ShaderStage::Compute, onlyUsed); } else { - return ctx.CurPipelineState().GetReadOnlyResources(stage, onlyUsed); + return ctx.CurPipelineState().GetReadOnlyDescriptors(stage, onlyUsed); } } @@ -371,38 +372,6 @@ const ShaderReflection *Following::GetReflection(ICaptureContext &ctx) return GetReflection(ctx, Stage); } -const ShaderBindpointMapping &Following::GetMapping(ICaptureContext &ctx, ShaderStage stage) -{ - bool copy = false, clear = false, compute = false; - GetActionContext(ctx, copy, clear, compute); - - if(copy || clear) - { - static ShaderBindpointMapping mapping; - - // for PS only add a single mapping to get the copy source - if(copy && stage == ShaderStage::Pixel) - mapping.readOnlyResources = {Bindpoint(0, 0)}; - else - mapping.readOnlyResources.clear(); - - return mapping; - } - else if(compute) - { - return ctx.CurPipelineState().GetBindpointMapping(ShaderStage::Compute); - } - else - { - return ctx.CurPipelineState().GetBindpointMapping(stage); - } -} - -const ShaderBindpointMapping &Following::GetMapping(ICaptureContext &ctx) -{ - return GetMapping(ctx, Stage); -} - namespace TextureListFilter { enum Columns @@ -2437,22 +2406,22 @@ void TextureViewer::OpenResourceContextMenu(ResourceId id, bool input, } } -void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res, bool force, +void TextureViewer::InitResourcePreview(ResourcePreview *prev, Descriptor res, bool force, Following &follow, const QString &bindName, const QString &slotName) { Subresource sub = {0, 0, ~0U}; - if(res.resourceId != ResourceId() || force) + if(res.resource != ResourceId() || force) { QString fullname = bindName; - if(!m_Ctx.IsAutogeneratedName(res.resourceId)) + if(!m_Ctx.IsAutogeneratedName(res.resource)) { if(!fullname.isEmpty()) fullname += lit(" = "); - fullname += m_Ctx.GetResourceName(res.resourceId); + fullname += m_Ctx.GetResourceName(res.resource); } if(fullname.isEmpty()) - fullname = m_Ctx.GetResourceName(res.resourceId); + fullname = m_Ctx.GetResourceName(res.resource); prev->setResourceName(fullname); @@ -2461,7 +2430,7 @@ void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res prev->setActive(true); prev->setSelected(m_Following == follow); - if(m_Ctx.GetTexture(res.resourceId)) + if(m_Ctx.GetTexture(res.resource)) { if(res.firstMip >= 0) sub.mip = res.firstMip; @@ -2470,8 +2439,8 @@ void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res } else { - res.resourceId = ResourceId(); - res.typeCast = CompType::Typeless; + res.resource = ResourceId(); + res.format = ResourceFormat(); } } else if(m_Following == follow) @@ -2480,8 +2449,8 @@ void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res prev->setActive(true); prev->setSelected(true); - res.resourceId = ResourceId(); - res.typeCast = CompType::Typeless; + res.resource = ResourceId(); + res.format = ResourceFormat(); } else { @@ -2492,10 +2461,10 @@ void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res return; } - prev->setProperty("id", QVariant::fromValue(res.resourceId)); + prev->setProperty("id", QVariant::fromValue(res.resource)); prev->setProperty("mip", sub.mip); prev->setProperty("slice", sub.slice); - prev->setProperty("cast", uint32_t(res.typeCast)); + prev->setProperty("cast", uint32_t(res.format.compType)); GUIInvoke::call(prev, [this, prev] { UI_PreviewResized(prev); }); } @@ -2525,102 +2494,85 @@ void TextureViewer::UI_PreviewResized(ResourcePreview *prev) } void TextureViewer::InitStageResourcePreviews(ShaderStage stage, - const rdcarray &resourceDetails, - const rdcarray &mapping, - rdcarray &ResList, + const rdcarray &shaderInterface, + const rdcarray &descriptors, ThumbnailStrip *prevs, int &prevIndex, bool copy, bool rw) { - for(int residx = 0; residx < ResList.count(); residx++) + for(const UsedDescriptor &desc : descriptors) { - const rdcarray &resArray = ResList[residx].resources; - uint32_t dynamicallyUsedResCount = ResList[residx].dynamicallyUsedCount; - int32_t firstIndex = ResList[residx].firstIndex; - int arrayLen = resArray.count(); + Following follow(*this, rw ? FollowType::ReadWrite : FollowType::ReadOnly, desc.access.stage, + desc.access.index, desc.access.arrayElement); - int idx = mapping.indexOf(ResList[residx].bindPoint); + // show if it's referenced by the shader - regardless of empty or not + bool show = !desc.access.staticallyUnused || copy; - // don't display thumbnails for resources that are not bound - if(idx < 0) - continue; + // omit buffers even if the shader uses them, unless this is a copy + if(desc.descriptor.resource != ResourceId() && m_Ctx.GetTexture(desc.descriptor.resource) == NULL) + show = copy; - const bool collapseArray = arrayLen > 8 && dynamicallyUsedResCount > 20; + // it's the one we're following + show = show || (follow == m_Following); - for(int i = 0; i < arrayLen; i++) + ResourcePreview *prev = NULL; + + if(prevIndex < prevs->thumbs().size()) { - int arrayIdx = firstIndex + i; + prev = prevs->thumbs()[prevIndex]; - if(!resArray[i].dynamicallyUsed) + // don't use it if we're not actually going to show it + if(!show && !prev->isActive()) + continue; + } + else + { + // don't create it if we're not actually going to show it + if(!show) continue; - const BoundResource &res = resArray[i]; + prev = UI_CreateThumbnail(prevs); + } - Following follow(*this, rw ? FollowType::ReadWrite : FollowType::ReadOnly, stage, idx, - arrayIdx); + prevIndex++; - // show if it's referenced by the shader - regardless of empty or not - bool show = mapping[idx].used || copy; + QString slotName; + QString bindName; - // omit buffers even if the shader uses them. - if(res.resourceId != ResourceId() && m_Ctx.GetTexture(res.resourceId) == NULL) - show = copy; + if(copy) + { + slotName = tr("SRC"); + bindName = tr("Source"); + } + else if(desc.access.index == DescriptorAccess::NoShaderBinding) + { + // this is a sensible name but we should query the API for name it prefers + slotName = QFormatStr("Descriptor[%1]").arg(desc.access.arrayElement); - // it's the one we're following - show = show || (follow == m_Following); - - ResourcePreview *prev = NULL; - - if(prevIndex < prevs->thumbs().size()) + // batch up these updates for now and send them off after previews are done + if(show) + m_DescriptorThumbUpdates.push_back({desc.access, prev}); + } + else + { + slotName = QFormatStr("%1 %2%3") + .arg(m_Ctx.CurPipelineState().Abbrev(stage)) + .arg(rw ? lit("RW ") : lit("")) + .arg(desc.access.index); + if(desc.access.index < shaderInterface.size()) { - prev = prevs->thumbs()[prevIndex]; + const ShaderResource &bind = shaderInterface[desc.access.index]; + bindName = bind.name; - // don't use it if we're not actually going to show it - if(!show && !prev->isActive()) - continue; - } - else - { - // don't create it if we're not actually going to show it - if(!show) - continue; - - prev = UI_CreateThumbnail(prevs); - } - - prevIndex++; - - QString slotName = QFormatStr("%1 %2%3") - .arg(m_Ctx.CurPipelineState().Abbrev(stage)) - .arg(rw ? lit("RW ") : lit("")) - .arg(idx); - - if(collapseArray) - slotName += QFormatStr(" Arr[%1]").arg(arrayLen); - else - slotName += QFormatStr("[%1]").arg(arrayIdx); - - if(copy) - slotName = tr("SRC"); - - QString bindName; - - for(const ShaderResource &bind : resourceDetails) - { - if(bind.bindPoint == idx) + if(bind.bindArraySize > 1) { - bindName = bind.name; - break; + slotName += QFormatStr("[%1]").arg(desc.access.arrayElement); + bindName += QFormatStr("[%1]").arg(desc.access.arrayElement); } } - - if(copy) - bindName = tr("Source"); - - InitResourcePreview(prev, show ? res : BoundResource(), show, follow, bindName, slotName); - - if(collapseArray) - break; } + + InitResourcePreview(prev, show ? desc.descriptor : Descriptor(), show, follow, bindName, + slotName); } } @@ -3186,17 +3138,8 @@ void TextureViewer::OnEventChanged(uint32_t eventId) { ShaderStage stage = stages[i]; - const ShaderBindpointMapping &mapping = Following::GetMapping(m_Ctx, stage); - - if(!mapping.readOnlyResources.empty()) - m_ReadOnlyResources[(uint32_t)stage] = Following::GetReadOnlyResources(m_Ctx, stage, true); - else - m_ReadOnlyResources[(uint32_t)stage].clear(); - - if(!mapping.readWriteResources.empty()) - m_ReadWriteResources[(uint32_t)stage] = Following::GetReadWriteResources(m_Ctx, stage, true); - else - m_ReadWriteResources[(uint32_t)stage].clear(); + m_ReadOnlyResources[(uint32_t)stage] = Following::GetReadOnlyResources(m_Ctx, stage, true); + m_ReadWriteResources[(uint32_t)stage] = Following::GetReadWriteResources(m_Ctx, stage, true); } UI_UpdateCachedTexture(); @@ -3227,9 +3170,9 @@ void TextureViewer::OnEventChanged(uint32_t eventId) w->setWindowTitle(m_Ctx.GetResourceName(id)); } - rdcarray RTs = Following::GetOutputTargets(m_Ctx); - BoundResource Depth = Following::GetDepthTarget(m_Ctx); - BoundResource DepthResolve = Following::GetDepthResolveTarget(m_Ctx); + rdcarray RTs = Following::GetOutputTargets(m_Ctx); + Descriptor Depth = Following::GetDepthTarget(m_Ctx); + Descriptor DepthResolve = Following::GetDepthResolveTarget(m_Ctx); int outIndex = 0; int inIndex = 0; @@ -3237,7 +3180,7 @@ void TextureViewer::OnEventChanged(uint32_t eventId) ui->outputThumbs->setUpdatesEnabled(false); ui->inputThumbs->setUpdatesEnabled(false); - for(int rt = 0; rt < RTs.count(); rt++) + for(uint32_t rt = 0; rt < RTs.size(); rt++) { ResourcePreview *prev; @@ -3290,21 +3233,73 @@ void TextureViewer::OnEventChanged(uint32_t eventId) const rdcarray empty; + m_DescriptorThumbUpdates.clear(); + // display resources used for all stages for(int i = 0; i < count; i++) { ShaderStage stage = stages[i]; const ShaderReflection *details = Following::GetReflection(m_Ctx, stage); - const ShaderBindpointMapping &mapping = Following::GetMapping(m_Ctx, stage); InitStageResourcePreviews(stage, details != NULL ? details->readWriteResources : empty, - mapping.readWriteResources, m_ReadWriteResources[(uint32_t)stage], - ui->outputThumbs, outIndex, copy, true); + m_ReadWriteResources[(uint32_t)stage], ui->outputThumbs, outIndex, + copy, true); InitStageResourcePreviews(stage, details != NULL ? details->readOnlyResources : empty, - mapping.readOnlyResources, m_ReadOnlyResources[(uint32_t)stage], - ui->inputThumbs, inIndex, copy, false); + m_ReadOnlyResources[(uint32_t)stage], ui->inputThumbs, inIndex, copy, + false); + } + + if(!m_DescriptorThumbUpdates.empty()) + { + m_Ctx.Replay().AsyncInvoke([this](IReplayController *r) { + // we could collate ranges by descriptor store, but in practice we don't expect descriptors to be + // scattered across multiple stores. So to keep the code simple for now we do a linear sweep + ResourceId store; + rdcarray ranges; + rdcarray locations; + + for(const DescriptorThumbUpdate &update : m_DescriptorThumbUpdates) + { + if(update.access.descriptorStore != store) + { + if(store != ResourceId()) + locations.append(r->GetDescriptorLocations(store, ranges)); + + store = update.access.descriptorStore; + ranges.clear(); + } + + // if the last range is contiguous with this access, append this access as a new range to query + if(!ranges.empty() && ranges.back().descriptorSize == update.access.byteSize && + ranges.back().offset + ranges.back().descriptorSize == update.access.byteOffset) + { + ranges.back().count++; + continue; + } + + DescriptorRange range; + range.offset = update.access.byteOffset; + range.descriptorSize = update.access.byteSize; + ranges.push_back(range); + } + + if(store != ResourceId()) + locations.append(r->GetDescriptorLocations(store, ranges)); + + for(size_t i = 0; i < m_DescriptorThumbUpdates.size(); i++) + { + if(i < locations.size()) + m_DescriptorThumbUpdates[i].slotName = locations[i].logicalBindName; + } + + GUIInvoke::call(this, [this]() { + for(DescriptorThumbUpdate &update : m_DescriptorThumbUpdates) + if(!update.slotName.isEmpty()) + update.preview->setSlotName(update.slotName); + }); + }); } // hide others diff --git a/qrenderdoc/Windows/TextureViewer.h b/qrenderdoc/Windows/TextureViewer.h index 7c9e7bbd7..c5b06af23 100644 --- a/qrenderdoc/Windows/TextureViewer.h +++ b/qrenderdoc/Windows/TextureViewer.h @@ -48,13 +48,14 @@ struct Following FollowType Type; ShaderStage Stage; int index; - int arrayEl; + uint32_t arrayEl; // this is only for QVariant compatibility and will generate an invalid Following instance! do not // use! Following(); - Following(const TextureViewer &tex, FollowType t, ShaderStage s, int i, int a); + Following(const TextureViewer &tex, FollowType type, ShaderStage stage, uint32_t index, + uint32_t arrayElement); Following(const Following &other); Following &operator=(const Following &other); @@ -67,23 +68,20 @@ struct Following CompType GetTypeHint(ICaptureContext &ctx); ResourceId GetResourceId(ICaptureContext &ctx); - BoundResource GetBoundResource(ICaptureContext &ctx, int arrayIdx); + Descriptor GetDescriptor(ICaptureContext &ctx, uint32_t arrayIdx); - static rdcarray GetOutputTargets(ICaptureContext &ctx); + static rdcarray GetOutputTargets(ICaptureContext &ctx); - static BoundResource GetDepthTarget(ICaptureContext &ctx); - static BoundResource GetDepthResolveTarget(ICaptureContext &ctx); - static rdcarray GetReadWriteResources(ICaptureContext &ctx, ShaderStage stage, - bool onlyUsed); - static rdcarray GetReadOnlyResources(ICaptureContext &ctx, ShaderStage stage, - bool onlyUsed); + static Descriptor GetDepthTarget(ICaptureContext &ctx); + static Descriptor GetDepthResolveTarget(ICaptureContext &ctx); + static rdcarray GetReadWriteResources(ICaptureContext &ctx, ShaderStage stage, + bool onlyUsed); + static rdcarray GetReadOnlyResources(ICaptureContext &ctx, ShaderStage stage, + bool onlyUsed); const ShaderReflection *GetReflection(ICaptureContext &ctx); static const ShaderReflection *GetReflection(ICaptureContext &ctx, ShaderStage stage); - const ShaderBindpointMapping &GetMapping(ICaptureContext &ctx); - static const ShaderBindpointMapping &GetMapping(ICaptureContext &ctx, ShaderStage stage); - private: const TextureViewer &tex; }; @@ -268,12 +266,11 @@ private: ResourcePreview *UI_CreateThumbnail(ThumbnailStrip *strip); void UI_CreateThumbnails(); - void InitResourcePreview(ResourcePreview *prev, BoundResource res, bool force, Following &follow, + void InitResourcePreview(ResourcePreview *prev, Descriptor res, bool force, Following &follow, const QString &bindName, const QString &slotName); - void InitStageResourcePreviews(ShaderStage stage, const rdcarray &resourceDetails, - const rdcarray &mapping, - rdcarray &ResList, ThumbnailStrip *prevs, + void InitStageResourcePreviews(ShaderStage stage, const rdcarray &shaderInterface, + const rdcarray &descriptors, ThumbnailStrip *prevs, int &prevIndex, bool copy, bool rw); void UI_PreviewResized(ResourcePreview *prev); @@ -360,8 +357,17 @@ private: friend struct Following; - rdcarray m_ReadOnlyResources[NumShaderStages]; - rdcarray m_ReadWriteResources[NumShaderStages]; + rdcarray m_ReadOnlyResources[NumShaderStages]; + rdcarray m_ReadWriteResources[NumShaderStages]; + + struct DescriptorThumbUpdate + { + DescriptorAccess access; + ResourcePreview *preview; + QString slotName; + }; + + rdcarray m_DescriptorThumbUpdates; QTime m_CustomShaderTimer; int m_CustomShaderWriteTime = 0;