From c5242e574a1303f1204d5e698671aa5ac5355186 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 2 Apr 2020 16:43:29 +0100 Subject: [PATCH] Fetch inputs and derivatives --- renderdoc/driver/vulkan/vk_shaderdebug.cpp | 195 +++++++++++++++++---- 1 file changed, 159 insertions(+), 36 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index 648eabd16..e6291f584 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -111,6 +111,8 @@ enum class InputSpecConstant Count, }; +static const uint32_t validMagicNumber = 12345; + static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structStride, VulkanCreationInfo::ShaderModuleReflection &shadRefl, StorageMode storageMode, bool usePrimitiveID, bool useSampleID) @@ -148,10 +150,29 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt } } + rdcspv::MemoryAccessAndParamDatas alignedAccess; + alignedAccess.setAligned(sizeof(uint32_t)); + rdcspv::Id uint32Type = editor.DeclareType(rdcspv::scalar()); rdcspv::Id floatType = editor.DeclareType(rdcspv::scalar()); rdcspv::Id boolType = editor.DeclareType(rdcspv::scalar()); + rdcarray uintConsts; + + auto getUIntConst = [&uintConsts, &editor](uint32_t c) { + for(uint32_t i = (uint32_t)uintConsts.size(); i <= c; i++) + uintConsts.push_back(editor.AddConstantImmediate(uint32_t(i))); + + return uintConsts[c]; + }; + + rdcspv::StorageClass bufferClass; + + if(storageMode == Binding) + bufferClass = editor.StorageBufferClass(); + else + bufferClass = rdcspv::StorageClass::PhysicalStorageBuffer; + // remove all other entry point rdcspv::Id entryID; for(const rdcspv::EntryPoint &e : editor.GetEntries()) @@ -267,6 +288,27 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt rdcspv::Id PSInput; + enum Variant + { + Variant_Base, + Variant_ddxcoarse, + Variant_ddycoarse, + Variant_ddxfine, + Variant_ddyfine, + Variant_Count, + }; + + struct valueAndDerivs + { + rdcspv::Id valueType; + rdcspv::Id data[Variant_Count]; + uint32_t structIndex; + rdcspv::OperationList storeOps; + }; + + rdcarray values; + values.resize(shadRefl.refl.inputSignature.size()); + { rdcarray ids; rdcarray offsets; @@ -285,15 +327,17 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt default: RDCERR("Unexpected type %s", ToStr(param.compType).c_str()); } - indices.push_back((uint32_t)offsets.size()); + values[i].structIndex = (uint32_t)offsets.size(); offsets.push_back(structStride); structStride += param.compCount * (base.width / 8); if(param.compCount == 1) - ids.push_back(editor.DeclareType(base)); + values[i].valueType = editor.DeclareType(base); else - ids.push_back(editor.DeclareType(rdcspv::Vector(base, param.compCount))); + values[i].valueType = editor.DeclareType(rdcspv::Vector(base, param.compCount)); + + ids.push_back(values[i].valueType); // align offset conservatively, to 16-byte aligned. We do this with explicit uints so we can // preview with spirv-cross (and because it doesn't cost anything particularly) @@ -314,8 +358,8 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt PSInput, uint32_t(i), rdcspv::DecorationParam(offsets[i]))); } - for(size_t i = 0; i < shadRefl.refl.inputSignature.size(); i++) - editor.SetMemberName(PSInput, indices[i], shadRefl.refl.inputSignature[i].varName); + for(size_t i = 0; i < values.size(); i++) + editor.SetMemberName(PSInput, values[i].structIndex, shadRefl.refl.inputSignature[i].varName); editor.SetName(PSInput, "__rd_PSInput"); } @@ -350,11 +394,6 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt editor.SetName(destXY, "destXY"); - rdcspv::Id uintConsts[] = { - editor.AddConstantImmediate(0), editor.AddConstantImmediate(1), - editor.AddConstantImmediate(2), - }; - rdcspv::Id PSHit = editor.DeclareStructType({ // float4 pos; float4Type, @@ -362,9 +401,10 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt uint32Type, // uint sample; uint32Type, - // float derivValid; - floatType, - // + // uint valid; + uint32Type, + // uint padding; + uint32Type, // IN PSInput, @@ -403,11 +443,15 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt editor.AddDecoration(rdcspv::OpMemberDecorate( PSHit, member, rdcspv::DecorationParam(offs))); - editor.SetMemberName(PSHit, member, "derivValid"); - offs += sizeof(float); + editor.SetMemberName(PSHit, member, "valid"); + offs += sizeof(uint32_t); member++; - offs += sizeof(float); // padding + editor.AddDecoration(rdcspv::OpMemberDecorate( + PSHit, member, rdcspv::DecorationParam(offs))); + editor.SetMemberName(PSHit, member, "padding"); + offs += sizeof(uint32_t); + member++; RDCASSERT((offs % sizeof(Vec4f)) == 0); RDCASSERT((structStride % sizeof(Vec4f)) == 0); @@ -472,15 +516,12 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt editor.SetMemberName(bufBase, 1, "hits"); } - rdcspv::StorageClass bufferClass; rdcspv::Id bufptrtype; rdcspv::Id ssboVar; rdcspv::Id addressConstant; if(storageMode == Binding) { - bufferClass = editor.StorageBufferClass(); - // the pointers are SSBO pointers bufptrtype = editor.DeclareType(rdcspv::Pointer(bufBase, bufferClass)); @@ -522,9 +563,6 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt } else { - // our pointers are physical storage buffer pointers - bufferClass = rdcspv::StorageClass::PhysicalStorageBuffer; - bufptrtype = editor.DeclareType(rdcspv::Pointer(bufBase, bufferClass)); // add the extension @@ -568,6 +606,8 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt rdcspv::Id glsl450 = editor.ImportExtInst("GLSL.std.450"); + editor.AddCapability(rdcspv::Capability::DerivativeControl); + { rdcspv::OperationList ops; @@ -578,6 +618,58 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt ops.add(rdcspv::OpLabel(editor.MakeId())); { + // grab all the values here and get any derivatives we need now before we branch non-uniformly + for(size_t i = 0; i < values.size(); i++) + { + const SPIRVInterfaceAccess &access = shadRefl.patchData.inputs[i]; + const SigParameter ¶m = shadRefl.refl.inputSignature[i]; + + rdcarray accessIndices; + for(uint32_t idx : access.accessChain) + accessIndices.push_back(getUIntConst(idx)); + + rdcspv::Id ptrType = + editor.DeclareType(rdcspv::Pointer(values[i].valueType, rdcspv::StorageClass::Input)); + rdcspv::Id ptr = + ops.add(rdcspv::OpAccessChain(ptrType, editor.MakeId(), access.ID, accessIndices)); + rdcspv::Id base = ops.add(rdcspv::OpLoad(values[i].valueType, editor.MakeId(), ptr)); + + values[i].data[Variant_Base] = base; + + editor.SetName(base, StringFormat::Fmt("__rd_base_%zu_%s", i, param.varName.c_str())); + + // only float values have derivatives + if(param.compType == CompType::Float) + { + values[i].data[Variant_ddxcoarse] = + ops.add(rdcspv::OpDPdxCoarse(values[i].valueType, editor.MakeId(), base)); + values[i].data[Variant_ddycoarse] = + ops.add(rdcspv::OpDPdyCoarse(values[i].valueType, editor.MakeId(), base)); + values[i].data[Variant_ddxfine] = + ops.add(rdcspv::OpDPdxFine(values[i].valueType, editor.MakeId(), base)); + values[i].data[Variant_ddyfine] = + ops.add(rdcspv::OpDPdyFine(values[i].valueType, editor.MakeId(), base)); + + editor.SetName(values[i].data[Variant_ddxcoarse], + StringFormat::Fmt("__rd_ddxcoarse_%zu_%s", i, param.varName.c_str())); + editor.SetName(values[i].data[Variant_ddycoarse], + StringFormat::Fmt("__rd_ddycoarse_%zu_%s", i, param.varName.c_str())); + editor.SetName(values[i].data[Variant_ddxfine], + StringFormat::Fmt("__rd_ddxfine_%zu_%s", i, param.varName.c_str())); + editor.SetName(values[i].data[Variant_ddyfine], + StringFormat::Fmt("__rd_ddyfine_%zu_%s", i, param.varName.c_str())); + } + else + { + values[i].data[Variant_ddxcoarse] = values[i].data[Variant_ddycoarse] = + values[i].data[Variant_ddxfine] = values[i].data[Variant_ddyfine] = + editor.AddConstant(rdcspv::OpConstantNull(values[i].valueType, editor.MakeId())); + + editor.SetName(values[i].data[Variant_ddxcoarse], + StringFormat::Fmt("__rd_noderiv_%zu_%s", i, param.varName.c_str())); + } + } + rdcspv::Id structPtr = ssboVar; if(structPtr == rdcspv::Id()) @@ -592,7 +684,7 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt // get a pointer to buffer.hit_count rdcspv::Id hit_count = - ops.add(rdcspv::OpAccessChain(uintPtr, editor.MakeId(), structPtr, {uintConsts[0]})); + ops.add(rdcspv::OpAccessChain(uintPtr, editor.MakeId(), structPtr, {getUIntConst(0)})); rdcspv::Id scope = editor.AddConstantImmediate((uint32_t)rdcspv::Scope::Device); rdcspv::Id semantics = @@ -647,7 +739,7 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt // allocate a slot with atomic add rdcspv::Id slot = ops.add(rdcspv::OpAtomicIAdd(uint32Type, editor.MakeId(), hit_count, scope, - semantics, uintConsts[1])); + semantics, getUIntConst(1))); editor.SetName(slot, "slot"); @@ -663,15 +755,12 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt // get a pointer to the hit for our slot rdcspv::Id hit = - ops.add(rdcspv::OpAccessChain(hitptr, editor.MakeId(), structPtr, {uintConsts[1], slot})); + ops.add(rdcspv::OpAccessChain(hitptr, editor.MakeId(), structPtr, {getUIntConst(1), slot})); // store fixed properties - rdcspv::MemoryAccessAndParamDatas alignedAccess; - alignedAccess.setAligned(sizeof(uint32_t)); - rdcspv::Id storePtr = - ops.add(rdcspv::OpAccessChain(float4BufPtr, editor.MakeId(), hit, {uintConsts[0]})); + ops.add(rdcspv::OpAccessChain(float4BufPtr, editor.MakeId(), hit, {getUIntConst(0)})); ops.add(rdcspv::OpStore(storePtr, fragCoordLoaded, alignedAccess)); rdcspv::Id loaded; @@ -692,10 +781,11 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt else { // explicitly store 0 - loaded = uintConsts[0]; + loaded = getUIntConst(0); } - storePtr = ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {uintConsts[1]})); + storePtr = + ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(1)})); ops.add(rdcspv::OpStore(storePtr, loaded, alignedAccess)); if(sampleIndex.base != rdcspv::Id()) @@ -715,13 +805,45 @@ static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structSt else { // explicitly store 0 - loaded = uintConsts[0]; + loaded = getUIntConst(0); } - storePtr = ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {uintConsts[2]})); + storePtr = + ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(2)})); ops.add(rdcspv::OpStore(storePtr, loaded, alignedAccess)); - // TODO store custom properties, and derivatives + storePtr = + ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(3)})); + ops.add(rdcspv::OpStore(storePtr, editor.AddConstantImmediate(validMagicNumber), alignedAccess)); + + // store 0 in the padding + storePtr = + ops.add(rdcspv::OpAccessChain(uint32BufPtr, editor.MakeId(), hit, {getUIntConst(4)})); + ops.add(rdcspv::OpStore(storePtr, getUIntConst(0), alignedAccess)); + + { + 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)})), + }; + + for(size_t i = 0; i < values.size(); i++) + { + rdcspv::Id ptrType = editor.DeclareType(rdcspv::Pointer(values[i].valueType, bufferClass)); + + for(size_t j = 0; j < Variant_Count; j++) + { + rdcspv::Id ptr = ops.add(rdcspv::OpAccessChain(ptrType, editor.MakeId(), outputPtrs[j], + {getUIntConst(values[i].structIndex)})); + ops.add(rdcspv::OpStore(ptr, values[i].data[j], alignedAccess)); + } + } + } // join up with the early-outs we did ops.add(rdcspv::OpBranch(killLabel2)); @@ -1270,8 +1392,9 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ Vec4f pos; uint32_t prim; uint32_t sample; - float derivValid; - // padding and remaining data + uint32_t valid; + uint32_t padding; + // PSInput base, ddx, .... }; for(uint32_t i = 0; i < numHits; i++)