From 338e670e7b942e5989982cd271888fc1663e6294 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Thu, 26 Oct 2023 12:03:31 -0400 Subject: [PATCH 1/3] Support for dynamic array of textures access for Texture footprint. --- source/slang/slang-ir-lower-binding-query.cpp | 109 +++++++++++++++++- .../nv-shader-texture-footprint-array.slang | 74 ++++++++++++ 2 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang diff --git a/source/slang/slang-ir-lower-binding-query.cpp b/source/slang/slang-ir-lower-binding-query.cpp index 0935f1e543..2f3f1bae15 100644 --- a/source/slang/slang-ir-lower-binding-query.cpp +++ b/source/slang/slang-ir-lower-binding-query.cpp @@ -288,7 +288,114 @@ struct BindingQueryLoweringContext : public WorkListPass // OpaqueValueInfo computeOpaqueValueInfo(IRInst* opaqueValue) { - if (auto globalParam = as(opaqueValue)) + if (auto getElement = as(opaqueValue)) + { + IRInst* baseInst = getElement->getBase(); + IRInst* indexInst = getElement->getIndex(); + + IRInst* elementType = getElement->getDataType(); + + // TODO(JS): This a hack to make this work for arrays of resource type. + // It won't work in the general case as it stands because we would need + // to propogate layout kind types needed at usage sites. + // Without knowing the resource kind that is being processed it's not possible + // to accumulate the calculation. + // + // So presumably we need to request a binding query for a specific resource kind. + // We could do this by making the type of the binding query hold the type. + + // We need to add instructions which will work out the binding for the base + OpaqueValueInfo baseInfo = findOrComputeOpaqueValueInfo(baseInst); + + // If we couldn't find it we are done + if (baseInfo.registerIndex == nullptr || + baseInfo.registerSpace == nullptr) + { + return baseInfo; + } + + + LayoutResourceKind kind = LayoutResourceKind::None; + Index stride = 1; + + if (auto resourceType = as(elementType)) + { + const auto shape = resourceType->getShape(); + + switch (shape) + { + case SLANG_TEXTURE_1D: + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_3D: + case SLANG_TEXTURE_CUBE: + case SLANG_STRUCTURED_BUFFER: + case SLANG_BYTE_ADDRESS_BUFFER: + case SLANG_TEXTURE_BUFFER: + { + const auto access = resourceType->getAccess(); + bool isReadOnly = (access == SLANG_RESOURCE_ACCESS_READ); + + kind = isReadOnly ? LayoutResourceKind::ShaderResource : LayoutResourceKind::UnorderedAccess; + break; + } + default: break; + } + } + else if (as< IRSamplerStateTypeBase>(elementType)) + { + kind = LayoutResourceKind::SamplerState; + } + else if (as(elementType)) + { + kind = LayoutResourceKind::ConstantBuffer; + } + + if (kind == LayoutResourceKind::None) + { + // Can't determine the kind + return OpaqueValueInfo(); + } + + // If the element type has type layout we can try and use that + if (auto layoutDecoration = elementType->findDecoration()) + { + // We have to calculate + if (auto elementTypeLayout = as(layoutDecoration->getLayout())) + { + IRTypeSizeAttr* sizeAttr = elementTypeLayout->findSizeAttr(kind); + sizeAttr = sizeAttr ? sizeAttr : elementTypeLayout->findSizeAttr(LayoutResourceKind::DescriptorTableSlot); + + if (!sizeAttr) + { + // Couldn't work it out + return OpaqueValueInfo(); + } + + // TODO(JS): Perhaps we have to do something else if not finite? + stride = sizeAttr->getFiniteSize(); + } + } + + SLANG_UNUSED(indexInst); + + // Okay we need to create an instruction which is + // base + stride * index + + IRBuilder builder(module); + + builder.setInsertBefore(opaqueValue); + + auto calcRegisterInst = builder.emitAdd(indexType, + builder.emitMul(indexType, builder.getIntValue(indexType, stride), indexInst), + baseInfo.registerIndex); + + OpaqueValueInfo finalInfo; + finalInfo.registerIndex = calcRegisterInst; + finalInfo.registerSpace = baseInfo.registerSpace; + + return finalInfo; + } + else if (auto globalParam = as(opaqueValue)) { // The simple/base case is when we have a global shader // parameter that has layout information attached. diff --git a/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang b/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang new file mode 100644 index 0000000000..3441668011 --- /dev/null +++ b/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang @@ -0,0 +1,74 @@ +//DISABLE_TEST:SIMPLE:-target dxil-assembly -entry fragmentMain -profile sm_6_5 -stage fragment -DNV_SHADER_EXTN_SLOT=u0 + +//TEST:SIMPLE(filecheck=SPIRV):-target spirv-assembly -entry fragmentMain -stage fragment +//DISABLED_TEST:SIMPLE(filecheck=DXIL):-target dxil-assembly -entry fragmentMain -stage fragment +//TEST:SIMPLE(filecheck=HLSL):-target hlsl -entry fragmentMain -stage fragment + +//DISABLED_TEST:SIMPLE:-target spirv-assembly -entry fragmentMain -stage fragment +//DISABLED_TEST:SIMPLE:-target dxil-assembly -entry fragmentMain -stage fragment +//DISABLED_TEST:SIMPLE:-target hlsl -entry fragmentMain -stage fragment + +uniform Texture2D textures[] : register(t2, space10); +uniform SamplerState sampler; +uniform RWStructuredBuffer outputBuffer; + +static Texture2D _getBindlessTexture2d(uint texIdx) +{ + return textures[NonUniformResourceIndex(texIdx)]; +} + +void accumulate(inout uint r, uint u) +{ + r = r ^ u; +} + +void accumulate(inout uint r, bool b) +{ + accumulate(r, uint(b)); +} + +void accumulate(inout uint r, uint2 u) +{ + accumulate(r, u.x); + accumulate(r, u.y); +} + +void accumulate(inout uint r, uint3 u) +{ + accumulate(r, u.x); + accumulate(r, u.y); + accumulate(r, u.z); +} + +void accumulate(inout uint r, TextureFootprint2D f) +{ + accumulate(r, f.anchor); + accumulate(r, f.offset); + accumulate(r, f.mask); + accumulate(r, f.lod); + accumulate(r, f.granularity); + accumulate(r, f.isSingleLevel); +} + +cbuffer Uniforms +{ + uniform float2 coords; + uniform uint granularity; +}; + +void fragmentMain( + float v : VARYING) +{ + uint index = uint(v); + uint r = 0; + + accumulate(r, _getBindlessTexture2d(index).queryFootprintCoarse(granularity, sampler, coords)); + +// SPIRV: Extension "SPV_NV_shader_image_footprint" +// SPIRV: ImageSampleFootprintNV + +// HLSL: NvFootprintCoarse + + outputBuffer[index] = r; +} + From 878c77e1585dda3d80375c4cbe4f09baa51ece19 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Thu, 26 Oct 2023 12:15:53 -0400 Subject: [PATCH 2/3] Do a check for DXIL for dynamic array/footprint. --- .../query/footprint/nv-shader-texture-footprint-array.slang | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang b/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang index 3441668011..dc60cf263d 100644 --- a/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang +++ b/tests/gpu-feature/texture/query/footprint/nv-shader-texture-footprint-array.slang @@ -1,7 +1,7 @@ //DISABLE_TEST:SIMPLE:-target dxil-assembly -entry fragmentMain -profile sm_6_5 -stage fragment -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV):-target spirv-assembly -entry fragmentMain -stage fragment -//DISABLED_TEST:SIMPLE(filecheck=DXIL):-target dxil-assembly -entry fragmentMain -stage fragment +//TEST:SIMPLE(filecheck=DXIL):-target dxil-assembly -entry fragmentMain -profile sm_6_5 -stage fragment -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=HLSL):-target hlsl -entry fragmentMain -stage fragment //DISABLED_TEST:SIMPLE:-target spirv-assembly -entry fragmentMain -stage fragment @@ -67,6 +67,8 @@ void fragmentMain( // SPIRV: Extension "SPV_NV_shader_image_footprint" // SPIRV: ImageSampleFootprintNV +// DXIL: struct struct.NvShaderExtnStruct + // HLSL: NvFootprintCoarse outputBuffer[index] = r; From 5c167c3189aaa226f9471cbeb6aa22a3e694d23b Mon Sep 17 00:00:00 2001 From: slangbot Date: Wed, 19 Feb 2025 06:56:56 +0800 Subject: [PATCH 3/3] format code (#40) --- source/slang/slang-ir-lower-binding-query.cpp | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/source/slang/slang-ir-lower-binding-query.cpp b/source/slang/slang-ir-lower-binding-query.cpp index 2f3f1bae15..541640aaf9 100644 --- a/source/slang/slang-ir-lower-binding-query.cpp +++ b/source/slang/slang-ir-lower-binding-query.cpp @@ -308,8 +308,7 @@ struct BindingQueryLoweringContext : public WorkListPass OpaqueValueInfo baseInfo = findOrComputeOpaqueValueInfo(baseInst); // If we couldn't find it we are done - if (baseInfo.registerIndex == nullptr || - baseInfo.registerSpace == nullptr) + if (baseInfo.registerIndex == nullptr || baseInfo.registerSpace == nullptr) { return baseInfo; } @@ -324,24 +323,26 @@ struct BindingQueryLoweringContext : public WorkListPass switch (shape) { - case SLANG_TEXTURE_1D: - case SLANG_TEXTURE_2D: - case SLANG_TEXTURE_3D: - case SLANG_TEXTURE_CUBE: - case SLANG_STRUCTURED_BUFFER: - case SLANG_BYTE_ADDRESS_BUFFER: - case SLANG_TEXTURE_BUFFER: + case SLANG_TEXTURE_1D: + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_3D: + case SLANG_TEXTURE_CUBE: + case SLANG_STRUCTURED_BUFFER: + case SLANG_BYTE_ADDRESS_BUFFER: + case SLANG_TEXTURE_BUFFER: { const auto access = resourceType->getAccess(); bool isReadOnly = (access == SLANG_RESOURCE_ACCESS_READ); - kind = isReadOnly ? LayoutResourceKind::ShaderResource : LayoutResourceKind::UnorderedAccess; + kind = isReadOnly ? LayoutResourceKind::ShaderResource + : LayoutResourceKind::UnorderedAccess; break; } - default: break; + default: + break; } } - else if (as< IRSamplerStateTypeBase>(elementType)) + else if (as(elementType)) { kind = LayoutResourceKind::SamplerState; } @@ -363,7 +364,9 @@ struct BindingQueryLoweringContext : public WorkListPass if (auto elementTypeLayout = as(layoutDecoration->getLayout())) { IRTypeSizeAttr* sizeAttr = elementTypeLayout->findSizeAttr(kind); - sizeAttr = sizeAttr ? sizeAttr : elementTypeLayout->findSizeAttr(LayoutResourceKind::DescriptorTableSlot); + sizeAttr = sizeAttr ? sizeAttr + : elementTypeLayout->findSizeAttr( + LayoutResourceKind::DescriptorTableSlot); if (!sizeAttr) { @@ -385,7 +388,8 @@ struct BindingQueryLoweringContext : public WorkListPass builder.setInsertBefore(opaqueValue); - auto calcRegisterInst = builder.emitAdd(indexType, + auto calcRegisterInst = builder.emitAdd( + indexType, builder.emitMul(indexType, builder.getIntValue(indexType, stride), indexInst), baseInfo.registerIndex);