diff options
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 2 | ||||
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters | 6 | ||||
| -rw-r--r-- | slang-gfx.h | 18 | ||||
| -rw-r--r-- | slang.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-reflection-api.cpp | 21 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.h | 1 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.cpp | 8 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.h | 7 | ||||
| -rw-r--r-- | tools/gfx-unit-test/root-shader-parameter.cpp | 135 | ||||
| -rw-r--r-- | tools/gfx-unit-test/root-shader-parameter.slang | 32 | ||||
| -rw-r--r-- | tools/gfx/d3d12/descriptor-heap-d3d12.h | 2 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 395 |
12 files changed, 555 insertions, 79 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj index 0b0be2a07..b44864334 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj @@ -289,6 +289,7 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\resolve-resource-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\root-mutable-shader-object.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\root-shader-parameter.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-buffers-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-textures-tests.cpp" />
<ClCompile Include="..\..\..\tools\unit-test\slang-unit-test.cpp" />
@@ -302,6 +303,7 @@ <None Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.slang" />
<None Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.slang" />
<None Include="..\..\..\tools\gfx-unit-test\resolve-resource-shader.slang" />
+ <None Include="..\..\..\tools\gfx-unit-test\root-shader-parameter.slang" />
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang" />
</ItemGroup>
<ItemGroup>
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters index e96c7bfcc..fd1ff52cd 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters @@ -68,6 +68,9 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\root-mutable-shader-object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\root-shader-parameter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-buffers-tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -103,6 +106,9 @@ <None Include="..\..\..\tools\gfx-unit-test\resolve-resource-shader.slang">
<Filter>Source Files</Filter>
</None>
+ <None Include="..\..\..\tools\gfx-unit-test\root-shader-parameter.slang">
+ <Filter>Source Files</Filter>
+ </None>
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang">
<Filter>Source Files</Filter>
</None>
diff --git a/slang-gfx.h b/slang-gfx.h index d0e80d923..a9dfe7b28 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -44,6 +44,11 @@ typedef uint64_t DeviceAddress; const uint64_t kTimeoutInfinite = 0xFFFFFFFFFFFFFFFF; +enum class StructType +{ + D3D12ExtendedDesc, +}; + enum class StageType { Unknown, @@ -2012,6 +2017,9 @@ public: ISlangFileSystem* shaderCacheFileSystem = nullptr; // Configurations for Slang compiler. SlangDesc slang = {}; + + uint32_t extendedDescCount = 0; + void** extendedDescs = nullptr; }; virtual SLANG_NO_THROW Result SLANG_MCALL getNativeDeviceHandles(InteropHandles* outHandles) = 0; @@ -2384,4 +2392,12 @@ extern "C" SLANG_GFX_API const char* SLANG_MCALL gfxGetDeviceTypeName(DeviceType type); } -}// renderer_test +// Extended descs. +struct D3D12DeviceExtendedDesc +{ + StructType structType = StructType::D3D12ExtendedDesc; + const char* rootParameterShaderAttributeName = nullptr; + bool debugBreakOnD3D12Error = false; +}; + +} @@ -2043,6 +2043,7 @@ extern "C" SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangReflectionTypeLayout* typeLayout, SlangInt index); SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt index); SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index); + SLANG_API SlangReflectionVariable* spReflectionTypeLayout_getBindingRangeVariable(SlangReflectionTypeLayout* typeLayout, SlangInt index); SLANG_API SlangInt spReflectionTypeLayout_getFieldBindingRangeOffset(SlangReflectionTypeLayout* typeLayout, SlangInt fieldIndex); SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index); @@ -2659,6 +2660,12 @@ namespace slang index); } + VariableReflection* getBindingRangeVariable(SlangInt index) + { + return (VariableReflection*)spReflectionTypeLayout_getBindingRangeVariable( + (SlangReflectionTypeLayout*)this, index); + } + SlangInt getBindingRangeDescriptorSetIndex(SlangInt index) { return spReflectionTypeLayout_getBindingRangeDescriptorSetIndex( diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index 714dc292f..8bcab8ada 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -1559,6 +1559,7 @@ namespace Slang TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; bindingRange.leafTypeLayout = typeLayout; + bindingRange.variable = path.primary ? path.primary->var->getVariable() : nullptr; bindingRange.bindingType = bindingType; bindingRange.count = multiplier; bindingRange.descriptorSetIndex = -1; @@ -1745,6 +1746,7 @@ namespace Slang // TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; bindingRange.leafTypeLayout = typeLayout; + bindingRange.variable = path.primary ? path.primary->var->getVariable() : nullptr; bindingRange.bindingType = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE; bindingRange.count = multiplier; bindingRange.descriptorSetIndex = 0; @@ -1817,6 +1819,7 @@ namespace Slang // TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; bindingRange.leafTypeLayout = typeLayout; + bindingRange.variable = path.primary ? path.primary->var->getVariable() : nullptr; bindingRange.bindingType = bindingType; bindingRange.count = multiplier; bindingRange.descriptorSetIndex = 0; @@ -2016,6 +2019,24 @@ SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafT return convert(bindingRange.leafTypeLayout); } +SLANG_API SlangReflectionVariable* spReflectionTypeLayout_getBindingRangeVariable( + SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if (!typeLayout) + return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if (index < 0) + return 0; + if (index >= extTypeLayout->m_bindingRanges.getCount()) + return 0; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + + return convert(bindingRange.variable); +} + + SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) { auto typeLayout = convert(inTypeLayout); diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index 82d333fa9..d66a77365 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -431,6 +431,7 @@ public: struct BindingRangeInfo { + VarDeclBase* variable; TypeLayout* leafTypeLayout; SlangBindingType bindingType; LayoutSize count; diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index 1133e3842..ecd19f179 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -202,6 +202,14 @@ namespace gfx_test const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); deviceDesc.slang.searchPaths = searchPaths; + + gfx::D3D12DeviceExtendedDesc extDesc = {}; + extDesc.rootParameterShaderAttributeName = "root"; + + deviceDesc.extendedDescCount = 1; + void* extDescPtr = &extDesc; + deviceDesc.extendedDescs = &extDescPtr; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); if (SLANG_FAILED(createDeviceResult)) { diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 67660d4f5..2977ac599 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -87,6 +87,13 @@ namespace gfx_test { SLANG_IGNORE_TEST } +#if SLANG_WIN32 + // Skip d3d12 tests on x86 now since dxc doesn't function correctly there on Windows 11. + if (api == Slang::RenderApiFlag::D3D12) + { + SLANG_IGNORE_TEST + } +#endif try { renderDocBeginFrame(); diff --git a/tools/gfx-unit-test/root-shader-parameter.cpp b/tools/gfx-unit-test/root-shader-parameter.cpp new file mode 100644 index 000000000..a7b92843d --- /dev/null +++ b/tools/gfx-unit-test/root-shader-parameter.cpp @@ -0,0 +1,135 @@ +#include "tools/unit-test/slang-unit-test.h" + +#include "slang-gfx.h" +#include "gfx-test-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "source/core/slang-basic.h" + +using namespace gfx; + +namespace gfx_test +{ + ComPtr<IBufferResource> createBuffer(IDevice* device, uint32_t content) + { + ComPtr<IBufferResource> buffer; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = sizeof(uint32_t); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)&content, buffer.writeRef())); + + return buffer; + } + void rootShaderParameterTestImpl(IDevice* device, UnitTestContext* context) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "root-shader-parameter", "computeMain", slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + Slang::List<ComPtr<IBufferResource>> buffers; + Slang::List<ComPtr<IResourceView>> srvs, uavs; + + for (uint32_t i = 0; i < 9; i++) + { + buffers.add(createBuffer(device, i == 0 ? 10 : i)); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(buffers[i], nullptr, viewDesc, bufferView.writeRef())); + uavs.add(bufferView); + + viewDesc.type = IResourceView::Type::ShaderResource; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(buffers[i], nullptr, viewDesc, bufferView.writeRef())); + srvs.add(bufferView); + } + + ComPtr<IShaderObject> rootObject; + device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); + + ComPtr<IShaderObject> g, s1, s2; + device->createMutableShaderObject( + slangReflection->findTypeByName("S0"), ShaderObjectContainerType::None, g.writeRef()); + device->createMutableShaderObject( + slangReflection->findTypeByName("S1"), ShaderObjectContainerType::None, s1.writeRef()); + device->createMutableShaderObject( + slangReflection->findTypeByName("S1"), ShaderObjectContainerType::None, s2.writeRef()); + + { + auto cursor = ShaderCursor(s1); + cursor["c0"].setResource(srvs[2]); + cursor["c1"].setResource(uavs[3]); + cursor["c2"].setResource(srvs[4]); + } + { + auto cursor = ShaderCursor(s2); + cursor["c0"].setResource(srvs[5]); + cursor["c1"].setResource(uavs[6]); + cursor["c2"].setResource(srvs[7]); + } + { + auto cursor = ShaderCursor(g); + cursor["b0"].setResource(srvs[0]); + cursor["b1"].setResource(srvs[1]); + cursor["s1"].setObject(s1); + cursor["s2"].setObject(s2); + } + { + auto cursor = ShaderCursor(rootObject); + cursor["g"].setObject(g); + cursor["buffer"].setResource(uavs[8]); + } + + { + ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + { + auto encoder = commandBuffer->encodeComputeCommands(); + auto root = encoder->bindPipeline(pipelineState); + root->copyFrom(rootObject, transientHeap); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + } + + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } + + compareComputeResult( + device, buffers[8], Slang::makeArray<uint32_t>(10 - 1 + 2 - 3 + 4 + 5 - 6 + 7)); + } + + SLANG_UNIT_TEST(rootShaderParameterD3D12) + { + runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + } +} diff --git a/tools/gfx-unit-test/root-shader-parameter.slang b/tools/gfx-unit-test/root-shader-parameter.slang new file mode 100644 index 000000000..bf7af1851 --- /dev/null +++ b/tools/gfx-unit-test/root-shader-parameter.slang @@ -0,0 +1,32 @@ +// root-shader-parameter.slang + +// Test use of root shader parameters. +[__AttributeUsage(_AttributeTargets.Var)] +struct rootAttribute {}; + +struct S1 +{ + StructuredBuffer<uint> c0; + [root] RWStructuredBuffer<uint> c1; + StructuredBuffer<uint> c2; +} + +struct S0 +{ + StructuredBuffer<uint> b0; + [root] StructuredBuffer<uint> b1; + ParameterBlock<S1> s1; + ConstantBuffer<S1> s2; +} + +ParameterBlock<S0> g; +[root] RWStructuredBuffer<uint> buffer; + +[shader("compute")] +[numthreads(1,1,1)] +void computeMain( + uint3 sv_dispatchThreadID : SV_DispatchThreadID) +{ + buffer[0] = g.b0[0] - g.b1[0] + g.s1.c0[0] - g.s1.c1[0] + g.s1.c2[0] + g.s2.c0[0] - g.s2.c1[0] + g.s2.c2[0]; + // 10-1+2-3+4+5-6+7 +} diff --git a/tools/gfx/d3d12/descriptor-heap-d3d12.h b/tools/gfx/d3d12/descriptor-heap-d3d12.h index 2718f09e1..35574dd12 100644 --- a/tools/gfx/d3d12/descriptor-heap-d3d12.h +++ b/tools/gfx/d3d12/descriptor-heap-d3d12.h @@ -262,7 +262,7 @@ public: if (descriptor.cpuHandle.ptr >= subHeap->getCpuHandle(0).ptr) { auto subIndex = descriptor.cpuHandle.ptr - subHeap->getCpuHandle(0).ptr; - if (subIndex < subHeap->getSize()) + if (subIndex < (SIZE_T)subHeap->getSize()) { subHeap->free(descriptor); break; diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index e5a1d1876..72474f549 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -228,6 +228,8 @@ public: struct Submitter { virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0; + virtual void setRootUAV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0; + virtual void setRootSRV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0; virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) = 0; virtual void setRootSignature(ID3D12RootSignature* rootSignature) = 0; virtual void setRootConstants(Index rootParamIndex, Index dstOffsetIn32BitValues, Index countOf32BitValues, void const* srcData) = 0; @@ -398,7 +400,11 @@ public: public: D3D12Descriptor m_descriptor; RefPtr<D3D12GeneralExpandingDescriptorHeap> m_allocator; - ~ResourceViewInternalImpl() { m_allocator->free(m_descriptor); } + ~ResourceViewInternalImpl() + { + if (m_descriptor.cpuHandle.ptr) + m_allocator->free(m_descriptor); + } }; class ResourceViewImpl @@ -653,6 +659,14 @@ public: { m_commandList->SetGraphicsRootConstantBufferView(index, gpuBufferLocation); } + virtual void setRootUAV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override + { + m_commandList->SetGraphicsRootUnorderedAccessView(index, gpuBufferLocation); + } + virtual void setRootSRV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override + { + m_commandList->SetGraphicsRootShaderResourceView(index, gpuBufferLocation); + } virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) override { m_commandList->SetGraphicsRootDescriptorTable(index, baseDescriptor); @@ -689,6 +703,14 @@ public: { m_commandList->SetComputeRootConstantBufferView(index, gpuBufferLocation); } + virtual void setRootUAV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override + { + m_commandList->SetComputeRootUnorderedAccessView(index, gpuBufferLocation); + } + virtual void setRootSRV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override + { + m_commandList->SetComputeRootShaderResourceView(index, gpuBufferLocation); + } virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) override { m_commandList->SetComputeRootDescriptorTable(index, baseDescriptor); @@ -1136,6 +1158,8 @@ public: /// An index into the sub-object array if this binding range is treated /// as a sub-object. uint32_t subObjectIndex; + + bool isRootParameter; }; /// Offset information for a sub-object range @@ -1192,9 +1216,30 @@ public: struct RootParameterInfo { - D3D12_ROOT_PARAMETER rootParameter; + IResourceView::Type type; }; + static bool isBindingRangeRootParameter( + SlangSession* globalSession, + const char* rootParameterAttributeName, + slang::TypeLayoutReflection* typeLayout, + Index bindingRangeIndex) + { + bool isRootParameter = false; + if (rootParameterAttributeName) + { + if (auto variable = typeLayout->getBindingRangeVariable(bindingRangeIndex)) + { + if (variable->findUserAttributeByName( + globalSession, rootParameterAttributeName)) + { + isRootParameter = true; + } + } + } + return isRootParameter; + } + struct Builder { public: @@ -1206,6 +1251,7 @@ public: slang::TypeLayoutReflection* m_elementTypeLayout; List<BindingRangeInfo> m_bindingRanges; List<SubObjectRangeInfo> m_subObjectRanges; + List<RootParameterInfo> m_rootParamsInfo; /// The number of sub-objects (not just sub-object *ranges*) stored in instances of this layout uint32_t m_subObjectCount = 0; @@ -1266,45 +1312,76 @@ public: bindingRangeInfo.bindingType = slangBindingType; bindingRangeInfo.resourceShape = slangLeafTypeLayout->getResourceShape(); bindingRangeInfo.count = count; - - switch (slangBindingType) + bindingRangeInfo.isRootParameter = isBindingRangeRootParameter( + m_renderer->slangContext.globalSession, + static_cast<D3D12Device*>(m_renderer) + ->m_extendedDesc.rootParameterShaderAttributeName, + typeLayout, + r); + if (bindingRangeInfo.isRootParameter) { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - case slang::BindingType::ExistentialValue: - bindingRangeInfo.baseIndex = m_subObjectCount; - bindingRangeInfo.subObjectIndex = m_subObjectCount; - m_subObjectCount += count; - break; - case slang::BindingType::RawBuffer: - case slang::BindingType::MutableRawBuffer: - if (slangLeafTypeLayout->getType()->getElementType() != nullptr) + RootParameterInfo rootInfo = {}; + switch (slangBindingType) { - // A structured buffer occupies both a resource slot and - // a sub-object slot. + case slang::BindingType::RayTracingAccelerationStructure: + rootInfo.type = IResourceView::Type::AccelerationStructure; + break; + case slang::BindingType::RawBuffer: + case slang::BindingType::TypedBuffer: + rootInfo.type = IResourceView::Type::ShaderResource; + break; + case slang::BindingType::MutableRawBuffer: + case slang::BindingType::MutableTypedBuffer: + rootInfo.type = IResourceView::Type::UnorderedAccess; + break; + } + bindingRangeInfo.baseIndex = (uint32_t)m_rootParamsInfo.getCount(); + for (uint32_t i = 0; i < count; i++) + { + m_rootParamsInfo.add(rootInfo); + } + } + else + { + switch (slangBindingType) + { + case slang::BindingType::ConstantBuffer: + case slang::BindingType::ParameterBlock: + case slang::BindingType::ExistentialValue: + bindingRangeInfo.baseIndex = m_subObjectCount; bindingRangeInfo.subObjectIndex = m_subObjectCount; m_subObjectCount += count; - } - bindingRangeInfo.baseIndex = m_ownCounts.resource; - m_ownCounts.resource += count; - break; - case slang::BindingType::Sampler: - bindingRangeInfo.baseIndex = m_ownCounts.sampler; - m_ownCounts.sampler += count; - break; + break; + case slang::BindingType::RawBuffer: + case slang::BindingType::MutableRawBuffer: + if (slangLeafTypeLayout->getType()->getElementType() != nullptr) + { + // A structured buffer occupies both a resource slot and + // a sub-object slot. + bindingRangeInfo.subObjectIndex = m_subObjectCount; + m_subObjectCount += count; + } + bindingRangeInfo.baseIndex = m_ownCounts.resource; + m_ownCounts.resource += count; + break; + case slang::BindingType::Sampler: + bindingRangeInfo.baseIndex = m_ownCounts.sampler; + m_ownCounts.sampler += count; + break; - case slang::BindingType::CombinedTextureSampler: - // TODO: support this case... - break; + case slang::BindingType::CombinedTextureSampler: + // TODO: support this case... + break; - case slang::BindingType::VaryingInput: - case slang::BindingType::VaryingOutput: - break; + case slang::BindingType::VaryingInput: + case slang::BindingType::VaryingOutput: + break; - default: - bindingRangeInfo.baseIndex = m_ownCounts.resource; - m_ownCounts.resource += count; - break; + default: + bindingRangeInfo.baseIndex = m_ownCounts.resource; + m_ownCounts.resource += count; + break; + } } m_bindingRanges.add(bindingRangeInfo); } @@ -1423,7 +1500,7 @@ public: // The only resource usage that leaks into the surrounding context // is the number of root parameters consumed. // - objectCounts.rootParam = subObjectRange.layout->getTotalRootParameterCount(); + objectCounts.rootParam = subObjectRange.layout->getTotalRootTableParameterCount(); } break; @@ -1540,7 +1617,8 @@ public: uint32_t getTotalResourceDescriptorCountWithoutOrdinaryDataBuffer() { return m_totalCounts.resource - getOrdinaryDataBufferCount(); } - uint32_t getTotalRootParameterCount() { return m_totalCounts.rootParam; } + uint32_t getOwnUserRootParameterCount() { return (uint32_t)m_rootParamsInfo.getCount(); } + uint32_t getTotalRootTableParameterCount() { return m_totalCounts.rootParam; } uint32_t getChildRootParameterCount() { return m_childRootParameterCount; } uint32_t getTotalOrdinaryDataSize() const { return m_totalOrdinaryDataSize; } @@ -1555,6 +1633,11 @@ public: slang::TypeReflection* getType() { return m_elementTypeLayout->getType(); } + const RootParameterInfo& getRootParameterInfo(Index index) + { + return m_rootParamsInfo[index]; + } + protected: Result _init(Builder* builder) { @@ -1565,7 +1648,8 @@ public: m_containerType = builder->m_containerType; m_bindingRanges = _Move(builder->m_bindingRanges); - m_subObjectRanges = builder->m_subObjectRanges; + m_subObjectRanges = _Move(builder->m_subObjectRanges); + m_rootParamsInfo = _Move(builder->m_rootParamsInfo); m_ownCounts = builder->m_ownCounts; m_totalCounts = builder->m_totalCounts; @@ -1578,6 +1662,7 @@ public: List<BindingRangeInfo> m_bindingRanges; List<SubObjectRangeInfo> m_subObjectRanges; + List<RootParameterInfo> m_rootParamsInfo; BindingOffset m_ownCounts; BindingOffset m_totalCounts; @@ -1661,6 +1746,12 @@ public: struct RootSignatureDescBuilder { + D3D12Device* m_device; + + RootSignatureDescBuilder(D3D12Device* device) + : m_device(device) + {} + // We will use one descriptor set for the global scope and one additional // descriptor set for each `ParameterBlock` binding range in the shader object // hierarchy, regardless of the shader's `space` indices. @@ -1767,14 +1858,6 @@ public: pending += other.pending; } }; - - Index reserveRootParameters(Index count) - { - Index result = m_rootParameters.getCount(); - m_rootParameters.setCount(result + count); - return result; - } - /// Add a new descriptor set to the layout being computed. /// /// Note that a "descriptor set" in the layout may amount to @@ -1797,8 +1880,34 @@ public: D3D12_DESCRIPTOR_RANGE_TYPE rangeType, UINT registerIndex, UINT spaceIndex, - UINT count) + UINT count, + bool isRootParameter) { + if (isRootParameter) + { + D3D12_ROOT_PARAMETER rootParam = {}; + switch (rangeType) + { + case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: + rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: + rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + break; + default: + getDebugCallback()->handleMessage( + DebugMessageType::Error, + DebugMessageSource::Layer, + "A shader parameter marked as root parameter is neither SRV nor UAV."); + return SLANG_FAIL; + } + rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rootParam.Descriptor.RegisterSpace = spaceIndex; + rootParam.Descriptor.ShaderRegister = registerIndex; + m_rootParameters.add(rootParam); + return SLANG_OK; + } + auto& descriptorSet = m_descriptorSets[physicalDescriptorSetIndex]; D3D12_DESCRIPTOR_RANGE range = {}; @@ -1843,7 +1952,8 @@ public: BindingRegisterOffset const& containerOffset, BindingRegisterOffset const& elementOffset, Index logicalDescriptorSetIndex, - Index descriptorRangeIndex) + Index descriptorRangeIndex, + bool isRootParameter) { auto bindingType = typeLayout->getDescriptorSetDescriptorRangeType(logicalDescriptorSetIndex, descriptorRangeIndex); auto count = typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(logicalDescriptorSetIndex, descriptorRangeIndex); @@ -1858,7 +1968,8 @@ public: rangeType, (UINT)index + elementOffset[rangeType], (UINT)space + containerOffset.spaceOffset, - (UINT)count); + (UINT)count, + isRootParameter); } /// Add one binding range to the computed layout. @@ -1884,6 +1995,11 @@ public: auto logicalDescriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex); auto firstDescriptorRangeIndex = typeLayout->getBindingRangeFirstDescriptorRangeIndex(bindingRangeIndex); Index descriptorRangeCount = typeLayout->getBindingRangeDescriptorRangeCount(bindingRangeIndex); + bool isRootParameter = isBindingRangeRootParameter( + m_device->slangContext.globalSession, + m_device->m_extendedDesc.rootParameterShaderAttributeName, + typeLayout, + bindingRangeIndex); for( Index i = 0; i < descriptorRangeCount; ++i ) { auto descriptorRangeIndex = firstDescriptorRangeIndex + i; @@ -1898,7 +2014,8 @@ public: containerOffset, elementOffset, logicalDescriptorSetIndex, - descriptorRangeIndex); + descriptorRangeIndex, + isRootParameter); } } @@ -1938,7 +2055,8 @@ public: descriptorRangeType, offsetForRangeType, containerOffset.primary.spaceOffset, - 1); + 1, + false); } addAsValue(typeLayout, physicalDescriptorSetIndex, containerOffset, elementOffset); @@ -2140,7 +2258,7 @@ public: // binding/descritpor ranges and nested parameter blocks // based on the computed layout information for `program`. // - RootSignatureDescBuilder builder; + RootSignatureDescBuilder builder(device); auto layout = program->getLayout(); // The layout information computed by Slang breaks up shader @@ -2459,7 +2577,11 @@ public: m_data.setCount(uniformSize); memset(m_data.getBuffer(), 0, uniformSize); } - + m_rootArguments.setCount(layout->getOwnUserRootParameterCount()); + memset( + m_rootArguments.getBuffer(), + 0, + sizeof(D3D12_GPU_VIRTUAL_ADDRESS) * m_rootArguments.getCount()); // Each shader object will own CPU descriptor heap memory // for any resource or sampler descriptors it might store // as part of its value. @@ -2981,12 +3103,36 @@ public: return SLANG_OK; } - + Result bindRootArguments(BindingContext* context, uint32_t& index) + { + auto layoutImpl = getLayout(); + for (Index i = 0; i < m_rootArguments.getCount(); i++) + { + switch (layoutImpl->getRootParameterInfo(i).type) + { + case IResourceView::Type::ShaderResource: + case IResourceView::Type::AccelerationStructure: + context->submitter->setRootSRV(index, m_rootArguments[i]); + break; + case IResourceView::Type::UnorderedAccess: + context->submitter->setRootUAV(index, m_rootArguments[i]); + break; + default: + continue; + } + index++; + } + for (auto& subObject : m_objects) + { + SLANG_RETURN_ON_FAIL(subObject->bindRootArguments(context, index)); + } + return SLANG_OK; + } /// A CPU-memory descriptor set holding any descriptors used to represent the resources/samplers in this object's state DescriptorSet m_descriptorSet; ShortList<RefPtr<Resource>, 8> m_boundResources; - + List<D3D12_GPU_VIRTUAL_ADDRESS> m_rootArguments; /// A constant buffer used to stored ordinary data for this object /// and existential-type sub-objects. /// @@ -3106,8 +3252,12 @@ public: // Note: We do not direclty use `bindAsParameterBlock` here because we also // need to bind the entry points into the same descriptor set that is // being used for the root object. - // + BindingOffset rootOffset; + + // Bind all root parameters first. + Super::bindRootArguments(context, rootOffset.rootParam); + DescriptorSet descriptorSet; SLANG_RETURN_ON_FAIL(prepareToBindAsParameterBlock( context, /* inout */ rootOffset, specializedLayout, descriptorSet)); @@ -4984,6 +5134,7 @@ public: // D3D12Device members. Desc m_desc; + D3D12DeviceExtendedDesc m_extendedDesc; gfx::DeviceInfo m_info; String m_adapterName; @@ -5551,9 +5702,11 @@ Result D3D12Device::_createDevice(DeviceCheckFlags deviceCheckFlags, const Unown { // Make break infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); - // infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true); - + if (m_extendedDesc.debugBreakOnD3D12Error) + { + infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); + } + // Apparently there is a problem with sm 6.3 with spurious errors, with debug layer enabled D3D12_FEATURE_DATA_SHADER_MODEL featureShaderModel; featureShaderModel.HighestShaderModel = D3D_SHADER_MODEL(0x63); @@ -5625,9 +5778,19 @@ static bool _isSupportedNVAPIOp(ID3D12Device* dev, uint32_t op) Result D3D12Device::initialize(const Desc& desc) { - SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc)); + // Find extended desc. + for (uint32_t i = 0; i < desc.extendedDescCount; i++) + { + StructType stype; + memcpy(&stype, desc.extendedDescs[i], sizeof(stype)); + if (stype == StructType::D3D12ExtendedDesc) + { + memcpy(&m_extendedDesc, desc.extendedDescs[i], sizeof(m_extendedDesc)); + } + } + // Initialize queue index allocator. // Support max 32 queues. m_queueIndexAllocator.initPool(32); @@ -6855,6 +7018,7 @@ Result D3D12Device::createBufferView( uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; uavDesc.Format = D3DUtil::getMapFormat(desc.format); uavDesc.Buffer.FirstElement = desc.bufferRange.firstElement; + uint64_t viewSize = 0; if (desc.bufferElementSize) { uavDesc.Buffer.StructureByteStride = desc.bufferElementSize; @@ -6862,6 +7026,7 @@ Result D3D12Device::createBufferView( desc.bufferRange.elementCount == 0 ? UINT(resourceDesc.sizeInBytes / desc.bufferElementSize) : (UINT)desc.bufferRange.elementCount; + viewSize = (uint64_t)desc.bufferElementSize * uavDesc.Buffer.NumElements; } else if(desc.format == Format::Unknown) { @@ -6870,6 +7035,7 @@ Result D3D12Device::createBufferView( ? UINT(resourceDesc.sizeInBytes / 4) : UINT(desc.bufferRange.elementCount / 4); uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW; + viewSize = 4ull * uavDesc.Buffer.NumElements; } else { @@ -6880,15 +7046,28 @@ Result D3D12Device::createBufferView( desc.bufferRange.elementCount == 0 ? UINT(resourceDesc.sizeInBytes / sizeInfo.blockSizeInBytes) : (UINT)desc.bufferRange.elementCount; + viewSize = (uint64_t)uavDesc.Buffer.NumElements * sizeInfo.blockSizeInBytes; + } + + if (viewSize >= (1ull << 32) - 8) + { + // D3D12 does not support view descriptors that has size near 4GB. + // We will not create actual SRV/UAVs for such large buffers. + // However, a buffer this large can still be bound as root parameter. + // So instead of failing, we quietly ignore descriptor creation. + viewImpl->m_descriptor.cpuHandle.ptr = 0; + } + else + { + auto counterResourceImpl = static_cast<BufferResourceImpl*>(counterBuffer); + SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); + viewImpl->m_allocator = m_cpuViewHeap; + m_device->CreateUnorderedAccessView( + resourceImpl->m_resource, + counterResourceImpl ? counterResourceImpl->m_resource.getResource() : nullptr, + &uavDesc, + viewImpl->m_descriptor.cpuHandle); } - auto counterResourceImpl = static_cast<BufferResourceImpl*>(counterBuffer); - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_cpuViewHeap; - m_device->CreateUnorderedAccessView( - resourceImpl->m_resource, - counterResourceImpl ? counterResourceImpl->m_resource.getResource() : nullptr, - &uavDesc, - viewImpl->m_descriptor.cpuHandle); } break; @@ -6900,6 +7079,7 @@ Result D3D12Device::createBufferView( srvDesc.Buffer.StructureByteStride = 0; srvDesc.Buffer.FirstElement = desc.bufferRange.firstElement; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + uint64_t viewSize = 0; if (desc.bufferElementSize) { srvDesc.Buffer.StructureByteStride = desc.bufferElementSize; @@ -6907,6 +7087,7 @@ Result D3D12Device::createBufferView( desc.bufferRange.elementCount == 0 ? UINT(resourceDesc.sizeInBytes / desc.bufferElementSize) : (UINT)desc.bufferRange.elementCount; + viewSize = (uint64_t)desc.bufferElementSize * srvDesc.Buffer.NumElements; } else if (desc.format == Format::Unknown) { @@ -6915,6 +7096,7 @@ Result D3D12Device::createBufferView( ? UINT(resourceDesc.sizeInBytes / 4) : UINT(desc.bufferRange.elementCount / 4); srvDesc.Buffer.Flags |= D3D12_BUFFER_SRV_FLAG_RAW; + viewSize = 4ull * srvDesc.Buffer.NumElements; } else { @@ -6925,11 +7107,23 @@ Result D3D12Device::createBufferView( desc.bufferRange.elementCount == 0 ? UINT(resourceDesc.sizeInBytes / sizeInfo.blockSizeInBytes) : (UINT)desc.bufferRange.elementCount; + viewSize = (uint64_t)srvDesc.Buffer.NumElements * sizeInfo.blockSizeInBytes; + } + if (viewSize >= (1ull << 32) - 8) + { + // D3D12 does not support view descriptors that has size near 4GB. + // We will not create actual SRV/UAVs for such large buffers. + // However, a buffer this large can still be bound as root parameter. + // So instead of failing, we quietly ignore descriptor creation. + viewImpl->m_descriptor.cpuHandle.ptr = 0; + } + else + { + SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); + viewImpl->m_allocator = m_cpuViewHeap; + m_device->CreateShaderResourceView( + resourceImpl->m_resource, &srvDesc, viewImpl->m_descriptor.cpuHandle); } - - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_cpuViewHeap; - m_device->CreateShaderResourceView(resourceImpl->m_resource, &srvDesc, viewImpl->m_descriptor.cpuHandle); } break; } @@ -8232,6 +8426,41 @@ Result D3D12Device::ShaderObjectImpl::setResource(ShaderOffset const& offset, IR auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); + if (bindingRange.isRootParameter && resourceView) + { + auto& rootArg = m_rootArguments[bindingRange.baseIndex]; + switch (resourceView->getViewDesc()->type) + { + case IResourceView::Type::AccelerationStructure: + { + auto resourceViewImpl = static_cast<D3D12AccelerationStructureImpl*>(resourceView); + rootArg = resourceViewImpl->getDeviceAddress(); + } + break; + case IResourceView::Type::ShaderResource: + case IResourceView::Type::UnorderedAccess: + { + auto resourceViewImpl = static_cast<ResourceViewImpl*>(resourceView); + if (resourceViewImpl->m_resource->isBuffer()) + { + rootArg = static_cast<BufferResourceImpl*>(resourceViewImpl->m_resource.Ptr()) + ->getDeviceAddress(); + } + else + { + getDebugCallback()->handleMessage( + DebugMessageType::Error, + DebugMessageSource::Layer, + "The shader parameter at the specified offset is a root parameter, and " + "therefore can only be a buffer view."); + return SLANG_FAIL; + } + } + break; + } + return SLANG_OK; + } + if (resourceView == nullptr) { // Create null descriptor for the binding. @@ -8265,12 +8494,24 @@ Result D3D12Device::ShaderObjectImpl::setResource(ShaderOffset const& offset, IR } auto descriptorSlotIndex = bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex; - d3dDevice->CopyDescriptorsSimple( - 1, - m_descriptorSet.resourceTable.getCpuHandle( - bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex), - internalResourceView->m_descriptor.cpuHandle, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + if (internalResourceView->m_descriptor.cpuHandle.ptr) + { + d3dDevice->CopyDescriptorsSimple( + 1, + m_descriptorSet.resourceTable.getCpuHandle( + bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex), + internalResourceView->m_descriptor.cpuHandle, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + else + { + getDebugCallback()->handleMessage( + DebugMessageType::Error, + DebugMessageSource::Layer, + "IShaderObject::setResource: the resource view cannot be set to this shader parameter. " + "A possible reason is that the view is too large to be supported by D3D12."); + return SLANG_FAIL; + } return SLANG_OK; } |
