diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index e09f6d26c..c6c5dbbb7 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -2151,12 +2151,12 @@ IBufferViewer *CaptureContext::ViewBuffer(uint64_t byteOffset, uint64_t byteSize return viewer; } -IBufferViewer *CaptureContext::ViewTextureAsBuffer(uint32_t arrayIdx, uint32_t mip, ResourceId id, +IBufferViewer *CaptureContext::ViewTextureAsBuffer(ResourceId id, const Subresource &sub, const rdcstr &format) { BufferViewer *viewer = new BufferViewer(*this, false, m_MainWindow); - viewer->ViewTexture(arrayIdx, mip, id, format); + viewer->ViewTexture(id, sub, format); return viewer; } diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index f94a7d7a7..4e3c5b047 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -244,7 +244,7 @@ public: IBufferViewer *ViewBuffer(uint64_t byteOffset, uint64_t byteSize, ResourceId id, const rdcstr &format = "") override; - IBufferViewer *ViewTextureAsBuffer(uint32_t arrayIdx, uint32_t mip, ResourceId id, + IBufferViewer *ViewTextureAsBuffer(ResourceId id, const Subresource &sub, const rdcstr &format = "") override; IConstantBufferPreviewer *ViewConstantBuffer(ShaderStage stage, uint32_t slot, diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index b8c040dba..47f249781 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -295,13 +295,11 @@ struct IBufferViewer const rdcstr &format = "") = 0; DOCUMENT(R"(In a raw buffer viewer, load the contents from a particular texture resource. -:param int arrayIdx: The array slice to load from. -:param int mip: The mip level to load from. :param ~renderdoc.ResourceId id: The ID of the texture itself. +:param Subresource sub: The subresource within this texture to use. :param str format: Optionally a HLSL/GLSL style formatting string. )"); - virtual void ViewTexture(uint32_t arrayIdx, uint32_t mip, ResourceId id, - const rdcstr &format = "") = 0; + virtual void ViewTexture(ResourceId id, const Subresource &sub, const rdcstr &format = "") = 0; protected: IBufferViewer() = default; @@ -1863,14 +1861,13 @@ through the execution of a given shader. DOCUMENT(R"(Show a new :class:`BufferViewer` window, showing a read-only view of a texture's raw bytes. -:param int arrayIdx: The array slice to load from. -:param int mip: The mip level to load from. :param ~renderdoc.ResourceId id: The ID of the texture itself. +:param Subresource sub: The subresource within this texture to use. :param str format: Optionally a HLSL/GLSL style formatting string. :return: The new :class:`BufferViewer` window opened, but not shown. :rtype: BufferViewer )"); - virtual IBufferViewer *ViewTextureAsBuffer(uint32_t arrayIdx, uint32_t mip, ResourceId id, + virtual IBufferViewer *ViewTextureAsBuffer(ResourceId id, const Subresource &sub, const rdcstr &format = "") = 0; DOCUMENT(R"(Show a new :class:`ConstantBufferPreviewer` window, showing a read-only view of a the diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index cbef4293a..bc55bb4b3 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -2212,7 +2212,7 @@ void BufferViewer::OnEventChanged(uint32_t eventId) } else { - buf->storage = r->GetTextureData(m_BufferID, m_TexArrayIdx, m_TexMip); + buf->storage = r->GetTextureData(m_BufferID, m_TexSub); } } @@ -2939,15 +2939,14 @@ void BufferViewer::ViewBuffer(uint64_t byteOffset, uint64_t byteSize, ResourceId processFormat(format); } -void BufferViewer::ViewTexture(uint32_t arrayIdx, uint32_t mip, ResourceId id, const rdcstr &format) +void BufferViewer::ViewTexture(ResourceId id, const Subresource &sub, const rdcstr &format) { if(!m_Ctx.IsCaptureLoaded()) return; m_IsBuffer = false; - m_TexArrayIdx = arrayIdx; - m_TexMip = mip; m_BufferID = id; + m_TexSub = sub; updateWindowTitle(); diff --git a/qrenderdoc/Windows/BufferViewer.h b/qrenderdoc/Windows/BufferViewer.h index 838596a30..150e69796 100644 --- a/qrenderdoc/Windows/BufferViewer.h +++ b/qrenderdoc/Windows/BufferViewer.h @@ -85,7 +85,7 @@ public: } void ViewBuffer(uint64_t byteOffset, uint64_t byteSize, ResourceId id, const rdcstr &format = "") override; - void ViewTexture(uint32_t arrayIdx, uint32_t mip, ResourceId id, const rdcstr &format = "") override; + void ViewTexture(ResourceId id, const Subresource &sub, const rdcstr &format = "") override; // ICaptureViewer void OnCaptureLoaded() override; @@ -175,8 +175,7 @@ private: // data from raw buffer view bool m_IsBuffer = true; QString m_Format; - uint32_t m_TexArrayIdx = 0; - uint32_t m_TexMip = 0; + Subresource m_TexSub = {0, 0, 0}; uint64_t m_ByteOffset = 0; uint64_t m_ObjectByteSize = UINT64_MAX; uint64_t m_ByteSize = UINT64_MAX; diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index 84e45cc4e..317c4eced 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -1958,7 +1958,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in if(tex->type == TextureType::Buffer) { IBufferViewer *viewer = m_Ctx.ViewTextureAsBuffer( - 0, 0, tex->resourceId, FormatElement::GenerateTextureBufferFormat(*tex)); + tex->resourceId, Subresource(), FormatElement::GenerateTextureBufferFormat(*tex)); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 0fb01a11c..d5fa2a53f 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -1845,7 +1845,7 @@ void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in if(tex->type == TextureType::Buffer) { IBufferViewer *viewer = m_Ctx.ViewTextureAsBuffer( - 0, 0, tex->resourceId, FormatElement::GenerateTextureBufferFormat(*tex)); + tex->resourceId, Subresource(), FormatElement::GenerateTextureBufferFormat(*tex)); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp index dd13ea25d..2a11df4de 100644 --- a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp @@ -2144,7 +2144,7 @@ void GLPipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int c if(tex->type == TextureType::Buffer) { IBufferViewer *viewer = m_Ctx.ViewTextureAsBuffer( - 0, 0, tex->resourceId, FormatElement::GenerateTextureBufferFormat(*tex)); + tex->resourceId, Subresource(), FormatElement::GenerateTextureBufferFormat(*tex)); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 281f0dd8d..699104789 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -2540,7 +2540,7 @@ void VulkanPipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, i if(tex->type == TextureType::Buffer) { IBufferViewer *viewer = m_Ctx.ViewTextureAsBuffer( - 0, 0, tex->resourceId, FormatElement::GenerateTextureBufferFormat(*tex)); + tex->resourceId, Subresource(), FormatElement::GenerateTextureBufferFormat(*tex)); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/qrenderdoc/Windows/PixelHistoryView.cpp b/qrenderdoc/Windows/PixelHistoryView.cpp index 8bc327290..9d379021e 100644 --- a/qrenderdoc/Windows/PixelHistoryView.cpp +++ b/qrenderdoc/Windows/PixelHistoryView.cpp @@ -633,7 +633,7 @@ void PixelHistoryView::updateWindowTitle() TextureDescription *tex = m_Ctx.GetTexture(m_ID); if(tex->msSamp > 1) - title += tr(" @ Sample %1").arg(m_Display.sampleIdx); + title += tr(" @ Sample %1").arg(m_Display.subresource.sample); setWindowTitle(title); } @@ -698,8 +698,8 @@ void PixelHistoryView::startDebug(EventTag tag) ShaderDebugTrace *trace = NULL; m_Ctx.Replay().AsyncInvoke([this, &trace, &done, tag](IReplayController *r) { - trace = r->DebugPixel((uint32_t)m_Pixel.x(), (uint32_t)m_Pixel.y(), m_Display.sampleIdx, - tag.primitive); + trace = r->DebugPixel((uint32_t)m_Pixel.x(), (uint32_t)m_Pixel.y(), + m_Display.subresource.sample, tag.primitive); if(trace->states.isEmpty()) { diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index 7547ad0c5..1e385fd85 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -424,11 +424,10 @@ struct CaptureContextInvoker : ICaptureContext id, format); } - virtual IBufferViewer *ViewTextureAsBuffer(uint32_t arrayIdx, uint32_t mip, ResourceId id, + virtual IBufferViewer *ViewTextureAsBuffer(ResourceId id, const Subresource &sub, const rdcstr &format = "") override { - return InvokeRetFunction(&ICaptureContext::ViewTextureAsBuffer, arrayIdx, mip, - id, format); + return InvokeRetFunction(&ICaptureContext::ViewTextureAsBuffer, id, sub, format); } virtual IConstantBufferPreviewer *ViewConstantBuffer(ShaderStage stage, uint32_t slot, diff --git a/qrenderdoc/Windows/ResourceInspector.cpp b/qrenderdoc/Windows/ResourceInspector.cpp index cddd167be..b67e81770 100644 --- a/qrenderdoc/Windows/ResourceInspector.cpp +++ b/qrenderdoc/Windows/ResourceInspector.cpp @@ -451,7 +451,7 @@ void ResourceInspector::on_viewContents_clicked() if(tex->type == TextureType::Buffer) { IBufferViewer *viewer = m_Ctx.ViewTextureAsBuffer( - 0, 0, tex->resourceId, FormatElement::GenerateTextureBufferFormat(*tex)); + tex->resourceId, Subresource(), FormatElement::GenerateTextureBufferFormat(*tex)); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 1bd33c163..ded22d711 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -725,8 +725,8 @@ void TextureViewer::HighlightUsage() m_Ctx.GetTimelineBar()->HighlightResourceUsage(texptr->resourceId); } -void TextureViewer::RT_FetchCurrentPixel(uint32_t x, uint32_t y, PixelValue &pickValue, - PixelValue &realValue) +void TextureViewer::RT_FetchCurrentPixel(IReplayController *r, uint32_t x, uint32_t y, + PixelValue &pickValue, PixelValue &realValue) { TextureDescription *texptr = GetCurrentTexture(); @@ -736,18 +736,38 @@ void TextureViewer::RT_FetchCurrentPixel(uint32_t x, uint32_t y, PixelValue &pic if(m_TexDisplay.flipY) y = (texptr->height - 1) - y; - x = qMax(0U, x >> m_TexDisplay.mip); - y = qMax(0U, y >> m_TexDisplay.mip); + x = qMax(0U, x >> m_TexDisplay.subresource.mip); + y = qMax(0U, y >> m_TexDisplay.subresource.mip); - pickValue = m_Output->PickPixel(m_TexDisplay.resourceId, true, x, y, m_TexDisplay.sliceFace, - m_TexDisplay.mip, m_TexDisplay.sampleIdx); + ResourceId overlayResId = m_Output->GetDebugOverlayTexID(); + + if((m_TexDisplay.overlay == DebugOverlay::QuadOverdrawDraw || + m_TexDisplay.overlay == DebugOverlay::QuadOverdrawPass || + m_TexDisplay.overlay == DebugOverlay::TriangleSizeDraw || + m_TexDisplay.overlay == DebugOverlay::TriangleSizePass) && + overlayResId != ResourceId()) + { + realValue = + r->PickPixel(overlayResId, x, y, {m_TexDisplay.subresource.mip, 0, 0}, CompType::Typeless); + } + else + { + realValue = + r->PickPixel(m_TexDisplay.resourceId, x, y, m_TexDisplay.subresource, m_TexDisplay.typeCast); + } if(m_TexDisplay.customShaderId != ResourceId()) - realValue = m_Output->PickPixel(m_TexDisplay.resourceId, false, x, y, m_TexDisplay.sliceFace, - m_TexDisplay.mip, m_TexDisplay.sampleIdx); + { + pickValue = r->PickPixel(m_Output->GetCustomShaderTexID(), x, y, + {m_TexDisplay.subresource.mip, 0, 0}, CompType::Typeless); + } + else + { + pickValue = realValue; + } } -void TextureViewer::RT_PickPixelsAndUpdate(IReplayController *) +void TextureViewer::RT_PickPixelsAndUpdate(IReplayController *r) { PixelValue pickValue, realValue; @@ -757,7 +777,7 @@ void TextureViewer::RT_PickPixelsAndUpdate(IReplayController *) uint32_t x = (uint32_t)m_PickedPoint.x(); uint32_t y = (uint32_t)m_PickedPoint.y(); - RT_FetchCurrentPixel(x, y, pickValue, realValue); + RT_FetchCurrentPixel(r, x, y, pickValue, realValue); m_Output->SetPixelContextLocation(x, y); @@ -769,21 +789,21 @@ void TextureViewer::RT_PickPixelsAndUpdate(IReplayController *) GUIInvoke::call(this, [this]() { UI_UpdateStatusText(); }); } -void TextureViewer::RT_PickHoverAndUpdate(IReplayController *) +void TextureViewer::RT_PickHoverAndUpdate(IReplayController *r) { PixelValue pickValue, realValue; uint32_t x = (uint32_t)m_CurHoverPixel.x(); uint32_t y = (uint32_t)m_CurHoverPixel.y(); - RT_FetchCurrentPixel(x, y, pickValue, realValue); + RT_FetchCurrentPixel(r, x, y, pickValue, realValue); m_CurHoverValue = pickValue; GUIInvoke::call(this, [this]() { UI_UpdateStatusText(); }); } -void TextureViewer::RT_UpdateAndDisplay(IReplayController *) +void TextureViewer::RT_UpdateAndDisplay(IReplayController *r) { if(m_Output != NULL) m_Output->SetTextureDisplay(m_TexDisplay); @@ -791,7 +811,7 @@ void TextureViewer::RT_UpdateAndDisplay(IReplayController *) GUIInvoke::call(this, [this]() { ui->render->update(); }); } -void TextureViewer::RT_UpdateVisualRange(IReplayController *) +void TextureViewer::RT_UpdateVisualRange(IReplayController *r) { TextureDescription *texptr = GetCurrentTexture(); @@ -819,8 +839,19 @@ void TextureViewer::RT_UpdateVisualRange(IReplayController *) m_TexDisplay.blue && fmt.compCount > 2, m_TexDisplay.alpha && fmt.compCount > 3, }; + ResourceId textureId = m_TexDisplay.resourceId; + Subresource sub = m_TexDisplay.subresource; + CompType typeCast = m_TexDisplay.typeCast; + + if(m_TexDisplay.customShaderId != ResourceId() && m_Output->GetCustomShaderTexID() != ResourceId()) + { + textureId = m_Output->GetCustomShaderTexID(); + sub.slice = sub.sample = 0; + typeCast = CompType::Typeless; + } + PixelValue min, max; - rdctie(min, max) = m_Output->GetMinMax(); + rdctie(min, max) = r->GetMinMax(textureId, sub, typeCast); // exclude any channels where the min == max, as this destroys the histogram's utility. // When we do this, after we have the histogram we set the appropriate bucket to max - to still @@ -842,8 +873,9 @@ void TextureViewer::RT_UpdateVisualRange(IReplayController *) } } - rdcarray histogram = m_Output->GetHistogram(ui->rangeHistogram->rangeMin(), - ui->rangeHistogram->rangeMax(), channels); + rdcarray histogram = + r->GetHistogram(textureId, sub, typeCast, ui->rangeHistogram->rangeMin(), + ui->rangeHistogram->rangeMax(), channels); if(!histogram.empty()) { @@ -934,10 +966,10 @@ void TextureViewer::UI_UpdateStatusText() ui->pickSwatch->setPalette(Pal); } - int y = m_CurHoverPixel.y() >> (int)m_TexDisplay.mip; + int y = m_CurHoverPixel.y() >> (int)m_TexDisplay.subresource.mip; - uint32_t mipWidth = qMax(1U, tex.width >> (int)m_TexDisplay.mip); - uint32_t mipHeight = qMax(1U, tex.height >> (int)m_TexDisplay.mip); + uint32_t mipWidth = qMax(1U, tex.width >> (int)m_TexDisplay.subresource.mip); + uint32_t mipHeight = qMax(1U, tex.height >> (int)m_TexDisplay.subresource.mip); if(m_Ctx.APIProps().pipelineType == GraphicsAPI::OpenGL) y = (int)(mipHeight - 1) - y; @@ -946,7 +978,7 @@ void TextureViewer::UI_UpdateStatusText() y = qMax(0, y); - int x = m_CurHoverPixel.x() >> (int)m_TexDisplay.mip; + int x = m_CurHoverPixel.x() >> (int)m_TexDisplay.subresource.mip; float invWidth = 1.0f / mipWidth; float invHeight = 1.0f / mipHeight; @@ -972,8 +1004,8 @@ void TextureViewer::UI_UpdateStatusText() if(m_PickedPoint.x() >= 0) { - x = m_PickedPoint.x() >> (int)m_TexDisplay.mip; - y = m_PickedPoint.y() >> (int)m_TexDisplay.mip; + x = m_PickedPoint.x() >> (int)m_TexDisplay.subresource.mip; + y = m_PickedPoint.y() >> (int)m_TexDisplay.subresource.mip; if(m_Ctx.APIProps().pipelineType == GraphicsAPI::OpenGL) y = (int)(mipHeight - 1) - y; if(m_TexDisplay.flipY) @@ -1294,8 +1326,8 @@ void TextureViewer::UI_OnTextureSelectionChanged(bool newdraw) ui->mipLevel->clear(); - m_TexDisplay.mip = 0; - m_TexDisplay.sliceFace = 0; + m_TexDisplay.subresource.mip = 0; + m_TexDisplay.subresource.slice = 0; bool usemipsettings = true; bool useslicesettings = true; @@ -1930,7 +1962,7 @@ void TextureViewer::GotoLocation(int x, int y) m_PickedPoint = QPoint(x, y); - uint32_t mipHeight = qMax(1U, tex->height >> (int)m_TexDisplay.mip); + uint32_t mipHeight = qMax(1U, tex->height >> (int)m_TexDisplay.subresource.mip); if(m_Ctx.APIProps().pipelineType == GraphicsAPI::OpenGL) m_PickedPoint.setY((int)(mipHeight - 1) - m_PickedPoint.y()); if(m_TexDisplay.flipY) @@ -2164,15 +2196,18 @@ void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res if(m_Ctx.GetTexture(res.resourceId)) { m_Ctx.Replay().AsyncInvoke([this, winData, res](IReplayController *) { - m_Output->AddThumbnail(winData, res.resourceId, res.typeCast, - res.firstMip >= 0 ? res.firstMip : 0, - res.firstSlice >= 0 ? res.firstSlice : 0); + Subresource sub = {0, 0, ~0U}; + if(res.firstMip >= 0) + sub.mip = res.firstMip; + if(res.firstSlice >= 0) + sub.slice = res.firstSlice; + m_Output->AddThumbnail(winData, res.resourceId, sub, res.typeCast); }); } else { m_Ctx.Replay().AsyncInvoke([this, winData](IReplayController *) { - m_Output->AddThumbnail(winData, ResourceId(), CompType::Typeless, 0, 0); + m_Output->AddThumbnail(winData, ResourceId(), {0, 0, ~0U}, CompType::Typeless); }); } @@ -2189,7 +2224,7 @@ void TextureViewer::InitResourcePreview(ResourcePreview *prev, BoundResource res WindowingData winData = m_Ctx.CreateWindowingData(prev->thumbWidget()); m_Ctx.Replay().AsyncInvoke([this, winData](IReplayController *) { - m_Output->AddThumbnail(winData, ResourceId(), CompType::Typeless, 0, 0); + m_Output->AddThumbnail(winData, ResourceId(), {0, 0, ~0U}, CompType::Typeless); }); } else @@ -2501,7 +2536,7 @@ void TextureViewer::render_keyPress(QKeyEvent *e) bool nudged = false; - int increment = 1 << (int)m_TexDisplay.mip; + int increment = 1 << (int)m_TexDisplay.subresource.mip; if(e->key() == Qt::Key_Up && m_PickedPoint.y() > 0) { @@ -3354,8 +3389,20 @@ void TextureViewer::AutoFitRange() return; m_Ctx.Replay().AsyncInvoke([this](IReplayController *r) { + + ResourceId textureId = m_TexDisplay.resourceId; + Subresource sub = m_TexDisplay.subresource; + CompType typeCast = m_TexDisplay.typeCast; + + if(m_TexDisplay.customShaderId != ResourceId() && m_Output->GetCustomShaderTexID() != ResourceId()) + { + textureId = m_Output->GetCustomShaderTexID(); + sub.slice = sub.sample = 0; + typeCast = CompType::Typeless; + } + PixelValue min, max; - rdctie(min, max) = m_Output->GetMinMax(); + rdctie(min, max) = r->GetMinMax(textureId, sub, typeCast); { float minval = FLT_MAX; @@ -3478,27 +3525,27 @@ void TextureViewer::on_mipLevel_currentIndexChanged(int index) TextureDescription &tex = *texptr; - uint32_t prevSlice = m_TexDisplay.sliceFace; + uint32_t prevSlice = m_TexDisplay.subresource.slice; if(tex.mips > 1) { - m_TexDisplay.mip = (uint32_t)qMax(0, index); - m_TexDisplay.sampleIdx = 0; + m_TexDisplay.subresource.mip = (uint32_t)qMax(0, index); + m_TexDisplay.subresource.sample = 0; } else { - m_TexDisplay.mip = 0; - m_TexDisplay.sampleIdx = (uint32_t)qMax(0, index); - if(m_TexDisplay.sampleIdx == tex.msSamp) - m_TexDisplay.sampleIdx = ~0U; + m_TexDisplay.subresource.mip = 0; + m_TexDisplay.subresource.sample = (uint32_t)qMax(0, index); + if(m_TexDisplay.subresource.sample == tex.msSamp) + m_TexDisplay.subresource.sample = ~0U; } // For 3D textures, update the slice list for this mip if(tex.depth > 1) { - uint32_t newSlice = prevSlice >> (int)m_TexDisplay.mip; + uint32_t newSlice = prevSlice >> (int)m_TexDisplay.subresource.mip; - uint32_t numSlices = qMax(1U, tex.depth >> (int)m_TexDisplay.mip); + uint32_t numSlices = qMax(1U, tex.depth >> (int)m_TexDisplay.subresource.mip); ui->sliceFace->clear(); @@ -3528,7 +3575,7 @@ void TextureViewer::on_sliceFace_currentIndexChanged(int index) return; TextureDescription &tex = *texptr; - m_TexDisplay.sliceFace = (uint32_t)qMax(0, index); + m_TexDisplay.subresource.slice = (uint32_t)qMax(0, index); INVOKE_MEMFN(RT_UpdateVisualRange); @@ -3553,7 +3600,7 @@ void TextureViewer::ShowGotoPopup() { QPoint p = m_PickedPoint; - uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.mip); + uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); if(m_Ctx.APIProps().pipelineType == GraphicsAPI::OpenGL) p.setY((int)(mipHeight - 1) - p.y()); @@ -3570,17 +3617,8 @@ void TextureViewer::on_viewTexBuffer_clicked() if(texptr) { - uint32_t slice = m_TexDisplay.sliceFace; - - if(texptr->msSamp > 1) - { - slice *= texptr->msSamp; - if(m_TexDisplay.sampleIdx < texptr->msSamp) - slice += m_TexDisplay.sampleIdx; - } - IBufferViewer *viewer = - m_Ctx.ViewTextureAsBuffer(slice, m_TexDisplay.mip, texptr->resourceId, + m_Ctx.ViewTextureAsBuffer(texptr->resourceId, m_TexDisplay.subresource, FormatElement::GenerateTextureBufferFormat(*texptr)); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); @@ -3612,8 +3650,8 @@ void TextureViewer::on_saveTex_clicked() // overwrite save params with current texture display settings m_SaveConfig.resourceId = m_TexDisplay.resourceId; m_SaveConfig.typeCast = m_TexDisplay.typeCast; - m_SaveConfig.slice.sliceIndex = (int)m_TexDisplay.sliceFace; - m_SaveConfig.mip = (int)m_TexDisplay.mip; + m_SaveConfig.slice.sliceIndex = (int)m_TexDisplay.subresource.slice; + m_SaveConfig.mip = (int)m_TexDisplay.subresource.mip; m_SaveConfig.channelExtract = -1; if(m_TexDisplay.red && !m_TexDisplay.green && !m_TexDisplay.blue && !m_TexDisplay.alpha) @@ -3692,12 +3730,12 @@ void TextureViewer::on_debugPixelContext_clicked() if(m_PickedPoint.x() < 0 || m_PickedPoint.y() < 0) return; - int x = m_PickedPoint.x() >> (int)m_TexDisplay.mip; - int y = m_PickedPoint.y() >> (int)m_TexDisplay.mip; + int x = m_PickedPoint.x() >> (int)m_TexDisplay.subresource.mip; + int y = m_PickedPoint.y() >> (int)m_TexDisplay.subresource.mip; TextureDescription *texptr = GetCurrentTexture(); - uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.mip); + uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); if(m_TexDisplay.flipY) y = (int)(mipHeight - 1) - y; @@ -3706,7 +3744,7 @@ void TextureViewer::on_debugPixelContext_clicked() ShaderDebugTrace *trace = NULL; m_Ctx.Replay().AsyncInvoke([this, &trace, &done, x, y](IReplayController *r) { - trace = r->DebugPixel((uint32_t)x, (uint32_t)y, m_TexDisplay.sampleIdx, ~0U); + trace = r->DebugPixel((uint32_t)x, (uint32_t)y, m_TexDisplay.subresource.sample, ~0U); if(trace->states.isEmpty()) { @@ -3755,10 +3793,10 @@ void TextureViewer::on_pixelHistory_clicked() ANALYTIC_SET(UIFeatures.PixelHistory, true); - int x = m_PickedPoint.x() >> (int)m_TexDisplay.mip; - int y = m_PickedPoint.y() >> (int)m_TexDisplay.mip; + int x = m_PickedPoint.x() >> (int)m_TexDisplay.subresource.mip; + int y = m_PickedPoint.y() >> (int)m_TexDisplay.subresource.mip; - uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.mip); + uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); if(m_TexDisplay.flipY) y = (int)(mipHeight - 1) - y; @@ -3777,8 +3815,8 @@ void TextureViewer::on_pixelHistory_clicked() QThread::msleep(150); m_Ctx.Replay().AsyncInvoke([this, texptr, x, y, hist, histWidget](IReplayController *r) { rdcarray history = - r->PixelHistory(texptr->resourceId, (uint32_t)x, (int32_t)y, m_TexDisplay.sliceFace, - m_TexDisplay.mip, m_TexDisplay.sampleIdx, m_TexDisplay.typeCast); + r->PixelHistory(texptr->resourceId, (uint32_t)x, (int32_t)y, m_TexDisplay.subresource, + m_TexDisplay.typeCast); GUIInvoke::call(this, [hist, histWidget, history] { if(histWidget) diff --git a/qrenderdoc/Windows/TextureViewer.h b/qrenderdoc/Windows/TextureViewer.h index 089896f1c..d400f977e 100644 --- a/qrenderdoc/Windows/TextureViewer.h +++ b/qrenderdoc/Windows/TextureViewer.h @@ -216,7 +216,8 @@ protected: void changeEvent(QEvent *event) override; private: - void RT_FetchCurrentPixel(uint32_t x, uint32_t y, PixelValue &pickValue, PixelValue &realValue); + void RT_FetchCurrentPixel(IReplayController *r, uint32_t x, uint32_t y, PixelValue &pickValue, + PixelValue &realValue); void RT_PickPixelsAndUpdate(IReplayController *); void RT_PickHoverAndUpdate(IReplayController *); void RT_UpdateAndDisplay(IReplayController *); diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index d595c33b6..f52dc3da3 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -264,18 +264,12 @@ See :meth:`ReplayController.BuildCustomShader` for creating an appropriate custo )"); ResourceId customShaderId; - DOCUMENT("Select the mip of the texture to display."); - uint32_t mip = 0; + DOCUMENT(R"(The subresource of the texture to display. - DOCUMENT("Select the slice or face of the texture to display if it's an array, 3D, or cube tex."); - uint32_t sliceFace = 0; - - DOCUMENT(R"(Select the sample of the texture to display if it's a multi-sampled texture. - -If this is set to :data:`ResolveSamples` then a default resolve will be performed that averages all -samples. +If the :data:`Subresource.sample` member is set to :data:`ResolveSamples` then a default resolve +will be performed that averages all samples. )"); - uint32_t sampleIdx = 0; + Subresource subresource = {0, 0, 0}; DOCUMENT(R"(``True`` if the rendered image should be as close as possible in value to the input. diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index c95923fac..a5c6fcceb 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -1528,6 +1528,49 @@ union PixelValue DECLARE_REFLECTION_STRUCT(PixelValue); +DOCUMENT("Specifies a subresource within a texture."); +struct Subresource +{ + DOCUMENT(""); + Subresource(uint32_t mip = 0, uint32_t slice = 0, uint32_t sample = 0) + : mip(mip), slice(slice), sample(sample) + { + } + Subresource(const Subresource &) = default; + + bool operator==(const Subresource &o) const + { + return mip == o.mip && slice == o.slice && sample == o.sample; + } + bool operator!=(const Subresource &o) const { return !(*this == o); } + bool operator<(const Subresource &o) const + { + if(!(mip == o.mip)) + return mip < o.mip; + if(!(slice == o.slice)) + return slice < o.slice; + if(!(sample == o.sample)) + return sample < o.sample; + return false; + } + + DOCUMENT("The mip level in the texture."); + uint32_t mip; + DOCUMENT(R"(The slice within the texture. For 3D textures this is a depth slice, for arrays it is +an array slice. + +.. note:: + Cubemaps are simply 2D array textures with a special meaning, so the faces of a cubemap are the 2D + array slices in the standard order: X+, X-, Y+, Y-, Z+, Z-. Cubemap arrays are 2D arrays with + ``6 * N`` faces, where each cubemap within the array takes up 6 slices in the above order. +)"); + uint32_t slice; + DOCUMENT("The sample in a multisampled texture."); + uint32_t sample; +}; + +DECLARE_REFLECTION_STRUCT(Subresource); + DOCUMENT("The value of pixel output at a particular event."); struct ModificationValue { diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index e7b347e09..7d325e996 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -740,17 +740,16 @@ Should only be called for texture outputs. :param WindowingData window: A :class:`WindowingData` describing the native window. :param ResourceId textureId: The texture ID to display in the thumbnail preview. +:param Subresource sub: The subresource within this texture to use. :param CompType typeCast: If possible interpret the texture with this type instead of its normal type. If set to :data:`CompType.Typeless` then no cast is applied, otherwise where allowed the texture data will be reinterpreted - e.g. from unsigned integers to floats, or to unsigned normalised values. -:param int slice: The slice of the texture to display. -:param int mip: The mip of the texture to display. :return: A boolean indicating if the thumbnail was successfully created. :rtype: ``bool`` )"); - virtual bool AddThumbnail(WindowingData window, ResourceId textureId, CompType typeCast, - uint32_t mip, uint32_t slice) = 0; + virtual bool AddThumbnail(WindowingData window, ResourceId textureId, const Subresource &sub, + CompType typeCast) = 0; DOCUMENT(R"(Render to the window handle specified when the output was created. @@ -780,34 +779,6 @@ Should only be called for texture outputs. DOCUMENT("Disable the pixel context view from rendering."); virtual void DisablePixelContext() = 0; - DOCUMENT(R"(Retrieves the minimum and maximum values in the current texture. - -Should only be called for texture outputs. - -:return: A tuple with the minimum and maximum pixel values respectively. -:rtype: ``tuple`` of PixelValue and PixelValue -)"); - virtual rdcpair GetMinMax() = 0; - - DOCUMENT(R"(Retrieve a list of values that can be used to show a histogram of values for the -current texture. - -The output list contains N buckets, and each bucket has the number of pixels that falls in each -bucket when the pixel values are divided between ``minval`` and ``maxval``. - -Should only be called for texture outputs. - -:param float minval: The lower end of the smallest bucket. If any values are below this, they are - not added to any bucket. -:param float maxval: The upper end of the largest bucket. If any values are above this, they are - not added to any bucket. -:param list channels: A list of four ``bool`` values indicating whether each of RGBA should be - included in the count. -:return: A list of the unnormalised bucket values. -:rtype: ``list`` of ``int`` -)"); - virtual rdcarray GetHistogram(float minval, float maxval, bool channels[4]) = 0; - DOCUMENT(R"(Retrieves the :class:`ResourceId` containing the contents of the texture after being passed through a custom shader pass. @@ -828,29 +799,6 @@ Should only be called for texture outputs. )"); virtual ResourceId GetDebugOverlayTexID() = 0; - DOCUMENT(R"(Retrieve the contents of a particular pixel in a texture. - -Should only be called for texture outputs. - -.. note:: - X and Y co-ordinates are always considered to be top-left, even on GL, for consistency between - APIs and preventing the need for API-specific code in most cases. This means if co-ordinates are - fetched from e.g. viewport or scissor data or other GL pipeline state which is perhaps in - bottom-left co-ordinates, care must be taken to translate them. - -:param ResourceId textureId: The texture to pick the pixel from. -:param bool customShader: Whether to apply the configured custom shader. -:param int x: The x co-ordinate to pick from. -:param int y: The y co-ordinate to pick from. -:param int sliceFace: The slice of an array or 3D texture, or face of a cubemap texture. -:param int mip: The mip level to pick from. -:param int sample: The multisample sample to pick from. -:return: The contents of the pixel. -:rtype: PixelValue -)"); - virtual PixelValue PickPixel(ResourceId textureId, bool customShader, uint32_t x, uint32_t y, - uint32_t sliceFace, uint32_t mip, uint32_t sample) = 0; - DOCUMENT(R"(Retrieves the vertex and instance that is under the cursor location, when viewed relative to the current window with the current mesh display configuration. @@ -1235,6 +1183,67 @@ only ever have one result (only one entry point per shader). virtual ShaderReflection *GetShader(ResourceId pipeline, ResourceId shader, ShaderEntryPoint entry) = 0; + DOCUMENT(R"(Retrieve the contents of a particular pixel in a texture. + +.. note:: + X and Y co-ordinates are always considered to be top-left, even on GL, for consistency between + APIs and preventing the need for API-specific code in most cases. This means if co-ordinates are + fetched from e.g. viewport or scissor data or other GL pipeline state which is perhaps in + bottom-left co-ordinates, care must be taken to translate them. + +:param ResourceId textureId: The texture to pick the pixel from. +:param int x: The x co-ordinate to pick from. +:param int y: The y co-ordinate to pick from. +:param Subresource sub: The subresource within this texture to use. +:param CompType typeCast: If possible interpret the texture with this type instead of its normal + type. If set to :data:`CompType.Typeless` then no cast is applied, otherwise where allowed the + texture data will be reinterpreted - e.g. from unsigned integers to floats, or to unsigned + normalised values. +:return: The contents of the pixel. +:rtype: PixelValue +)"); + virtual PixelValue PickPixel(ResourceId textureId, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast) = 0; + + DOCUMENT(R"(Retrieves the minimum and maximum values in the specified texture. + +:param ResourceId textureId: The texture to get the values from. +:param Subresource sub: The subresource within this texture to use. +:param CompType typeCast: If possible interpret the texture with this type instead of its normal + type. If set to :data:`CompType.Typeless` then no cast is applied, otherwise where allowed the + texture data will be reinterpreted - e.g. from unsigned integers to floats, or to unsigned + normalised values. +:return: A tuple with the minimum and maximum pixel values respectively. +:rtype: ``tuple`` of PixelValue and PixelValue +)"); + virtual rdcpair GetMinMax(ResourceId textureId, const Subresource &sub, + CompType typeCast) = 0; + + DOCUMENT(R"(Retrieve a list of values that can be used to show a histogram of values for the +specified texture. + +The output list contains N buckets, and each bucket has the number of pixels that falls in each +bucket when the pixel values are divided between ``minval`` and ``maxval``. + +:param ResourceId textureId: The texture to get the histogram from. +:param Subresource sub: The subresource within this texture to use. +:param CompType typeCast: If possible interpret the texture with this type instead of its normal + type. If set to :data:`CompType.Typeless` then no cast is applied, otherwise where allowed the + texture data will be reinterpreted - e.g. from unsigned integers to floats, or to unsigned + normalised values. +:param float minval: The lower end of the smallest bucket. If any values are below this, they are + not added to any bucket. +:param float maxval: The upper end of the largest bucket. If any values are above this, they are + not added to any bucket. +:param list channels: A list of four ``bool`` values indicating whether each of RGBA should be + included in the count. +:return: A list of the unnormalised bucket values. +:rtype: ``list`` of ``int`` +)"); + virtual rdcarray GetHistogram(ResourceId textureId, const Subresource &sub, + CompType typeCast, float minval, float maxval, + bool channels[4]) = 0; + DOCUMENT(R"(Retrieve the history of modifications to the selected pixel on the selected texture. .. note:: @@ -1246,8 +1255,7 @@ only ever have one result (only one entry point per shader). :param ResourceId texture: The texture to search for modifications. :param int x: The x co-ordinate. :param int y: The y co-ordinate. -:param int slice: The slice of an array or 3D texture, or face of a cubemap texture. -:param int mip: The mip level to pick from. +:param Subresource sub: The subresource within this texture to use. :param int sampleIdx: The multi-sampled sample. Ignored if non-multisampled texture. :param CompType typeCast: If possible interpret the texture with this type instead of its normal type. If set to :data:`CompType.Typeless` then no cast is applied, otherwise where allowed the @@ -1257,8 +1265,7 @@ only ever have one result (only one entry point per shader). :rtype: ``list`` of :class:`PixelModification` )"); virtual rdcarray PixelHistory(ResourceId texture, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, uint32_t sampleIdx, - CompType typeCast) = 0; + const Subresource &sub, CompType typeCast) = 0; DOCUMENT(R"(Retrieve a debugging trace from running a vertex shader. @@ -1369,17 +1376,12 @@ texture to something compatible with the target file format. DOCUMENT(R"(Retrieve the contents of one subresource of a texture as a ``bytes``. -For multi-sampled images, they are treated as if they are an array that is Nx longer, with each -array slice being expanded in-place so it would be slice 0: sample 0, slice 0: sample 1, slice 1: -sample 0, etc. - :param ResourceId tex: The id of the texture to retrieve data from. -:param int arrayIdx: The slice of an array or 3D texture, or face of a cubemap texture. -:param int mip: The mip level to pick from. +:param Subresource sub: The subresource within this texture to use. :return: The requested texture contents. :rtype: ``bytes`` )"); - virtual bytebuf GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip) = 0; + virtual bytebuf GetTextureData(ResourceId tex, const Subresource &sub) = 0; static const uint32_t NoPreference = ~0U; diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 50febf634..32565753b 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -110,17 +110,20 @@ public: { m_Proxy->RenderHighlightBox(w, h, scale); } - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) { - return m_Proxy->GetMinMax(m_TextureID, sliceFace, mip, sample, typeCast, minval, maxval); + m_Proxy->PickPixel(m_TextureID, x, y, sub, typeCast, pixel); } - bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram) + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval) { - return m_Proxy->GetHistogram(m_TextureID, sliceFace, mip, sample, typeCast, minval, maxval, - channels, histogram); + return m_Proxy->GetMinMax(m_TextureID, sub, typeCast, minval, maxval); + } + bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram) + { + return m_Proxy->GetHistogram(m_TextureID, sub, typeCast, minval, maxval, channels, histogram); } bool RenderTexture(TextureDisplay cfg) { @@ -128,11 +131,6 @@ public: cfg.resourceId = m_TextureID; return m_Proxy->RenderTexture(cfg); } - void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, - uint32_t sample, CompType typeCast, float pixel[4]) - { - m_Proxy->PickPixel(m_TextureID, x, y, sliceFace, mip, sample, typeCast, pixel); - } uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y) { @@ -153,20 +151,19 @@ public: m_Proxy->BuildCustomShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } void FreeCustomShader(ResourceId id) { m_Proxy->FreeTargetResource(id); } - ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, - uint32_t sampleIdx, CompType typeCast) + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast) { - m_CustomTexID = - m_Proxy->ApplyCustomShader(shader, m_TextureID, mip, arrayIdx, sampleIdx, typeCast); + m_CustomTexID = m_Proxy->ApplyCustomShader(shader, m_TextureID, sub, typeCast); return m_CustomTexID; } const std::vector &GetResources() { return m_Resources; } std::vector GetTextures() { return {m_TextureID}; } TextureDescription GetTexture(ResourceId id) { return m_Proxy->GetTexture(m_TextureID); } - void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, - const GetTextureDataParams ¶ms, bytebuf &data) + void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, + bytebuf &data) { - m_Proxy->GetTextureData(m_TextureID, arrayIdx, mip, params, data); + m_Proxy->GetTextureData(m_TextureID, sub, params, data); } // handle a couple of operations ourselves to return a simple fake log @@ -249,8 +246,8 @@ public: } void FreeTargetResource(ResourceId id) {} std::vector PixelHistory(std::vector events, ResourceId target, - uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast) { return std::vector(); } @@ -293,8 +290,7 @@ public: return ResourceId(); } - void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, - size_t dataSize) + void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize) { RDCERR("Calling proxy-render functions on an image viewer"); } @@ -742,14 +738,14 @@ void ImageViewer::RefreshFile() if(!dds) { - m_Proxy->SetProxyTextureData(m_TextureID, 0, 0, data, datasize); + m_Proxy->SetProxyTextureData(m_TextureID, Subresource(), data, datasize); free(data); } else { for(uint32_t i = 0; i < texDetails.arraysize * texDetails.mips; i++) { - m_Proxy->SetProxyTextureData(m_TextureID, i / texDetails.mips, i % texDetails.mips, + m_Proxy->SetProxyTextureData(m_TextureID, {i % texDetails.mips, i / texDetails.mips}, read_data.subdata[i], (size_t)read_data.subsizes[i]); delete[] read_data.subdata[i]; diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 1e067ac07..b49eaa01d 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -876,7 +876,7 @@ void ReplayProxy::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, template void ReplayProxy::Proxied_GetTextureData(ParamSerialiser ¶mser, ReturnSerialiser &retser, - ResourceId tex, uint32_t arrayIdx, uint32_t mip, + ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { const ReplayProxyPacket expectedPacket = eReplayProxy_GetTextureData; @@ -885,8 +885,7 @@ void ReplayProxy::Proxied_GetTextureData(ParamSerialiser ¶mser, ReturnSerial { BEGIN_PARAMS(); SERIALISE_ELEMENT(tex); - SERIALISE_ELEMENT(arrayIdx); - SERIALISE_ELEMENT(mip); + SERIALISE_ELEMENT(sub); SERIALISE_ELEMENT(params); END_PARAMS(); } @@ -894,7 +893,7 @@ void ReplayProxy::Proxied_GetTextureData(ParamSerialiser ¶mser, ReturnSerial { REMOTE_EXECUTION(); if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored) - m_Remote->GetTextureData(tex, arrayIdx, mip, params, data); + m_Remote->GetTextureData(tex, sub, params, data); } // over-estimate of total uncompressed data written. Since the decompression chain needs to know @@ -948,10 +947,10 @@ void ReplayProxy::Proxied_GetTextureData(ParamSerialiser ¶mser, ReturnSerial CheckError(packet, expectedPacket); } -void ReplayProxy::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +void ReplayProxy::GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { - PROXY_FUNCTION(GetTextureData, tex, arrayIdx, mip, params, data); + PROXY_FUNCTION(GetTextureData, tex, sub, params, data); } template @@ -1411,8 +1410,7 @@ void ReplayProxy::RemoveReplacement(ResourceId id) template std::vector ReplayProxy::Proxied_PixelHistory( ParamSerialiser ¶mser, ReturnSerialiser &retser, std::vector events, - ResourceId target, uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, uint32_t sampleIdx, - CompType typeCast) + ResourceId target, uint32_t x, uint32_t y, const Subresource &sub, CompType typeCast) { const ReplayProxyPacket expectedPacket = eReplayProxy_PixelHistory; ReplayProxyPacket packet = eReplayProxy_PixelHistory; @@ -1424,9 +1422,7 @@ std::vector ReplayProxy::Proxied_PixelHistory( SERIALISE_ELEMENT(target); SERIALISE_ELEMENT(x); SERIALISE_ELEMENT(y); - SERIALISE_ELEMENT(slice); - SERIALISE_ELEMENT(mip); - SERIALISE_ELEMENT(sampleIdx); + SERIALISE_ELEMENT(sub); SERIALISE_ELEMENT(typeCast); END_PARAMS(); } @@ -1434,7 +1430,7 @@ std::vector ReplayProxy::Proxied_PixelHistory( { REMOTE_EXECUTION(); if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored) - ret = m_Remote->PixelHistory(events, target, x, y, slice, mip, sampleIdx, typeCast); + ret = m_Remote->PixelHistory(events, target, x, y, sub, typeCast); } SERIALISE_RETURN(ret); @@ -1444,10 +1440,9 @@ std::vector ReplayProxy::Proxied_PixelHistory( std::vector ReplayProxy::PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + const Subresource &sub, CompType typeCast) { - PROXY_FUNCTION(PixelHistory, events, target, x, y, slice, mip, sampleIdx, typeCast); + PROXY_FUNCTION(PixelHistory, events, target, x, y, sub, typeCast); } template @@ -2087,7 +2082,7 @@ void ReplayProxy::CacheBufferData(ResourceId buff) template void ReplayProxy::Proxied_CacheTextureData(ParamSerialiser ¶mser, ReturnSerialiser &retser, - ResourceId tex, uint32_t arrayIdx, uint32_t mip, + ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms) { const ReplayProxyPacket expectedPacket = eReplayProxy_CacheTextureData; @@ -2096,8 +2091,7 @@ void ReplayProxy::Proxied_CacheTextureData(ParamSerialiser ¶mser, ReturnSeri { BEGIN_PARAMS(); SERIALISE_ELEMENT(tex); - SERIALISE_ELEMENT(arrayIdx); - SERIALISE_ELEMENT(mip); + SERIALISE_ELEMENT(sub); SERIALISE_ELEMENT(params); END_PARAMS(); } @@ -2107,7 +2101,7 @@ void ReplayProxy::Proxied_CacheTextureData(ParamSerialiser ¶mser, ReturnSeri { REMOTE_EXECUTION(); if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored) - m_Remote->GetTextureData(tex, arrayIdx, mip, params, data); + m_Remote->GetTextureData(tex, sub, params, data); } { @@ -2116,7 +2110,7 @@ void ReplayProxy::Proxied_CacheTextureData(ParamSerialiser ¶mser, ReturnSeri SERIALISE_ELEMENT(packet); } - TextureCacheEntry entry = {tex, arrayIdx, mip}; + TextureCacheEntry entry = {tex, sub}; DeltaTransferBytes(retser, m_ProxyTextureData[entry], data); retser.EndChunk(); @@ -2124,10 +2118,10 @@ void ReplayProxy::Proxied_CacheTextureData(ParamSerialiser ¶mser, ReturnSeri CheckError(packet, expectedPacket); } -void ReplayProxy::CacheTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +void ReplayProxy::CacheTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms) { - PROXY_FUNCTION(CacheTextureData, tex, arrayIdx, mip, params); + PROXY_FUNCTION(CacheTextureData, tex, sub, params); } #pragma endregion Proxied Functions @@ -2210,18 +2204,27 @@ void ReplayProxy::RemapProxyTextureIfNeeded(TextureDescription &tex, GetTextureD } } -void ReplayProxy::EnsureTexCached(ResourceId texid, uint32_t arrayIdx, uint32_t mip) +void ReplayProxy::EnsureTexCached(ResourceId texid, const Subresource &sub) { if(m_Reader.IsErrored() || m_Writer.IsErrored()) return; - TextureCacheEntry entry = {texid, arrayIdx, mip}; + TextureCacheEntry entry = {texid, sub}; - // 3D textures shouldn't cache by array index, since we fetch the whole texture at once. + // ignore parameters in the key which don't matter for this texture { auto it = m_TextureInfo.find(texid); - if(it != m_TextureInfo.end() && it->second.dimension == 3) - entry.arrayIdx = 0; + if(it != m_TextureInfo.end()) + { + if(it->second.mips <= 1) + entry.sub.mip = 0; + + if(it->second.dimension == 3 || it->second.arraysize <= 1) + entry.sub.slice = 0; + + if(it->second.msSamp <= 1) + entry.sub.sample = 0; + } } if(m_LocalTextures.find(texid) != m_LocalTextures.end()) @@ -2245,25 +2248,20 @@ void ReplayProxy::EnsureTexCached(ResourceId texid, uint32_t arrayIdx, uint32_t for(uint32_t sample = 0; sample < proxy.msSamp; sample++) { - // MSAA array textures are remapped so it's: - // [slice 0 samp 0, slice 0 samp 1, slice 1 samp 0, slice 1 samp 1, ...] - // so we need to calculate the effective array index to fetch and set the data. - // For non-MSAA textures this operation does nothing (sample is 0, proxy.msSamp is 1) - uint32_t sampleArrayIdx = arrayIdx * proxy.msSamp + sample; + Subresource s = sub; + s.sample = sample; - TextureCacheEntry sampleArrayEntry = entry; - sampleArrayEntry.arrayIdx = sampleArrayIdx; + TextureCacheEntry sampleArrayEntry = {texid, s}; #if ENABLED(TRANSFER_RESOURCE_CONTENTS_DELTAS) - CacheTextureData(texid, sampleArrayIdx, mip, proxy.params); + CacheTextureData(texid, s, proxy.params); #else - GetTextureData(texid, sampleArrayIdx, mip, proxy.params, m_ProxyTextureData[entry]); + GetTextureData(texid, s, proxy.params, m_ProxyTextureData[entry]); #endif auto it = m_ProxyTextureData.find(sampleArrayEntry); if(it != m_ProxyTextureData.end()) - m_Proxy->SetProxyTextureData(proxy.id, sampleArrayIdx, mip, it->second.data(), - it->second.size()); + m_Proxy->SetProxyTextureData(proxy.id, s, it->second.data(), it->second.size()); } m_TextureProxyCache.insert(entry); @@ -2418,9 +2416,7 @@ void ReplayProxy::RefreshPreviewWindow() cfg.hdrMultiplier = -1.0f; cfg.linearDisplayAsGamma = true; cfg.customShaderId = ResourceId(); - cfg.mip = 0; - cfg.sliceFace = 0; - cfg.sampleIdx = 0; + cfg.subresource = {0, 0, 0}; cfg.rawOutput = false; cfg.backgroundColor = FloatVector(0, 0, 0, 0); cfg.overlay = DebugOverlay::NoOverlay; @@ -2611,7 +2607,7 @@ bool ReplayProxy::Tick(int type) { case eReplayProxy_CacheBufferData: CacheBufferData(ResourceId()); break; case eReplayProxy_CacheTextureData: - CacheTextureData(ResourceId(), 0, 0, GetTextureDataParams()); + CacheTextureData(ResourceId(), Subresource(), GetTextureDataParams()); break; case eReplayProxy_ReplayLog: ReplayLog(0, (ReplayLogType)0); break; case eReplayProxy_FetchStructuredFile: FetchStructuredFile(); break; @@ -2634,7 +2630,7 @@ bool ReplayProxy::Tick(int type) case eReplayProxy_GetTextureData: { bytebuf dummy; - GetTextureData(ResourceId(), 0, 0, GetTextureDataParams(), dummy); + GetTextureData(ResourceId(), Subresource(), GetTextureDataParams(), dummy); break; } case eReplayProxy_SavePipelineState: SavePipelineState(0); break; @@ -2690,7 +2686,7 @@ bool ReplayProxy::Tick(int type) std::vector()); break; case eReplayProxy_PixelHistory: - PixelHistory(std::vector(), ResourceId(), 0, 0, 0, 0, 0, CompType::Typeless); + PixelHistory(std::vector(), ResourceId(), 0, 0, Subresource(), CompType::Typeless); break; case eReplayProxy_DisassembleShader: DisassembleShader(ResourceId(), NULL, ""); break; case eReplayProxy_GetDisassemblyTargets: GetDisassemblyTargets(); break; diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 9bedfe8ec..41348c4cf 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -245,42 +245,11 @@ public: return m_Proxy->RenderHighlightBox(w, h, scale); } - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) - { - if(m_Proxy) - { - EnsureTexCached(texid, sliceFace, mip); - if(texid == ResourceId() || m_ProxyTextures[texid] == ResourceId()) - return false; - return m_Proxy->GetMinMax(m_ProxyTextures[texid], sliceFace, mip, sample, typeCast, minval, - maxval); - } - - return false; - } - - bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram) - { - if(m_Proxy) - { - EnsureTexCached(texid, sliceFace, mip); - if(texid == ResourceId() || m_ProxyTextures[texid] == ResourceId()) - return false; - return m_Proxy->GetHistogram(m_ProxyTextures[texid], sliceFace, mip, sample, typeCast, minval, - maxval, channels, histogram); - } - - return false; - } - bool RenderTexture(TextureDisplay cfg) { if(m_Proxy) { - EnsureTexCached(cfg.resourceId, cfg.sliceFace, cfg.mip); + EnsureTexCached(cfg.resourceId, cfg.subresource); if(cfg.resourceId == ResourceId() || m_ProxyTextures[cfg.resourceId] == ResourceId()) return false; cfg.resourceId = m_ProxyTextures[cfg.resourceId]; @@ -299,12 +268,12 @@ public: return false; } - void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, - uint32_t sample, CompType typeCast, float pixel[4]) + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) { if(m_Proxy) { - EnsureTexCached(texture, sliceFace, mip); + EnsureTexCached(texture, sub); if(texture == ResourceId() || m_ProxyTextures[texture] == ResourceId()) return; @@ -318,14 +287,43 @@ public: (m_APIProps.localRenderer == GraphicsAPI::OpenGL)) { TextureDescription tex = m_Proxy->GetTexture(texture); - uint32_t mipHeight = RDCMAX(1U, tex.height >> mip); + uint32_t mipHeight = RDCMAX(1U, tex.height >> sub.mip); y = (mipHeight - 1) - y; } - m_Proxy->PickPixel(texture, x, y, sliceFace, mip, sample, typeCast, pixel); + m_Proxy->PickPixel(texture, x, y, sub, typeCast, pixel); } } + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval) + { + if(m_Proxy) + { + EnsureTexCached(texid, sub); + if(texid == ResourceId() || m_ProxyTextures[texid] == ResourceId()) + return false; + return m_Proxy->GetMinMax(m_ProxyTextures[texid], sub, typeCast, minval, maxval); + } + + return false; + } + + bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram) + { + if(m_Proxy) + { + EnsureTexCached(texid, sub); + if(texid == ResourceId() || m_ProxyTextures[texid] == ResourceId()) + return false; + return m_Proxy->GetHistogram(m_ProxyTextures[texid], sub, typeCast, minval, maxval, channels, + histogram); + } + + return false; + } + void RenderMesh(uint32_t eventId, const std::vector &secondaryDraws, const MeshDisplay &cfg) { @@ -433,17 +431,16 @@ public: m_Proxy->FreeTargetResource(id); } - ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, - uint32_t sampleIdx, CompType typeCast) + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast) { if(m_Proxy) { - EnsureTexCached(texid, 0, mip); + EnsureTexCached(texid, sub); if(texid == ResourceId() || m_ProxyTextures[texid] == ResourceId()) return ResourceId(); texid = m_ProxyTextures[texid]; - ResourceId customResourceId = - m_Proxy->ApplyCustomShader(shader, texid, mip, arrayIdx, sampleIdx, typeCast); + ResourceId customResourceId = m_Proxy->ApplyCustomShader(shader, texid, sub, typeCast); m_LocalTextures.insert(customResourceId); m_ProxyTextures[customResourceId] = customResourceId; return customResourceId; @@ -498,7 +495,7 @@ public: IMPLEMENT_FUNCTION_PROXIED(void, GetBufferData, ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData); - IMPLEMENT_FUNCTION_PROXIED(void, GetTextureData, ResourceId tex, uint32_t arrayIdx, uint32_t mip, + IMPLEMENT_FUNCTION_PROXIED(void, GetTextureData, ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data); IMPLEMENT_FUNCTION_PROXIED(void, InitPostVSBuffers, uint32_t eventId); @@ -522,8 +519,7 @@ public: IMPLEMENT_FUNCTION_PROXIED(std::vector, PixelHistory, std::vector events, ResourceId target, uint32_t x, - uint32_t y, uint32_t slice, uint32_t mip, uint32_t sampleIdx, - CompType typeCast); + uint32_t y, const Subresource &sub, CompType typeCast); IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace, DebugVertex, uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace, DebugPixel, uint32_t eventId, uint32_t x, uint32_t y, @@ -542,8 +538,8 @@ public: // and GetTextureData, but they do extra work to try and optimise transfer by delta-encoding the // difference in the returned data to the last time the resource was cached IMPLEMENT_FUNCTION_PROXIED(void, CacheBufferData, ResourceId buff); - IMPLEMENT_FUNCTION_PROXIED(void, CacheTextureData, ResourceId tex, uint32_t arrayIdx, - uint32_t mip, const GetTextureDataParams ¶ms); + IMPLEMENT_FUNCTION_PROXIED(void, CacheTextureData, ResourceId tex, const Subresource &sub, + const GetTextureDataParams ¶ms); // utility function to serialise the contents of a byte array given the previous contents that's // available on both sides of the communication. @@ -558,8 +554,7 @@ public: return ResourceId(); } - void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, - size_t dataSize) + void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize) { RDCERR("Calling proxy-render functions on a proxy serialiser"); } @@ -577,7 +572,7 @@ public: } private: - void EnsureTexCached(ResourceId texid, uint32_t arrayIdx, uint32_t mip); + void EnsureTexCached(ResourceId texid, const Subresource &sub); void RemapProxyTextureIfNeeded(TextureDescription &tex, GetTextureDataParams ¶ms); void EnsureBufCached(ResourceId bufid); IMPLEMENT_FUNCTION_PROXIED(bool, NeedRemapForFetch, const ResourceFormat &format); @@ -590,16 +585,13 @@ private: struct TextureCacheEntry { ResourceId replayid; - uint32_t arrayIdx; - uint32_t mip; + Subresource sub; bool operator<(const TextureCacheEntry &o) const { if(replayid != o.replayid) return replayid < o.replayid; - if(arrayIdx != o.arrayIdx) - return arrayIdx < o.arrayIdx; - return mip < o.mip; + return sub < o.sub; } }; // this cache only exists on the client side, with the proxy renderer. This denotes cases where we diff --git a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp index ff8086849..d0f0d6c62 100644 --- a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp +++ b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp @@ -281,8 +281,7 @@ void D3D11DebugManager::PixelHistoryCopyPixel(CopyPixelParams &p, uint32_t x, ui std::vector D3D11Replay::PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + const Subresource &sub, CompType typeCast) { std::vector history; @@ -297,6 +296,10 @@ std::vector D3D11Replay::PixelHistory(std::vector if(details.texFmt == DXGI_FORMAT_UNKNOWN) return history; + uint32_t slice = sub.slice; + uint32_t mip = sub.mip; + uint32_t sampleIdx = sub.sample; + D3D11MarkerRegion historyMarker( StringFormat::Fmt("Doing PixelHistory on %llu, (%u,%u) %u, %u, %u over %u events", target, x, y, slice, mip, sampleIdx, (uint32_t)events.size())); diff --git a/renderdoc/driver/d3d11/d3d11_rendertexture.cpp b/renderdoc/driver/d3d11/d3d11_rendertexture.cpp index 21c240bb7..509c5a180 100644 --- a/renderdoc/driver/d3d11/d3d11_rendertexture.cpp +++ b/renderdoc/driver/d3d11/d3d11_rendertexture.cpp @@ -507,10 +507,10 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha) TextureShaderDetails details = GetDebugManager()->GetShaderDetails(cfg.resourceId, cfg.typeCast, cfg.rawOutput ? true : false); - int sampleIdx = (int)RDCCLAMP(cfg.sampleIdx, 0U, details.sampleCount - 1); + int sampleIdx = (int)RDCCLAMP(cfg.subresource.sample, 0U, details.sampleCount - 1); // hacky resolve - if(cfg.sampleIdx == ~0U) + if(cfg.subresource.sample == ~0U) sampleIdx = -int(details.sampleCount); pixelData.SampleIdx = sampleIdx; @@ -529,9 +529,9 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha) float tex_x = float(details.texWidth); float tex_y = float(details.texType == eTexType_1D ? 100 : details.texHeight); - pixelData.TextureResolutionPS.x = float(RDCMAX(1U, details.texWidth >> cfg.mip)); - pixelData.TextureResolutionPS.y = float(RDCMAX(1U, details.texHeight >> cfg.mip)); - pixelData.TextureResolutionPS.z = float(RDCMAX(1U, details.texDepth >> cfg.mip)); + pixelData.TextureResolutionPS.x = float(RDCMAX(1U, details.texWidth >> cfg.subresource.mip)); + pixelData.TextureResolutionPS.y = float(RDCMAX(1U, details.texHeight >> cfg.subresource.mip)); + pixelData.TextureResolutionPS.z = float(RDCMAX(1U, details.texDepth >> cfg.subresource.mip)); if(details.texArraySize > 1 && details.texType != eTexType_3D) pixelData.TextureResolutionPS.z = float(details.texArraySize); @@ -635,7 +635,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha) { uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); - d[0] = cfg.mip; + d[0] = cfg.subresource.mip; } else { @@ -650,7 +650,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha) { uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); - d[0] = cfg.sliceFace; + d[0] = cfg.subresource.slice; } else { @@ -665,7 +665,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha) { int32_t *d = (int32_t *)(byteData + var.descriptor.offset); - d[0] = cfg.sampleIdx; + d[0] = cfg.subresource.sample; } else { @@ -703,14 +703,15 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha) } } - pixelData.MipLevel = (float)cfg.mip; + pixelData.MipLevel = (float)cfg.subresource.mip; pixelData.OutputDisplayFormat = RESTYPE_TEX2D; - pixelData.Slice = float(RDCCLAMP(cfg.sliceFace, 0U, details.texArraySize - 1) + 0.001f); + pixelData.Slice = float(RDCCLAMP(cfg.subresource.slice, 0U, details.texArraySize - 1)); if(details.texType == eTexType_3D) { pixelData.OutputDisplayFormat = RESTYPE_TEX3D; - pixelData.Slice = float(RDCCLAMP(cfg.sliceFace, 0U, (details.texDepth >> cfg.mip) - 1) + 0.001f); + pixelData.Slice = float( + RDCCLAMP(cfg.subresource.slice, 0U, (details.texDepth >> cfg.subresource.mip) - 1) + 0.001f); } else if(details.texType == eTexType_1D) { diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index ca37a92a4..f0c280d3a 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1590,128 +1590,91 @@ ResourceId D3D11Replay::GetLiveID(ResourceId id) return m_pDevice->GetResourceManager()->GetLiveID(id); } -bool D3D11Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram) +void D3D11Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) { - if(minval >= maxval) - return false; - - TextureShaderDetails details = GetDebugManager()->GetShaderDetails(texid, typeCast, true); - - if(details.texFmt == DXGI_FORMAT_UNKNOWN) - return false; - D3D11RenderStateTracker tracker(m_pImmediateContext); - HistogramCBufferData cdata; - cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth >> mip, 1U); - cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight >> mip, 1U); - cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth >> mip, 1U); - if(details.texType == eTexType_3D) - cdata.HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, (details.texDepth >> mip) - 1); - else - cdata.HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, details.texArraySize - 1); - cdata.HistogramMip = mip; - cdata.HistogramSample = (int)RDCCLAMP(sample, 0U, details.sampleCount - 1); - if(sample == ~0U) - cdata.HistogramSample = -int(details.sampleCount); - cdata.HistogramMin = minval; + D3D11MarkerRegion marker("PickPixel"); - // The calculation in the shader normalises each value between min and max, then multiplies by the - // number of buckets. - // But any value equal to HistogramMax must go into NUM_BUCKETS-1, so add a small delta. - cdata.HistogramMax = maxval + maxval * 1e-6f; + m_pImmediateContext->OMSetRenderTargets(1, &m_PixelPick.RTV, NULL); - cdata.HistogramChannels = 0; - if(channels[0]) - cdata.HistogramChannels |= 0x1; - if(channels[1]) - cdata.HistogramChannels |= 0x2; - if(channels[2]) - cdata.HistogramChannels |= 0x4; - if(channels[3]) - cdata.HistogramChannels |= 0x8; - cdata.HistogramFlags = 0; + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - Vec4u YUVDownsampleRate = {}; - Vec4u YUVAChannels = {}; + m_pImmediateContext->ClearRenderTargetView(m_PixelPick.RTV, color); - GetYUVShaderParameters(details.texFmt, YUVDownsampleRate, YUVAChannels); + D3D11_VIEWPORT viewport; + RDCEraseEl(viewport); - cdata.HistogramYUVDownsampleRate = YUVDownsampleRate; - cdata.HistogramYUVAChannels = YUVAChannels; + SetOutputDimensions(100, 100); - int srvOffset = 0; - int intIdx = 0; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = 100; + viewport.Height = 100; + + m_pImmediateContext->RSSetViewports(1, &viewport); - if(IsUIntFormat(details.texFmt)) { - cdata.HistogramFlags |= TEXDISPLAY_UINT_TEX; - srvOffset = 10; - intIdx = 1; - } - if(IsIntFormat(details.texFmt)) - { - cdata.HistogramFlags |= TEXDISPLAY_SINT_TEX; - srvOffset = 20; - intIdx = 2; + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = true; + texDisplay.flipY = false; + texDisplay.subresource = sub; + texDisplay.customShaderId = ResourceId(); + texDisplay.rangeMin = 0.0f; + texDisplay.rangeMax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.resourceId = texture; + texDisplay.typeCast = typeCast; + texDisplay.rawOutput = true; + texDisplay.xOffset = -float(x << sub.mip); + texDisplay.yOffset = -float(y << sub.mip); + + RenderTextureInternal(texDisplay, false); } - ID3D11Buffer *cbuf = GetDebugManager()->MakeCBuffer(&cdata, sizeof(cdata)); + D3D11_BOX box; + box.front = 0; + box.back = 1; + box.left = 0; + box.right = 1; + box.top = 0; + box.bottom = 1; - UINT zeroes[] = {0, 0, 0, 0}; - m_pImmediateContext->ClearUnorderedAccessViewUint(m_Histogram.HistogramUAV, zeroes); - - m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL); - - ID3D11UnorderedAccessView *uavs[D3D11_1_UAV_SLOT_COUNT] = {0}; - UINT UAV_keepcounts[D3D11_1_UAV_SLOT_COUNT]; - memset(&UAV_keepcounts[0], 0xff, sizeof(UAV_keepcounts)); - - const UINT numUAVs = - m_pImmediateContext->IsFL11_1() ? D3D11_1_UAV_SLOT_COUNT : D3D11_PS_CS_UAV_REGISTER_COUNT; - uavs[0] = m_Histogram.HistogramUAV; - m_pImmediateContext->CSSetUnorderedAccessViews(0, numUAVs, uavs, UAV_keepcounts); - - m_pImmediateContext->CSSetConstantBuffers(0, 1, &cbuf); - - m_pImmediateContext->CSSetShaderResources(srvOffset, eTexType_Max, details.srv); - - m_pImmediateContext->CSSetShader(m_Histogram.HistogramCS[details.texType][intIdx], NULL, 0); - - int tilesX = (int)ceil(cdata.HistogramTextureResolution.x / - float(HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK)); - int tilesY = (int)ceil(cdata.HistogramTextureResolution.y / - float(HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK)); - - m_pImmediateContext->Dispatch(tilesX, tilesY, 1); - - m_pImmediateContext->CopyResource(m_Histogram.ResultStageBuff, m_Histogram.ResultBuff); + m_pImmediateContext->CopySubresourceRegion(m_PixelPick.StageTexture, 0, 0, 0, 0, + m_PixelPick.Texture, 0, &box); D3D11_MAPPED_SUBRESOURCE mapped; - - HRESULT hr = m_pImmediateContext->Map(m_Histogram.ResultStageBuff, 0, D3D11_MAP_READ, 0, &mapped); - - histogram.clear(); - histogram.resize(HGRAM_NUM_BUCKETS); + mapped.pData = NULL; + HRESULT hr = m_pImmediateContext->Map(m_PixelPick.StageTexture, 0, D3D11_MAP_READ, 0, &mapped); if(FAILED(hr)) { - RDCERR("Can't map histogram stage buff HRESULT: %s", ToStr(hr).c_str()); + RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); + } + + float *pix = (float *)mapped.pData; + + if(pix == NULL) + { + RDCERR("Failed to map pick-pixel staging texture."); } else { - memcpy(&histogram[0], mapped.pData, sizeof(uint32_t) * HGRAM_NUM_BUCKETS); - - m_pImmediateContext->Unmap(m_Histogram.ResultStageBuff, 0); + pixel[0] = pix[0]; + pixel[1] = pix[1]; + pixel[2] = pix[2]; + pixel[3] = pix[3]; } - return true; + m_pImmediateContext->Unmap(m_PixelPick.StageTexture, 0); } -bool D3D11Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) +bool D3D11Replay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, + float *minval, float *maxval) { TextureShaderDetails details = GetDebugManager()->GetShaderDetails(texid, typeCast, true); @@ -1721,16 +1684,16 @@ bool D3D11Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, D3D11RenderStateTracker tracker(m_pImmediateContext); HistogramCBufferData cdata; - cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth >> mip, 1U); - cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight >> mip, 1U); - cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth >> mip, 1U); + cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth >> sub.mip, 1U); + cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight >> sub.mip, 1U); + cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth >> sub.mip, 1U); if(details.texType == eTexType_3D) - cdata.HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, (details.texDepth >> mip) - 1); + cdata.HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, (details.texDepth >> sub.mip) - 1); else - cdata.HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, details.texArraySize - 1); - cdata.HistogramMip = mip; - cdata.HistogramSample = (int)RDCCLAMP(sample, 0U, details.sampleCount - 1); - if(sample == ~0U) + cdata.HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, details.texArraySize - 1); + cdata.HistogramMip = sub.mip; + cdata.HistogramSample = (int)RDCCLAMP(sub.sample, 0U, details.sampleCount - 1); + if(sub.sample == ~0U) cdata.HistogramSample = -int(details.sampleCount); cdata.HistogramMin = 0.0f; cdata.HistogramMax = 1.0f; @@ -1823,6 +1786,129 @@ bool D3D11Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, return true; } +bool D3D11Replay::GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, + float minval, float maxval, bool channels[4], + std::vector &histogram) +{ + if(minval >= maxval) + return false; + + TextureShaderDetails details = GetDebugManager()->GetShaderDetails(texid, typeCast, true); + + if(details.texFmt == DXGI_FORMAT_UNKNOWN) + return false; + + D3D11RenderStateTracker tracker(m_pImmediateContext); + + HistogramCBufferData cdata; + cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth >> sub.mip, 1U); + cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight >> sub.mip, 1U); + cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth >> sub.mip, 1U); + if(details.texType == eTexType_3D) + cdata.HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, (details.texDepth >> sub.mip) - 1); + else + cdata.HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, details.texArraySize - 1); + cdata.HistogramMip = sub.mip; + cdata.HistogramSample = (int)RDCCLAMP(sub.sample, 0U, details.sampleCount - 1); + if(sub.sample == ~0U) + cdata.HistogramSample = -int(details.sampleCount); + cdata.HistogramMin = minval; + + // The calculation in the shader normalises each value between min and max, then multiplies by the + // number of buckets. + // But any value equal to HistogramMax must go into NUM_BUCKETS-1, so add a small delta. + cdata.HistogramMax = maxval + maxval * 1e-6f; + + cdata.HistogramChannels = 0; + if(channels[0]) + cdata.HistogramChannels |= 0x1; + if(channels[1]) + cdata.HistogramChannels |= 0x2; + if(channels[2]) + cdata.HistogramChannels |= 0x4; + if(channels[3]) + cdata.HistogramChannels |= 0x8; + cdata.HistogramFlags = 0; + + Vec4u YUVDownsampleRate = {}; + Vec4u YUVAChannels = {}; + + GetYUVShaderParameters(details.texFmt, YUVDownsampleRate, YUVAChannels); + + cdata.HistogramYUVDownsampleRate = YUVDownsampleRate; + cdata.HistogramYUVAChannels = YUVAChannels; + + int srvOffset = 0; + int intIdx = 0; + + if(IsUIntFormat(details.texFmt)) + { + cdata.HistogramFlags |= TEXDISPLAY_UINT_TEX; + srvOffset = 10; + intIdx = 1; + } + if(IsIntFormat(details.texFmt)) + { + cdata.HistogramFlags |= TEXDISPLAY_SINT_TEX; + srvOffset = 20; + intIdx = 2; + } + + if(details.texType == eTexType_3D) + cdata.HistogramSlice = float(sub.slice); + + ID3D11Buffer *cbuf = GetDebugManager()->MakeCBuffer(&cdata, sizeof(cdata)); + + UINT zeroes[] = {0, 0, 0, 0}; + m_pImmediateContext->ClearUnorderedAccessViewUint(m_Histogram.HistogramUAV, zeroes); + + m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL); + + ID3D11UnorderedAccessView *uavs[D3D11_1_UAV_SLOT_COUNT] = {0}; + UINT UAV_keepcounts[D3D11_1_UAV_SLOT_COUNT]; + memset(&UAV_keepcounts[0], 0xff, sizeof(UAV_keepcounts)); + + const UINT numUAVs = + m_pImmediateContext->IsFL11_1() ? D3D11_1_UAV_SLOT_COUNT : D3D11_PS_CS_UAV_REGISTER_COUNT; + uavs[0] = m_Histogram.HistogramUAV; + m_pImmediateContext->CSSetUnorderedAccessViews(0, numUAVs, uavs, UAV_keepcounts); + + m_pImmediateContext->CSSetConstantBuffers(0, 1, &cbuf); + + m_pImmediateContext->CSSetShaderResources(srvOffset, eTexType_Max, details.srv); + + m_pImmediateContext->CSSetShader(m_Histogram.HistogramCS[details.texType][intIdx], NULL, 0); + + int tilesX = (int)ceil(cdata.HistogramTextureResolution.x / + float(HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK)); + int tilesY = (int)ceil(cdata.HistogramTextureResolution.y / + float(HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK)); + + m_pImmediateContext->Dispatch(tilesX, tilesY, 1); + + m_pImmediateContext->CopyResource(m_Histogram.ResultStageBuff, m_Histogram.ResultBuff); + + D3D11_MAPPED_SUBRESOURCE mapped; + + HRESULT hr = m_pImmediateContext->Map(m_Histogram.ResultStageBuff, 0, D3D11_MAP_READ, 0, &mapped); + + histogram.clear(); + histogram.resize(HGRAM_NUM_BUCKETS); + + if(FAILED(hr)) + { + RDCERR("Can't map histogram stage buff HRESULT: %s", ToStr(hr).c_str()); + } + else + { + memcpy(&histogram[0], mapped.pData, sizeof(uint32_t) * HGRAM_NUM_BUCKETS); + + m_pImmediateContext->Unmap(m_Histogram.ResultStageBuff, 0); + } + + return true; +} + void D3D11Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, bytebuf &retData) { auto it = WrappedID3D11Buffer::m_BufferList.find(buff); @@ -1840,7 +1926,7 @@ void D3D11Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t lengt GetDebugManager()->GetBufferData(buffer, offset, length, retData); } -void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +void D3D11Replay::GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { D3D11RenderStateTracker tracker(m_pImmediateContext); @@ -1869,7 +1955,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, 1, 1); - if(mip >= mips || arrayIdx >= desc.ArraySize) + if(sub.mip >= mips || sub.slice >= desc.ArraySize) return; if(params.remap != RemapTexture::NoRemap) @@ -1891,7 +1977,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip desc.ArraySize = 1; } - subresource = arrayIdx * mips + mip; + subresource = sub.slice * mips + sub.mip; HRESULT hr = m_pDevice->CreateTexture1D(&desc, NULL, &d); @@ -1903,11 +1989,11 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip return; } - bytesize = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + bytesize = GetByteSize(desc.Width, 1, 1, desc.Format, sub.mip); if(params.remap != RemapTexture::NoRemap) { - subresource = mip; + subresource = sub.mip; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -1927,7 +2013,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; rtvDesc.Format = desc.Format; - rtvDesc.Texture1D.MipSlice = mip; + rtvDesc.Texture1D.MipSlice = sub.mip; ID3D11RenderTargetView *wrappedrtv = NULL; hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); @@ -1959,10 +2045,9 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = 0; + texDisplay.subresource = sub; + texDisplay.subresource.sample = 0; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.resourceId = tex; @@ -1973,7 +2058,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // we scale our texture rendering by output dimension. To counteract that, add a manual // scale here - texDisplay.scale = 1.0f / float(1 << mip); + texDisplay.scale = 1.0f / float(1 << sub.mip); RenderTextureInternal(texDisplay, false); } @@ -2019,7 +2104,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, 1); - if(mip >= mips || arrayIdx >= desc.ArraySize) + if(sub.mip >= mips || sub.slice >= desc.ArraySize) return; if(params.remap != RemapTexture::NoRemap) @@ -2042,7 +2127,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip desc.ArraySize = 1; } - subresource = arrayIdx * mips + mip; + subresource = sub.slice * mips + sub.mip; HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &d); @@ -2054,11 +2139,11 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip return; } - bytesize = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + bytesize = GetByteSize(desc.Width, desc.Height, 1, desc.Format, sub.mip); if(params.remap != RemapTexture::NoRemap) { - subresource = mip; + subresource = sub.mip; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -2078,7 +2163,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Format = desc.Format; - rtvDesc.Texture2D.MipSlice = mip; + rtvDesc.Texture2D.MipSlice = sub.mip; ID3D11RenderTargetView *wrappedrtv = NULL; hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); @@ -2111,12 +2196,10 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = params.resolve ? ~0U : arrayIdx; + texDisplay.subresource.mip = sub.mip; + texDisplay.subresource.slice = sub.slice; + texDisplay.subresource.sample = params.resolve ? ~0U : sub.sample; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; - if(sampleCount > 1) - texDisplay.sliceFace /= sampleCount; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.resourceId = tex; @@ -2127,7 +2210,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // we scale our texture rendering by output dimension. To counteract that, add a manual // scale here - texDisplay.scale = 1.0f / float(1 << mip); + texDisplay.scale = 1.0f / float(1 << sub.mip); RenderTextureInternal(texDisplay, false); } @@ -2153,7 +2236,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip return; } - m_pImmediateContext->ResolveSubresource(resolveTex, arrayIdx, wrapTex, arrayIdx, desc.Format); + m_pImmediateContext->ResolveSubresource(resolveTex, sub.slice, wrapTex, sub.slice, desc.Format); m_pImmediateContext->CopyResource(d, resolveTex); SAFE_RELEASE(resolveTex); @@ -2161,6 +2244,8 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip else if(wasms) { GetDebugManager()->CopyTex2DMSToArray(UNWRAP(WrappedID3D11Texture2D1, d), wrapTex->GetReal()); + + subresource = (sub.slice * sampleCount + sub.sample) * mips + sub.mip; } else { @@ -2185,7 +2270,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, desc.Depth); - if(mip >= mips) + if(sub.mip >= mips) return; if(params.remap != RemapTexture::NoRemap) @@ -2205,7 +2290,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip } } - subresource = mip; + subresource = sub.mip; HRESULT hr = m_pDevice->CreateTexture3D(&desc, NULL, &d); @@ -2217,11 +2302,11 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip return; } - bytesize = GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, mip); + bytesize = GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, sub.mip); if(params.remap != RemapTexture::NoRemap) { - subresource = mip; + subresource = sub.mip; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -2241,7 +2326,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; rtvDesc.Format = desc.Format; - rtvDesc.Texture3D.MipSlice = mip; + rtvDesc.Texture3D.MipSlice = sub.mip; rtvDesc.Texture3D.FirstWSlice = 0; rtvDesc.Texture3D.WSize = 1; ID3D11RenderTargetView *wrappedrtv = NULL; @@ -2251,7 +2336,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip 0, 0, (float)desc.Width, (float)desc.Height, 0.0f, 1.0f, }; - for(UINT i = 0; i < (desc.Depth >> mip); i++) + for(UINT i = 0; i < (desc.Depth >> sub.mip); i++) { rtvDesc.Texture3D.FirstWSlice = i; hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); @@ -2279,10 +2364,10 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = 0; + texDisplay.subresource.mip = sub.mip; + texDisplay.subresource.slice = i; + texDisplay.subresource.sample = 0; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = i; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.resourceId = tex; @@ -2293,7 +2378,7 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // we scale our texture rendering by output dimension. To counteract that, add a manual // scale here - texDisplay.scale = 1.0f / float(1 << mip); + texDisplay.scale = 1.0f / float(1 << sub.mip); RenderTextureInternal(texDisplay, false); @@ -2328,10 +2413,10 @@ void D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // for 3D textures if we wanted a particular slice (arrayIdx > 0) // copy it into the beginning. - if(intercept.numSlices > 1 && arrayIdx > 0 && (int)arrayIdx < intercept.numSlices) + if(intercept.numSlices > 1 && sub.slice > 0 && (int)sub.slice < intercept.numSlices) { byte *dst = data.data(); - byte *src = data.data() + intercept.app.DepthPitch * arrayIdx; + byte *src = data.data() + intercept.app.DepthPitch * sub.slice; for(int row = 0; row < intercept.numRows; row++) { @@ -3118,91 +3203,6 @@ uint32_t D3D11Replay::PickVertex(uint32_t eventId, int32_t width, int32_t height return ~0U; } -void D3D11Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, - uint32_t mip, uint32_t sample, CompType typeCast, float pixel[4]) -{ - D3D11RenderStateTracker tracker(m_pImmediateContext); - - D3D11MarkerRegion marker("PickPixel"); - - m_pImmediateContext->OMSetRenderTargets(1, &m_PixelPick.RTV, NULL); - - float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - m_pImmediateContext->ClearRenderTargetView(m_PixelPick.RTV, color); - - D3D11_VIEWPORT viewport; - RDCEraseEl(viewport); - - SetOutputDimensions(100, 100); - - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = 100; - viewport.Height = 100; - - m_pImmediateContext->RSSetViewports(1, &viewport); - - { - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = true; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = sample; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = sliceFace; - texDisplay.rangeMin = 0.0f; - texDisplay.rangeMax = 1.0f; - texDisplay.scale = 1.0f; - texDisplay.resourceId = texture; - texDisplay.typeCast = typeCast; - texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << mip); - texDisplay.yOffset = -float(y << mip); - - RenderTextureInternal(texDisplay, false); - } - - D3D11_BOX box; - box.front = 0; - box.back = 1; - box.left = 0; - box.right = 1; - box.top = 0; - box.bottom = 1; - - m_pImmediateContext->CopySubresourceRegion(m_PixelPick.StageTexture, 0, 0, 0, 0, - m_PixelPick.Texture, 0, &box); - - D3D11_MAPPED_SUBRESOURCE mapped; - mapped.pData = NULL; - HRESULT hr = m_pImmediateContext->Map(m_PixelPick.StageTexture, 0, D3D11_MAP_READ, 0, &mapped); - - if(FAILED(hr)) - { - RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); - } - - float *pix = (float *)mapped.pData; - - if(pix == NULL) - { - RDCERR("Failed to map pick-pixel staging texture."); - } - else - { - pixel[0] = pix[0]; - pixel[1] = pix[1]; - pixel[2] = pix[2]; - pixel[3] = pix[3]; - } - - m_pImmediateContext->Unmap(m_PixelPick.StageTexture, 0); -} - void D3D11Replay::CreateCustomShaderTex(uint32_t w, uint32_t h) { D3D11_TEXTURE2D_DESC texdesc; @@ -3242,8 +3242,8 @@ void D3D11Replay::CreateCustomShaderTex(uint32_t w, uint32_t h) } } -ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, - uint32_t arrayIdx, uint32_t sampleIdx, CompType typeCast) +ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, + const Subresource &sub, CompType typeCast) { TextureShaderDetails details = GetDebugManager()->GetShaderDetails(texid, typeCast, false); @@ -3258,7 +3258,7 @@ ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, u desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - desc.Texture2D.MipSlice = mip; + desc.Texture2D.MipSlice = sub.mip; WrappedID3D11Texture2D1 *wrapped = (WrappedID3D11Texture2D1 *)m_CustomShaderTex; HRESULT hr = m_pDevice->CreateRenderTargetView(wrapped, &desc, &customRTV); @@ -3282,8 +3282,8 @@ ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, u viewport.TopLeftX = 0; viewport.TopLeftY = 0; - viewport.Width = (float)RDCMAX(1U, details.texWidth >> mip); - viewport.Height = (float)RDCMAX(1U, details.texHeight >> mip); + viewport.Width = (float)RDCMAX(1U, details.texWidth >> sub.mip); + viewport.Height = (float)RDCMAX(1U, details.texHeight >> sub.mip); m_pImmediateContext->RSSetViewports(1, &viewport); @@ -3298,16 +3298,15 @@ ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, u disp.backgroundColor = FloatVector(0, 0, 0, 1.0); disp.hdrMultiplier = -1.0f; disp.linearDisplayAsGamma = false; - disp.mip = mip; - disp.sampleIdx = sampleIdx; + disp.subresource = sub; disp.overlay = DebugOverlay::NoOverlay; disp.rangeMin = 0.0f; disp.rangeMax = 1.0f; disp.rawOutput = false; disp.scale = 1.0f; - disp.sliceFace = arrayIdx; - SetOutputDimensions(RDCMAX(1U, details.texWidth >> mip), RDCMAX(1U, details.texHeight >> mip)); + SetOutputDimensions(RDCMAX(1U, details.texWidth >> sub.mip), + RDCMAX(1U, details.texHeight >> sub.mip)); RenderTextureInternal(disp, true); @@ -3451,7 +3450,7 @@ ResourceId D3D11Replay::CreateProxyTexture(const TextureDescription &templateTex return ret; } -void D3D11Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, +void D3D11Replay::SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize) { if(texid == ResourceId()) @@ -3469,22 +3468,21 @@ void D3D11Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint3 uint32_t mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, 1, 1); - if(mip >= mips || arrayIdx >= desc.ArraySize) + if(sub.mip >= mips || sub.slice >= desc.ArraySize) { - RDCERR("arrayIdx %d and mip %d invalid for tex", arrayIdx, mip); + RDCERR("arrayIdx %d and mip %d invalid for tex", sub.slice, sub.mip); return; } - uint32_t sub = arrayIdx * mips + mip; - - if(dataSize < GetByteSize(desc.Width, 1, 1, desc.Format, mip)) + if(dataSize < GetByteSize(desc.Width, 1, 1, desc.Format, sub.mip)) { RDCERR("Insufficient data provided to SetProxyTextureData"); return; } - ctx->UpdateSubresource(tex->GetReal(), sub, NULL, data, GetRowPitch(desc.Width, desc.Format, mip), - GetByteSize(desc.Width, 1, 1, desc.Format, mip)); + ctx->UpdateSubresource(tex->GetReal(), sub.slice * mips + sub.mip, NULL, data, + GetRowPitch(desc.Width, desc.Format, sub.mip), + GetByteSize(desc.Width, 1, 1, desc.Format, sub.mip)); } else if(WrappedID3D11Texture2D1::m_TextureList.find(texid) != WrappedID3D11Texture2D1::m_TextureList.end()) @@ -3499,13 +3497,13 @@ void D3D11Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint3 UINT sampleCount = RDCMAX(1U, desc.SampleDesc.Count); - if(mip >= mips || arrayIdx >= desc.ArraySize * sampleCount) + if(sub.mip >= mips || sub.slice >= desc.ArraySize || sub.sample >= sampleCount) { - RDCERR("arrayIdx %d and mip %d invalid for tex", arrayIdx, mip); + RDCERR("arrayIdx %d, mip %d, slice %d invalid for tex", sub.slice, sub.mip, sub.sample); return; } - if(dataSize < GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)) + if(dataSize < GetByteSize(desc.Width, desc.Height, 1, desc.Format, sub.mip)) { RDCERR("Insufficient data provided to SetProxyTextureData"); return; @@ -3522,26 +3520,26 @@ void D3D11Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint3 uploadDesc.SampleDesc.Quality = 0; uploadDesc.ArraySize *= desc.SampleDesc.Count; + UINT unpackedSlice = sub.slice * desc.SampleDesc.Count + sub.sample; + // create an unwrapped texture to upload the data into a slice of ID3D11Texture2D *uploadTex = NULL; m_pDevice->GetReal()->CreateTexture2D(&uploadDesc, NULL, &uploadTex); - ctx->UpdateSubresource(uploadTex, arrayIdx, NULL, data, - GetRowPitch(desc.Width, desc.Format, mip), - GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)); + ctx->UpdateSubresource(uploadTex, unpackedSlice, NULL, data, + GetRowPitch(desc.Width, desc.Format, sub.mip), + GetByteSize(desc.Width, desc.Height, 1, desc.Format, sub.mip)); // copy that slice into MSAA sample - GetDebugManager()->CopyArrayToTex2DMS(tex->GetReal(), uploadTex, arrayIdx); + GetDebugManager()->CopyArrayToTex2DMS(tex->GetReal(), uploadTex, unpackedSlice); uploadTex->Release(); } else { - uint32_t sub = arrayIdx * mips + mip; - - ctx->UpdateSubresource(tex->GetReal(), sub, NULL, data, - GetRowPitch(desc.Width, desc.Format, mip), - GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)); + ctx->UpdateSubresource(tex->GetReal(), sub.slice * mips + sub.mip, NULL, data, + GetRowPitch(desc.Width, desc.Format, sub.mip), + GetByteSize(desc.Width, desc.Height, 1, desc.Format, sub.mip)); } } else if(WrappedID3D11Texture3D1::m_TextureList.find(texid) != @@ -3556,20 +3554,21 @@ void D3D11Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint3 uint32_t mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, desc.Depth); - if(mip >= mips) + if(sub.mip >= mips) { - RDCERR("arrayIdx %d and mip %d invalid for tex", arrayIdx, mip); + RDCERR("mip %d invalid for tex", sub.mip); return; } - if(dataSize < GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, mip)) + if(dataSize < GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, sub.mip)) { RDCERR("Insufficient data provided to SetProxyTextureData"); return; } - ctx->UpdateSubresource(tex->GetReal(), mip, NULL, data, GetRowPitch(desc.Width, desc.Format, mip), - GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip)); + ctx->UpdateSubresource(tex->GetReal(), sub.mip, NULL, data, + GetRowPitch(desc.Width, desc.Format, sub.mip), + GetByteSize(desc.Width, desc.Height, 1, desc.Format, sub.mip)); } else { diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 04a2dde8b..ddca494f0 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -169,18 +169,19 @@ public: ResourceId GetLiveID(ResourceId id); - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval); - bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]); + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval); + bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram); MeshFormat GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData); - void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, - const GetTextureDataParams ¶ms, bytebuf &data); + void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, + bytebuf &data); rdcarray GetCustomShaderEncodings() { @@ -201,8 +202,7 @@ public: std::vector FetchCounters(const std::vector &counters); ResourceId CreateProxyTexture(const TextureDescription &templateTex); - void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, - size_t dataSize); + void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize); bool IsTextureSupported(const ResourceFormat &format); bool NeedRemapForFetch(const ResourceFormat &format); @@ -223,16 +223,14 @@ public: const bytebuf &data); std::vector PixelHistory(std::vector events, ResourceId target, - uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast); + uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast); ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3], const uint32_t threadid[3]); - void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, - uint32_t sample, CompType typeCast, float pixel[4]); uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); @@ -243,8 +241,8 @@ public: void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); - ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, - uint32_t sampleIdx, CompType typeCast); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast); bool IsRenderOutput(ResourceId id); diff --git a/renderdoc/driver/d3d12/d3d12_rendertexture.cpp b/renderdoc/driver/d3d12/d3d12_rendertexture.cpp index 4e03f07fd..869d55fc5 100644 --- a/renderdoc/driver/d3d12/d3d12_rendertexture.cpp +++ b/renderdoc/driver/d3d12/d3d12_rendertexture.cpp @@ -392,10 +392,10 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture D3D12_RESOURCE_DESC resourceDesc = resource->GetDesc(); - pixelData.SampleIdx = (int)RDCCLAMP(cfg.sampleIdx, 0U, resourceDesc.SampleDesc.Count - 1); + pixelData.SampleIdx = (int)RDCCLAMP(cfg.subresource.sample, 0U, resourceDesc.SampleDesc.Count - 1); // hacky resolve - if(cfg.sampleIdx == ~0U) + if(cfg.subresource.sample == ~0U) pixelData.SampleIdx = -int(resourceDesc.SampleDesc.Count); if(resourceDesc.Format == DXGI_FORMAT_UNKNOWN) @@ -411,10 +411,12 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture float tex_y = float(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D ? 100 : resourceDesc.Height); - pixelData.TextureResolutionPS.x = float(RDCMAX(1U, uint32_t(resourceDesc.Width >> cfg.mip))); - pixelData.TextureResolutionPS.y = float(RDCMAX(1U, uint32_t(resourceDesc.Height >> cfg.mip))); + pixelData.TextureResolutionPS.x = + float(RDCMAX(1U, uint32_t(resourceDesc.Width >> cfg.subresource.mip))); + pixelData.TextureResolutionPS.y = + float(RDCMAX(1U, uint32_t(resourceDesc.Height >> cfg.subresource.mip))); pixelData.TextureResolutionPS.z = - float(RDCMAX(1U, uint32_t(resourceDesc.DepthOrArraySize >> cfg.mip))); + float(RDCMAX(1U, uint32_t(resourceDesc.DepthOrArraySize >> cfg.subresource.mip))); if(resourceDesc.DepthOrArraySize > 1 && resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) pixelData.TextureResolutionPS.z = float(resourceDesc.DepthOrArraySize); @@ -444,16 +446,17 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture vertexData.VertexScale.x = (tex_x / m_OutputWidth) * cfg.scale * 2.0f; vertexData.VertexScale.y = (tex_y / m_OutputHeight) * cfg.scale * 2.0f; - pixelData.MipLevel = (float)cfg.mip; + pixelData.MipLevel = (float)cfg.subresource.mip; pixelData.OutputDisplayFormat = RESTYPE_TEX2D; if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) pixelData.Slice = - float(RDCCLAMP(cfg.sliceFace, 0U, uint32_t((resourceDesc.DepthOrArraySize >> cfg.mip) - 1)) + + float(RDCCLAMP(cfg.subresource.slice, 0U, + uint32_t((resourceDesc.DepthOrArraySize >> cfg.subresource.mip) - 1)) + 0.001f); else - pixelData.Slice = - float(RDCCLAMP(cfg.sliceFace, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1)) + 0.001f); + pixelData.Slice = float( + RDCCLAMP(cfg.subresource.slice, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1)) + 0.001f); std::vector barriers; int resType = 0; @@ -580,7 +583,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture { uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); - d[0] = cfg.mip; + d[0] = cfg.subresource.mip; } else { @@ -595,7 +598,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture { uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset); - d[0] = cfg.sliceFace; + d[0] = cfg.subresource.slice; } else { @@ -610,7 +613,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture { int32_t *d = (int32_t *)(byteData + var.descriptor.offset); - d[0] = cfg.sampleIdx; + d[0] = cfg.subresource.sample; } else { diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 2bc966aa0..8754e649e 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -1701,99 +1701,6 @@ void D3D12Replay::RenderCheckerboard() } } -void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, - uint32_t mip, uint32_t sample, CompType typeCast, float pixel[4]) -{ - SetOutputDimensions(1, 1); - - { - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = true; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = sample; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = sliceFace; - texDisplay.rangeMin = 0.0f; - texDisplay.rangeMax = 1.0f; - texDisplay.scale = 1.0f; - texDisplay.resourceId = texture; - texDisplay.typeCast = typeCast; - texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << mip); - texDisplay.yOffset = -float(y << mip); - - RenderTextureInternal(GetDebugManager()->GetCPUHandle(PICK_PIXEL_RTV), texDisplay, - eTexDisplay_F32Render); - } - - ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); - - D3D12_RESOURCE_BARRIER barrier = {}; - - barrier.Transition.pResource = m_PixelPick.Texture; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; - - list->ResourceBarrier(1, &barrier); - - D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; - - src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src.pResource = m_PixelPick.Texture; - src.SubresourceIndex = 0; - - dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dst.pResource = m_General.ResultReadbackBuffer; - dst.PlacedFootprint.Offset = 0; - dst.PlacedFootprint.Footprint.Width = sizeof(Vec4f); - dst.PlacedFootprint.Footprint.Height = 1; - dst.PlacedFootprint.Footprint.Depth = 1; - dst.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; - dst.PlacedFootprint.Footprint.RowPitch = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; - - list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); - - std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter); - - list->ResourceBarrier(1, &barrier); - - list->Close(); - - m_pDevice->ExecuteLists(); - m_pDevice->FlushLists(); - - D3D12_RANGE range = {0, sizeof(Vec4f)}; - - float *pix = NULL; - HRESULT hr = m_General.ResultReadbackBuffer->Map(0, &range, (void **)&pix); - - if(FAILED(hr)) - { - RDCERR("Failed to map picking stage tex HRESULT: %s", ToStr(hr).c_str()); - } - - if(pix == NULL) - { - RDCERR("Failed to map pick-pixel staging texture."); - } - else - { - pixel[0] = pix[0]; - pixel[1] = pix[1]; - pixel[2] = pix[2]; - pixel[3] = pix[3]; - } - - range.End = 0; - - if(SUCCEEDED(hr)) - m_General.ResultReadbackBuffer->Unmap(0, &range); -} - uint32_t D3D12Replay::PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y) { @@ -2251,8 +2158,99 @@ uint32_t D3D12Replay::PickVertex(uint32_t eventId, int32_t width, int32_t height return ~0U; } -bool D3D12Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) +void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) +{ + SetOutputDimensions(1, 1); + + { + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = true; + texDisplay.flipY = false; + texDisplay.subresource = sub; + texDisplay.customShaderId = ResourceId(); + texDisplay.rangeMin = 0.0f; + texDisplay.rangeMax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.resourceId = texture; + texDisplay.typeCast = typeCast; + texDisplay.rawOutput = true; + texDisplay.xOffset = -float(x << sub.mip); + texDisplay.yOffset = -float(y << sub.mip); + + RenderTextureInternal(GetDebugManager()->GetCPUHandle(PICK_PIXEL_RTV), texDisplay, + eTexDisplay_F32Render); + } + + ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); + + D3D12_RESOURCE_BARRIER barrier = {}; + + barrier.Transition.pResource = m_PixelPick.Texture; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + + list->ResourceBarrier(1, &barrier); + + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + + src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.pResource = m_PixelPick.Texture; + src.SubresourceIndex = 0; + + dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst.pResource = m_General.ResultReadbackBuffer; + dst.PlacedFootprint.Offset = 0; + dst.PlacedFootprint.Footprint.Width = sizeof(Vec4f); + dst.PlacedFootprint.Footprint.Height = 1; + dst.PlacedFootprint.Footprint.Depth = 1; + dst.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + dst.PlacedFootprint.Footprint.RowPitch = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; + + list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); + + std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter); + + list->ResourceBarrier(1, &barrier); + + list->Close(); + + m_pDevice->ExecuteLists(); + m_pDevice->FlushLists(); + + D3D12_RANGE range = {0, sizeof(Vec4f)}; + + float *pix = NULL; + HRESULT hr = m_General.ResultReadbackBuffer->Map(0, &range, (void **)&pix); + + if(FAILED(hr)) + { + RDCERR("Failed to map picking stage tex HRESULT: %s", ToStr(hr).c_str()); + } + + if(pix == NULL) + { + RDCERR("Failed to map pick-pixel staging texture."); + } + else + { + pixel[0] = pix[0]; + pixel[1] = pix[1]; + pixel[2] = pix[2]; + pixel[3] = pix[3]; + } + + range.End = 0; + + if(SUCCEEDED(hr)) + m_General.ResultReadbackBuffer->Unmap(0, &range); +} + +bool D3D12Replay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, + float *minval, float *maxval) { ID3D12Resource *resource = m_pDevice->GetResourceList()[texid]; @@ -2262,24 +2260,24 @@ bool D3D12Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, D3D12_RESOURCE_DESC resourceDesc = resource->GetDesc(); HistogramCBufferData cdata; - cdata.HistogramTextureResolution.x = float(RDCMAX(1U, uint32_t(resourceDesc.Width >> mip))); - cdata.HistogramTextureResolution.y = float(RDCMAX(1U, uint32_t(resourceDesc.Height >> mip))); + cdata.HistogramTextureResolution.x = float(RDCMAX(1U, uint32_t(resourceDesc.Width >> sub.mip))); + cdata.HistogramTextureResolution.y = float(RDCMAX(1U, uint32_t(resourceDesc.Height >> sub.mip))); cdata.HistogramTextureResolution.z = - float(RDCMAX(1U, uint32_t(resourceDesc.DepthOrArraySize >> mip))); + float(RDCMAX(1U, uint32_t(resourceDesc.DepthOrArraySize >> sub.mip))); if(resourceDesc.DepthOrArraySize > 1 && resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) cdata.HistogramTextureResolution.z = float(resourceDesc.DepthOrArraySize); if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) cdata.HistogramSlice = - float(RDCCLAMP(sliceFace, 0U, uint32_t((resourceDesc.DepthOrArraySize >> mip) - 1))); + float(RDCCLAMP(sub.slice, 0U, uint32_t((resourceDesc.DepthOrArraySize >> sub.mip) - 1))); else cdata.HistogramSlice = - float(RDCCLAMP(sliceFace, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1))); + float(RDCCLAMP(sub.slice, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1))); - cdata.HistogramMip = mip; - cdata.HistogramSample = (int)RDCCLAMP(sample, 0U, resourceDesc.SampleDesc.Count - 1); - if(sample == ~0U) + cdata.HistogramMip = sub.mip; + cdata.HistogramSample = (int)RDCCLAMP(sub.sample, 0U, resourceDesc.SampleDesc.Count - 1); + if(sub.sample == ~0U) cdata.HistogramSample = -int(resourceDesc.SampleDesc.Count); cdata.HistogramMin = 0.0f; cdata.HistogramMax = 1.0f; @@ -2429,8 +2427,8 @@ bool D3D12Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, return true; } -bool D3D12Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], +bool D3D12Replay::GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, + float minval, float maxval, bool channels[4], std::vector &histogram) { if(minval >= maxval) @@ -2444,24 +2442,24 @@ bool D3D12Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mi D3D12_RESOURCE_DESC resourceDesc = resource->GetDesc(); HistogramCBufferData cdata; - cdata.HistogramTextureResolution.x = float(RDCMAX(1U, uint32_t(resourceDesc.Width >> mip))); - cdata.HistogramTextureResolution.y = float(RDCMAX(1U, uint32_t(resourceDesc.Height >> mip))); + cdata.HistogramTextureResolution.x = float(RDCMAX(1U, uint32_t(resourceDesc.Width >> sub.mip))); + cdata.HistogramTextureResolution.y = float(RDCMAX(1U, uint32_t(resourceDesc.Height >> sub.mip))); cdata.HistogramTextureResolution.z = - float(RDCMAX(1U, uint32_t(resourceDesc.DepthOrArraySize >> mip))); + float(RDCMAX(1U, uint32_t(resourceDesc.DepthOrArraySize >> sub.mip))); if(resourceDesc.DepthOrArraySize > 1 && resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) cdata.HistogramTextureResolution.z = float(resourceDesc.DepthOrArraySize); if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) cdata.HistogramSlice = - float(RDCCLAMP(sliceFace, 0U, uint32_t((resourceDesc.DepthOrArraySize >> mip) - 1))); + float(RDCCLAMP(sub.slice, 0U, uint32_t((resourceDesc.DepthOrArraySize >> sub.mip) - 1))); else cdata.HistogramSlice = - float(RDCCLAMP(sliceFace, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1))); + float(RDCCLAMP(sub.slice, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1))); - cdata.HistogramMip = mip; - cdata.HistogramSample = (int)RDCCLAMP(sample, 0U, resourceDesc.SampleDesc.Count - 1); - if(sample == ~0U) + cdata.HistogramMip = sub.mip; + cdata.HistogramSample = (int)RDCCLAMP(sub.sample, 0U, resourceDesc.SampleDesc.Count - 1); + if(sub.sample == ~0U) cdata.HistogramSample = -int(resourceDesc.SampleDesc.Count); cdata.HistogramMin = minval; cdata.HistogramFlags = 0; @@ -2985,7 +2983,7 @@ void D3D12Replay::RefreshDerivedReplacements() } } -void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +void D3D12Replay::GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { bool wasms = false; @@ -2999,9 +2997,11 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip return; } - D3D12MarkerRegion region( - m_pDevice->GetQueue(), - StringFormat::Fmt("GetTextureData(%u, %u, remap=%d)", mip, arrayIdx, params.remap)); + D3D12MarkerRegion region(m_pDevice->GetQueue(), + StringFormat::Fmt("GetTextureData(%u, %u, %u, remap=%d)", sub.mip, + sub.slice, sub.sample, params.remap)); + + Subresource s = sub; HRESULT hr = S_OK; @@ -3045,8 +3045,8 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // want to copy and then set arrayIdx to 0 to simplify subresource calculations if(copyDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) { - slice3DCopy = arrayIdx; - arrayIdx = 0; + slice3DCopy = s.slice; + s.slice = 0; } ID3D12Resource *srcTexture = resource; @@ -3080,8 +3080,8 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip SetOutputDimensions(uint32_t(copyDesc.Width), copyDesc.Height); - copyDesc.Width = RDCMAX(1ULL, copyDesc.Width >> mip); - copyDesc.Height = RDCMAX(1U, copyDesc.Height >> mip); + copyDesc.Width = RDCMAX(1ULL, copyDesc.Width >> s.mip); + copyDesc.Height = RDCMAX(1U, copyDesc.Height >> s.mip); ID3D12Resource *remapTexture; hr = m_pDevice->CreateCommittedResource(&defaultHeap, D3D12_HEAP_FLAG_NONE, ©Desc, @@ -3113,7 +3113,7 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip { rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; rtvDesc.Texture3D.WSize = 1; - loopCount = RDCMAX(0U, uint32_t(copyDesc.DepthOrArraySize >> mip)); + loopCount = RDCMAX(0U, uint32_t(copyDesc.DepthOrArraySize >> s.mip)); } // we only loop for 3D slices, other types we just do one remap for the desired mip/slice @@ -3132,12 +3132,12 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = resolve ? ~0U : arrayIdx; + texDisplay.subresource.mip = s.mip; + texDisplay.subresource.slice = s.slice; + if(copyDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) + texDisplay.subresource.slice = loop; + texDisplay.subresource.sample = resolve ? ~0U : s.sample; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; - if(sampleCount > 1) - texDisplay.sliceFace /= sampleCount; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.resourceId = tex; @@ -3148,7 +3148,7 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // we scale our texture rendering by output dimension. To counteract that, add a manual // scale here - texDisplay.scale = 1.0f / float(1 << mip); + texDisplay.scale = 1.0f / float(1 << s.mip); RenderTextureInternal(GetDebugManager()->GetCPUHandle(GET_TEX_RTV), texDisplay, flags); } @@ -3166,8 +3166,8 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // these have already been selected, don't need to fetch that subresource // when copying back to readback buffer - arrayIdx = 0; - mip = 0; + s.slice = 0; + s.mip = 0; // no longer depth, if it was isDepth = false; @@ -3179,8 +3179,8 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip copyDesc.DepthOrArraySize = 1; copyDesc.MipLevels = 1; - copyDesc.Width = RDCMAX(1ULL, copyDesc.Width >> mip); - copyDesc.Height = RDCMAX(1U, copyDesc.Height >> mip); + copyDesc.Width = RDCMAX(1ULL, copyDesc.Width >> s.mip); + copyDesc.Height = RDCMAX(1U, copyDesc.Height >> s.mip); ID3D12Resource *resolveTexture; hr = m_pDevice->CreateCommittedResource(&defaultHeap, D3D12_HEAP_FLAG_NONE, ©Desc, @@ -3219,7 +3219,7 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); list->ResolveSubresource(resolveTexture, 0, srcTexture, - arrayIdx * resDesc.DepthOrArraySize + mip, resDesc.Format); + s.slice * resDesc.DepthOrArraySize + s.mip, resDesc.Format); // real resource back to normal for(size_t i = 0; i < barriers.size(); i++) @@ -3239,8 +3239,8 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip // these have already been selected, don't need to fetch that subresource // when copying back to readback buffer - arrayIdx = 0; - mip = 0; + s.slice = 0; + s.mip = 0; } else if(wasms) { @@ -3313,6 +3313,9 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip isDepth ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_RENDER_TARGET; b.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; list->ResourceBarrier(1, &b); + + s.slice = s.slice * sampleCount + s.sample; + s.sample = 0; } if(list == NULL) @@ -3380,15 +3383,13 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip UINT arrayStride = copyDesc.MipLevels; UINT planeStride = copyDesc.DepthOrArraySize * copyDesc.MipLevels; - for(UINT i = 0; i < planes; i++) + for(UINT p = 0; p < planes; p++) { readbackDesc.Width = AlignUp(readbackDesc.Width, 512ULL); - UINT sub = mip + arrayIdx * arrayStride + i * planeStride; - UINT64 subSize = 0; - m_pDevice->GetCopyableFootprints(©Desc, sub, 1, readbackDesc.Width, layouts + i, - rowcounts + i, NULL, &subSize); + m_pDevice->GetCopyableFootprints(©Desc, s.mip + s.slice * arrayStride + p * planeStride, 1, + readbackDesc.Width, layouts + p, rowcounts + p, NULL, &subSize); readbackDesc.Width += subSize; } @@ -3405,17 +3406,17 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip __uuidof(ID3D12Resource), (void **)&readbackBuf); RDCASSERTEQUAL(hr, S_OK); - for(UINT i = 0; i < planes; i++) + for(UINT p = 0; p < planes; p++) { D3D12_TEXTURE_COPY_LOCATION dst, src; src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; src.pResource = srcTexture; - src.SubresourceIndex = mip + arrayIdx * arrayStride + i * planeStride; + src.SubresourceIndex = s.mip + s.slice * arrayStride + p * planeStride; dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst.pResource = readbackBuf; - dst.PlacedFootprint = layouts[i]; + dst.PlacedFootprint = layouts[p]; list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); } @@ -3455,11 +3456,11 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip copyDesc.Format == DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS || copyDesc.Format == DXGI_FORMAT_R32G8X24_TYPELESS) { - for(UINT s = 0; s < layouts[0].Footprint.Depth; s++) + for(UINT z = 0; z < layouts[0].Footprint.Depth; z++) { - for(UINT r = 0; r < layouts[0].Footprint.Height; r++) + for(UINT y = 0; y < layouts[0].Footprint.Height; y++) { - UINT row = r + s * layouts[0].Footprint.Height; + UINT row = y + z * layouts[0].Footprint.Height; uint32_t *dSrc = (uint32_t *)(pData + layouts[0].Footprint.RowPitch * row); uint8_t *sSrc = @@ -3486,11 +3487,11 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip } else // D24_S8 { - for(UINT s = 0; s < layouts[0].Footprint.Depth; s++) + for(UINT z = 0; z < layouts[0].Footprint.Depth; z++) { - for(UINT r = 0; r < rowcounts[0]; r++) + for(UINT y = 0; y < rowcounts[0]; y++) { - UINT row = r + s * rowcounts[0]; + UINT row = y + z * rowcounts[0]; // we can copy the depth from D24 as a 32-bit integer, since the remaining bits are // garbage @@ -3519,11 +3520,11 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip UINT dstRowPitch = GetByteSize(layouts[0].Footprint.Width, 1, 1, copyDesc.Format, 0); // copy row by row - for(UINT s = 0; s < layouts[0].Footprint.Depth; s++) + for(UINT z = 0; z < layouts[0].Footprint.Depth; z++) { - for(UINT r = 0; r < rowcounts[0]; r++) + for(UINT y = 0; y < rowcounts[0]; y++) { - UINT row = r + s * rowcounts[0]; + UINT row = y + z * rowcounts[0]; byte *src = pData + layouts[0].Footprint.RowPitch * row; byte *dst = data.data() + dstRowPitch * row; @@ -3536,10 +3537,10 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip if(layouts[0].Footprint.Depth > 1 && slice3DCopy > 0 && (int)slice3DCopy < layouts[0].Footprint.Depth) { - for(UINT r = 0; r < rowcounts[0]; r++) + for(UINT y = 0; y < rowcounts[0]; y++) { - UINT srcrow = r + slice3DCopy * rowcounts[0]; - UINT dstrow = r; + UINT srcrow = y + slice3DCopy * rowcounts[0]; + UINT dstrow = y; byte *src = pData + layouts[0].Footprint.RowPitch * srcrow; byte *dst = data.data() + dstRowPitch * dstrow; @@ -3567,8 +3568,8 @@ void D3D12Replay::BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf sourc BuildShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } -ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, - uint32_t arrayIdx, uint32_t sampleIdx, CompType typeCast) +ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, + const Subresource &sub, CompType typeCast) { ID3D12Resource *resource = m_pDevice->GetResourceList()[texid]; @@ -3625,7 +3626,7 @@ ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, u D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtvDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - rtvDesc.Texture2D.MipSlice = mip; + rtvDesc.Texture2D.MipSlice = sub.mip; m_pDevice->CreateRenderTargetView(m_CustomShaderTex, &rtvDesc, GetDebugManager()->GetCPUHandle(CUSTOM_SHADER_RTV)); @@ -3647,16 +3648,15 @@ ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, u disp.typeCast = typeCast; disp.hdrMultiplier = -1.0f; disp.linearDisplayAsGamma = false; - disp.mip = mip; - disp.sampleIdx = sampleIdx; + disp.subresource = sub; disp.overlay = DebugOverlay::NoOverlay; disp.rangeMin = 0.0f; disp.rangeMax = 1.0f; disp.rawOutput = false; disp.scale = 1.0f; - disp.sliceFace = arrayIdx; - SetOutputDimensions(RDCMAX(1U, (UINT)resDesc.Width >> mip), RDCMAX(1U, resDesc.Height >> mip)); + SetOutputDimensions(RDCMAX(1U, (UINT)resDesc.Width >> sub.mip), + RDCMAX(1U, resDesc.Height >> sub.mip)); RenderTextureInternal(GetDebugManager()->GetCPUHandle(CUSTOM_SHADER_RTV), disp, eTexDisplay_BlendAlpha); @@ -3668,8 +3668,7 @@ ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, u std::vector D3D12Replay::PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + const Subresource &sub, CompType typeCast) { return std::vector(); } @@ -3679,7 +3678,7 @@ ResourceId D3D12Replay::CreateProxyTexture(const TextureDescription &templateTex return ResourceId(); } -void D3D12Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, +void D3D12Replay::SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize) { } diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 61e04c353..e830a06d8 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -131,18 +131,19 @@ public: void AliasPostVSBuffers(uint32_t eventId, uint32_t alias) { m_PostVSAlias[alias] = eventId; } ResourceId GetLiveID(ResourceId id); - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval); - bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]); + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval); + bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram); MeshFormat GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData); - void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, - const GetTextureDataParams ¶ms, bytebuf &data); + void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, + bytebuf &data); rdcarray GetCustomShaderEncodings() { @@ -163,8 +164,7 @@ public: std::vector FetchCounters(const std::vector &counters); ResourceId CreateProxyTexture(const TextureDescription &templateTex); - void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, - size_t dataSize); + void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize); bool IsTextureSupported(const ResourceFormat &format); bool NeedRemapForFetch(const ResourceFormat &format); @@ -185,16 +185,14 @@ public: const bytebuf &data); std::vector PixelHistory(std::vector events, ResourceId target, - uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast); + uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast); ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3], const uint32_t threadid[3]); - void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, - uint32_t sample, CompType typeCast, float pixel[4]); uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); @@ -205,8 +203,8 @@ public: void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); - ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, - uint32_t sampleIdx, CompType typeCast); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast); bool IsRenderOutput(ResourceId id); diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 511675f71..1ee70ee86 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -1334,8 +1334,109 @@ void GLReplay::RestoreSamplerParams(GLenum target, GLuint texname, TextureSample GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_COMPARE_MODE, (GLint *)&state.compareMode); } -bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) +void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) +{ + WrappedOpenGL &drv = *m_pDriver; + + MakeCurrentReplayContext(m_DebugCtx); + + drv.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.pickPixelFBO); + drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, DebugData.pickPixelFBO); + + pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0.0f; + drv.glClearBufferfv(eGL_COLOR, 0, pixel); + + DebugData.outWidth = DebugData.outHeight = 1.0f; + drv.glViewport(0, 0, 1, 1); + + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.flipY = false; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = true; + texDisplay.subresource = sub; + texDisplay.customShaderId = ResourceId(); + texDisplay.rangeMin = 0.0f; + texDisplay.rangeMax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.resourceId = texture; + texDisplay.typeCast = typeCast; + texDisplay.rawOutput = true; + texDisplay.xOffset = -float(x << sub.mip); + texDisplay.yOffset = -float(y << sub.mip); + + RenderTextureInternal(texDisplay, eTexDisplay_MipShift); + + drv.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixel); + + if(!HasExt[ARB_gpu_shader5]) + { + auto &texDetails = m_pDriver->m_Textures[texDisplay.resourceId]; + + if(IsSIntFormat(texDetails.internalFormat)) + { + int32_t casted[4] = { + (int32_t)pixel[0], (int32_t)pixel[1], (int32_t)pixel[2], (int32_t)pixel[3], + }; + + memcpy(pixel, casted, sizeof(casted)); + } + else if(IsUIntFormat(texDetails.internalFormat)) + { + uint32_t casted[4] = { + (uint32_t)pixel[0], (uint32_t)pixel[1], (uint32_t)pixel[2], (uint32_t)pixel[3], + }; + + memcpy(pixel, casted, sizeof(casted)); + } + } + + { + auto &texDetails = m_pDriver->m_Textures[texture]; + + // need to read stencil separately as GL can't read both depth and stencil + // at the same time. + if(texDetails.internalFormat == eGL_DEPTH24_STENCIL8 || + texDetails.internalFormat == eGL_DEPTH32F_STENCIL8 || + texDetails.internalFormat == eGL_DEPTH_STENCIL || + texDetails.internalFormat == eGL_STENCIL_INDEX8) + { + texDisplay.red = texDisplay.blue = texDisplay.alpha = false; + + RenderTextureInternal(texDisplay, eTexDisplay_MipShift); + + uint32_t stencilpixel[4]; + drv.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)stencilpixel); + + if(!HasExt[ARB_gpu_shader5]) + { + // bits weren't aliased, so re-cast back to uint. + float fpix[4]; + memcpy(fpix, stencilpixel, sizeof(fpix)); + + stencilpixel[0] = (uint32_t)fpix[0]; + stencilpixel[1] = (uint32_t)fpix[1]; + } + + // not sure whether [0] or [1] will return stencil values, so use + // max of two because other channel should be 0 + pixel[1] = float(RDCMAX(stencilpixel[0], stencilpixel[1])) / 255.0f; + + // the first depth read will have read stencil instead. + // NULL it out so the UI sees only stencil + if(texDetails.internalFormat == eGL_STENCIL_INDEX8) + { + pixel[1] = float(RDCMAX(stencilpixel[0], stencilpixel[1])) / 255.0f; + pixel[0] = 0.0f; + } + } + } +} + +bool GLReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval) { auto &texDetails = m_pDriver->m_Textures[texid]; @@ -1349,14 +1450,12 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin }; Vec4u stencil[2] = {{0, 0, 0, 0}, {1, 1, 1, 1}}; - bool success = - GetMinMax(texid, sliceFace, mip, sample, typeCast, false, &depth[0].x, &depth[1].x); + bool success = GetMinMax(texid, sub, typeCast, false, &depth[0].x, &depth[1].x); if(!success) return false; - success = GetMinMax(texid, sliceFace, mip, sample, typeCast, true, (float *)&stencil[0].x, - (float *)&stencil[1].x); + success = GetMinMax(texid, sub, typeCast, true, (float *)&stencil[0].x, (float *)&stencil[1].x); if(!success) return false; @@ -1386,11 +1485,11 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin return true; } - return GetMinMax(texid, sliceFace, mip, sample, typeCast, false, minval, maxval); + return GetMinMax(texid, sub, typeCast, false, minval, maxval); } -bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, bool stencil, float *minval, float *maxval) +bool GLReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, bool stencil, + float *minval, float *maxval) { if(texid == ResourceId() || m_pDriver->m_Textures.find(texid) == m_pDriver->m_Textures.end()) return false; @@ -1485,18 +1584,18 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin (HistogramUBOData *)GL.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(HistogramUBOData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - cdata->HistogramTextureResolution.x = (float)RDCMAX(details.width >> mip, 1U); - cdata->HistogramTextureResolution.y = (float)RDCMAX(details.height >> mip, 1U); - cdata->HistogramTextureResolution.z = (float)RDCMAX(details.depth >> mip, 1U); + cdata->HistogramTextureResolution.x = (float)RDCMAX(details.width >> sub.mip, 1U); + cdata->HistogramTextureResolution.y = (float)RDCMAX(details.height >> sub.mip, 1U); + cdata->HistogramTextureResolution.z = (float)RDCMAX(details.depth >> sub.mip, 1U); if(texDetails.curType == eGL_TEXTURE_3D) cdata->HistogramSlice = - (float)RDCCLAMP(sliceFace, 0U, uint32_t(details.depth >> mip) - 1) + 0.001f; + (float)RDCCLAMP(sub.slice, 0U, uint32_t(details.depth >> sub.mip) - 1) + 0.001f; else - cdata->HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, details.arraysize - 1) + 0.001f; - cdata->HistogramMip = (int)mip; + cdata->HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, details.arraysize - 1) + 0.001f; + cdata->HistogramMip = (int)sub.mip; cdata->HistogramNumSamples = texDetails.samples; - cdata->HistogramSample = (int)RDCCLAMP(sample, 0U, details.msSamp - 1); - if(sample == ~0U) + cdata->HistogramSample = (int)RDCCLAMP(sub.sample, 0U, details.msSamp - 1); + if(sub.sample == ~0U) cdata->HistogramSample = -int(details.msSamp); cdata->HistogramMin = 0.0f; cdata->HistogramMax = 1.0f; @@ -1610,9 +1709,8 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin return true; } -bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram) +bool GLReplay::GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram) { if(minval >= maxval || texid == ResourceId()) return false; @@ -1746,18 +1844,18 @@ bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, (HistogramUBOData *)GL.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(HistogramUBOData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - cdata->HistogramTextureResolution.x = (float)RDCMAX(details.width >> mip, 1U); - cdata->HistogramTextureResolution.y = (float)RDCMAX(details.height >> mip, 1U); - cdata->HistogramTextureResolution.z = (float)RDCMAX(details.depth >> mip, 1U); + cdata->HistogramTextureResolution.x = (float)RDCMAX(details.width >> sub.mip, 1U); + cdata->HistogramTextureResolution.y = (float)RDCMAX(details.height >> sub.mip, 1U); + cdata->HistogramTextureResolution.z = (float)RDCMAX(details.depth >> sub.mip, 1U); if(texDetails.curType == eGL_TEXTURE_3D) cdata->HistogramSlice = - (float)RDCCLAMP(sliceFace, 0U, uint32_t(details.depth >> mip) - 1) + 0.001f; + (float)RDCCLAMP(sub.slice, 0U, uint32_t(details.depth >> sub.mip) - 1) + 0.001f; else - cdata->HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, details.arraysize - 1) + 0.001f; - cdata->HistogramMip = mip; + cdata->HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, details.arraysize - 1) + 0.001f; + cdata->HistogramMip = sub.mip; cdata->HistogramNumSamples = texDetails.samples; - cdata->HistogramSample = (int)RDCCLAMP(sample, 0U, details.msSamp - 1); - if(sample == ~0U) + cdata->HistogramSample = (int)RDCCLAMP(sub.sample, 0U, details.msSamp - 1); + if(sub.sample == ~0U) cdata->HistogramSample = -int(details.msSamp); cdata->HistogramMin = minval; @@ -2334,109 +2432,6 @@ uint32_t GLReplay::PickVertex(uint32_t eventId, int32_t width, int32_t height, return ret; } -void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, - uint32_t mip, uint32_t sample, CompType typeCast, float pixel[4]) -{ - WrappedOpenGL &drv = *m_pDriver; - - MakeCurrentReplayContext(m_DebugCtx); - - drv.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.pickPixelFBO); - drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, DebugData.pickPixelFBO); - - pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0.0f; - drv.glClearBufferfv(eGL_COLOR, 0, pixel); - - DebugData.outWidth = DebugData.outHeight = 1.0f; - drv.glViewport(0, 0, 1, 1); - - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.flipY = false; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = true; - texDisplay.mip = mip; - texDisplay.sampleIdx = sample; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = sliceFace; - texDisplay.rangeMin = 0.0f; - texDisplay.rangeMax = 1.0f; - texDisplay.scale = 1.0f; - texDisplay.resourceId = texture; - texDisplay.typeCast = typeCast; - texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << mip); - texDisplay.yOffset = -float(y << mip); - - RenderTextureInternal(texDisplay, eTexDisplay_MipShift); - - drv.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixel); - - if(!HasExt[ARB_gpu_shader5]) - { - auto &texDetails = m_pDriver->m_Textures[texDisplay.resourceId]; - - if(IsSIntFormat(texDetails.internalFormat)) - { - int32_t casted[4] = { - (int32_t)pixel[0], (int32_t)pixel[1], (int32_t)pixel[2], (int32_t)pixel[3], - }; - - memcpy(pixel, casted, sizeof(casted)); - } - else if(IsUIntFormat(texDetails.internalFormat)) - { - uint32_t casted[4] = { - (uint32_t)pixel[0], (uint32_t)pixel[1], (uint32_t)pixel[2], (uint32_t)pixel[3], - }; - - memcpy(pixel, casted, sizeof(casted)); - } - } - - { - auto &texDetails = m_pDriver->m_Textures[texture]; - - // need to read stencil separately as GL can't read both depth and stencil - // at the same time. - if(texDetails.internalFormat == eGL_DEPTH24_STENCIL8 || - texDetails.internalFormat == eGL_DEPTH32F_STENCIL8 || - texDetails.internalFormat == eGL_DEPTH_STENCIL || - texDetails.internalFormat == eGL_STENCIL_INDEX8) - { - texDisplay.red = texDisplay.blue = texDisplay.alpha = false; - - RenderTextureInternal(texDisplay, eTexDisplay_MipShift); - - uint32_t stencilpixel[4]; - drv.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)stencilpixel); - - if(!HasExt[ARB_gpu_shader5]) - { - // bits weren't aliased, so re-cast back to uint. - float fpix[4]; - memcpy(fpix, stencilpixel, sizeof(fpix)); - - stencilpixel[0] = (uint32_t)fpix[0]; - stencilpixel[1] = (uint32_t)fpix[1]; - } - - // not sure whether [0] or [1] will return stencil values, so use - // max of two because other channel should be 0 - pixel[1] = float(RDCMAX(stencilpixel[0], stencilpixel[1])) / 255.0f; - - // the first depth read will have read stencil instead. - // NULL it out so the UI sees only stencil - if(texDetails.internalFormat == eGL_STENCIL_INDEX8) - { - pixel[1] = float(RDCMAX(stencilpixel[0], stencilpixel[1])) / 255.0f; - pixel[0] = 0.0f; - } - } - } -} - void GLReplay::RenderCheckerboard() { MakeCurrentReplayContext(m_DebugCtx); diff --git a/renderdoc/driver/gl/gl_rendertexture.cpp b/renderdoc/driver/gl/gl_rendertexture.cpp index 36f3f155f..11679fecd 100644 --- a/renderdoc/driver/gl/gl_rendertexture.cpp +++ b/renderdoc/driver/gl/gl_rendertexture.cpp @@ -215,20 +215,20 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) loc = drv.glGetUniformLocation(customProgram, "RENDERDOC_SelectedMip"); if(loc >= 0) - drv.glProgramUniform1ui(customProgram, loc, cfg.mip); + drv.glProgramUniform1ui(customProgram, loc, cfg.subresource.mip); loc = drv.glGetUniformLocation(customProgram, "RENDERDOC_SelectedSliceFace"); if(loc >= 0) - drv.glProgramUniform1ui(customProgram, loc, cfg.sliceFace); + drv.glProgramUniform1ui(customProgram, loc, cfg.subresource.slice); loc = drv.glGetUniformLocation(customProgram, "RENDERDOC_SelectedSample"); if(loc >= 0) { - if(cfg.sampleIdx == ~0U) + if(cfg.subresource.sample == ~0U) drv.glProgramUniform1i(customProgram, loc, -texDetails.samples); else - drv.glProgramUniform1i(customProgram, loc, - (int)RDCCLAMP(cfg.sampleIdx, 0U, (uint32_t)texDetails.samples - 1)); + drv.glProgramUniform1i(customProgram, loc, (int)RDCCLAMP(cfg.subresource.sample, 0U, + (uint32_t)texDetails.samples - 1)); } loc = drv.glGetUniformLocation(customProgram, "RENDERDOC_TextureType"); @@ -289,8 +289,8 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) TextureSamplerMode mode = TextureSamplerMode::Point; - if(cfg.mip == 0 && cfg.scale < 1.0f && dsTexMode == eGL_NONE && resType != RESTYPE_TEXBUFFER && - resType != RESTYPE_TEXRECT) + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f && dsTexMode == eGL_NONE && + resType != RESTYPE_TEXBUFFER && resType != RESTYPE_TEXRECT) { mode = TextureSamplerMode::Linear; } @@ -365,7 +365,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) ubo->RangeMinimum = cfg.rangeMin; ubo->InverseRangeSize = 1.0f / (cfg.rangeMax - cfg.rangeMin); - ubo->MipLevel = (int)cfg.mip; + ubo->MipLevel = (int)cfg.subresource.mip; if(texDetails.curType != eGL_TEXTURE_3D) { uint32_t numSlices = RDCMAX((uint32_t)texDetails.depth, 1U); @@ -375,12 +375,13 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) if(texDetails.curType == eGL_TEXTURE_1D_ARRAY) numSlices = RDCMAX((uint32_t)texDetails.height, 1U); - uint32_t sliceFace = RDCCLAMP(cfg.sliceFace, 0U, numSlices - 1); + uint32_t sliceFace = RDCCLAMP(cfg.subresource.slice, 0U, numSlices - 1); ubo->Slice = (float)sliceFace + 0.001f; } else { - uint32_t sliceFace = RDCCLAMP(cfg.sliceFace, 0U, RDCMAX((uint32_t)texDetails.depth, 1U) - 1); + uint32_t sliceFace = + RDCCLAMP(cfg.subresource.slice, 0U, RDCMAX((uint32_t)texDetails.depth, 1U) - 1); ubo->Slice = (float)sliceFace + 0.001f; } @@ -397,22 +398,22 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) ubo->RawOutput = cfg.rawOutput ? 1 : 0; - ubo->TextureResolutionPS.x = float(RDCMAX(1, tex_x >> cfg.mip)); - ubo->TextureResolutionPS.y = float(RDCMAX(1, tex_y >> cfg.mip)); - ubo->TextureResolutionPS.z = float(RDCMAX(1, tex_z >> cfg.mip)); + ubo->TextureResolutionPS.x = float(RDCMAX(1, tex_x >> cfg.subresource.mip)); + ubo->TextureResolutionPS.y = float(RDCMAX(1, tex_y >> cfg.subresource.mip)); + ubo->TextureResolutionPS.z = float(RDCMAX(1, tex_z >> cfg.subresource.mip)); if(mipShift) - ubo->MipShift = float(1 << cfg.mip); + ubo->MipShift = float(1 << cfg.subresource.mip); else ubo->MipShift = 1.0f; ubo->OutputRes.x = DebugData.outWidth; ubo->OutputRes.y = DebugData.outHeight; - ubo->SampleIdx = (int)RDCCLAMP(cfg.sampleIdx, 0U, (uint32_t)texDetails.samples - 1); + ubo->SampleIdx = (int)RDCCLAMP(cfg.subresource.sample, 0U, (uint32_t)texDetails.samples - 1); // hacky resolve - if(cfg.sampleIdx == ~0U) + if(cfg.subresource.sample == ~0U) ubo->SampleIdx = -texDetails.samples; ubo->DecodeYUV = 0; diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 9a8e1d716..72187759c 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2252,7 +2252,7 @@ void GLReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, std: } } -void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +void GLReplay::GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { WrappedOpenGL &drv = *m_pDriver; @@ -2261,12 +2261,14 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, GLuint tempTex = 0; + Subresource s = sub; + GLenum texType = texDetails.curType; GLuint texname = texDetails.resource.name; GLenum intFormat = texDetails.internalFormat; - GLsizei width = RDCMAX(1, texDetails.width >> mip); - GLsizei height = RDCMAX(1, texDetails.height >> mip); - GLsizei depth = RDCMAX(1, texDetails.depth >> mip); + GLsizei width = RDCMAX(1, texDetails.width >> s.mip); + GLsizei height = RDCMAX(1, texDetails.height >> s.mip); + GLsizei depth = RDCMAX(1, texDetails.depth >> s.mip); GLsizei arraysize = 1; GLint samples = texDetails.samples; @@ -2371,12 +2373,10 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = params.resolve ? ~0U : arrayIdx; + texDisplay.subresource.mip = s.mip; + texDisplay.subresource.sample = params.resolve ? ~0U : s.sample; + texDisplay.subresource.slice = s.slice; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; - if(samples > 1) - texDisplay.sliceFace /= samples; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.scale = 1.0f; @@ -2390,7 +2390,7 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, { drv.glFramebufferTexture3D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, eGL_TEXTURE_3D, tempTex, 0, (GLint)d); - texDisplay.sliceFace = (uint32_t)d; + texDisplay.subresource.slice = (uint32_t)d; } drv.glViewport(0, 0, width, height); @@ -2421,12 +2421,10 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = params.resolve ? ~0U : arrayIdx; + texDisplay.subresource.mip = s.mip; + texDisplay.subresource.sample = params.resolve ? ~0U : s.sample; + texDisplay.subresource.slice = s.slice; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; - if(samples > 1) - texDisplay.sliceFace /= samples; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.scale = 1.0f; @@ -2458,8 +2456,8 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, depth = 1; arraysize = 1; samples = 1; - mip = 0; - arrayIdx = 0; + s.mip = 0; + s.slice = 0; drv.glDeleteFramebuffers(1, &fbo); } @@ -2489,7 +2487,7 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, drv.glBindFramebuffer(eGL_FRAMEBUFFER, fbos[1]); if(texType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) - drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texname, 0, arrayIdx); + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texname, 0, s.slice); else drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texType, texname, 0); @@ -2506,8 +2504,9 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, texType = eGL_TEXTURE_2D; texname = tempTex; depth = 1; - mip = 0; - arrayIdx = 0; + s.mip = 0; + s.slice = 0; + s.sample = 0; arraysize = 1; samples = 1; @@ -2529,6 +2528,10 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, texname = tempTex; depth = 1; arraysize = arraysize * samples; + // remap from slice & sample to just slice, given that each slice is expanded to N slices - one + // for each sample. + s.slice = s.slice * samples + s.sample; + s.sample = 0; samples = 1; } @@ -2594,8 +2597,8 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, }; - RDCASSERT(arrayIdx < ARRAY_COUNT(targets)); - target = targets[arrayIdx]; + RDCASSERT(s.slice < ARRAY_COUNT(targets)); + target = targets[s.slice]; } size_t dataSize = 0; @@ -2631,22 +2634,22 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, m_GetTexturePrevID = tex; - RDCASSERT(mip < ARRAY_COUNT(m_GetTexturePrevData)); + RDCASSERT(s.mip < ARRAY_COUNT(m_GetTexturePrevData)); // if we don't have this mip cached, fetch it now - if(m_GetTexturePrevData[mip] == NULL) + if(m_GetTexturePrevData[s.mip] == NULL) { - m_GetTexturePrevData[mip] = new byte[dataSize * arraysize]; + m_GetTexturePrevData[s.mip] = new byte[dataSize * arraysize]; if(IsGLES) - texDetails.GetCompressedImageDataGLES(mip, target, dataSize * arraysize, - m_GetTexturePrevData[mip]); + texDetails.GetCompressedImageDataGLES(s.mip, target, dataSize * arraysize, + m_GetTexturePrevData[s.mip]); else - drv.glGetCompressedTexImage(target, mip, m_GetTexturePrevData[mip]); + drv.glGetCompressedTexImage(target, s.mip, m_GetTexturePrevData[s.mip]); } // now copy the slice from the cache into ret - byte *src = m_GetTexturePrevData[mip]; - src += dataSize * arrayIdx; + byte *src = m_GetTexturePrevData[s.mip]; + src += dataSize * s.slice; memcpy(data.data(), src, dataSize); } @@ -2654,9 +2657,9 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, { // for non-arrays we can just readback without caching if(IsGLES) - texDetails.GetCompressedImageDataGLES(mip, target, dataSize, data.data()); + texDetails.GetCompressedImageDataGLES(s.mip, target, dataSize, data.data()); else - drv.glGetCompressedTexImage(target, mip, data.data()); + drv.glGetCompressedTexImage(target, s.mip, data.data()); } } else @@ -2682,24 +2685,24 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, m_GetTexturePrevID = tex; - RDCASSERT(mip < ARRAY_COUNT(m_GetTexturePrevData)); + RDCASSERT(s.mip < ARRAY_COUNT(m_GetTexturePrevData)); // if we don't have this mip cached, fetch it now - if(m_GetTexturePrevData[mip] == NULL) + if(m_GetTexturePrevData[s.mip] == NULL) { - m_GetTexturePrevData[mip] = new byte[dataSize * arraysize]; - drv.glGetTexImage(target, (GLint)mip, fmt, type, m_GetTexturePrevData[mip]); + m_GetTexturePrevData[s.mip] = new byte[dataSize * arraysize]; + drv.glGetTexImage(target, (GLint)s.mip, fmt, type, m_GetTexturePrevData[s.mip]); } // now copy the slice from the cache into ret - byte *src = m_GetTexturePrevData[mip]; - src += dataSize * arrayIdx; + byte *src = m_GetTexturePrevData[s.mip]; + src += dataSize * s.slice; memcpy(data.data(), src, dataSize); } else { - drv.glGetTexImage(target, (GLint)mip, fmt, type, data.data()); + drv.glGetTexImage(target, (GLint)s.mip, fmt, type, data.data()); } // packed D24S8 comes out the wrong way around from what we expect, so we re-swizzle it. @@ -2773,8 +2776,8 @@ void GLReplay::BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } -ResourceId GLReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, - uint32_t arrayIdx, uint32_t sampleIdx, CompType typeCast) +ResourceId GLReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast) { if(shader == ResourceId() || texid == ResourceId()) return ResourceId(); @@ -2787,13 +2790,13 @@ ResourceId GLReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint m_pDriver->glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.customFBO); m_pDriver->glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, eGL_TEXTURE_2D, - DebugData.customTex, mip); + DebugData.customTex, sub.mip); - m_pDriver->glViewport(0, 0, RDCMAX(1, texDetails.width >> mip), - RDCMAX(1, texDetails.height >> mip)); + m_pDriver->glViewport(0, 0, RDCMAX(1, texDetails.width >> sub.mip), + RDCMAX(1, texDetails.height >> sub.mip)); - DebugData.outWidth = float(RDCMAX(1, texDetails.width >> mip)); - DebugData.outHeight = float(RDCMAX(1, texDetails.height >> mip)); + DebugData.outWidth = float(RDCMAX(1, texDetails.width >> sub.mip)); + DebugData.outHeight = float(RDCMAX(1, texDetails.height >> sub.mip)); float clr[] = {0.0f, 0.8f, 0.0f, 0.0f}; m_pDriver->glClearBufferfv(eGL_COLOR, 0, clr); @@ -2808,14 +2811,12 @@ ResourceId GLReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint disp.typeCast = typeCast; disp.hdrMultiplier = -1.0f; disp.linearDisplayAsGamma = false; - disp.mip = mip; - disp.sampleIdx = sampleIdx; + disp.subresource = sub; disp.overlay = DebugOverlay::NoOverlay; disp.rangeMin = 0.0f; disp.rangeMax = 1.0f; disp.rawOutput = false; disp.scale = 1.0f; - disp.sliceFace = arrayIdx; RenderTextureInternal(disp, eTexDisplay_MipShift); @@ -3108,7 +3109,7 @@ ResourceId GLReplay::CreateProxyTexture(const TextureDescription &templateTex) return id; } -void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, +void GLReplay::SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize) { WrappedOpenGL &drv = *m_pDriver; @@ -3125,10 +3126,10 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t GLint depth = 1; if(target == eGL_TEXTURE_3D) - depth = RDCMAX(1, texdetails.depth >> mip); + depth = RDCMAX(1, texdetails.depth >> sub.mip); - GLint width = RDCMAX(1, texdetails.width >> mip); - GLint height = RDCMAX(1, texdetails.height >> mip); + GLint width = RDCMAX(1, texdetails.width >> sub.mip); + GLint height = RDCMAX(1, texdetails.height >> sub.mip); if(target == eGL_TEXTURE_1D_ARRAY) height = 1; @@ -3142,28 +3143,28 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t if(target == eGL_TEXTURE_1D) { - drv.glCompressedTextureSubImage1DEXT(tex, target, (GLint)mip, 0, width, fmt, + drv.glCompressedTextureSubImage1DEXT(tex, target, (GLint)sub.mip, 0, width, fmt, (GLsizei)dataSize, data); } else if(target == eGL_TEXTURE_1D_ARRAY) { - drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)mip, 0, (GLint)arrayIdx, width, 1, - fmt, (GLsizei)dataSize, data); + drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)sub.mip, 0, (GLint)sub.slice, width, + 1, fmt, (GLsizei)dataSize, data); } else if(target == eGL_TEXTURE_2D) { - drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)mip, 0, 0, width, height, fmt, + drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)sub.mip, 0, 0, width, height, fmt, (GLsizei)dataSize, data); } else if(target == eGL_TEXTURE_2D_ARRAY || target == eGL_TEXTURE_CUBE_MAP_ARRAY) { - drv.glCompressedTextureSubImage3DEXT(tex, target, (GLint)mip, 0, 0, (GLint)arrayIdx, width, - height, 1, fmt, (GLsizei)dataSize, data); + drv.glCompressedTextureSubImage3DEXT(tex, target, (GLint)sub.mip, 0, 0, (GLint)sub.slice, + width, height, 1, fmt, (GLsizei)dataSize, data); } else if(target == eGL_TEXTURE_3D) { - drv.glCompressedTextureSubImage3DEXT(tex, target, (GLint)mip, 0, 0, 0, width, height, depth, - fmt, (GLsizei)dataSize, data); + drv.glCompressedTextureSubImage3DEXT(tex, target, (GLint)sub.mip, 0, 0, 0, width, height, + depth, fmt, (GLsizei)dataSize, data); } else if(target == eGL_TEXTURE_CUBE_MAP) { @@ -3173,10 +3174,10 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, }; - RDCASSERT(arrayIdx < ARRAY_COUNT(targets)); - target = targets[arrayIdx]; + RDCASSERT(sub.slice < ARRAY_COUNT(targets)); + target = targets[sub.slice]; - drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)mip, 0, 0, width, height, fmt, + drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)sub.mip, 0, 0, width, height, fmt, (GLsizei)dataSize, data); } else if(target == eGL_TEXTURE_2D_MULTISAMPLE || target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) @@ -3204,27 +3205,27 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t if(target == eGL_TEXTURE_1D) { - drv.glTextureSubImage1DEXT(tex, target, (GLint)mip, 0, width, baseformat, datatype, data); + drv.glTextureSubImage1DEXT(tex, target, (GLint)sub.mip, 0, width, baseformat, datatype, data); } else if(target == eGL_TEXTURE_1D_ARRAY) { - drv.glTextureSubImage2DEXT(tex, target, (GLint)mip, 0, (GLint)arrayIdx, width, 1, baseformat, - datatype, data); + drv.glTextureSubImage2DEXT(tex, target, (GLint)sub.mip, 0, (GLint)sub.slice, width, 1, + baseformat, datatype, data); } else if(target == eGL_TEXTURE_2D) { - drv.glTextureSubImage2DEXT(tex, target, (GLint)mip, 0, 0, width, height, baseformat, datatype, - data); + drv.glTextureSubImage2DEXT(tex, target, (GLint)sub.mip, 0, 0, width, height, baseformat, + datatype, data); } else if(target == eGL_TEXTURE_2D_ARRAY || target == eGL_TEXTURE_CUBE_MAP_ARRAY) { - drv.glTextureSubImage3DEXT(tex, target, (GLint)mip, 0, 0, (GLint)arrayIdx, width, height, 1, - baseformat, datatype, data); + drv.glTextureSubImage3DEXT(tex, target, (GLint)sub.mip, 0, 0, (GLint)sub.slice, width, height, + 1, baseformat, datatype, data); } else if(target == eGL_TEXTURE_3D) { - drv.glTextureSubImage3DEXT(tex, target, (GLint)mip, 0, 0, 0, width, height, depth, baseformat, - datatype, data); + drv.glTextureSubImage3DEXT(tex, target, (GLint)sub.mip, 0, 0, 0, width, height, depth, + baseformat, datatype, data); } else if(target == eGL_TEXTURE_CUBE_MAP) { @@ -3234,11 +3235,11 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, }; - RDCASSERT(arrayIdx < ARRAY_COUNT(targets)); - target = targets[arrayIdx]; + RDCASSERT(sub.slice < ARRAY_COUNT(targets)); + target = targets[sub.slice]; - drv.glTextureSubImage2DEXT(tex, target, (GLint)mip, 0, 0, width, height, baseformat, datatype, - data); + drv.glTextureSubImage2DEXT(tex, target, (GLint)sub.mip, 0, 0, width, height, baseformat, + datatype, data); } else if(target == eGL_TEXTURE_2D_MULTISAMPLE || target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) { @@ -3251,6 +3252,8 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t width, height, texdetails.samples * RDCMAX(1, texdetails.depth)); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); + GLint unpackedSlice = sub.slice * texdetails.samples + sub.sample; + // packed D24S8 is expected the wrong way around from comes in, so we re-swizzle it here if(texdetails.internalFormat == eGL_DEPTH24_STENCIL8) { @@ -3271,19 +3274,19 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t } // upload the data to the given slice - drv.glTextureSubImage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 0, 0, 0, (GLint)arrayIdx, width, + drv.glTextureSubImage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 0, 0, 0, unpackedSlice, width, height, 1, baseformat, datatype, swizzled.data()); } else { // upload the data to the given slice - drv.glTextureSubImage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 0, 0, 0, (GLint)arrayIdx, width, + drv.glTextureSubImage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 0, 0, 0, unpackedSlice, width, height, 1, baseformat, datatype, data); } // copy this slice into the 2D MSAA texture CopyArrayToTex2DMS(tex, uploadTex, width, height, texdetails.depth, texdetails.samples, - texdetails.internalFormat, arrayIdx); + texdetails.internalFormat, unpackedSlice); // delete the temporary texture drv.glDeleteTextures(1, &uploadTex); @@ -3361,8 +3364,7 @@ std::vector GLReplay::GetUsage(ResourceId id) std::vector GLReplay::PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + const Subresource &sub, CompType typeCast) { GLNOTIMP("GLReplay::PixelHistory"); return std::vector(); diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index bad96388c..7208e9418 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -149,18 +149,19 @@ public: ResourceId GetLiveID(ResourceId id); - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval); - bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]); + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval); + bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram); MeshFormat GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &ret); - void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, - const GetTextureDataParams ¶ms, bytebuf &data); + void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, + bytebuf &data); void ReplaceResource(ResourceId from, ResourceId to); void RemoveReplacement(ResourceId id); @@ -200,28 +201,25 @@ public: const bytebuf &data); std::vector PixelHistory(std::vector events, ResourceId target, - uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast); + uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast); ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3], const uint32_t threadid[3]); - void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, - uint32_t sample, CompType typeCast, float pixel[4]); uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); ResourceId RenderOverlay(ResourceId id, CompType typeCast, FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, const std::vector &passEvents); - ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, - uint32_t sampleIdx, CompType typeCast); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast); ResourceId CreateProxyTexture(const TextureDescription &templateTex); - void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, - size_t dataSize); + void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize); bool IsTextureSupported(const ResourceFormat &format); bool NeedRemapForFetch(const ResourceFormat &format); @@ -240,8 +238,8 @@ private: const rdcarray &variables, rdcarray &outvars, const bytebuf &data); - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, bool stencil, float *minval, float *maxval); + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, bool stencil, + float *minval, float *maxval); void CreateCustomShaderTex(uint32_t w, uint32_t h); bool CreateOverlayProgram(GLuint Program, GLuint Pipeline, GLuint fragShader, diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index a3bf3b890..5d771dc91 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -110,8 +110,7 @@ struct EventInfo std::vector VulkanReplay::PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + const Subresource &sub, CompType typeCast) { VULKANNOTIMP("PixelHistory"); return std::vector(); @@ -1155,8 +1154,7 @@ VkImageLayout VulkanDebugManager::GetImageLayout(ResourceId image, VkImageAspect std::vector VulkanReplay::PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) + const Subresource &sub, CompType typeCast) { RDCDEBUG("PixelHistory: pixel: (%u, %u) with %u events", x, y, events.size()); std::vector history; @@ -1170,6 +1168,9 @@ std::vector VulkanReplay::PixelHistory(std::vectorGetImageLayout(target, VK_IMAGE_ASPECT_COLOR_BIT, mip); RDCASSERTNOTEQUAL(imgLayout, VK_IMAGE_LAYOUT_UNDEFINED); diff --git a/renderdoc/driver/vulkan/vk_rendertexture.cpp b/renderdoc/driver/vulkan/vk_rendertexture.cpp index 71d199601..577b848e3 100644 --- a/renderdoc/driver/vulkan/vk_rendertexture.cpp +++ b/renderdoc/driver/vulkan/vk_rendertexture.cpp @@ -275,37 +275,37 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn data->FlipY = cfg.flipY ? 1 : 0; - data->MipLevel = (int)cfg.mip; + data->MipLevel = (int)cfg.subresource.mip; data->Slice = 0; if(iminfo.type != VK_IMAGE_TYPE_3D) { uint32_t numSlices = RDCMAX((uint32_t)iminfo.arrayLayers, 1U); - uint32_t sliceFace = RDCCLAMP(cfg.sliceFace, 0U, numSlices - 1); + uint32_t sliceFace = RDCCLAMP(cfg.subresource.slice, 0U, numSlices - 1); data->Slice = (float)sliceFace + 0.001f; } else { - uint32_t sliceFace = RDCCLAMP(cfg.sliceFace, 0U, iminfo.extent.depth - 1); + uint32_t sliceFace = RDCCLAMP(cfg.subresource.slice, 0U, iminfo.extent.depth - 1); data->Slice = (float)sliceFace + 0.001f; } - data->TextureResolutionPS.x = float(RDCMAX(1, tex_x >> cfg.mip)); - data->TextureResolutionPS.y = float(RDCMAX(1, tex_y >> cfg.mip)); - data->TextureResolutionPS.z = float(RDCMAX(1, tex_z >> cfg.mip)); + data->TextureResolutionPS.x = float(RDCMAX(1, tex_x >> cfg.subresource.mip)); + data->TextureResolutionPS.y = float(RDCMAX(1, tex_y >> cfg.subresource.mip)); + data->TextureResolutionPS.z = float(RDCMAX(1, tex_z >> cfg.subresource.mip)); if(mipShift) - data->MipShift = float(1 << cfg.mip); + data->MipShift = float(1 << cfg.subresource.mip); else data->MipShift = 1.0f; data->Scale = cfg.scale; - int sampleIdx = (int)RDCCLAMP(cfg.sampleIdx, 0U, (uint32_t)SampleCount(iminfo.samples)); + int sampleIdx = (int)RDCCLAMP(cfg.subresource.sample, 0U, (uint32_t)SampleCount(iminfo.samples)); - sampleIdx = cfg.sampleIdx; + sampleIdx = cfg.subresource.sample; - if(cfg.sampleIdx == ~0U) + if(cfg.subresource.sample == ~0U) sampleIdx = -SampleCount(iminfo.samples); data->SampleIdx = sampleIdx; @@ -368,8 +368,8 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn customData->texDim.y = iminfo.extent.height; customData->texDim.z = iminfo.extent.depth; customData->texDim.w = iminfo.mipLevels; - customData->selectedMip = cfg.mip; - customData->selectedSliceFace = cfg.sliceFace; + customData->selectedMip = cfg.subresource.mip; + customData->selectedSliceFace = cfg.subresource.slice; customData->selectedSample = sampleIdx; customData->texType = (uint32_t)textype; customData->YUVDownsampleRate = YUVDownsampleRate; @@ -412,7 +412,7 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn imdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imdesc.imageView = Unwrap(liveImView); imdesc.sampler = Unwrap(m_General.PointSampler); - if(cfg.mip == 0 && cfg.scale < 1.0f) + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f) imdesc.sampler = Unwrap(m_TexRender.LinearSampler); VkDescriptorImageInfo altimdesc[2] = {}; @@ -422,7 +422,7 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn altimdesc[i - 1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; altimdesc[i - 1].imageView = Unwrap(texviews.views[i]); altimdesc[i - 1].sampler = Unwrap(m_General.PointSampler); - if(cfg.mip == 0 && cfg.scale < 1.0f) + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f) altimdesc[i - 1].sampler = Unwrap(m_TexRender.LinearSampler); } diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index a78b3fd17..d7c017cfd 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -719,162 +719,6 @@ std::string VulkanReplay::DisassembleShader(ResourceId pipeline, const ShaderRef return StringFormat::Fmt("; Invalid disassembly target %s", target.c_str()); } -void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, - uint32_t mip, uint32_t sample, CompType typeCast, float pixel[4]) -{ - int oldW = m_DebugWidth, oldH = m_DebugHeight; - - m_DebugWidth = m_DebugHeight = 1; - - VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texture]; - - bool isStencil = IsStencilFormat(iminfo.format); - - // do a second pass to render the stencil, if needed - for(int pass = 0; pass < (isStencil ? 2 : 1); pass++) - { - // render picked pixel to readback F32 RGBA texture - { - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = true; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = sample; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = sliceFace; - texDisplay.overlay = DebugOverlay::NoOverlay; - texDisplay.rangeMin = 0.0f; - texDisplay.rangeMax = 1.0f; - texDisplay.scale = 1.0f; - texDisplay.resourceId = texture; - texDisplay.typeCast = typeCast; - texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << mip); - texDisplay.yOffset = -float(y << mip); - - // only render green (stencil) in second pass - if(pass == 1) - { - texDisplay.green = true; - texDisplay.red = texDisplay.blue = texDisplay.alpha = false; - } - - VkClearValue clearval = {}; - VkRenderPassBeginInfo rpbegin = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - NULL, - Unwrap(m_PixelPick.RP), - Unwrap(m_PixelPick.FB), - {{ - 0, 0, - }, - {1, 1}}, - 1, - &clearval, - }; - - RenderTextureInternal(texDisplay, rpbegin, eTexDisplay_F32Render | eTexDisplay_MipShift); - } - - VkDevice dev = m_pDriver->GetDev(); - VkCommandBuffer cmd = m_pDriver->GetNextCmd(); - const VkDevDispatchTable *vt = ObjDisp(dev); - - VkResult vkr = VK_SUCCESS; - - { - VkImageMemoryBarrier pickimBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - 0, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - Unwrap(m_PixelPick.Image), - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; - - // update image layout from color attachment to transfer source, with proper memory barriers - pickimBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - pickimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - DoPipelineBarrier(cmd, 1, &pickimBarrier); - pickimBarrier.oldLayout = pickimBarrier.newLayout; - pickimBarrier.srcAccessMask = pickimBarrier.dstAccessMask; - - // do copy - VkBufferImageCopy region = { - 0, 128, 1, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {1, 1, 1}, - }; - vt->CmdCopyImageToBuffer(Unwrap(cmd), Unwrap(m_PixelPick.Image), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - Unwrap(m_PixelPick.ReadbackBuffer.buf), 1, ®ion); - - // update image layout back to color attachment - pickimBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - pickimBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - DoPipelineBarrier(cmd, 1, &pickimBarrier); - - vt->EndCommandBuffer(Unwrap(cmd)); - } - - // submit cmds and wait for idle so we can readback - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - - float *pData = NULL; - vt->MapMemory(Unwrap(dev), Unwrap(m_PixelPick.ReadbackBuffer.mem), 0, VK_WHOLE_SIZE, 0, - (void **)&pData); - - VkMappedMemoryRange range = { - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, - NULL, - Unwrap(m_PixelPick.ReadbackBuffer.mem), - 0, - VK_WHOLE_SIZE, - }; - - vkr = vt->InvalidateMappedMemoryRanges(Unwrap(dev), 1, &range); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - RDCASSERT(pData != NULL); - - if(pData == NULL) - { - RDCERR("Failed ot map readback buffer memory"); - } - else - { - // only write stencil to .y - if(pass == 1) - { - pixel[1] = ((uint32_t *)pData)[0] / 255.0f; - } - else - { - pixel[0] = pData[0]; - pixel[1] = pData[1]; - pixel[2] = pData[2]; - pixel[3] = pData[3]; - } - } - - vt->UnmapMemory(Unwrap(dev), Unwrap(m_PixelPick.ReadbackBuffer.mem)); - } - - m_DebugWidth = oldW; - m_DebugHeight = oldH; -} - void VulkanReplay::RenderCheckerboard() { auto it = m_OutputWindows.find(m_ActiveWinID); @@ -2121,8 +1965,162 @@ void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, } } -bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) +void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) +{ + int oldW = m_DebugWidth, oldH = m_DebugHeight; + + m_DebugWidth = m_DebugHeight = 1; + + VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texture]; + + bool isStencil = IsStencilFormat(iminfo.format); + + // do a second pass to render the stencil, if needed + for(int pass = 0; pass < (isStencil ? 2 : 1); pass++) + { + // render picked pixel to readback F32 RGBA texture + { + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = true; + texDisplay.flipY = false; + texDisplay.subresource = sub; + texDisplay.customShaderId = ResourceId(); + texDisplay.overlay = DebugOverlay::NoOverlay; + texDisplay.rangeMin = 0.0f; + texDisplay.rangeMax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.resourceId = texture; + texDisplay.typeCast = typeCast; + texDisplay.rawOutput = true; + texDisplay.xOffset = -float(x << sub.mip); + texDisplay.yOffset = -float(y << sub.mip); + + // only render green (stencil) in second pass + if(pass == 1) + { + texDisplay.green = true; + texDisplay.red = texDisplay.blue = texDisplay.alpha = false; + } + + VkClearValue clearval = {}; + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + NULL, + Unwrap(m_PixelPick.RP), + Unwrap(m_PixelPick.FB), + {{ + 0, 0, + }, + {1, 1}}, + 1, + &clearval, + }; + + RenderTextureInternal(texDisplay, rpbegin, eTexDisplay_F32Render | eTexDisplay_MipShift); + } + + VkDevice dev = m_pDriver->GetDev(); + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + const VkDevDispatchTable *vt = ObjDisp(dev); + + VkResult vkr = VK_SUCCESS; + + { + VkImageMemoryBarrier pickimBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + 0, + 0, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + Unwrap(m_PixelPick.Image), + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; + + // update image layout from color attachment to transfer source, with proper memory barriers + pickimBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + pickimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + DoPipelineBarrier(cmd, 1, &pickimBarrier); + pickimBarrier.oldLayout = pickimBarrier.newLayout; + pickimBarrier.srcAccessMask = pickimBarrier.dstAccessMask; + + // do copy + VkBufferImageCopy region = { + 0, 128, 1, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {1, 1, 1}, + }; + vt->CmdCopyImageToBuffer(Unwrap(cmd), Unwrap(m_PixelPick.Image), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + Unwrap(m_PixelPick.ReadbackBuffer.buf), 1, ®ion); + + // update image layout back to color attachment + pickimBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + pickimBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + DoPipelineBarrier(cmd, 1, &pickimBarrier); + + vt->EndCommandBuffer(Unwrap(cmd)); + } + + // submit cmds and wait for idle so we can readback + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + float *pData = NULL; + vt->MapMemory(Unwrap(dev), Unwrap(m_PixelPick.ReadbackBuffer.mem), 0, VK_WHOLE_SIZE, 0, + (void **)&pData); + + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + NULL, + Unwrap(m_PixelPick.ReadbackBuffer.mem), + 0, + VK_WHOLE_SIZE, + }; + + vkr = vt->InvalidateMappedMemoryRanges(Unwrap(dev), 1, &range); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + RDCASSERT(pData != NULL); + + if(pData == NULL) + { + RDCERR("Failed ot map readback buffer memory"); + } + else + { + // only write stencil to .y + if(pass == 1) + { + pixel[1] = ((uint32_t *)pData)[0] / 255.0f; + } + else + { + pixel[0] = pData[0]; + pixel[1] = pData[1]; + pixel[2] = pData[2]; + pixel[3] = pData[3]; + } + } + + vt->UnmapMemory(Unwrap(dev), Unwrap(m_PixelPick.ReadbackBuffer.mem)); + } + + m_DebugWidth = oldW; + m_DebugHeight = oldH; +} + +bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, + float *minval, float *maxval) { ImageLayouts &layouts = m_pDriver->m_ImageLayouts[texid]; @@ -2135,14 +2133,12 @@ bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, }; Vec4u stencil[2] = {{0, 0, 0, 0}, {1, 1, 1, 1}}; - bool success = - GetMinMax(texid, sliceFace, mip, sample, typeCast, false, &depth[0].x, &depth[1].x); + bool success = GetMinMax(texid, sub, typeCast, false, &depth[0].x, &depth[1].x); if(!success) return false; - success = GetMinMax(texid, sliceFace, mip, sample, typeCast, true, (float *)&stencil[0].x, - (float *)&stencil[1].x); + success = GetMinMax(texid, sub, typeCast, true, (float *)&stencil[0].x, (float *)&stencil[1].x); if(!success) return false; @@ -2157,11 +2153,11 @@ bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, return true; } - return GetMinMax(texid, sliceFace, mip, sample, typeCast, false, minval, maxval); + return GetMinMax(texid, sub, typeCast, false, minval, maxval); } -bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, bool stencil, float *minval, float *maxval) +bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, + bool stencil, float *minval, float *maxval) { VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); @@ -2325,18 +2321,18 @@ bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, HistogramUBOData *data = (HistogramUBOData *)m_Histogram.m_HistogramUBO.Map(NULL); - data->HistogramTextureResolution.x = (float)RDCMAX(uint32_t(iminfo.extent.width) >> mip, 1U); - data->HistogramTextureResolution.y = (float)RDCMAX(uint32_t(iminfo.extent.height) >> mip, 1U); - data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.extent.depth) >> mip, 1U); + data->HistogramTextureResolution.x = (float)RDCMAX(uint32_t(iminfo.extent.width) >> sub.mip, 1U); + data->HistogramTextureResolution.y = (float)RDCMAX(uint32_t(iminfo.extent.height) >> sub.mip, 1U); + data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.extent.depth) >> sub.mip, 1U); if(iminfo.type == VK_IMAGE_TYPE_3D) data->HistogramSlice = - (float)RDCCLAMP(sliceFace, 0U, uint32_t(iminfo.extent.depth >> mip) - 1) + 0.001f; + (float)RDCCLAMP(sub.slice, 0U, uint32_t(iminfo.extent.depth >> sub.mip) - 1) + 0.001f; else - data->HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, (uint32_t)iminfo.arrayLayers - 1) + 0.001f; - data->HistogramMip = (int)mip; + data->HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, (uint32_t)iminfo.arrayLayers - 1) + 0.001f; + data->HistogramMip = (int)sub.mip; data->HistogramNumSamples = iminfo.samples; - data->HistogramSample = (int)RDCCLAMP(sample, 0U, uint32_t(iminfo.samples) - 1); - if(sample == ~0U) + data->HistogramSample = (int)RDCCLAMP(sub.sample, 0U, uint32_t(iminfo.samples) - 1); + if(sub.sample == ~0U) data->HistogramSample = -iminfo.samples; data->HistogramMin = 0.0f; data->HistogramMax = 1.0f; @@ -2479,8 +2475,8 @@ bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, return true; } -bool VulkanReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], +bool VulkanReplay::GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, + float minval, float maxval, bool channels[4], std::vector &histogram) { if(minval >= maxval) @@ -2646,18 +2642,18 @@ bool VulkanReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t m HistogramUBOData *data = (HistogramUBOData *)m_Histogram.m_HistogramUBO.Map(NULL); - data->HistogramTextureResolution.x = (float)RDCMAX(uint32_t(iminfo.extent.width) >> mip, 1U); - data->HistogramTextureResolution.y = (float)RDCMAX(uint32_t(iminfo.extent.height) >> mip, 1U); - data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.extent.depth) >> mip, 1U); + data->HistogramTextureResolution.x = (float)RDCMAX(uint32_t(iminfo.extent.width) >> sub.mip, 1U); + data->HistogramTextureResolution.y = (float)RDCMAX(uint32_t(iminfo.extent.height) >> sub.mip, 1U); + data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.extent.depth) >> sub.mip, 1U); if(iminfo.type == VK_IMAGE_TYPE_3D) data->HistogramSlice = - (float)RDCCLAMP(sliceFace, 0U, uint32_t(iminfo.extent.depth >> mip) - 1) + 0.001f; + (float)RDCCLAMP(sub.slice, 0U, uint32_t(iminfo.extent.depth >> sub.mip) - 1) + 0.001f; else - data->HistogramSlice = (float)RDCCLAMP(sliceFace, 0U, (uint32_t)iminfo.arrayLayers - 1) + 0.001f; - data->HistogramMip = (int)mip; + data->HistogramSlice = (float)RDCCLAMP(sub.slice, 0U, (uint32_t)iminfo.arrayLayers - 1) + 0.001f; + data->HistogramMip = (int)sub.mip; data->HistogramNumSamples = iminfo.samples; - data->HistogramSample = (int)RDCCLAMP(sample, 0U, uint32_t(iminfo.samples) - 1); - if(sample == ~0U) + data->HistogramSample = (int)RDCCLAMP(sub.sample, 0U, uint32_t(iminfo.samples) - 1); + if(sub.sample == ~0U) data->HistogramSample = -iminfo.samples; data->HistogramMin = minval; @@ -2800,7 +2796,7 @@ std::vector VulkanReplay::GetUsage(ResourceId id) return m_pDriver->GetUsage(id); } -void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { bool wasms = false; @@ -2819,6 +2815,8 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi if(!layouts.isMemoryBound) return; + Subresource s = sub; + VkImageCreateInfo imCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, NULL, @@ -2910,9 +2908,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi imCreateInfo.imageType = VK_IMAGE_TYPE_2D; imCreateInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - imCreateInfo.extent.width = RDCMAX(1U, imCreateInfo.extent.width >> mip); - imCreateInfo.extent.height = RDCMAX(1U, imCreateInfo.extent.height >> mip); - imCreateInfo.extent.depth = RDCMAX(1U, imCreateInfo.extent.depth >> mip); + imCreateInfo.extent.width = RDCMAX(1U, imCreateInfo.extent.width >> s.mip); + imCreateInfo.extent.height = RDCMAX(1U, imCreateInfo.extent.height >> s.mip); + imCreateInfo.extent.depth = RDCMAX(1U, imCreateInfo.extent.depth >> s.mip); // convert a 3D texture into a 2D array, so we can render to the slices without needing // KHR_maintenance1 @@ -2976,7 +2974,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkSubpassDescription sub = { + VkSubpassDescription subpass = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, NULL, // inputs 1, &attRef, // color @@ -2992,7 +2990,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi 1, &attDesc, 1, - &sub, + &subpass, 0, NULL, // dependencies }; @@ -3023,12 +3021,11 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi texDisplay.linearDisplayAsGamma = false; texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = imInfo.type == VK_IMAGE_TYPE_3D ? 0 : (resolve ? ~0U : arrayIdx); + texDisplay.subresource.mip = s.mip; + texDisplay.subresource.slice = imInfo.type == VK_IMAGE_TYPE_3D ? i : s.slice; + texDisplay.subresource.sample = + imInfo.type == VK_IMAGE_TYPE_3D ? 0 : (resolve ? ~0U : s.sample); texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = imInfo.type == VK_IMAGE_TYPE_3D ? i : arrayIdx; - if(imInfo.samples > 1) - texDisplay.sliceFace /= imInfo.samples; texDisplay.rangeMin = params.blackPoint; texDisplay.rangeMax = params.whitePoint; texDisplay.scale = 1.0f; @@ -3115,8 +3112,8 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi // these have already been selected, don't need to fetch that subresource // when copying back to readback buffer - arrayIdx = 0; - mip = 0; + s.slice = 0; + s.mip = 0; // no longer depth, if it was isDepth = false; @@ -3128,8 +3125,8 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi imCreateInfo.arrayLayers = 1; imCreateInfo.mipLevels = 1; - imCreateInfo.extent.width = RDCMAX(1U, imCreateInfo.extent.width >> mip); - imCreateInfo.extent.height = RDCMAX(1U, imCreateInfo.extent.height >> mip); + imCreateInfo.extent.width = RDCMAX(1U, imCreateInfo.extent.width >> s.mip); + imCreateInfo.extent.height = RDCMAX(1U, imCreateInfo.extent.height >> s.mip); // create resolve texture vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); @@ -3151,7 +3148,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi RDCASSERT(!isDepth && !isStencil); VkImageResolve resolveRegion = { - {VK_IMAGE_ASPECT_COLOR_BIT, mip, arrayIdx, 1}, + {VK_IMAGE_ASPECT_COLOR_BIT, s.mip, s.slice, 1}, {0, 0, 0}, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, @@ -3284,8 +3281,8 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi // these have already been selected, don't need to fetch that subresource // when copying back to readback buffer - arrayIdx = 0; - mip = 0; + s.slice = 0; + s.mip = 0; } else if(wasms) { @@ -3455,6 +3452,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi srcImage = tmpImage; srcQueueIndex = m_pDriver->GetQueueFamilyIndex(); + + s.slice = s.slice * numSamples + s.sample; + s.sample = 0; } VkImageMemoryBarrier srcimBarrier = { @@ -3518,7 +3518,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi 0, 0, 0, - {copyAspects, mip, arrayIdx, 1}, + {copyAspects, s.mip, s.slice, 1}, { 0, 0, 0, }, @@ -3529,7 +3529,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi 0, 0, 0, - {VK_IMAGE_ASPECT_STENCIL_BIT, mip, arrayIdx, 1}, + {VK_IMAGE_ASPECT_STENCIL_BIT, s.mip, s.slice, 1}, { 0, 0, 0, }, @@ -3539,9 +3539,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi for(int i = 0; i < 2; i++) { - copyregion[i].imageExtent.width = RDCMAX(1U, copyregion[i].imageExtent.width >> mip); - copyregion[i].imageExtent.height = RDCMAX(1U, copyregion[i].imageExtent.height >> mip); - copyregion[i].imageExtent.depth = RDCMAX(1U, copyregion[i].imageExtent.depth >> mip); + copyregion[i].imageExtent.width = RDCMAX(1U, copyregion[i].imageExtent.width >> s.mip); + copyregion[i].imageExtent.height = RDCMAX(1U, copyregion[i].imageExtent.height >> s.mip); + copyregion[i].imageExtent.depth = RDCMAX(1U, copyregion[i].imageExtent.depth >> s.mip); } uint32_t dataSize = 0; @@ -3549,13 +3549,13 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi // for most combined depth-stencil images this will be large enough for both to be copied // separately, but for D24S8 we need to add extra space since they won't be copied packed dataSize = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, - imCreateInfo.format, mip); + imCreateInfo.format, s.mip); if(imCreateInfo.format == VK_FORMAT_D24_UNORM_S8_UINT) { dataSize = AlignUp(dataSize, 4U); dataSize += GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, - VK_FORMAT_S8_UINT, mip); + VK_FORMAT_S8_UINT, s.mip); } VkBufferCreateInfo bufInfo = { @@ -3590,7 +3590,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi { copyregion[1].bufferOffset = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, - GetDepthOnlyFormat(imCreateInfo.format), mip); + GetDepthOnlyFormat(imCreateInfo.format), s.mip); copyregion[1].bufferOffset = AlignUp(copyregion[1].bufferOffset, (VkDeviceSize)4); @@ -3604,7 +3604,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi { copyregion[0].imageSubresource.baseArrayLayer = i; copyregion[0].bufferOffset = - i * GetByteSize(imInfo.extent.width, imInfo.extent.height, 1, imCreateInfo.format, mip); + i * GetByteSize(imInfo.extent.width, imInfo.extent.height, 1, imCreateInfo.format, s.mip); vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuf, 1, copyregion); } @@ -3814,20 +3814,20 @@ void VulkanReplay::FreeCustomShader(ResourceId id) m_pDriver->ReleaseResource(GetResourceManager()->GetCurrentResource(id)); } -ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, - uint32_t arrayIdx, uint32_t sampleIdx, CompType typeCast) +ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, + const Subresource &sub, CompType typeCast) { if(shader == ResourceId() || texid == ResourceId()) return ResourceId(); VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texid]; - GetDebugManager()->CreateCustomShaderTex(iminfo.extent.width, iminfo.extent.height, mip); + GetDebugManager()->CreateCustomShaderTex(iminfo.extent.width, iminfo.extent.height, sub.mip); int oldW = m_DebugWidth, oldH = m_DebugHeight; - m_DebugWidth = RDCMAX(1U, iminfo.extent.width >> mip); - m_DebugHeight = RDCMAX(1U, iminfo.extent.height >> mip); + m_DebugWidth = RDCMAX(1U, iminfo.extent.width >> sub.mip); + m_DebugHeight = RDCMAX(1U, iminfo.extent.height >> sub.mip); TextureDisplay disp; disp.red = disp.green = disp.blue = disp.alpha = true; @@ -3839,14 +3839,12 @@ ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, disp.typeCast = typeCast; disp.hdrMultiplier = -1.0f; disp.linearDisplayAsGamma = false; - disp.mip = mip; - disp.sampleIdx = sampleIdx; + disp.subresource = sub; disp.overlay = DebugOverlay::NoOverlay; disp.rangeMin = 0.0f; disp.rangeMax = 1.0f; disp.rawOutput = false; disp.scale = 1.0f; - disp.sliceFace = arrayIdx; VkClearValue clearval = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; VkRenderPassBeginInfo rpbegin = { @@ -4094,8 +4092,8 @@ ResourceId VulkanReplay::CreateProxyTexture(const TextureDescription &templateTe return ResourceId(); } -void VulkanReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, - byte *data, size_t dataSize) +void VulkanReplay::SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, + size_t dataSize) { VULKANNOTIMP("SetProxyTextureData"); } diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 7374c6ca2..3facf42d8 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -309,11 +309,12 @@ public: CounterDescription DescribeCounter(GPUCounter counterID); std::vector FetchCounters(const std::vector &counters); - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval); - bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram); + void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]); + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval); + bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram); void InitPostVSBuffers(uint32_t eventId); void InitPostVSBuffers(const std::vector &passEvents); @@ -324,8 +325,8 @@ public: MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData); - void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, - const GetTextureDataParams ¶ms, bytebuf &data); + void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, + bytebuf &data); void ReplaceResource(ResourceId from, ResourceId to); void RemoveReplacement(ResourceId id); @@ -360,28 +361,25 @@ public: const bytebuf &data); std::vector PixelHistory(std::vector events, ResourceId target, - uint32_t x, uint32_t y, uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast); + uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast); ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3], const uint32_t threadid[3]); - void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, - uint32_t sample, CompType typeCast, float pixel[4]); uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); ResourceId RenderOverlay(ResourceId cfg, CompType typeCast, FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, const std::vector &passEvents); - ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, - uint32_t sampleIdx, CompType typeCast); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast); ResourceId CreateProxyTexture(const TextureDescription &templateTex); - void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, - size_t dataSize); + void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize); bool IsTextureSupported(const ResourceFormat &format); bool NeedRemapForFetch(const ResourceFormat &format); @@ -426,8 +424,8 @@ private: bool RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginInfo rpbegin, int flags); - bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, bool stencil, float *minval, float *maxval); + bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, bool stencil, + float *minval, float *maxval); VulkanDebugManager *GetDebugManager(); VulkanResourceManager *GetResourceManager(); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 738ccd7f9..f893fb3bc 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -813,6 +813,16 @@ void DoSerialise(SerialiserType &ser, PixelValue &el) SIZE_CHECK(16); } +template +void DoSerialise(SerialiserType &ser, Subresource &el) +{ + SERIALISE_MEMBER(mip); + SERIALISE_MEMBER(slice); + SERIALISE_MEMBER(sample); + + SIZE_CHECK(12); +} + template void DoSerialise(SerialiserType &ser, ModificationValue &el) { @@ -2263,6 +2273,8 @@ INSTANTIATE_SERIALISE_TYPE(MeshFormat) INSTANTIATE_SERIALISE_TYPE(FloatVector) INSTANTIATE_SERIALISE_TYPE(Uuid) INSTANTIATE_SERIALISE_TYPE(CounterDescription) +INSTANTIATE_SERIALISE_TYPE(PixelValue) +INSTANTIATE_SERIALISE_TYPE(Subresource) INSTANTIATE_SERIALISE_TYPE(PixelModification) INSTANTIATE_SERIALISE_TYPE(EventUsage) INSTANTIATE_SERIALISE_TYPE(CounterResult) diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 50ae77c23..d9075d606 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -652,7 +652,7 @@ bytebuf ReplayController::GetBufferData(ResourceId buff, uint64_t offset, uint64 return retData; } -bytebuf ReplayController::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip) +bytebuf ReplayController::GetTextureData(ResourceId tex, const Subresource &sub) { CHECK_REPLAY_THREAD(); @@ -666,7 +666,7 @@ bytebuf ReplayController::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint return ret; } - m_pDevice->GetTextureData(liveId, arrayIdx, mip, GetTextureDataParams(), ret); + m_pDevice->GetTextureData(liveId, sub, GetTextureDataParams(), ret); return ret; } @@ -696,8 +696,8 @@ bool ReplayController::SaveTexture(const TextureSave &saveData, const char *path } else { - if(sd.sample.sampleIndex != ~0U) - sd.sample.sampleIndex = RDCCLAMP(sd.sample.sampleIndex, 0U, td.msSamp); + if(sd.sample.sampleIndex >= 0) + sd.sample.sampleIndex = RDCCLAMP((uint32_t)sd.sample.sampleIndex, 0U, td.msSamp); } // don't support cube cruciform for non cubemaps, or @@ -742,7 +742,7 @@ bool ReplayController::SaveTexture(const TextureSave &saveData, const char *path // treat any multisampled texture as if it were an array // of dimension (on top of potential existing array - // dimension). GetTextureData() uses the same convention. + // dimension). if(td.msSamp > 1) { td.arraysize *= td.msSamp; @@ -964,8 +964,10 @@ bool ReplayController::SaveTexture(const TextureSave &saveData, const char *path params.blackPoint = sd.comp.blackPoint; params.whitePoint = sd.comp.whitePoint; + Subresource sub = {mip, slice / sampleCount, slice % sampleCount}; + bytebuf data; - m_pDevice->GetTextureData(liveid, slice, mip, params, data); + m_pDevice->GetTextureData(liveid, sub, params, data); if(data.empty()) { @@ -1553,14 +1555,15 @@ bool ReplayController::SaveTexture(const TextureSave &saveData, const char *path return success; } -rdcarray ReplayController::PixelHistory(ResourceId target, uint32_t x, - uint32_t y, uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) +rdcarray ReplayController::PixelHistory(ResourceId target, uint32_t x, uint32_t y, + const Subresource &sub, CompType typeCast) { CHECK_REPLAY_THREAD(); rdcarray ret; + Subresource subresource = sub; + for(size_t t = 0; t < m_Textures.size(); t++) { if(m_Textures[t].resourceId == target) @@ -1573,18 +1576,18 @@ rdcarray ReplayController::PixelHistory(ResourceId target, ui } if(m_Textures[t].msSamp == 1) - sampleIdx = ~0U; + subresource.sample = ~0U; if(m_Textures[t].dimension == 3) { - slice = RDCCLAMP(slice, 0U, m_Textures[t].depth >> mip); + subresource.slice = RDCCLAMP(subresource.slice, 0U, m_Textures[t].depth >> subresource.mip); } else { - slice = RDCCLAMP(slice, 0U, m_Textures[t].arraysize); + subresource.slice = RDCCLAMP(subresource.slice, 0U, m_Textures[t].arraysize); } - mip = RDCCLAMP(mip, 0U, m_Textures[t].mips); + subresource.mip = RDCCLAMP(subresource.mip, 0U, m_Textures[t].mips - 1); break; } @@ -1665,13 +1668,58 @@ rdcarray ReplayController::PixelHistory(ResourceId target, ui if(id == ResourceId()) return ret; - ret = m_pDevice->PixelHistory(events, id, x, y, slice, mip, sampleIdx, typeCast); + ret = m_pDevice->PixelHistory(events, id, x, y, subresource, typeCast); SetFrameEvent(m_EventID, true); return ret; } +PixelValue ReplayController::PickPixel(ResourceId tex, uint32_t x, uint32_t y, + const Subresource &sub, CompType typeCast) +{ + CHECK_REPLAY_THREAD(); + + PixelValue ret; + + RDCEraseEl(ret.floatValue); + + if(tex == ResourceId()) + return ret; + + m_pDevice->PickPixel(m_pDevice->GetLiveID(tex), x, y, sub, typeCast, ret.floatValue); + + return ret; +} + +rdcpair ReplayController::GetMinMax(ResourceId textureId, + const Subresource &sub, CompType typeCast) +{ + CHECK_REPLAY_THREAD(); + + PixelValue minval = {{0.0f, 0.0f, 0.0f, 0.0f}}; + PixelValue maxval = {{1.0f, 1.0f, 1.0f, 1.0f}}; + + m_pDevice->GetMinMax(m_pDevice->GetLiveID(textureId), sub, typeCast, &minval.floatValue[0], + &maxval.floatValue[0]); + + return make_rdcpair(minval, maxval); +} + +rdcarray ReplayController::GetHistogram(ResourceId textureId, const Subresource &sub, + CompType typeCast, float minval, float maxval, + bool channels[4]) +{ + CHECK_REPLAY_THREAD(); + + std::vector hist; + + m_pDevice->GetHistogram(m_pDevice->GetLiveID(textureId), sub, typeCast, minval, maxval, channels, + hist); + + return hist; +} + ShaderDebugTrace *ReplayController::DebugVertex(uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) { @@ -1831,8 +1879,7 @@ void ReplayController::ReplayLoop(WindowingData window, ResourceId texid) TextureDisplay d; d.resourceId = texid; - d.mip = 0; - d.sampleIdx = ~0U; + d.subresource = {0, 0, ~0U}; d.overlay = DebugOverlay::NoOverlay; d.typeCast = CompType::Typeless; d.hdrMultiplier = -1.0f; @@ -1843,7 +1890,6 @@ void ReplayController::ReplayLoop(WindowingData window, ResourceId texid) d.scale = 1.0f; d.xOffset = 0.0f; d.yOffset = 0.0f; - d.sliceFace = 0; d.rawOutput = false; d.red = d.green = d.blue = true; d.alpha = false; diff --git a/renderdoc/replay/replay_controller.h b/renderdoc/replay/replay_controller.h index 837f8fb8f..a9e8cc149 100644 --- a/renderdoc/replay/replay_controller.h +++ b/renderdoc/replay/replay_controller.h @@ -47,8 +47,8 @@ public: rdcpair GetDimensions(); void ClearThumbnails(); - bool AddThumbnail(WindowingData window, ResourceId texID, CompType typeCast, uint32_t mip, - uint32_t slice); + bool AddThumbnail(WindowingData window, ResourceId texID, const Subresource &sub, + CompType typeCast); void Display(); @@ -57,13 +57,8 @@ public: void SetPixelContextLocation(uint32_t x, uint32_t y); void DisablePixelContext(); - rdcpair GetMinMax(); - rdcarray GetHistogram(float minval, float maxval, bool channels[4]); - ResourceId GetCustomShaderTexID(); ResourceId GetDebugOverlayTexID(); - PixelValue PickPixel(ResourceId texID, bool customShader, uint32_t x, uint32_t y, - uint32_t sliceFace, uint32_t mip, uint32_t sample); rdcpair PickVertex(uint32_t eventId, uint32_t x, uint32_t y); private: @@ -94,8 +89,7 @@ private: { ResourceId texture; bool depthMode; - uint32_t mip; - uint32_t slice; + Subresource sub; uint64_t wndHandle; CompType typeCast; uint64_t outputID; @@ -184,8 +178,14 @@ public: rdcarray GetShaderEntryPoints(ResourceId shader); ShaderReflection *GetShader(ResourceId pipeline, ResourceId shader, ShaderEntryPoint entry); - rdcarray PixelHistory(ResourceId target, uint32_t x, uint32_t y, uint32_t slice, - uint32_t mip, uint32_t sampleIdx, CompType typeCast); + PixelValue PickPixel(ResourceId textureId, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast); + rdcpair GetMinMax(ResourceId textureId, const Subresource &sub, + CompType typeCast); + rdcarray GetHistogram(ResourceId textureId, const Subresource &sub, CompType typeCast, + float minval, float maxval, bool channels[4]); + rdcarray PixelHistory(ResourceId target, uint32_t x, uint32_t y, + const Subresource &sub, CompType typeCast); ShaderDebugTrace *DebugVertex(uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset); ShaderDebugTrace *DebugPixel(uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); @@ -197,7 +197,7 @@ public: rdcarray GetUsage(ResourceId id); bytebuf GetBufferData(ResourceId buff, uint64_t offset, uint64_t len); - bytebuf GetTextureData(ResourceId buff, uint32_t arrayIdx, uint32_t mip); + bytebuf GetTextureData(ResourceId buff, const Subresource &sub); bool SaveTexture(const TextureSave &saveData, const char *path); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index a9d66343d..0f4a52803 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -135,7 +135,7 @@ public: MeshDataStage stage) = 0; virtual void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData) = 0; - virtual void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + virtual void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) = 0; virtual void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, @@ -156,8 +156,7 @@ public: virtual std::vector PixelHistory(std::vector events, ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeCast) = 0; + const Subresource &sub, CompType typeCast) = 0; virtual ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) = 0; virtual ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample, @@ -201,14 +200,15 @@ public: virtual bool IsOutputWindowVisible(uint64_t id) = 0; virtual void FlipOutputWindow(uint64_t id) = 0; - virtual bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float *minval, float *maxval) = 0; - virtual bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, - CompType typeCast, float minval, float maxval, bool channels[4], - std::vector &histogram) = 0; + virtual bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, + float *maxval) = 0; + virtual bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, + float maxval, bool channels[4], std::vector &histogram) = 0; + virtual void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub, + CompType typeCast, float pixel[4]) = 0; virtual ResourceId CreateProxyTexture(const TextureDescription &templateTex) = 0; - virtual void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, + virtual void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize) = 0; virtual bool IsTextureSupported(const ResourceFormat &format) = 0; @@ -223,16 +223,14 @@ public: const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) = 0; virtual rdcarray GetCustomShaderEncodings() = 0; - virtual ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, - uint32_t arrayIdx, uint32_t sampleIdx, CompType typeCast) = 0; + virtual ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, + CompType typeCast) = 0; virtual void FreeCustomShader(ResourceId id) = 0; virtual void RenderCheckerboard() = 0; virtual void RenderHighlightBox(float w, float h, float scale) = 0; - virtual void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, - uint32_t mip, uint32_t sample, CompType typeCast, float pixel[4]) = 0; virtual uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y) = 0; }; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 54eeda1c8..78ed4ae6f 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -282,6 +282,10 @@ void ReplayOutput::RefreshOverlay() m_OverlayResourceId = ResourceId(); } } + else + { + m_OverlayDirty = false; + } } ResourceId ReplayOutput::GetCustomShaderTexID() @@ -328,8 +332,8 @@ bool ReplayOutput::SetPixelContext(WindowingData window) return m_PixelContext.outputID != 0; } -bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, CompType typeCast, - uint32_t mip, uint32_t slice) +bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, const Subresource &sub, + CompType typeCast) { CHECK_REPLAY_THREAD(); @@ -355,9 +359,8 @@ bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, CompType { m_Thumbnails[i].texture = texID; m_Thumbnails[i].depthMode = depthMode; + m_Thumbnails[i].sub = sub; m_Thumbnails[i].typeCast = typeCast; - m_Thumbnails[i].mip = mip; - m_Thumbnails[i].slice = slice; m_Thumbnails[i].dirty = true; return true; @@ -368,9 +371,8 @@ bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, CompType p.outputID = m_pDevice->MakeOutputWindow(window, false); p.texture = texID; p.depthMode = depthMode; + p.sub = sub; p.typeCast = typeCast; - p.mip = mip; - p.slice = slice; p.dirty = true; RDCASSERT(p.outputID > 0); @@ -380,100 +382,6 @@ bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, CompType return true; } -rdcpair ReplayOutput::GetMinMax() -{ - CHECK_REPLAY_THREAD(); - - PixelValue minval = {{0.0f, 0.0f, 0.0f, 0.0f}}; - PixelValue maxval = {{1.0f, 1.0f, 1.0f, 1.0f}}; - - ResourceId tex = m_pDevice->GetLiveID(m_RenderData.texDisplay.resourceId); - - CompType typeCast = m_RenderData.texDisplay.typeCast; - uint32_t slice = m_RenderData.texDisplay.sliceFace; - uint32_t mip = m_RenderData.texDisplay.mip; - uint32_t sample = m_RenderData.texDisplay.sampleIdx; - - if(m_RenderData.texDisplay.customShaderId != ResourceId() && - m_CustomShaderResourceId != ResourceId()) - { - tex = m_CustomShaderResourceId; - typeCast = CompType::Typeless; - slice = 0; - sample = 0; - } - - m_pDevice->GetMinMax(tex, slice, mip, sample, typeCast, &minval.floatValue[0], - &maxval.floatValue[0]); - - return make_rdcpair(minval, maxval); -} - -rdcarray ReplayOutput::GetHistogram(float minval, float maxval, bool channels[4]) -{ - CHECK_REPLAY_THREAD(); - - std::vector hist; - - ResourceId tex = m_pDevice->GetLiveID(m_RenderData.texDisplay.resourceId); - - CompType typeCast = m_RenderData.texDisplay.typeCast; - uint32_t slice = m_RenderData.texDisplay.sliceFace; - uint32_t mip = m_RenderData.texDisplay.mip; - uint32_t sample = m_RenderData.texDisplay.sampleIdx; - - if(m_RenderData.texDisplay.customShaderId != ResourceId() && - m_CustomShaderResourceId != ResourceId()) - { - tex = m_CustomShaderResourceId; - typeCast = CompType::Typeless; - slice = 0; - sample = 0; - } - - m_pDevice->GetHistogram(tex, slice, mip, sample, typeCast, minval, maxval, channels, hist); - - return hist; -} - -PixelValue ReplayOutput::PickPixel(ResourceId tex, bool customShader, uint32_t x, uint32_t y, - uint32_t sliceFace, uint32_t mip, uint32_t sample) -{ - CHECK_REPLAY_THREAD(); - - PixelValue ret; - - RDCEraseEl(ret.floatValue); - - if(tex == ResourceId()) - return ret; - - CompType typeCast = m_RenderData.texDisplay.typeCast; - - if(customShader && m_RenderData.texDisplay.customShaderId != ResourceId() && - m_CustomShaderResourceId != ResourceId()) - { - tex = m_CustomShaderResourceId; - typeCast = CompType::Typeless; - } - - // for 'heatmap' type overlays, pick from the overlay texture - if((m_RenderData.texDisplay.overlay == DebugOverlay::QuadOverdrawDraw || - m_RenderData.texDisplay.overlay == DebugOverlay::QuadOverdrawPass || - m_RenderData.texDisplay.overlay == DebugOverlay::TriangleSizeDraw || - m_RenderData.texDisplay.overlay == DebugOverlay::TriangleSizePass) && - m_OverlayResourceId != ResourceId()) - { - tex = m_OverlayResourceId; - typeCast = CompType::Typeless; - } - - m_pDevice->PickPixel(m_pDevice->GetLiveID(tex), x, y, sliceFace, mip, sample, typeCast, - ret.floatValue); - - return ret; -} - rdcpair ReplayOutput::PickVertex(uint32_t eventId, uint32_t x, uint32_t y) { CHECK_REPLAY_THREAD(); @@ -614,7 +522,7 @@ void ReplayOutput::DisplayContext() const float contextZoom = 8.0f; - disp.scale = contextZoom / float(1 << disp.mip); + disp.scale = contextZoom / float(1 << disp.subresource.mip); int32_t width = 0, height = 0; m_pDevice->GetOutputWindowDimensions(m_PixelContext.outputID, width, height); @@ -625,11 +533,11 @@ void ReplayOutput::DisplayContext() int x = (int)m_ContextX; int y = (int)m_ContextY; - x >>= disp.mip; - x <<= disp.mip; + x >>= disp.subresource.mip; + x <<= disp.subresource.mip; - y >>= disp.mip; - y <<= disp.mip; + y >>= disp.subresource.mip; + y <<= disp.subresource.mip; disp.xOffset = -(float)x * disp.scale; disp.yOffset = -(float)y * disp.scale; @@ -727,15 +635,14 @@ void ReplayOutput::Display() disp.hdrMultiplier = -1.0f; disp.linearDisplayAsGamma = true; disp.flipY = false; - disp.mip = m_Thumbnails[i].mip; - disp.sampleIdx = ~0U; + disp.subresource = m_Thumbnails[i].sub; + disp.subresource.sample = ~0U; disp.customShaderId = ResourceId(); disp.resourceId = m_pDevice->GetLiveID(m_Thumbnails[i].texture); disp.typeCast = m_Thumbnails[i].typeCast; disp.scale = -1.0f; disp.rangeMin = 0.0f; disp.rangeMax = 1.0f; - disp.sliceFace = m_Thumbnails[i].slice; disp.xOffset = 0.0f; disp.yOffset = 0.0f; disp.rawOutput = false; @@ -792,14 +699,14 @@ void ReplayOutput::DisplayTex() if(m_RenderData.texDisplay.customShaderId != ResourceId()) { - m_CustomShaderResourceId = m_pDevice->ApplyCustomShader( - m_RenderData.texDisplay.customShaderId, texDisplay.resourceId, texDisplay.mip, - texDisplay.sliceFace, texDisplay.sampleIdx, texDisplay.typeCast); + m_CustomShaderResourceId = + m_pDevice->ApplyCustomShader(m_RenderData.texDisplay.customShaderId, texDisplay.resourceId, + texDisplay.subresource, texDisplay.typeCast); texDisplay.resourceId = m_pDevice->GetLiveID(m_CustomShaderResourceId); texDisplay.typeCast = CompType::Typeless; texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = 0; + texDisplay.subresource.slice = 0; } FloatVector color; diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp index a49f67406..c7987d427 100644 --- a/renderdoccmd/renderdoccmd.cpp +++ b/renderdoccmd/renderdoccmd.cpp @@ -62,8 +62,7 @@ void DisplayRendererPreview(IReplayController *renderer, uint32_t width, uint32_ rdcarray texs = renderer->GetTextures(); TextureDisplay d; - d.mip = 0; - d.sampleIdx = ~0U; + d.subresource = {0, 0, ~0U}; d.overlay = DebugOverlay::NoOverlay; d.typeCast = CompType::Typeless; d.customShaderId = ResourceId(); @@ -75,7 +74,6 @@ void DisplayRendererPreview(IReplayController *renderer, uint32_t width, uint32_ d.scale = 1.0f; d.xOffset = 0.0f; d.yOffset = 0.0f; - d.sliceFace = 0; d.rawOutput = false; d.red = d.green = d.blue = true; d.alpha = false; diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index 502439a21..dc6a7bd10 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -148,7 +148,6 @@ class TestCase: self.capture_filename = "" self.controller: rd.ReplayController = None self._variables = [] - self.pickout: rd.ReplayOutput = None def get_ref_path(self, name: str, extra: bool = False): if extra: @@ -308,16 +307,7 @@ class TestCase: if type(y) is float: y = int(tex_details.height * y) - if self.pickout is None: - self.pickout: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), - rd.ReplayOutputType.Texture) - self.check(self.pickout is not None) - - texdisplay = rd.TextureDisplay() - texdisplay.resourceId = tex - self.pickout.SetTextureDisplay(texdisplay) - - picked: rd.PixelValue = self.pickout.PickPixel(tex, False, x, y, 0, 0, 0) + picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless) if not util.value_compare(picked.floatValue, value, eps): raise TestFailureException( @@ -339,11 +329,9 @@ class TestCase: self.check_capture() self.controller.Shutdown() - self.pickout = None def invoketest(self, debugMode): self.run() - self.pickout = None self.debugMode = debugMode def get_first_draw(self): diff --git a/util/test/tests/GL/GL_Parameter_Zoo.py b/util/test/tests/GL/GL_Parameter_Zoo.py index 329749bf9..f60d4e301 100644 --- a/util/test/tests/GL/GL_Parameter_Zoo.py +++ b/util/test/tests/GL/GL_Parameter_Zoo.py @@ -14,7 +14,7 @@ class GL_Parameter_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(self.get_last_draw().eventId, True) - data = self.controller.GetTextureData(id, 0, 0) + data = self.controller.GetTextureData(id, rd.Subresource(0, 0, 0)) first_pixel = struct.unpack_from("BBBB", data, 0) val = [255, 0, 255, 255] diff --git a/util/test/tests/GL/GL_Per_Type_Tex_Units.py b/util/test/tests/GL/GL_Per_Type_Tex_Units.py index a03042197..dc7d45e87 100644 --- a/util/test/tests/GL/GL_Per_Type_Tex_Units.py +++ b/util/test/tests/GL/GL_Per_Type_Tex_Units.py @@ -41,7 +41,7 @@ class GL_Per_Type_Tex_Units(rdtest.TestCase): raise rdtest.TestFailureException( "First texture should be 8x8, not {}x{}".format(tex_details.width, tex_details.height)) - data = self.controller.GetTextureData(id, 0, 0) + data = self.controller.GetTextureData(id, rd.Subresource(0, 0, 0)) first_pixel = struct.unpack_from("BBBB", data, 0) if not rdtest.value_compare(first_pixel, (255, 0, 0, 255)): @@ -71,7 +71,7 @@ class GL_Per_Type_Tex_Units(rdtest.TestCase): "First texture should be 4x4x4, not {}x{}x{}".format(tex_details.width, tex_details.height, tex_details.depth)) - data = self.controller.GetTextureData(id, 0, 0) + data = self.controller.GetTextureData(id, rd.Subresource(0, 0, 0)) first_pixel = struct.unpack_from("BBBB", data, 0) if not rdtest.value_compare(first_pixel, (0, 255, 0, 255)): diff --git a/util/test/tests/Iter_Test.py b/util/test/tests/Iter_Test.py index 85f6b9e01..96dfacad3 100644 --- a/util/test/tests/Iter_Test.py +++ b/util/test/tests/Iter_Test.py @@ -135,7 +135,7 @@ class Iter_Test(rdtest.TestCase): rdtest.log.print("Fetching history for %d,%d on target %s" % (x, y, str(target))) - history = self.controller.PixelHistory(target, x, y, 0, 0, 0, rd.CompType.Typeless) + history = self.controller.PixelHistory(target, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless) rdtest.log.success("Pixel %d,%d has %d history events" % (x, y, len(history))) diff --git a/util/test/tests/Vulkan/VK_Line_Raster.py b/util/test/tests/Vulkan/VK_Line_Raster.py index cb5216497..279d5abdc 100644 --- a/util/test/tests/Vulkan/VK_Line_Raster.py +++ b/util/test/tests/Vulkan/VK_Line_Raster.py @@ -21,7 +21,7 @@ class VK_Line_Raster(rdtest.TestCase): x = self.view[0] * col + p[0] y = self.view[1] * row + p[1] - picked: rd.PixelValue = self.out.PickPixel(self.tex.resourceId, False, x, y, 0, 0, 0) + picked: rd.PixelValue = self.controller.PickPixel(self.tex, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless) ret.append(rdtest.value_compare(picked.floatValue, [0.0, 1.0, 1.0, 1.0])) return ret @@ -34,16 +34,11 @@ class VK_Line_Raster(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, False) - # Make an output so we can pick pixels - self.out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) - pipe: rd.PipeState = self.controller.GetPipelineState() - self.tex = rd.TextureDisplay() - self.tex.resourceId = pipe.GetOutputTargets()[0].resourceId - self.out.SetTextureDisplay(self.tex) + self.tex = pipe.GetOutputTargets()[0].resourceId - texdetails = self.get_texture(self.tex.resourceId) + texdetails = self.get_texture(self.tex) # Top left we expect a regular line segment. s = self.sample(0, 0) @@ -85,5 +80,3 @@ class VK_Line_Raster(rdtest.TestCase): rdtest.log.success("{} line not supported".format(n)) rdtest.log.success("All lines look as expected") - - self.out.Shutdown()