From db563bb0bf1c92411694a1634b40dfd110bbd9af Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 30 Oct 2019 17:14:12 +0000 Subject: [PATCH] Refactor public interface around handling of textures * Subresource handling is more consistent - we pass around a struct now that contains the array slice, mip level, and sample. We remove the concept of 'MSAA textures count samples as extra slices within the real slices' and internalise that completely. This also means we have a consistent set everywhere that we need to refer to a subresource. * Functions that used to be in the ReplayOutput and use a couple of implicit parameters from the texture viewer configuration are now in the ReplayController and take them explicitly. This includes GetMinMax, GetHistogram, and PickPixel. * Since these functions aren't ReplayOutput relative, if you want to decode the custom shader texture or the overlay texture you need to pass that ID directly. --- qrenderdoc/Code/CaptureContext.cpp | 4 +- qrenderdoc/Code/CaptureContext.h | 2 +- qrenderdoc/Code/Interface/QRDInterface.h | 11 +- qrenderdoc/Windows/BufferViewer.cpp | 7 +- qrenderdoc/Windows/BufferViewer.h | 5 +- .../D3D11PipelineStateViewer.cpp | 2 +- .../D3D12PipelineStateViewer.cpp | 2 +- .../PipelineState/GLPipelineStateViewer.cpp | 2 +- .../VulkanPipelineStateViewer.cpp | 2 +- qrenderdoc/Windows/PixelHistoryView.cpp | 6 +- qrenderdoc/Windows/PythonShell.cpp | 5 +- qrenderdoc/Windows/ResourceInspector.cpp | 2 +- qrenderdoc/Windows/TextureViewer.cpp | 168 +++--- qrenderdoc/Windows/TextureViewer.h | 3 +- renderdoc/api/replay/control_types.h | 14 +- renderdoc/api/replay/data_types.h | 43 ++ renderdoc/api/replay/renderdoc_replay.h | 134 ++--- renderdoc/core/image_viewer.cpp | 48 +- renderdoc/core/replay_proxy.cpp | 84 ++- renderdoc/core/replay_proxy.h | 102 ++-- renderdoc/driver/d3d11/d3d11_pixelhistory.cpp | 7 +- .../driver/d3d11/d3d11_rendertexture.cpp | 23 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 513 +++++++++--------- renderdoc/driver/d3d11/d3d11_replay.h | 28 +- .../driver/d3d12/d3d12_rendertexture.cpp | 27 +- renderdoc/driver/d3d12/d3d12_replay.cpp | 329 ++++++----- renderdoc/driver/d3d12/d3d12_replay.h | 28 +- renderdoc/driver/gl/gl_debug.cpp | 257 +++++---- renderdoc/driver/gl/gl_rendertexture.cpp | 33 +- renderdoc/driver/gl/gl_replay.cpp | 166 +++--- renderdoc/driver/gl/gl_replay.h | 32 +- renderdoc/driver/vulkan/vk_pixelhistory.cpp | 9 +- renderdoc/driver/vulkan/vk_rendertexture.cpp | 28 +- renderdoc/driver/vulkan/vk_replay.cpp | 438 ++++++++------- renderdoc/driver/vulkan/vk_replay.h | 32 +- renderdoc/replay/renderdoc_serialise.inl | 12 + renderdoc/replay/replay_controller.cpp | 80 ++- renderdoc/replay/replay_controller.h | 24 +- renderdoc/replay/replay_driver.h | 24 +- renderdoc/replay/replay_output.cpp | 131 +---- renderdoccmd/renderdoccmd.cpp | 4 +- util/test/rdtest/testcase.py | 14 +- util/test/tests/GL/GL_Parameter_Zoo.py | 2 +- util/test/tests/GL/GL_Per_Type_Tex_Units.py | 4 +- util/test/tests/Iter_Test.py | 2 +- util/test/tests/Vulkan/VK_Line_Raster.py | 13 +- 46 files changed, 1449 insertions(+), 1457 deletions(-) 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()