diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 3a2d41d01..95538d4ea 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -2620,9 +2620,9 @@ IBufferViewer *CaptureContext::ViewConstantBuffer(ShaderStage stage, uint32_t sl } IPixelHistoryView *CaptureContext::ViewPixelHistory(ResourceId texID, uint32_t x, uint32_t y, - const TextureDisplay &display) + uint32_t view, const TextureDisplay &display) { - return new PixelHistoryView(*this, texID, QPoint(x, y), display, m_MainWindow); + return new PixelHistoryView(*this, texID, QPoint(x, y), view, display, m_MainWindow); } QWidget *CaptureContext::CreateBuiltinWindow(const rdcstr &objectName) diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index 861e07702..0409771dc 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -269,7 +269,7 @@ public: const rdcstr &format = "") override; IBufferViewer *ViewConstantBuffer(ShaderStage stage, uint32_t slot, uint32_t idx) override; - IPixelHistoryView *ViewPixelHistory(ResourceId texID, uint32_t x, uint32_t y, + IPixelHistoryView *ViewPixelHistory(ResourceId texID, uint32_t x, uint32_t y, uint32_t view, const TextureDisplay &display) override; QWidget *CreateBuiltinWindow(const rdcstr &objectName) override; diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 8261890db..3a42a3028 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -2624,12 +2624,13 @@ operation. :param renderdoc.ResourceId id: The ID of the texture to show the history of. :param int x: The x co-ordinate of the pixel to search for. :param int y: The y co-ordinate of the pixel to search for. +:param int view: The layered or multiview rendering view index of the pixel to search for. :param renderdoc.TextureDisplay display: The texture display configuration to use when looking up the history. :return: The new :class:`PixelHistoryView` window opened, but not shown. :rtype: PixelHistoryView )"); - virtual IPixelHistoryView *ViewPixelHistory(ResourceId id, uint32_t x, uint32_t y, + virtual IPixelHistoryView *ViewPixelHistory(ResourceId id, uint32_t x, uint32_t y, uint32_t view, const TextureDisplay &display) = 0; DOCUMENT(R"(Creates and returns a built-in window. diff --git a/qrenderdoc/Windows/PixelHistoryView.cpp b/qrenderdoc/Windows/PixelHistoryView.cpp index 2185fb2ce..8ac14b8e7 100644 --- a/qrenderdoc/Windows/PixelHistoryView.cpp +++ b/qrenderdoc/Windows/PixelHistoryView.cpp @@ -611,7 +611,7 @@ private: } }; -PixelHistoryView::PixelHistoryView(ICaptureContext &ctx, ResourceId id, QPoint point, +PixelHistoryView::PixelHistoryView(ICaptureContext &ctx, ResourceId id, QPoint point, uint32_t view, const TextureDisplay &display, QWidget *parent) : QFrame(parent), ui(new Ui::PixelHistoryView), m_Ctx(ctx) { @@ -622,6 +622,7 @@ PixelHistoryView::PixelHistoryView(ICaptureContext &ctx, ResourceId id, QPoint p m_Pixel = point; m_Display = display; m_ID = id; + m_View = view; updateWindowTitle(); @@ -770,6 +771,7 @@ void PixelHistoryView::startDebug(EventTag tag) DebugPixelInputs inputs; inputs.sample = m_Display.subresource.sample; inputs.primitive = tag.primitive; + inputs.view = m_View; trace = r->DebugPixel((uint32_t)m_Pixel.x(), (uint32_t)m_Pixel.y(), inputs); if(trace->debugger == NULL) diff --git a/qrenderdoc/Windows/PixelHistoryView.h b/qrenderdoc/Windows/PixelHistoryView.h index adaed550d..14242d7e7 100644 --- a/qrenderdoc/Windows/PixelHistoryView.h +++ b/qrenderdoc/Windows/PixelHistoryView.h @@ -40,7 +40,7 @@ class PixelHistoryView : public QFrame, public IPixelHistoryView, public ICaptur Q_OBJECT public: - explicit PixelHistoryView(ICaptureContext &ctx, ResourceId id, QPoint point, + explicit PixelHistoryView(ICaptureContext &ctx, ResourceId id, QPoint point, uint32_t view, const TextureDisplay &display, QWidget *parent = 0); ~PixelHistoryView(); @@ -74,6 +74,7 @@ private: ResourceId m_ID; TextureDisplay m_Display; QPoint m_Pixel; + uint32_t m_View; PixelHistoryItemModel *m_Model; bool m_ShowFailures = true; void startDebug(EventTag tag); diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index 40d179fae..63ce4f8bc 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -851,10 +851,10 @@ struct CaptureContextInvoker : ObjectForwarder } virtual IPixelHistoryView *ViewPixelHistory(ResourceId texID, uint32_t x, uint32_t y, - const TextureDisplay &display) override + uint32_t view, const TextureDisplay &display) override { return InvokeRetFunction(&ICaptureContext::ViewPixelHistory, texID, x, y, - display); + view, display); } virtual QWidget *CreateBuiltinWindow(const rdcstr &objectName) override diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index c138a94a3..a08ab62dc 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -4098,9 +4098,11 @@ void TextureViewer::on_debugPixelContext_clicked() bool done = false; ShaderDebugTrace *trace = NULL; - m_Ctx.Replay().AsyncInvoke([this, &trace, &done, x, y](IReplayController *r) { + uint32_t view = m_TexDisplay.subresource.slice - m_Following.GetFirstArraySlice(m_Ctx); + m_Ctx.Replay().AsyncInvoke([this, &trace, &done, x, y, view](IReplayController *r) { DebugPixelInputs inputs; inputs.sample = m_TexDisplay.subresource.sample; + inputs.view = view; trace = r->DebugPixel((uint32_t)x, (uint32_t)y, inputs); if(trace->debugger == NULL) @@ -4160,7 +4162,8 @@ void TextureViewer::on_pixelHistory_clicked() if(m_TexDisplay.flipY) y = (int)(mipHeight - 1) - y; - IPixelHistoryView *hist = m_Ctx.ViewPixelHistory(texptr->resourceId, x, y, m_TexDisplay); + uint32_t view = m_TexDisplay.subresource.slice - m_Following.GetFirstArraySlice(m_Ctx); + IPixelHistoryView *hist = m_Ctx.ViewPixelHistory(texptr->resourceId, x, y, view, m_TexDisplay); m_Ctx.AddDockWindow(hist->Widget(), DockReference::TransientPopupArea, this, 0.3f); diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index b76e008eb..ca604eb35 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -3052,15 +3052,17 @@ struct PSHit Vec4f pos; uint32_t prim; uint32_t sample; + uint32_t view; uint32_t valid; float ddxDerivCheck; + uint32_t padding[3]; // PSInput base, ddx, .... }; static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structStride, VulkanCreationInfo::ShaderModuleReflection &shadRefl, const uint32_t paramAlign, StorageMode storageMode, - bool usePrimitiveID, bool useSampleID) + bool usePrimitiveID, bool useSampleID, bool useViewIndex) { rdcspv::Editor editor(fragspv); @@ -3182,7 +3184,7 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt rdcspv::Id base; rdcspv::Id type; uint32_t member = ~0U; - } fragCoord, primitiveID, sampleIndex; + } fragCoord, primitiveID, sampleIndex, viewIndex; // look to see which ones are already provided for(size_t i = 0; i < shadRefl.refl->inputSignature.size(); i++) @@ -3211,6 +3213,14 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt ? editor.DeclareType(rdcspv::scalar()) : editor.DeclareType(rdcspv::scalar()); } + else if(param.systemValue == ShaderBuiltin::MultiViewIndex) + { + access = &viewIndex; + + access->type = VarTypeCompType(param.varType) == CompType::SInt + ? editor.DeclareType(rdcspv::scalar()) + : editor.DeclareType(rdcspv::scalar()); + } if(access) { @@ -3276,6 +3286,25 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt editor.AddCapability(rdcspv::Capability::SampleRateShading); } + if(viewIndex.base == rdcspv::Id() && useViewIndex) + { + rdcspv::Id type = editor.DeclareType(rdcspv::scalar()); + rdcspv::Id ptrType = editor.DeclareType(rdcspv::Pointer(type, rdcspv::StorageClass::Input)); + + viewIndex.base = + editor.AddVariable(rdcspv::OpVariable(ptrType, editor.MakeId(), rdcspv::StorageClass::Input)); + viewIndex.type = type; + + editor.AddDecoration(rdcspv::OpDecorate( + viewIndex.base, + rdcspv::DecorationParam(rdcspv::BuiltIn::ViewIndex))); + editor.AddDecoration(rdcspv::OpDecorate(viewIndex.base, rdcspv::Decoration::Flat)); + + addedInputs.push_back(viewIndex.base); + + editor.AddCapability(rdcspv::Capability::MultiView); + } + rdcspv::Id PSInput; enum Variant @@ -3381,10 +3410,13 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt uint32Type, // uint sample; uint32Type, + // uint view; + uint32Type, // uint valid; uint32Type, // float ddxDerivCheck; floatType, + // // IN PSInput, @@ -3421,6 +3453,12 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt offs += sizeof(uint32_t); member++; + editor.AddDecoration(rdcspv::OpMemberDecorate( + PSHit, member, rdcspv::DecorationParam(offs))); + editor.SetMemberName(PSHit, member, "view"); + offs += sizeof(uint32_t); + member++; + editor.AddDecoration(rdcspv::OpMemberDecorate( PSHit, member, rdcspv::DecorationParam(offs))); editor.SetMemberName(PSHit, member, "valid"); @@ -3433,6 +3471,9 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt offs += sizeof(uint32_t); member++; + // + offs += sizeof(uint32_t) * 3; + RDCASSERT((offs % sizeof(Vec4f)) == 0); RDCASSERT((structStride % sizeof(Vec4f)) == 0); @@ -3471,14 +3512,14 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt editor.AddDecoration(rdcspv::OpDecorate( PSHitRTArray, rdcspv::DecorationParam(structStride * 5 + - sizeof(Vec4f) * 2))); + sizeof(Vec4f) * 3))); rdcspv::Id bufBase = editor.DeclareStructType({ // uint hit_count; uint32Type, - // uint test; + // uint total_count; uint32Type, - // + // // PSHit hits[]; PSHitRTArray, @@ -3553,6 +3594,8 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt // add the extension editor.AddExtension(storageMode == KHR_bda ? "SPV_KHR_physical_storage_buffer" : "SPV_EXT_physical_storage_buffer"); + if(useViewIndex) + editor.AddExtension("SPV_KHR_multiview"); // change the memory model to physical storage buffer 64 rdcspv::Iter it = editor.Begin(rdcspv::Section::MemoryModel); @@ -3878,12 +3921,44 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(2)})); ops.add(rdcspv::OpStore(storePtr, loaded, alignedAccess)); + if(viewIndex.base != rdcspv::Id()) + { + if(viewIndex.member == ~0U) + { + loaded = ops.add(rdcspv::OpLoad(viewIndex.type, editor.MakeId(), viewIndex.base)); + } + else + { + rdcspv::Id inPtrType = + editor.DeclareType(rdcspv::Pointer(viewIndex.type, rdcspv::StorageClass::Input)); + + rdcspv::Id viewidxptr = + ops.add(rdcspv::OpAccessChain(inPtrType, editor.MakeId(), viewIndex.base, + {editor.AddConstantImmediate(viewIndex.member)})); + loaded = ops.add(rdcspv::OpLoad(viewIndex.type, editor.MakeId(), viewidxptr)); + } + + // if it was loaded as signed int by the shader and not as unsigned by us, bitcast to + // unsigned. + if(viewIndex.type != uint32Type) + loaded = ops.add(rdcspv::OpBitcast(uint32Type, editor.MakeId(), loaded)); + } + else + { + // explicitly store 0 + loaded = getUIntConst(0); + } + storePtr = ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(3)})); + ops.add(rdcspv::OpStore(storePtr, loaded, alignedAccess)); + + storePtr = + ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(4)})); ops.add(rdcspv::OpStore(storePtr, editor.AddConstantImmediate(validMagicNumber), alignedAccess)); // store ddx(gl_FragCoord.x) to check that derivatives are working - storePtr = ops.add(rdcspv::OpAccessChain(floatBufPtr, editor.MakeId(), hit, {getUIntConst(4)})); + storePtr = ops.add(rdcspv::OpAccessChain(floatBufPtr, editor.MakeId(), hit, {getUIntConst(5)})); rdcspv::Id fragCoord_ddx_x = ops.add(rdcspv::OpCompositeExtract(floatType, editor.MakeId(), fragCoord_ddx, {0})); ops.add(rdcspv::OpStore(storePtr, fragCoord_ddx_x, alignedAccess)); @@ -3892,11 +3967,11 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt rdcspv::Id inputPtrType = editor.DeclareType(rdcspv::Pointer(PSInput, bufferClass)); rdcspv::Id outputPtrs[Variant_Count] = { - ops.add(rdcspv::OpAccessChain(inputPtrType, editor.MakeId(), hit, {getUIntConst(5)})), ops.add(rdcspv::OpAccessChain(inputPtrType, editor.MakeId(), hit, {getUIntConst(6)})), ops.add(rdcspv::OpAccessChain(inputPtrType, editor.MakeId(), hit, {getUIntConst(7)})), ops.add(rdcspv::OpAccessChain(inputPtrType, editor.MakeId(), hit, {getUIntConst(8)})), ops.add(rdcspv::OpAccessChain(inputPtrType, editor.MakeId(), hit, {getUIntConst(9)})), + ops.add(rdcspv::OpAccessChain(inputPtrType, editor.MakeId(), hit, {getUIntConst(10)})), }; for(size_t i = 0; i < values.size(); i++) @@ -4300,6 +4375,43 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ RDCLOG("useSampleID is %u because of bare capability", useSampleID); } + bool useViewIndex = (view == ~0U) ? false : true; + if(useViewIndex) + { + ResourceId rp = state.GetRenderPass(); + if(rp != ResourceId()) + { + const VulkanCreationInfo::RenderPass &rpInfo = + m_pDriver->GetDebugManager()->GetRenderPassInfo(rp); + for(auto it = rpInfo.subpasses.begin(); it != rpInfo.subpasses.end(); ++it) + { + if(it->multiviews.isEmpty()) + { + if(Vulkan_Debug_ShaderDebugLogging()) + RDCLOG( + "Disabling useViewIndex because at least one subpass does not have multiple views"); + useViewIndex = false; + break; + } + } + } + else + { + useViewIndex = pipe.viewMask != 0; + if(!useViewIndex && Vulkan_Debug_ShaderDebugLogging()) + RDCLOG("Disabling useViewIndex because viewMask is zero"); + } + } + else + { + if(Vulkan_Debug_ShaderDebugLogging()) + RDCLOG("Disabling useViewIndex from input view %u", view); + } + if(useViewIndex) + { + builtins[ShaderBuiltin::MultiViewIndex] = ShaderVariable(rdcstr(), view, 0U, 0U, 0U); + } + StorageMode storageMode = Binding; if(m_pDriver->GetExtensions(NULL).ext_KHR_buffer_device_address) @@ -4349,7 +4461,7 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ uint32_t structStride = 0; CreatePSInputFetcher(fragspv, structStride, shadRefl, paramAlign, storageMode, usePrimitiveID, - useSampleID); + useSampleID, useViewIndex); if(!Vulkan_Debug_PSDebugDumpDirPath().empty()) FileIO::WriteAll(Vulkan_Debug_PSDebugDumpDirPath() + "/debug_psinput_after.spv", fragspv); @@ -4489,8 +4601,8 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ } // create fragment shader with modified code - VkShaderModuleCreateInfo moduleCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + VkShaderModuleCreateInfo moduleCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; VkSpecializationMapEntry specMaps[] = { { (uint32_t)InputSpecConstant::Address, @@ -4724,6 +4836,13 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ continue; } + // if we're looking for a specific view, ignore hits from the wrong view + if(useViewIndex) + { + if(hit->view != view) + continue; + } + // see if this hit is a closer match than the previous winner. // if there's no previous winner it's clearly better