diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | build/visual-studio/gfx/gfx.vcxproj | 4 | ||||
| -rw-r--r-- | build/visual-studio/gfx/gfx.vcxproj.filters | 12 | ||||
| -rw-r--r-- | tests/compute/array-param.slang | 2 | ||||
| -rw-r--r-- | tools/gfx/d3d11/render-d3d11.cpp | 13 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 13 | ||||
| -rw-r--r-- | tools/gfx/open-gl/render-gl.cpp | 13 | ||||
| -rw-r--r-- | tools/gfx/render-graphics-common.cpp | 1289 | ||||
| -rw-r--r-- | tools/gfx/render-graphics-common.h | 22 | ||||
| -rw-r--r-- | tools/gfx/render.h | 81 | ||||
| -rw-r--r-- | tools/gfx/shader-cursor.cpp | 249 | ||||
| -rw-r--r-- | tools/gfx/shader-cursor.h | 123 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 13 | ||||
| -rw-r--r-- | tools/render-test/render-test-main.cpp | 1544 |
14 files changed, 1833 insertions, 1546 deletions
diff --git a/.gitignore b/.gitignore index 22349e8d4..9d3adf5e3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.sdf *.ilk *.obj +*.slang-module .clang-format bin/ intermediate/ diff --git a/build/visual-studio/gfx/gfx.vcxproj b/build/visual-studio/gfx/gfx.vcxproj index 9a188c070..d04ac9c2a 100644 --- a/build/visual-studio/gfx/gfx.vcxproj +++ b/build/visual-studio/gfx/gfx.vcxproj @@ -183,7 +183,9 @@ <ClInclude Include="..\..\..\tools\gfx\nvapi\nvapi-include.h" /> <ClInclude Include="..\..\..\tools\gfx\nvapi\nvapi-util.h" /> <ClInclude Include="..\..\..\tools\gfx\open-gl\render-gl.h" /> + <ClInclude Include="..\..\..\tools\gfx\render-graphics-common.h" /> <ClInclude Include="..\..\..\tools\gfx\render.h" /> + <ClInclude Include="..\..\..\tools\gfx\shader-cursor.h" /> <ClInclude Include="..\..\..\tools\gfx\surface.h" /> <ClInclude Include="..\..\..\tools\gfx\vector-math.h" /> <ClInclude Include="..\..\..\tools\gfx\vulkan\render-vk.h" /> @@ -206,7 +208,9 @@ <ClCompile Include="..\..\..\tools\gfx\model.cpp" /> <ClCompile Include="..\..\..\tools\gfx\nvapi\nvapi-util.cpp" /> <ClCompile Include="..\..\..\tools\gfx\open-gl\render-gl.cpp" /> + <ClCompile Include="..\..\..\tools\gfx\render-graphics-common.cpp" /> <ClCompile Include="..\..\..\tools\gfx\render.cpp" /> + <ClCompile Include="..\..\..\tools\gfx\shader-cursor.cpp" /> <ClCompile Include="..\..\..\tools\gfx\surface.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\render-vk.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-api.cpp" /> diff --git a/build/visual-studio/gfx/gfx.vcxproj.filters b/build/visual-studio/gfx/gfx.vcxproj.filters index 2044ede93..ada84b968 100644 --- a/build/visual-studio/gfx/gfx.vcxproj.filters +++ b/build/visual-studio/gfx/gfx.vcxproj.filters @@ -45,9 +45,15 @@ <ClInclude Include="..\..\..\tools\gfx\open-gl\render-gl.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\tools\gfx\render-graphics-common.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\tools\gfx\render.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\tools\gfx\shader-cursor.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\tools\gfx\surface.h"> <Filter>Header Files</Filter> </ClInclude> @@ -110,9 +116,15 @@ <ClCompile Include="..\..\..\tools\gfx\open-gl\render-gl.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\tools\gfx\render-graphics-common.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\tools\gfx\render.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\tools\gfx\shader-cursor.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\tools\gfx\surface.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/tests/compute/array-param.slang b/tests/compute/array-param.slang index f1b06b352..ceac34e78 100644 --- a/tests/compute/array-param.slang +++ b/tests/compute/array-param.slang @@ -1,5 +1,5 @@ //TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -compile-arg -O3 -//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj //TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 //TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp index 6a58501fd..48cf7770d 100644 --- a/tools/gfx/d3d11/render-d3d11.cpp +++ b/tools/gfx/d3d11/render-d3d11.cpp @@ -6,6 +6,7 @@ //WORKING: #include "options.h" #include "../render.h" +#include "../render-graphics-common.h" #include "../d3d/d3d-util.h" #include "../nvapi/nvapi-util.h" @@ -51,7 +52,7 @@ using namespace Slang; namespace gfx { -class D3D11Renderer : public Renderer +class D3D11Renderer : public GraphicsAPIRenderer { public: enum @@ -1776,8 +1777,11 @@ D3D11_COLOR_WRITE_ENABLE translateRenderTargetWriteMask(RenderTargetWriteMaskT m return D3D11_COLOR_WRITE_ENABLE(result); } -Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) +Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& inDesc, PipelineState** outState) { + GraphicsPipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + auto programImpl = (ShaderProgramImpl*) desc.program; ComPtr<ID3D11DepthStencilState> depthStencilState; @@ -1905,8 +1909,11 @@ Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes return SLANG_OK; } -Result D3D11Renderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) +Result D3D11Renderer::createComputePipelineState(const ComputePipelineStateDesc& inDesc, PipelineState** outState) { + ComputePipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + auto programImpl = (ShaderProgramImpl*) desc.program; auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index 886754f0e..d3f030b88 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -5,6 +5,7 @@ //WORKING:#include "options.h" #include "../render.h" +#include "../render-graphics-common.h" #include "../surface.h" @@ -61,7 +62,7 @@ struct ID3D12GraphicsCommandList1 {}; namespace gfx { using namespace Slang; -class D3D12Renderer : public Renderer +class D3D12Renderer : public GraphicsAPIRenderer { public: // Renderer implementation @@ -3520,8 +3521,11 @@ Result D3D12Renderer::createDescriptorSet(DescriptorSetLayout* layout, Descripto return SLANG_OK; } -Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) +Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& inDesc, PipelineState** outState) { + GraphicsPipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; auto programImpl = (ShaderProgramImpl*) desc.program; auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout; @@ -3618,8 +3622,11 @@ Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes return SLANG_OK; } -Result D3D12Renderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) +Result D3D12Renderer::createComputePipelineState(const ComputePipelineStateDesc& inDesc, PipelineState** outState) { + ComputePipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; auto programImpl = (ShaderProgramImpl*) desc.program; diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp index bf873212c..8be8165aa 100644 --- a/tools/gfx/open-gl/render-gl.cpp +++ b/tools/gfx/open-gl/render-gl.cpp @@ -5,6 +5,7 @@ //WORKING:#include "options.h" #include "../render.h" +#include "../render-graphics-common.h" #include <stdio.h> #include <stdlib.h> @@ -76,7 +77,7 @@ using namespace Slang; namespace gfx { -class GLRenderer : public Renderer +class GLRenderer : public GraphicsAPIRenderer { public: @@ -1376,8 +1377,11 @@ Result GLRenderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram* return SLANG_OK; } -Result GLRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) +Result GLRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& inDesc, PipelineState** outState) { + GraphicsPipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + auto programImpl = (ShaderProgramImpl*) desc.program; auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout; @@ -1390,8 +1394,11 @@ Result GLRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& return SLANG_OK; } -Result GLRenderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) +Result GLRenderer::createComputePipelineState(const ComputePipelineStateDesc& inDesc, PipelineState** outState) { + ComputePipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + auto programImpl = (ShaderProgramImpl*) desc.program; auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; diff --git a/tools/gfx/render-graphics-common.cpp b/tools/gfx/render-graphics-common.cpp new file mode 100644 index 000000000..d3d469fc2 --- /dev/null +++ b/tools/gfx/render-graphics-common.cpp @@ -0,0 +1,1289 @@ +#include "render-graphics-common.h" +using namespace Slang; + +namespace gfx +{ + +gfx::StageType translateStage(SlangStage slangStage) +{ + switch (slangStage) + { + default: + SLANG_ASSERT(!"unhandled case"); + return gfx::StageType::Unknown; + +#define CASE(FROM, TO) \ + case SLANG_STAGE_##FROM: \ + return gfx::StageType::TO + + CASE(VERTEX, Vertex); + CASE(HULL, Hull); + CASE(DOMAIN, Domain); + CASE(GEOMETRY, Geometry); + CASE(FRAGMENT, Fragment); + + CASE(COMPUTE, Compute); + + CASE(RAY_GENERATION, RayGeneration); + CASE(INTERSECTION, Intersection); + CASE(ANY_HIT, AnyHit); + CASE(CLOSEST_HIT, ClosestHit); + CASE(MISS, Miss); + CASE(CALLABLE, Callable); + +#undef CASE + } +} + +class GraphicsCommonShaderObjectLayout : public ShaderObjectLayout +{ +public: + struct BindingRangeInfo + { + slang::BindingType bindingType; + Index count; + Index baseIndex; + Index descriptorSetIndex; + Index rangeIndexInDescriptorSet; + // Index subObjectRangeIndex = -1; + }; + + struct SubObjectRangeInfo + { + RefPtr<GraphicsCommonShaderObjectLayout> layout; + // Index baseIndex; + // Index count; + Index bindingRangeIndex; + }; + + struct DescriptorSetInfo : public RefObject + { + RefPtr<DescriptorSetLayout> layout; + Slang::Int space = -1; + }; + + struct Builder + { + public: + Builder(Renderer* renderer) + : m_renderer(renderer) + {} + + List<BindingRangeInfo> m_bindingRanges; + List<SubObjectRangeInfo> m_subObjectRanges; + + Index m_resourceViewCount = 0; + Index m_samplerCount = 0; + Index m_combinedTextureSamplerCount = 0; + Index m_subObjectCount = 0; + Index m_varyingInputCount = 0; + Index m_varyingOutputCount = 0; + + struct DescriptorSetBuildInfo : public RefObject + { + List<DescriptorSetLayout::SlotRangeDesc> slotRangeDescs; + Index space; + }; + List<RefPtr<DescriptorSetBuildInfo>> m_descriptorSetBuildInfos; + Dictionary<Index, Index> m_mapSpaceToDescriptorSetIndex; + + Index findOrAddDescriptorSet(Index space) + { + Index index; + if (m_mapSpaceToDescriptorSetIndex.TryGetValue(space, index)) + return index; + + RefPtr<DescriptorSetBuildInfo> info = new DescriptorSetBuildInfo(); + info->space = space; + + index = m_descriptorSetBuildInfos.getCount(); + m_descriptorSetBuildInfos.add(info); + + m_mapSpaceToDescriptorSetIndex.Add(space, index); + return index; + } + + static DescriptorSlotType _mapDescriptorType(slang::BindingType slangBindingType) + { + switch (slangBindingType) + { + default: + return DescriptorSlotType::Unknown; + +#define CASE(FROM, TO) \ + case slang::BindingType::FROM: \ + return DescriptorSlotType::TO + + CASE(Sampler, Sampler); + CASE(CombinedTextureSampler, CombinedImageSampler); + CASE(Texture, SampledImage); + CASE(MutableTexture, StorageImage); + CASE(TypedBuffer, UniformTexelBuffer); + CASE(MutableTypedBuffer, StorageTexelBuffer); + CASE(RawBuffer, UniformBuffer); + CASE(MutableRawBuffer, StorageBuffer); + CASE(InputRenderTarget, InputAttachment); + CASE(InlineUniformData, InlineUniformBlock); + CASE(RayTracingAccelerationStructure, RayTracingAccelerationStructure); + CASE(ConstantBuffer, UniformBuffer); + CASE(PushConstant, RootConstant); + +#undef CASE + } + } + + slang::TypeLayoutReflection* unwrapParameterGroups(slang::TypeLayoutReflection* typeLayout) + { + for (;;) + { + if (!typeLayout->getType()) + { + if (auto elementTypeLayout = typeLayout->getElementTypeLayout()) + typeLayout = elementTypeLayout; + } + + switch (typeLayout->getKind()) + { + default: + return typeLayout; + + case slang::TypeReflection::Kind::ConstantBuffer: + case slang::TypeReflection::Kind::ParameterBlock: + typeLayout = typeLayout->getElementTypeLayout(); + continue; + } + } + } + + void _addDescriptorSets( + slang::TypeLayoutReflection* typeLayout, + slang::VariableLayoutReflection* varLayout = nullptr) + { + SlangInt descriptorSetCount = typeLayout->getDescriptorSetCount(); + for (SlangInt s = 0; s < descriptorSetCount; ++s) + { + auto descriptorSetIndex = + findOrAddDescriptorSet(typeLayout->getDescriptorSetSpaceOffset(s)); + auto descriptorSetInfo = m_descriptorSetBuildInfos[descriptorSetIndex]; + + SlangInt descriptorRangeCount = typeLayout->getDescriptorSetDescriptorRangeCount(s); + for (SlangInt r = 0; r < descriptorRangeCount; ++r) + { + auto slangBindingType = typeLayout->getDescriptorSetDescriptorRangeType(s, r); + auto gfxDescriptorType = _mapDescriptorType(slangBindingType); + + DescriptorSetLayout::SlotRangeDesc descriptorRangeDesc; + descriptorRangeDesc.binding = + typeLayout->getDescriptorSetDescriptorRangeIndexOffset(s, r); + descriptorRangeDesc.count = + typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(s, r); + descriptorRangeDesc.type = gfxDescriptorType; + + if (varLayout) + { + auto category = typeLayout->getDescriptorSetDescriptorRangeCategory(s, r); + descriptorRangeDesc.binding += varLayout->getOffset(category); + } + + descriptorSetInfo->slotRangeDescs.add(descriptorRangeDesc); + } + } + } + + Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout) + { + typeLayout = unwrapParameterGroups(typeLayout); + + m_elementTypeLayout = typeLayout; + + // First we will use the Slang layout information to allocate + // the descriptor set layout(s) required to store values + // of the given type. + // + _addDescriptorSets(typeLayout); + + // Next we will compute the binding ranges that are used to store + // the logical contents of the object in memory. These will relate + // to the descriptor ranges in the various sets, but not always + // in a one-to-one fashion. + + SlangInt bindingRangeCount = typeLayout->getBindingRangeCount(); + for (SlangInt r = 0; r < bindingRangeCount; ++r) + { + slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r); + SlangInt count = typeLayout->getBindingRangeBindingCount(r); + slang::TypeLayoutReflection* slangLeafTypeLayout = + typeLayout->getBindingRangeLeafTypeLayout(r); + + SlangInt descriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(r); + SlangInt rangeIndexInDescriptorSet = + typeLayout->getBindingRangeFirstDescriptorRangeIndex(r); + + Index baseIndex = 0; + switch (slangBindingType) + { + case slang::BindingType::ConstantBuffer: + case slang::BindingType::ParameterBlock: + case slang::BindingType::ExistentialValue: + baseIndex = m_subObjectCount; + m_subObjectCount += count; + break; + + case slang::BindingType::Sampler: + baseIndex = m_samplerCount; + m_samplerCount += count; + break; + + case slang::BindingType::CombinedTextureSampler: + baseIndex = m_combinedTextureSamplerCount; + m_combinedTextureSamplerCount += count; + break; + + case slang::BindingType::VaryingInput: + baseIndex = m_varyingInputCount; + m_varyingInputCount += count; + break; + + case slang::BindingType::VaryingOutput: + baseIndex = m_varyingOutputCount; + m_varyingOutputCount += count; + break; + + default: + baseIndex = m_resourceViewCount; + m_resourceViewCount += count; + break; + } + + BindingRangeInfo bindingRangeInfo; + bindingRangeInfo.bindingType = slangBindingType; + bindingRangeInfo.count = count; + // bindingRangeInfo.descriptorSetIndex = descriptorSetIndex; + // bindingRangeInfo.rangeIndexInDescriptorSet = slotRangeIndex; + // bindingRangeInfo.subObjectRangeIndex = subObjectRangeIndex; + bindingRangeInfo.baseIndex = baseIndex; + bindingRangeInfo.descriptorSetIndex = descriptorSetIndex; + bindingRangeInfo.rangeIndexInDescriptorSet = rangeIndexInDescriptorSet; + + m_bindingRanges.add(bindingRangeInfo); + +#if 0 + SlangInt binding = typeLayout->getBindingRangeIndexOffset(r); + SlangInt space = typeLayout->getBindingRangeSpaceOffset(r); + SlangInt subObjectRangeIndex = typeLayout->getBindingRangeSubObjectRangeIndex(r); + + DescriptorSetLayout::SlotRangeDesc slotRange; + slotRange.type = _mapDescriptorType(slangBindingType); + slotRange.count = count; + slotRange.binding = binding; + + Index descriptorSetIndex = findOrAddDescriptorSet(space); + RefPtr<DescriptorSetBuildInfo> descriptorSetInfo = m_descriptorSetInfos[descriptorSetIndex]; + + Index slotRangeIndex = descriptorSetInfo->slotRanges.getCount(); + descriptorSetInfo->slotRanges.add(slotRange); +#endif + } + + SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount(); + for (SlangInt r = 0; r < subObjectRangeCount; ++r) + { + SlangInt bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(r); + auto slangBindingType = typeLayout->getBindingRangeType(bindingRangeIndex); + slang::TypeLayoutReflection* slangLeafTypeLayout = + typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); + + // A sub-object range can either represent a sub-object of a known + // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>` + // (in which case we can pre-compute a layout to use, based on + // the type `Foo`) *or* it can represent a sub-object of some + // existential type (e.g., `IBar`) in which case we cannot + // know the appropraite type/layout of sub-object to allocate. + // + RefPtr<GraphicsCommonShaderObjectLayout> subObjectLayout; + if (slangBindingType != slang::BindingType::ExistentialValue) + { + GraphicsCommonShaderObjectLayout::createForElementType( + m_renderer, + slangLeafTypeLayout->getElementTypeLayout(), + subObjectLayout.writeRef()); + } + + SubObjectRangeInfo subObjectRange; + subObjectRange.bindingRangeIndex = bindingRangeIndex; + subObjectRange.layout = subObjectLayout; + + m_subObjectRanges.add(subObjectRange); + } + +#if 0 + SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount(); + for(SlangInt r = 0; r < subObjectRangeCount; ++r) + { + + // TODO: Still need a way to map the binding ranges for + // the sub-object over so that they can be used to + // set/get the sub-object as needed. + } +#endif + return SLANG_OK; + } + + SlangResult build(GraphicsCommonShaderObjectLayout** outLayout) + { + RefPtr<GraphicsCommonShaderObjectLayout> layout = + new GraphicsCommonShaderObjectLayout(); + SLANG_RETURN_ON_FAIL(layout->_init(this)); + + *outLayout = layout.detach(); + return SLANG_OK; + } + + Renderer* m_renderer = nullptr; + slang::TypeLayoutReflection* m_elementTypeLayout = nullptr; + }; + + static Result createForElementType( + Renderer* renderer, + slang::TypeLayoutReflection* elementType, + GraphicsCommonShaderObjectLayout** outLayout) + { + Builder builder(renderer); + builder.setElementTypeLayout(elementType); + return builder.build(outLayout); + } + + List<RefPtr<DescriptorSetInfo>> const& getDescriptorSets() { return m_descriptorSets; } + + List<BindingRangeInfo> const& getBindingRanges() { return m_bindingRanges; } + + Index getBindingRangeCount() { return m_bindingRanges.getCount(); } + + BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; } + + slang::TypeLayoutReflection* getElementTypeLayout() { return m_elementTypeLayout; } + + Index getResourceViewCount() { return m_resourceViewCount; } + Index getSamplerCount() { return m_samplerCount; } + Index getCombinedTextureSamplerCount() { return m_combinedTextureSamplerCount; } + Index getSubObjectCount() { return m_subObjectCount; } + + SubObjectRangeInfo const& getSubObjectRange(Index index) { return m_subObjectRanges[index]; } + List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; } + + Renderer* getRenderer() { return m_renderer; } + +protected: + Result _init(Builder const* builder) + { + auto renderer = builder->m_renderer; + m_renderer = renderer; + + m_elementTypeLayout = builder->m_elementTypeLayout; + m_bindingRanges = builder->m_bindingRanges; + + for (auto descriptorSetBuildInfo : builder->m_descriptorSetBuildInfos) + { + auto& slotRangeDescs = descriptorSetBuildInfo->slotRangeDescs; + DescriptorSetLayout::Desc desc; + desc.slotRangeCount = slotRangeDescs.getCount(); + desc.slotRanges = slotRangeDescs.getBuffer(); + + RefPtr<DescriptorSetLayout> descriptorSetLayout; + SLANG_RETURN_ON_FAIL( + m_renderer->createDescriptorSetLayout(desc, descriptorSetLayout.writeRef())); + + RefPtr<DescriptorSetInfo> descriptorSetInfo = new DescriptorSetInfo(); + descriptorSetInfo->layout = descriptorSetLayout; + descriptorSetInfo->space = descriptorSetBuildInfo->space; + + m_descriptorSets.add(descriptorSetInfo); + } + + m_resourceViewCount = builder->m_resourceViewCount; + m_samplerCount = builder->m_samplerCount; + m_combinedTextureSamplerCount = builder->m_combinedTextureSamplerCount; + m_subObjectCount = builder->m_subObjectCount; + + m_subObjectRanges = builder->m_subObjectRanges; + + return SLANG_OK; + } + + Renderer* m_renderer; + List<RefPtr<DescriptorSetInfo>> m_descriptorSets; + List<BindingRangeInfo> m_bindingRanges; + slang::TypeLayoutReflection* m_elementTypeLayout; + Index m_resourceViewCount = 0; + Index m_samplerCount = 0; + Index m_combinedTextureSamplerCount = 0; + Index m_subObjectCount = 0; + List<SubObjectRangeInfo> m_subObjectRanges; +}; + +class EntryPointLayout : public GraphicsCommonShaderObjectLayout +{ + typedef GraphicsCommonShaderObjectLayout Super; + +public: + struct VaryingInputInfo + {}; + + struct VaryingOutputInfo + {}; + + struct Builder : Super::Builder + { + Builder(Renderer* renderer) + : Super::Builder(renderer) + {} + + Result build(EntryPointLayout** outLayout) + { + RefPtr<EntryPointLayout> layout = new EntryPointLayout(); + SLANG_RETURN_ON_FAIL(layout->_init(this)); + + *outLayout = layout.detach(); + return SLANG_OK; + } + + void _addEntryPointParam(slang::VariableLayoutReflection* entryPointParam) + { + auto slangStage = entryPointParam->getStage(); + auto typeLayout = entryPointParam->getTypeLayout(); + + SlangInt bindingRangeCount = typeLayout->getBindingRangeCount(); + for (SlangInt r = 0; r < bindingRangeCount; ++r) + { + slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r); + SlangInt count = typeLayout->getBindingRangeBindingCount(r); + + switch (slangBindingType) + { + default: + break; + + case slang::BindingType::VaryingInput: + { + VaryingInputInfo info; + + m_varyingInputs.add(info); + } + break; + + case slang::BindingType::VaryingOutput: + { + VaryingOutputInfo info; + m_varyingOutputs.add(info); + } + break; + } + } + } + + void addEntryPointParams(slang::EntryPointLayout* entryPointLayout) + { + m_slangEntryPointLayout = entryPointLayout; + + setElementTypeLayout(entryPointLayout->getTypeLayout()); + + m_stage = translateStage(entryPointLayout->getStage()); + _addEntryPointParam(entryPointLayout->getVarLayout()); + _addEntryPointParam(entryPointLayout->getResultVarLayout()); + } + + slang::EntryPointLayout* m_slangEntryPointLayout = nullptr; + + gfx::StageType m_stage; + List<VaryingInputInfo> m_varyingInputs; + List<VaryingOutputInfo> m_varyingOutputs; + }; + + Result _init(Builder const* builder) + { + auto renderer = builder->m_renderer; + + SLANG_RETURN_ON_FAIL(Super::_init(builder)); + + m_slangEntryPointLayout = builder->m_slangEntryPointLayout; + m_stage = builder->m_stage; + m_varyingInputs = builder->m_varyingInputs; + m_varyingOutputs = builder->m_varyingOutputs; + + return SLANG_OK; + } + + List<VaryingInputInfo> const& getVaryingInputs() { return m_varyingInputs; } + List<VaryingOutputInfo> const& getVaryingOutputs() { return m_varyingOutputs; } + + gfx::StageType getStage() const { return m_stage; } + + slang::EntryPointLayout* getSlangLayout() const { return m_slangEntryPointLayout; }; + + slang::EntryPointLayout* m_slangEntryPointLayout; + gfx::StageType m_stage; + List<VaryingInputInfo> m_varyingInputs; + List<VaryingOutputInfo> m_varyingOutputs; +}; + +class GraphicsCommonProgramLayout : public GraphicsCommonShaderObjectLayout +{ + typedef GraphicsCommonShaderObjectLayout Super; + +public: + struct EntryPointInfo + { + RefPtr<EntryPointLayout> layout; + Index rangeOffset; + }; + + struct Builder : Super::Builder + { + Builder(Renderer* renderer) + : Super::Builder(renderer) + {} + + Result build(GraphicsCommonProgramLayout** outLayout) + { + RefPtr<GraphicsCommonProgramLayout> layout = new GraphicsCommonProgramLayout(); + SLANG_RETURN_ON_FAIL(layout->_init(this)); + + *outLayout = layout.detach(); + return SLANG_OK; + } + + void addGlobalParams(slang::VariableLayoutReflection* globalsLayout) + { + setElementTypeLayout(globalsLayout->getTypeLayout()); + } + + void addEntryPoint(EntryPointLayout* entryPointLayout) + { + EntryPointInfo info; + info.layout = entryPointLayout; + + if (m_descriptorSetBuildInfos.getCount()) + { + info.rangeOffset = m_descriptorSetBuildInfos[0]->slotRangeDescs.getCount(); + } + + auto slangEntryPointLayout = entryPointLayout->getSlangLayout(); + _addDescriptorSets( + slangEntryPointLayout->getTypeLayout(), slangEntryPointLayout->getVarLayout()); + + m_entryPoints.add(info); + } + + List<EntryPointInfo> m_entryPoints; + }; + + Slang::Int getRenderTargetCount() { return m_renderTargetCount; } + + PipelineLayout* getPipelineLayout() { return m_pipelineLayout; } + + Index findEntryPointIndex(gfx::StageType stage) + { + auto entryPointCount = m_entryPoints.getCount(); + for (Index i = 0; i < entryPointCount; ++i) + { + auto entryPoint = m_entryPoints[i]; + if (entryPoint.layout->getStage() == stage) + return i; + } + return -1; + } + + EntryPointInfo const& getEntryPoint(Index index) { return m_entryPoints[index]; } + + List<EntryPointInfo> const& getEntryPoints() const { return m_entryPoints; } + +protected: + Result _init(Builder const* builder) + { + auto renderer = builder->m_renderer; + + SLANG_RETURN_ON_FAIL(Super::_init(builder)); + + m_entryPoints = builder->m_entryPoints; + + List<PipelineLayout::DescriptorSetDesc> pipelineDescriptorSets; + _addDescriptorSetsRec(this, pipelineDescriptorSets); + +#if 0 + _createInputLayout(builder); +#endif + + auto fragmentEntryPointIndex = findEntryPointIndex(gfx::StageType::Fragment); + if (fragmentEntryPointIndex != -1) + { + auto fragmentEntryPoint = getEntryPoint(fragmentEntryPointIndex); + m_renderTargetCount = fragmentEntryPoint.layout->getVaryingOutputs().getCount(); + } + + PipelineLayout::Desc pipelineLayoutDesc; + pipelineLayoutDesc.renderTargetCount = m_renderTargetCount; + pipelineLayoutDesc.descriptorSetCount = pipelineDescriptorSets.getCount(); + pipelineLayoutDesc.descriptorSets = pipelineDescriptorSets.getBuffer(); + + SLANG_RETURN_ON_FAIL( + renderer->createPipelineLayout(pipelineLayoutDesc, m_pipelineLayout.writeRef())); + + return SLANG_OK; + } + + static void _addDescriptorSetsRec( + GraphicsCommonShaderObjectLayout* layout, + List<PipelineLayout::DescriptorSetDesc>& ioPipelineDescriptorSets) + { + for (auto descriptorSetInfo : layout->getDescriptorSets()) + { + PipelineLayout::DescriptorSetDesc pipelineDescriptorSet; + pipelineDescriptorSet.layout = descriptorSetInfo->layout; + pipelineDescriptorSet.space = descriptorSetInfo->space; + + ioPipelineDescriptorSets.add(pipelineDescriptorSet); + } + + // TODO: next we need to recurse into the "sub-objects" of `layout` and + // add their descriptor sets as well. + } + +#if 0 + Result _createInputLayout(Builder const* builder) + { + auto renderer = builder->m_renderer; + + List<InputElementDesc> const& inputElements = builder->getInputElements(); + SLANG_RETURN_ON_FAIL(renderer->createInputLayout(inputElements.getBuffer(), inputElements.getCount(), m_inputLayout.writeRef())); + + return SLANG_OK; + } +#endif + + List<EntryPointInfo> m_entryPoints; + gfx::UInt m_renderTargetCount = 0; + + RefPtr<PipelineLayout> m_pipelineLayout; +}; + +class GraphicsCommonShaderObject : public ShaderObject +{ +public: + static Result create( + Renderer* renderer, + GraphicsCommonShaderObjectLayout* layout, + GraphicsCommonShaderObject** outShaderObject) + { + RefPtr<GraphicsCommonShaderObject> object = new GraphicsCommonShaderObject(); + SLANG_RETURN_ON_FAIL(object->init(renderer, layout)); + + *outShaderObject = object.detach(); + return SLANG_OK; + } + + Renderer* getRenderer() { return m_layout->getRenderer(); } + + Index getEntryPointCount() { return 0; } + + ShaderObject* getEntryPoint(Index index) { return nullptr; } + + GraphicsCommonShaderObjectLayout* getLayout() { return m_layout; } + + slang::TypeLayoutReflection* getElementTypeLayout() { return m_layout->getElementTypeLayout(); } + + SlangResult setData(ShaderOffset const& offset, void const* data, size_t size) + { + Renderer* renderer = getRenderer(); + + char* dest = (char*)renderer->map(m_buffer, MapFlavor::HostWrite); + memcpy(dest + offset.uniformOffset, data, size); + renderer->unmap(m_buffer); + + return SLANG_OK; + } + + virtual SlangResult setObject(ShaderOffset const& offset, ShaderObject* object) SLANG_OVERRIDE + { + if (offset.bindingRangeIndex < 0) + return SLANG_E_INVALID_ARG; + if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) + return SLANG_E_INVALID_ARG; + auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); + + // TODO: Is this reasonable to store the base index directly in the binding range? + m_objects[bindingRange.baseIndex + offset.bindingArrayIndex] = + reinterpret_cast<GraphicsCommonShaderObject*>(object); + + // auto& subObjectRange = + // m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex); + // m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex] = object; + +#if 0 + + SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0); + SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount()); + auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex]; + + descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer); + return SLANG_OK; +#else + return SLANG_E_NOT_IMPLEMENTED; +#endif + } + + virtual SlangResult getObject(ShaderOffset const& offset, ShaderObject** outObject) SLANG_OVERRIDE + { + SLANG_ASSERT(outObject); + if (offset.bindingRangeIndex < 0) + return SLANG_E_INVALID_ARG; + if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) + return SLANG_E_INVALID_ARG; + auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); + + *outObject = m_objects[bindingRange.baseIndex + offset.bindingArrayIndex]; + + // auto& subObjectRange = + // m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex); *outObject = + // m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex]; + + return SLANG_OK; + +#if 0 + SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0); + SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount()); + auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex]; + + descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer); + return SLANG_OK; +#endif + } + + ShaderObject* getObject(ShaderOffset const& offset) + { + ShaderObject* object = nullptr; + SLANG_RETURN_NULL_ON_FAIL(getObject(offset, &object)); + return object; + } + + SlangResult setResource(ShaderOffset const& offset, ResourceView* resourceView) + { + if (offset.bindingRangeIndex < 0) + return SLANG_E_INVALID_ARG; + if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) + return SLANG_E_INVALID_ARG; + auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); + + m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = resourceView; + return SLANG_OK; + } + + SlangResult setSampler(ShaderOffset const& offset, SamplerState* sampler) + { + if (offset.bindingRangeIndex < 0) + return SLANG_E_INVALID_ARG; + if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) + return SLANG_E_INVALID_ARG; + auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); + + m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] = sampler; + return SLANG_OK; + } + + SlangResult setCombinedTextureSampler( + ShaderOffset const& offset, ResourceView* textureView, SamplerState* sampler) + { + if (offset.bindingRangeIndex < 0) + return SLANG_E_INVALID_ARG; + if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) + return SLANG_E_INVALID_ARG; + auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); + + auto& slot = m_combinedTextureSamplers[bindingRange.baseIndex + offset.bindingArrayIndex]; + slot.textureView = textureView; + slot.sampler = sampler; + return SLANG_OK; + } + +protected: + friend class ProgramVars; + + Result init(Renderer* renderer, GraphicsCommonShaderObjectLayout* layout) + { + m_layout = layout; + + // If the layout tells us that there is any uniform data, + // then we need to allocate a constant buffer to hold that data. + // + // TODO: Do we need to allocate a shadow copy for use from + // the CPU? + // + // TODO: When/where do we bind this constant buffer into + // a descriptor set for later use? + // + size_t uniformSize = layout->getElementTypeLayout()->getSize(); + if (uniformSize) + { + BufferResource::Desc bufferDesc; + bufferDesc.init(uniformSize); + bufferDesc.cpuAccessFlags |= Resource::AccessFlag::Write; + SLANG_RETURN_ON_FAIL(renderer->createBufferResource( + Resource::Usage::ConstantBuffer, bufferDesc, nullptr, m_buffer.writeRef())); + } + +#if 0 + // If the layout tells us there are any descriptor sets to + // allocate, then we do so now. + // + for(auto descriptorSetInfo : layout->getDescriptorSets()) + { + RefPtr<DescriptorSet> descriptorSet; + SLANG_RETURN_ON_FAIL(renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef())); + m_descriptorSets.add(descriptorSet); + } +#endif + + m_resourceViews.setCount(layout->getResourceViewCount()); + m_samplers.setCount(layout->getSamplerCount()); + m_combinedTextureSamplers.setCount(layout->getCombinedTextureSamplerCount()); + + // If the layout specifies that we have any sub-objects, then + // we need to size the array to account for them. + // + Index subObjectCount = layout->getSubObjectCount(); + m_objects.setCount(subObjectCount); + + for (auto subObjectRangeInfo : layout->getSubObjectRanges()) + { + RefPtr<GraphicsCommonShaderObjectLayout> subObjectLayout = subObjectRangeInfo.layout; + + // In the case where the sub-object range represents an + // existential-type leaf field (e.g., an `IBar`), we + // cannot pre-allocate the objet(s) to go into that + // range, since we can't possibly know what to allocate + // at this point. + // + if (!subObjectLayout) + continue; + // + // Otherwise, we will allocate a sub-object to fill + // in each entry in this range, based on the layout + // information we already have. + + auto& bindingRangeInfo = layout->getBindingRange(subObjectRangeInfo.bindingRangeIndex); + for (Index i = 0; i < bindingRangeInfo.count; ++i) + { + RefPtr<GraphicsCommonShaderObject> subObject; + SLANG_RETURN_ON_FAIL( + GraphicsCommonShaderObject::create(renderer, subObjectLayout, subObject.writeRef())); + m_objects[bindingRangeInfo.baseIndex + i] = subObject; + } + } + + return SLANG_OK; + } + + Result apply( + Renderer* renderer, + PipelineType pipelineType, + PipelineLayout* pipelineLayout, + Index& ioRootIndex) + { + GraphicsCommonShaderObjectLayout* layout = m_layout; + + // Create the descritpor sets required by the layout... + // + List<RefPtr<DescriptorSet>> descriptorSets; + for (auto descriptorSetInfo : layout->getDescriptorSets()) + { + RefPtr<DescriptorSet> descriptorSet; + SLANG_RETURN_ON_FAIL( + renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef())); + descriptorSets.add(descriptorSet); + } + + SLANG_RETURN_ON_FAIL(_bindIntoDescriptorSets(descriptorSets.getBuffer())); + + for (auto descriptorSet : descriptorSets) + { + renderer->setDescriptorSet(pipelineType, pipelineLayout, ioRootIndex++, descriptorSet); + } + + return SLANG_OK; + } + + Result _bindIntoDescriptorSet( + DescriptorSet* descriptorSet, Index baseRangeIndex, Index subObjectRangeArrayIndex) + { + GraphicsCommonShaderObjectLayout* layout = m_layout; + + if (m_buffer) + { + descriptorSet->setConstantBuffer(baseRangeIndex, subObjectRangeArrayIndex, m_buffer); + baseRangeIndex++; + } + + for (auto bindingRangeInfo : layout->getBindingRanges()) + { + switch (bindingRangeInfo.bindingType) + { + case slang::BindingType::VaryingInput: + case slang::BindingType::VaryingOutput: + continue; + + default: + break; + } + + SLANG_ASSERT(bindingRangeInfo.descriptorSetIndex == 0); + + auto count = bindingRangeInfo.count; + auto baseIndex = bindingRangeInfo.baseIndex; + + auto descriptorRangeIndex = baseRangeIndex + bindingRangeInfo.rangeIndexInDescriptorSet; + auto descriptorArrayBaseIndex = subObjectRangeArrayIndex * count; + + switch (bindingRangeInfo.bindingType) + { + case slang::BindingType::ConstantBuffer: + case slang::BindingType::ParameterBlock: + break; + + case slang::BindingType::ExistentialValue: + // + // TODO: If the existential value is one that "fits" into the storage available, + // then we should write its data directly into that area. Otherwise, we need + // to bind its content as "pending" data which will come after any other data + // beloning to the same set (that is, it's starting descriptorRangeIndex will + // need to be one after the number of ranges accounted for in the original type) + // + break; + + case slang::BindingType::CombinedTextureSampler: + for (Index i = 0; i < count; ++i) + { + auto& slot = m_combinedTextureSamplers[baseIndex + i]; + descriptorSet->setCombinedTextureSampler( + descriptorRangeIndex, + descriptorArrayBaseIndex + i, + slot.textureView, + slot.sampler); + } + break; + + case slang::BindingType::Sampler: + for (Index i = 0; i < count; ++i) + { + descriptorSet->setSampler( + descriptorRangeIndex, + descriptorArrayBaseIndex + i, + m_samplers[baseIndex + i]); + } + break; + + default: + for (Index i = 0; i < count; ++i) + { + descriptorSet->setResource( + descriptorRangeIndex, + descriptorArrayBaseIndex + i, + m_resourceViews[baseIndex + i]); + } + break; + } + } + + return SLANG_OK; + } + +public: + virtual Result _bindIntoDescriptorSets(RefPtr<DescriptorSet>* descriptorSets) + { + GraphicsCommonShaderObjectLayout* layout = m_layout; + + if (m_buffer) + { + // TODO: look up binding infor for default constant buffer... + descriptorSets[0]->setConstantBuffer(0, 0, m_buffer); + } + + // Fill in the descriptor sets based on binding ranges + // + for (auto bindingRangeInfo : layout->getBindingRanges()) + { + DescriptorSet* descriptorSet = descriptorSets[bindingRangeInfo.descriptorSetIndex]; + auto rangeIndex = bindingRangeInfo.rangeIndexInDescriptorSet; + auto baseIndex = bindingRangeInfo.baseIndex; + auto count = bindingRangeInfo.count; + switch (bindingRangeInfo.bindingType) + { + case slang::BindingType::ConstantBuffer: + case slang::BindingType::ParameterBlock: + for (Index i = 0; i < count; ++i) + { + GraphicsCommonShaderObject* subObject = m_objects[baseIndex + i]; + + subObject->_bindIntoDescriptorSet(descriptorSet, rangeIndex, i); + } + break; + + case slang::BindingType::CombinedTextureSampler: + for (Index i = 0; i < count; ++i) + { + auto& slot = m_combinedTextureSamplers[baseIndex + i]; + descriptorSet->setCombinedTextureSampler( + rangeIndex, i, slot.textureView, slot.sampler); + } + break; + + case slang::BindingType::Sampler: + for (Index i = 0; i < count; ++i) + { + descriptorSet->setSampler(rangeIndex, i, m_samplers[baseIndex + i]); + } + break; + + case slang::BindingType::VaryingInput: + case slang::BindingType::VaryingOutput: + break; + + case slang::BindingType::ExistentialValue: + // Here we are binding as if existential value is the same + // as a constant buffer or parameter block, which will lead + // to incorrect results... + for (Index i = 0; i < count; ++i) + { + GraphicsCommonShaderObject* subObject = m_objects[baseIndex + i]; + + subObject->_bindIntoDescriptorSet(descriptorSet, rangeIndex, i); + } + break; + + default: + for (Index i = 0; i < count; ++i) + { + descriptorSet->setResource(rangeIndex, i, m_resourceViews[baseIndex + i]); + } + break; + } + } + return SLANG_OK; + } + + RefPtr<GraphicsCommonShaderObjectLayout> m_layout = nullptr; + RefPtr<BufferResource> m_buffer; + + List<RefPtr<ResourceView>> m_resourceViews; + + List<RefPtr<SamplerState>> m_samplers; + + struct CombinedTextureSamplerSlot + { + RefPtr<ResourceView> textureView; + RefPtr<SamplerState> sampler; + }; + List<CombinedTextureSamplerSlot> m_combinedTextureSamplers; + + // List<RefPtr<DescriptorSet>> m_descriptorSets; + List<RefPtr<GraphicsCommonShaderObject>> m_objects; +}; + +class EntryPointVars : public GraphicsCommonShaderObject +{ + typedef GraphicsCommonShaderObject Super; + +public: + static Result + create(Renderer* renderer, EntryPointLayout* layout, EntryPointVars** outShaderObject) + { + RefPtr<EntryPointVars> object = new EntryPointVars(); + SLANG_RETURN_ON_FAIL(object->init(renderer, layout)); + + *outShaderObject = object.detach(); + return SLANG_OK; + } + + EntryPointLayout* getLayout() { return static_cast<EntryPointLayout*>(m_layout.Ptr()); } + +protected: + Result init(Renderer* renderer, EntryPointLayout* layout) + { + SLANG_RETURN_ON_FAIL(Super::init(renderer, layout)); + return SLANG_OK; + } +}; + +class ProgramVars : public GraphicsCommonShaderObject +{ + typedef GraphicsCommonShaderObject Super; + +public: + static Result create(Renderer* renderer, GraphicsCommonProgramLayout* layout, ProgramVars** outShaderObject) + { + RefPtr<ProgramVars> object = new ProgramVars(); + SLANG_RETURN_ON_FAIL(object->init(renderer, layout)); + + *outShaderObject = object.detach(); + return SLANG_OK; + } + + GraphicsCommonProgramLayout* getLayout() { return static_cast<GraphicsCommonProgramLayout*>(m_layout.Ptr()); } + + void apply(Renderer* renderer, PipelineType pipelineType) + { + auto pipelineLayout = getLayout()->getPipelineLayout(); + + Index rootIndex = 0; + GraphicsCommonShaderObject::apply(renderer, pipelineType, pipelineLayout, rootIndex); + +#if 0 + + Index descriptorSetCount = m_descriptorSets.getCount(); + for(Index descriptorSetIndex = 0; descriptorSetIndex < descriptorSetCount; ++descriptorSetIndex) + { + renderer->setDescriptorSet( + pipelineType, + pipelineLayout, + descriptorSetIndex, + m_descriptorSets[descriptorSetIndex]); + } +#endif + + // TODO: We also need to bind any descriptor sets that are + // part of sub-objects of this object. + } + + List<RefPtr<EntryPointVars>> const& getEntryPoints() const { return m_entryPoints; } + + + Index getEntryPointCount() { return m_entryPoints.getCount(); } + ShaderObject* getEntryPoint(Index index) { return m_entryPoints[index]; } + + +protected: + virtual Result _bindIntoDescriptorSets(RefPtr<DescriptorSet>* descriptorSets) + { + SLANG_RETURN_ON_FAIL(Super::_bindIntoDescriptorSets(descriptorSets)); + + auto entryPointCount = m_entryPoints.getCount(); + for (Index i = 0; i < entryPointCount; ++i) + { + auto entryPoint = m_entryPoints[i]; + auto& entryPointInfo = getLayout()->getEntryPoint(i); + + SLANG_RETURN_ON_FAIL(entryPoint->_bindIntoDescriptorSet( + descriptorSets[0], entryPointInfo.rangeOffset, 0)); + } + + return SLANG_OK; + } + + Result init(Renderer* renderer, GraphicsCommonProgramLayout* layout) + { + SLANG_RETURN_ON_FAIL(Super::init(renderer, layout)); + + for (auto entryPointInfo : layout->getEntryPoints()) + { + RefPtr<EntryPointVars> entryPoint; + SLANG_RETURN_ON_FAIL( + EntryPointVars::create(renderer, entryPointInfo.layout, entryPoint.writeRef())); + m_entryPoints.add(entryPoint); + } + + return SLANG_OK; + } + + List<RefPtr<EntryPointVars>> m_entryPoints; +}; + + +Result GraphicsAPIRenderer::createShaderObjectLayout( + slang::TypeLayoutReflection* typeLayout, ShaderObjectLayout** outLayout) +{ + RefPtr<GraphicsCommonShaderObjectLayout> layout; + SLANG_RETURN_ON_FAIL(GraphicsCommonShaderObjectLayout::createForElementType( + this, typeLayout, layout.writeRef())); + *outLayout = layout.detach(); + return SLANG_OK; +} + +Result GraphicsAPIRenderer::createShaderObject(ShaderObjectLayout* layout, ShaderObject** outObject) +{ + RefPtr<GraphicsCommonShaderObject> shaderObject; + SLANG_RETURN_ON_FAIL(GraphicsCommonShaderObject::create(this, + reinterpret_cast<GraphicsCommonShaderObjectLayout*>(layout), shaderObject.writeRef())); + *outObject = shaderObject.detach(); + return SLANG_OK; +} + +Result GraphicsAPIRenderer::createRootShaderObject( + ShaderObjectLayout* rootLayout, ShaderObject** outObject) +{ + RefPtr<ProgramVars> shaderObject; + SLANG_RETURN_ON_FAIL(ProgramVars::create(this, + dynamic_cast<GraphicsCommonProgramLayout*>(rootLayout), + shaderObject.writeRef())); + *outObject = shaderObject.detach(); + return SLANG_OK; +} + +Result GraphicsAPIRenderer::createRootShaderObjectLayout( + slang::ProgramLayout* layout, ShaderObjectLayout** outLayout) +{ + RefPtr<GraphicsCommonProgramLayout> programLayout; + auto slangReflection = layout; + { + GraphicsCommonProgramLayout::Builder builder(this); + builder.addGlobalParams(slangReflection->getGlobalParamsVarLayout()); + + // TODO: Also need to reflect entry points here. + + SlangInt entryPointCount = slangReflection->getEntryPointCount(); + for (SlangInt e = 0; e < entryPointCount; ++e) + { + auto slangEntryPoint = slangReflection->getEntryPointByIndex(e); + + EntryPointLayout::Builder entryPointBuilder(this); + entryPointBuilder.addEntryPointParams(slangEntryPoint); + + RefPtr<EntryPointLayout> entryPointLayout; + SLANG_RETURN_ON_FAIL(entryPointBuilder.build(entryPointLayout.writeRef())); + + builder.addEntryPoint(entryPointLayout); + } + + SLANG_RETURN_ON_FAIL(builder.build(programLayout.writeRef())); + } + *outLayout = programLayout.detach(); + return SLANG_OK; +} + +Result GraphicsAPIRenderer::bindRootShaderObject(PipelineType pipelineType, ShaderObject* object) +{ + auto programVars = dynamic_cast<ProgramVars*>(object); + if (!programVars) + return SLANG_E_INVALID_HANDLE; + + programVars->apply(this, pipelineType); + return SLANG_OK; +} + +void GraphicsAPIRenderer::preparePipelineDesc(GraphicsPipelineStateDesc& desc) +{ + if (desc.rootShaderObjectLayout) + { + auto rootLayout = dynamic_cast<GraphicsCommonProgramLayout*>(desc.rootShaderObjectLayout); + desc.renderTargetCount = rootLayout->getRenderTargetCount(); + desc.pipelineLayout = rootLayout->getPipelineLayout(); + } +} + +void GraphicsAPIRenderer::preparePipelineDesc(ComputePipelineStateDesc& desc) +{ + if (desc.rootShaderObjectLayout) + { + auto rootLayout = dynamic_cast<GraphicsCommonProgramLayout*>(desc.rootShaderObjectLayout); + desc.pipelineLayout = rootLayout->getPipelineLayout(); + } +} + +} diff --git a/tools/gfx/render-graphics-common.h b/tools/gfx/render-graphics-common.h new file mode 100644 index 000000000..5bb4cb59e --- /dev/null +++ b/tools/gfx/render-graphics-common.h @@ -0,0 +1,22 @@ +#pragma once + +#include "tools/gfx/render.h" + +namespace gfx +{ + +class GraphicsAPIRenderer : public Renderer +{ +public: + virtual Result createShaderObjectLayout( + slang::TypeLayoutReflection* typeLayout, ShaderObjectLayout** outLayout) SLANG_OVERRIDE; + virtual Result createRootShaderObjectLayout( + slang::ProgramLayout* programLayout, ShaderObjectLayout** outLayout) SLANG_OVERRIDE; + virtual Result createShaderObject(ShaderObjectLayout* layout, ShaderObject** outObject) SLANG_OVERRIDE; + virtual Result createRootShaderObject(ShaderObjectLayout* rootLayout, ShaderObject** outObject) SLANG_OVERRIDE; + virtual Result bindRootShaderObject(PipelineType pipelineType, ShaderObject* object) SLANG_OVERRIDE; + void preparePipelineDesc(GraphicsPipelineStateDesc& desc); + void preparePipelineDesc(ComputePipelineStateDesc& desc); +}; + +} diff --git a/tools/gfx/render.h b/tools/gfx/render.h index 5ad338594..fb9e10724 100644 --- a/tools/gfx/render.h +++ b/tools/gfx/render.h @@ -634,6 +634,38 @@ public: void const* data) = 0; }; +struct ShaderOffset +{ + SlangInt uniformOffset = 0; + SlangInt bindingRangeIndex = 0; + SlangInt bindingArrayIndex = 0; +}; + +class ShaderObjectLayout : public Slang::RefObject +{}; + +class ShaderObject : public Slang::RefObject +{ +public: + ShaderObject* getObject(ShaderOffset const& offset) + { + ShaderObject* object = nullptr; + SLANG_RETURN_NULL_ON_FAIL(getObject(offset, &object)); + return object; + } + + virtual slang::TypeLayoutReflection* getElementTypeLayout() = 0; + virtual Slang::Index getEntryPointCount() = 0; + virtual ShaderObject* getEntryPoint(Slang::Index index) = 0; + virtual SlangResult setData(ShaderOffset const& offset, void const* data, size_t size) = 0; + virtual SlangResult getObject(ShaderOffset const& offset, ShaderObject** object) = 0; + virtual SlangResult setObject(ShaderOffset const& offset, ShaderObject* object) = 0; + virtual SlangResult setResource(ShaderOffset const& offset, ResourceView* resourceView) = 0; + virtual SlangResult setSampler(ShaderOffset const& offset, SamplerState* sampler) = 0; + virtual SlangResult setCombinedTextureSampler( + ShaderOffset const& offset, ResourceView* textureView, SamplerState* sampler) = 0; +}; + enum class StencilOp : uint8_t { Keep, @@ -779,11 +811,14 @@ struct BlendDesc struct GraphicsPipelineStateDesc { ShaderProgram* program; - PipelineLayout* pipelineLayout; + // Application should set either pipelineLayout or rootShaderObjectLayout, but not both. + PipelineLayout* pipelineLayout = nullptr; + // Application should set either pipelineLayout or rootShaderObjectLayout, but not both. + ShaderObjectLayout* rootShaderObjectLayout = nullptr; InputLayout* inputLayout; UInt framebufferWidth; UInt framebufferHeight; - UInt renderTargetCount; + UInt renderTargetCount = 0; // Not used if rootShaderObjectLayout is set. DepthStencilDesc depthStencil; RasterizerDesc rasterizer; BlendDesc blend; @@ -792,7 +827,8 @@ struct GraphicsPipelineStateDesc struct ComputePipelineStateDesc { ShaderProgram* program; - PipelineLayout* pipelineLayout; + PipelineLayout* pipelineLayout = nullptr; + ShaderObjectLayout* rootShaderObjectLayout = nullptr; }; class PipelineState : public Slang::RefObject @@ -910,6 +946,45 @@ public: return layout; } + virtual Result createShaderObjectLayout( + slang::TypeLayoutReflection* typeLayout, ShaderObjectLayout** outLayout) = 0; + + inline RefPtr<ShaderObjectLayout> createShaderObjectLayout(slang::TypeLayoutReflection* typeLayout) + { + RefPtr<ShaderObjectLayout> layout; + SLANG_RETURN_NULL_ON_FAIL(createShaderObjectLayout(typeLayout, layout.writeRef())); + return layout; + } + + virtual Result createRootShaderObjectLayout(slang::ProgramLayout* layout, ShaderObjectLayout** outLayout) = 0; + + inline RefPtr<ShaderObjectLayout> createRootShaderObjectLayout(slang::ProgramLayout* layout) + { + RefPtr<ShaderObjectLayout> result; + SLANG_RETURN_NULL_ON_FAIL(createRootShaderObjectLayout(layout, result.writeRef())); + return result; + } + + virtual Result createShaderObject(ShaderObjectLayout* layout, ShaderObject** outObject) = 0; + + inline RefPtr<ShaderObject> createShaderObject(ShaderObjectLayout* layout) + { + RefPtr<ShaderObject> object; + SLANG_RETURN_NULL_ON_FAIL(createShaderObject(layout, object.writeRef())); + return object; + } + + virtual Result createRootShaderObject(ShaderObjectLayout* layout, ShaderObject** outObject) = 0; + + inline RefPtr<ShaderObject> createRootShaderObject(ShaderObjectLayout* layout) + { + RefPtr<ShaderObject> object; + SLANG_RETURN_NULL_ON_FAIL(createRootShaderObject(layout, object.writeRef())); + return object; + } + + virtual Result bindRootShaderObject(PipelineType pipelineType, ShaderObject* object) = 0; + virtual Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) = 0; inline RefPtr<PipelineLayout> createPipelineLayout(const PipelineLayout::Desc& desc) diff --git a/tools/gfx/shader-cursor.cpp b/tools/gfx/shader-cursor.cpp new file mode 100644 index 000000000..c4a9ac607 --- /dev/null +++ b/tools/gfx/shader-cursor.cpp @@ -0,0 +1,249 @@ +#include "shader-cursor.h" + +namespace gfx +{ + +Result gfx::ShaderCursor::getDereferenced(ShaderCursor& outCursor) const +{ + switch (m_typeLayout->getKind()) + { + default: + return SLANG_E_INVALID_ARG; + + case slang::TypeReflection::Kind::ConstantBuffer: + case slang::TypeReflection::Kind::ParameterBlock: + { + ShaderObject* subObject = m_baseObject->getObject(m_offset); + outCursor = ShaderCursor(subObject); + return SLANG_OK; + } + } +} + +Result ShaderCursor::getField(Slang::UnownedStringSlice const& name, ShaderCursor& outCursor) +{ + // If this cursor is invalid, then can't possible fetch a field. + // + if (!isValid()) + return SLANG_E_INVALID_ARG; + + // If the cursor is valid, we want to consider the type of data + // it is referencing. + // + switch (m_typeLayout->getKind()) + { + // The easy/expected case is when the value has a structure type. + // + case slang::TypeReflection::Kind::Struct: + { + // We start by looking up the index of a field matching `name`. + // + // If there is no such field, we have an error. + // + SlangInt fieldIndex = m_typeLayout->findFieldIndexByName(name.begin(), name.end()); + if (fieldIndex == -1) + return SLANG_E_INVALID_ARG; + + // Once we know the index of the field being referenced, + // we create a cursor to point at the field, based on + // the offset information already in this cursor, plus + // offsets derived from the field's layout. + // + slang::VariableLayoutReflection* fieldLayout = + m_typeLayout->getFieldByIndex((unsigned int)fieldIndex); + ShaderCursor fieldCursor; + + // The field cursorwill point into the same parent object. + // + fieldCursor.m_baseObject = m_baseObject; + + // The type being pointed to is the tyep of the field. + // + fieldCursor.m_typeLayout = fieldLayout->getTypeLayout(); + + // The byte offset is the current offset plus the relative offset of the field. + // The offset in binding ranges is computed similarly. + // + fieldCursor.m_offset.uniformOffset = m_offset.uniformOffset + fieldLayout->getOffset(); + fieldCursor.m_offset.bindingRangeIndex = + m_offset.bindingRangeIndex + m_typeLayout->getFieldBindingRangeOffset(fieldIndex); + + // The index of the field within any binding ranges will be the same + // as the index computed for the parent structure. + // + // Note: this case would arise for an array of structures with texture-type + // fields. Suppose we have: + // + // struct S { Texture2D t; Texture2D u; } + // S g[4]; + // + // In this scenario, `g` holds two binding ranges: + // + // * Range #0 comprises 4 textures, representing `g[...].t` + // * Range #1 comprises 4 textures, representing `g[...].u` + // + // A cursor for `g[2]` would have a `bindingRangeIndex` of zero but + // a `bindingArrayIndex` of 2, iindicating that we could end up + // referencing either range, but no matter what we know the index + // is 2. Thus when we form a cursor for `g[2].u` we want to + // apply the binding range offset to get a `bindingRangeIndex` of + // 1, while the `bindingArrayIndex` is unmodified. + // + // The result is that `g[2].u` is stored in range #1 at array index 2. + // + fieldCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex; + + outCursor = fieldCursor; + return SLANG_OK; + } + break; + + // In some cases the user might be trying to acess a field by name + // from a cursor that references a constant buffer or parameter block, + // and in these cases we want the access to Just Work. + // + case slang::TypeReflection::Kind::ConstantBuffer: + case slang::TypeReflection::Kind::ParameterBlock: + { + // We basically need to "dereference" the current cursor + // to go from a pointer to a constant buffer to a pointer + // to the *contents* of the constant buffer. + // + ShaderCursor d = getDereferenced(); + return d.getField(name, outCursor); + } + break; + } + + return SLANG_E_INVALID_ARG; +} + +ShaderCursor ShaderCursor::getElement(Slang::Index index) +{ + // TODO: need to auto-dereference various buffer types... + + if (m_typeLayout->getKind() == slang::TypeReflection::Kind::Array) + { + ShaderCursor elementCursor; + elementCursor.m_baseObject = m_baseObject; + elementCursor.m_typeLayout = m_typeLayout->getElementTypeLayout(); + elementCursor.m_offset.uniformOffset = + m_offset.uniformOffset + + index * m_typeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM); + elementCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex; + elementCursor.m_offset.bindingArrayIndex = + m_offset.bindingArrayIndex * m_typeLayout->getElementCount() + index; + return elementCursor; + } + + return ShaderCursor(); +} + + +static int _peek(Slang::UnownedStringSlice const& slice) +{ + const char* b = slice.begin(); + const char* e = slice.end(); + if (b == e) + return -1; + return *b; +} + +static int _get(Slang::UnownedStringSlice& slice) +{ + const char* b = slice.begin(); + const char* e = slice.end(); + if (b == e) + return -1; + auto result = *b++; + slice = Slang::UnownedStringSlice(b, e); + return result; +} + +Result ShaderCursor::followPath(Slang::UnownedStringSlice const& path, ShaderCursor& ioCursor) +{ + ShaderCursor cursor = ioCursor; + + enum + { + ALLOW_NAME = 0x1, + ALLOW_SUBSCRIPT = 0x2, + ALLOW_DOT = 0x4, + }; + int state = ALLOW_NAME | ALLOW_SUBSCRIPT; + + Slang::UnownedStringSlice rest = path; + for (;;) + { + int c = _peek(rest); + + if (c == -1) + break; + else if (c == '.') + { + if (!(state & ALLOW_DOT)) + return SLANG_E_INVALID_ARG; + + _get(rest); + state = ALLOW_NAME; + continue; + } + else if (c == '[') + { + if (!(state & ALLOW_SUBSCRIPT)) + return SLANG_E_INVALID_ARG; + + _get(rest); + Slang::Index index = 0; + while (_peek(rest) != ']') + { + int d = _get(rest); + if (d >= '0' && d <= '9') + { + index = index * 10 + (d - '0'); + } + else + { + return SLANG_E_INVALID_ARG; + } + } + + if (_peek(rest) != ']') + return SLANG_E_INVALID_ARG; + _get(rest); + + cursor = cursor.getElement(index); + state = ALLOW_DOT | ALLOW_SUBSCRIPT; + continue; + } + else + { + const char* nameBegin = rest.begin(); + for (;;) + { + switch (_peek(rest)) + { + default: + _get(rest); + continue; + + case -1: + case '.': + case '[': + break; + } + break; + } + char const* nameEnd = rest.begin(); + Slang::UnownedStringSlice name(nameBegin, nameEnd); + cursor = cursor.getField(name); + state = ALLOW_DOT | ALLOW_SUBSCRIPT; + continue; + } + } + + ioCursor = cursor; + return SLANG_OK; +} + +} // namespace gfx diff --git a/tools/gfx/shader-cursor.h b/tools/gfx/shader-cursor.h new file mode 100644 index 000000000..8f48f3581 --- /dev/null +++ b/tools/gfx/shader-cursor.h @@ -0,0 +1,123 @@ +#pragma once + +#include "tools/gfx/render.h" +#include "core/slang-basic.h" + +namespace gfx +{ + +/// Represents a "pointer" to the storage for a shader parameter of a (dynamically) known type. +/// +/// A `ShaderCursor` serves as a pointer-like type for things stored inside a `ShaderObject`. +/// +/// A cursor that points to the entire content of a shader object can be formed as +/// `ShaderCursor(someObject)`. A cursor pointing to a structure field or array element can be +/// formed from another cursor using `getField` or `getElement` respectively. +/// +/// Given a cursor pointing to a value of some "primitive" type, we can set or get the value +/// using operations like `setResource`, `getResource`, etc. +/// +/// Because type information for shader parameters is being reflected dynamically, all type +/// checking for shader cursors occurs at runtime, and errors may occur when attempting to +/// set a parameter using a value of an inappropriate type. As much as possible, `ShaderCursor` +/// attempts to protect against these cases and return an error `Result` or an invalid +/// cursor, rather than allowing operations to proceed with incorrect types. +/// +struct ShaderCursor +{ + ShaderObject* m_baseObject = nullptr; + slang::TypeLayoutReflection* m_typeLayout = nullptr; + ShaderOffset m_offset; + + /// Get the type (layout) of the value being pointed at by the cursor + slang::TypeLayoutReflection* getTypeLayout() const { return m_typeLayout; } + + /// Is this cursor valid (that is, does it seem to point to an actual location)? + /// + /// This check is equivalent to checking whether a pointer is null, so it is + /// a very weak sense of "valid." In particular, it is possible to form a + /// `ShaderCursor` for which `isValid()` is true, but attempting to get or + /// set the value would be an error (like dereferencing a garbage pointer). + /// + bool isValid() const { return m_baseObject != nullptr; } + + Result getDereferenced(ShaderCursor& outCursor) const; + + ShaderCursor getDereferenced() + { + ShaderCursor result; + getDereferenced(result); + return result; + } + + /// Form a cursor pointing to the field with the given `name` within the value this cursor + /// points at. + /// + /// If the operation succeeds, then the field cursor is written to `outCursor`. + Result getField(Slang::UnownedStringSlice const& name, ShaderCursor& outCursor); + + ShaderCursor getField(Slang::UnownedStringSlice const& name) + { + ShaderCursor cursor; + getField(name, cursor); + return cursor; + } + + ShaderCursor getField(Slang::String const& name) { return getField(name.getUnownedSlice()); } + + ShaderCursor getElement(Slang::Index index); + + static Result followPath(Slang::UnownedStringSlice const& path, ShaderCursor& ioCursor); + + static Result followPath(Slang::String const& path, ShaderCursor& ioCursor) + { + return followPath(path.getUnownedSlice(), ioCursor); + } + + ShaderCursor getPath(Slang::UnownedStringSlice const& path) + { + ShaderCursor result(*this); + followPath(path, result); + return result; + } + + ShaderCursor getPath(Slang::String const& path) + { + ShaderCursor result(*this); + followPath(path, result); + return result; + } + + ShaderCursor() {} + + ShaderCursor(ShaderObject* object) + : m_baseObject(object) + , m_typeLayout(object->getElementTypeLayout()) + {} + + SlangResult setData(void const* data, size_t size) + { + return m_baseObject->setData(m_offset, data, size); + } + + SlangResult setObject(ShaderObject* object) + { + return m_baseObject->setObject(m_offset, object); + } + + SlangResult setResource(ResourceView* resourceView) + { + return m_baseObject->setResource(m_offset, resourceView); + } + + SlangResult setSampler(SamplerState* sampler) + { + return m_baseObject->setSampler(m_offset, sampler); + } + + SlangResult setCombinedTextureSampler(ResourceView* textureView, SamplerState* sampler) + { + return m_baseObject->setCombinedTextureSampler(m_offset, textureView, sampler); + } +}; +} diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index 6f2411f24..0f6e3cdaa 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -3,6 +3,7 @@ //WORKING:#include "options.h" #include "../render.h" +#include "../render-graphics-common.h" #include "../../source/core/slang-smart-pointer.h" @@ -29,7 +30,7 @@ namespace gfx { using namespace Slang; -class VKRenderer : public Renderer +class VKRenderer : public GraphicsAPIRenderer { public: enum @@ -2721,8 +2722,11 @@ Result VKRenderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram* return SLANG_OK; } -Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) +Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& inDesc, PipelineState** outState) { + GraphicsPipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + VkPipelineCache pipelineCache = VK_NULL_HANDLE; auto programImpl = (ShaderProgramImpl*) desc.program; @@ -2849,8 +2853,11 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& return SLANG_OK; } -Result VKRenderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) +Result VKRenderer::createComputePipelineState(const ComputePipelineStateDesc& inDesc, PipelineState** outState) { + ComputePipelineStateDesc desc = inDesc; + preparePipelineDesc(desc); + VkPipelineCache pipelineCache = VK_NULL_HANDLE; auto programImpl = (ShaderProgramImpl*) desc.program; diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 197ee2b46..5903c49f7 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -4,7 +4,7 @@ #include "options.h" #include "render.h" - +#include "shader-cursor.h" #include "slang-support.h" #include "surface.h" #include "png-serialize-util.h" @@ -165,1495 +165,13 @@ public: virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) override; protected: - RefPtr<ProgramVars> m_programVars; + RefPtr<ShaderObject> m_programVars; ShaderOutputPlan m_outputPlan; }; -struct ShaderOffset -{ - SlangInt uniformOffset = 0; - SlangInt bindingRangeIndex = 0; - SlangInt bindingArrayIndex = 0; -}; - -class ShaderObjectLayout : public RefObject -{ -public: - struct BindingRangeInfo - { - slang::BindingType bindingType; - Index count; - Index baseIndex; - Index descriptorSetIndex; - Index rangeIndexInDescriptorSet; -// Index subObjectRangeIndex = -1; - }; - - struct SubObjectRangeInfo - { - RefPtr<ShaderObjectLayout> layout; -// Index baseIndex; -// Index count; - Index bindingRangeIndex; - }; - - struct DescriptorSetInfo : public RefObject - { - RefPtr<DescriptorSetLayout> layout; - Slang::Int space = -1; - }; - - struct Builder - { - public: - Builder(Renderer* renderer) - : m_renderer(renderer) - {} - - List<BindingRangeInfo> m_bindingRanges; - List<SubObjectRangeInfo> m_subObjectRanges; - - Index m_resourceViewCount = 0; - Index m_samplerCount = 0; - Index m_combinedTextureSamplerCount = 0; - Index m_subObjectCount = 0; - Index m_varyingInputCount = 0; - Index m_varyingOutputCount = 0; - - struct DescriptorSetBuildInfo : public RefObject - { - List<DescriptorSetLayout::SlotRangeDesc> slotRangeDescs; - Index space; - }; - List<RefPtr<DescriptorSetBuildInfo>> m_descriptorSetBuildInfos; - Dictionary<Index, Index> m_mapSpaceToDescriptorSetIndex; - - Index findOrAddDescriptorSet(Index space) - { - Index index; - if(m_mapSpaceToDescriptorSetIndex.TryGetValue(space, index)) - return index; - - RefPtr<DescriptorSetBuildInfo> info = new DescriptorSetBuildInfo(); - info->space = space; - - index = m_descriptorSetBuildInfos.getCount(); - m_descriptorSetBuildInfos.add(info); - - m_mapSpaceToDescriptorSetIndex.Add(space, index); - return index; - } - - static DescriptorSlotType _mapDescriptorType(slang::BindingType slangBindingType) - { - switch(slangBindingType) - { - default: return DescriptorSlotType::Unknown; - - #define CASE(FROM, TO) \ - case slang::BindingType::FROM: return DescriptorSlotType::TO - - CASE(Sampler, Sampler); - CASE(CombinedTextureSampler, CombinedImageSampler); - CASE(Texture, SampledImage); - CASE(MutableTexture, StorageImage); - CASE(TypedBuffer, UniformTexelBuffer); - CASE(MutableTypedBuffer, StorageTexelBuffer); - CASE(RawBuffer, UniformBuffer); - CASE(MutableRawBuffer, StorageBuffer); - CASE(InputRenderTarget, InputAttachment); - CASE(InlineUniformData, InlineUniformBlock); - CASE(RayTracingAccelerationStructure, RayTracingAccelerationStructure); - CASE(ConstantBuffer, UniformBuffer); - CASE(PushConstant, RootConstant); - - #undef CASE - } - } - - slang::TypeLayoutReflection* unwrapParameterGroups(slang::TypeLayoutReflection* typeLayout) - { - for(;;) - { - if(!typeLayout->getType()) - { - if(auto elementTypeLayout = typeLayout->getElementTypeLayout()) - typeLayout = elementTypeLayout; - } - - switch(typeLayout->getKind()) - { - default: - return typeLayout; - - case slang::TypeReflection::Kind::ConstantBuffer: - case slang::TypeReflection::Kind::ParameterBlock: - typeLayout = typeLayout->getElementTypeLayout(); - continue; - } - } - } - - void _addDescriptorSets(slang::TypeLayoutReflection* typeLayout, slang::VariableLayoutReflection* varLayout = nullptr) - { - SlangInt descriptorSetCount = typeLayout->getDescriptorSetCount(); - for(SlangInt s = 0; s < descriptorSetCount; ++s) - { - auto descriptorSetIndex = findOrAddDescriptorSet(typeLayout->getDescriptorSetSpaceOffset(s)); - auto descriptorSetInfo = m_descriptorSetBuildInfos[descriptorSetIndex]; - - SlangInt descriptorRangeCount = typeLayout->getDescriptorSetDescriptorRangeCount(s); - for(SlangInt r = 0; r < descriptorRangeCount; ++r) - { - auto slangBindingType = typeLayout->getDescriptorSetDescriptorRangeType(s, r); - auto gfxDescriptorType = _mapDescriptorType(slangBindingType); - - DescriptorSetLayout::SlotRangeDesc descriptorRangeDesc; - descriptorRangeDesc.binding = typeLayout->getDescriptorSetDescriptorRangeIndexOffset(s, r); - descriptorRangeDesc.count = typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(s, r); - descriptorRangeDesc.type = gfxDescriptorType; - - if(varLayout) - { - auto category = typeLayout->getDescriptorSetDescriptorRangeCategory(s, r); - descriptorRangeDesc.binding += varLayout->getOffset(category); - } - - descriptorSetInfo->slotRangeDescs.add(descriptorRangeDesc); - } - } - } - - Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout) - { - typeLayout = unwrapParameterGroups(typeLayout); - - m_elementTypeLayout = typeLayout; - - // First we will use the Slang layout information to allocate - // the descriptor set layout(s) required to store values - // of the given type. - // - _addDescriptorSets(typeLayout); - - // Next we will compute the binding ranges that are used to store - // the logical contents of the object in memory. These will relate - // to the descriptor ranges in the various sets, but not always - // in a one-to-one fashion. - - SlangInt bindingRangeCount = typeLayout->getBindingRangeCount(); - for(SlangInt r = 0; r < bindingRangeCount; ++r) - { - slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r); - SlangInt count = typeLayout->getBindingRangeBindingCount(r); - slang::TypeLayoutReflection* slangLeafTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(r); - - SlangInt descriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(r); - SlangInt rangeIndexInDescriptorSet = typeLayout->getBindingRangeFirstDescriptorRangeIndex(r); - - Index baseIndex = 0; - switch(slangBindingType) - { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - case slang::BindingType::ExistentialValue: - baseIndex = m_subObjectCount; - m_subObjectCount += count; - break; - - case slang::BindingType::Sampler: - baseIndex = m_samplerCount; - m_samplerCount += count; - break; - - case slang::BindingType::CombinedTextureSampler: - baseIndex = m_combinedTextureSamplerCount; - m_combinedTextureSamplerCount += count; - break; - - case slang::BindingType::VaryingInput: - baseIndex = m_varyingInputCount; - m_varyingInputCount += count; - break; - - case slang::BindingType::VaryingOutput: - baseIndex = m_varyingOutputCount; - m_varyingOutputCount += count; - break; - - default: - baseIndex = m_resourceViewCount; - m_resourceViewCount += count; - break; - } - - BindingRangeInfo bindingRangeInfo; - bindingRangeInfo.bindingType = slangBindingType; - bindingRangeInfo.count = count; -// bindingRangeInfo.descriptorSetIndex = descriptorSetIndex; -// bindingRangeInfo.rangeIndexInDescriptorSet = slotRangeIndex; -// bindingRangeInfo.subObjectRangeIndex = subObjectRangeIndex; - bindingRangeInfo.baseIndex = baseIndex; - bindingRangeInfo.descriptorSetIndex = descriptorSetIndex; - bindingRangeInfo.rangeIndexInDescriptorSet = rangeIndexInDescriptorSet; - - m_bindingRanges.add(bindingRangeInfo); - -#if 0 - SlangInt binding = typeLayout->getBindingRangeIndexOffset(r); - SlangInt space = typeLayout->getBindingRangeSpaceOffset(r); - SlangInt subObjectRangeIndex = typeLayout->getBindingRangeSubObjectRangeIndex(r); - - DescriptorSetLayout::SlotRangeDesc slotRange; - slotRange.type = _mapDescriptorType(slangBindingType); - slotRange.count = count; - slotRange.binding = binding; - - Index descriptorSetIndex = findOrAddDescriptorSet(space); - RefPtr<DescriptorSetBuildInfo> descriptorSetInfo = m_descriptorSetInfos[descriptorSetIndex]; - - Index slotRangeIndex = descriptorSetInfo->slotRanges.getCount(); - descriptorSetInfo->slotRanges.add(slotRange); -#endif - } - - SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount(); - for(SlangInt r = 0; r < subObjectRangeCount; ++r) - { - SlangInt bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(r); - auto slangBindingType = typeLayout->getBindingRangeType(bindingRangeIndex); - slang::TypeLayoutReflection* slangLeafTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); - - // A sub-object range can either represent a sub-object of a known - // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>` - // (in which case we can pre-compute a layout to use, based on - // the type `Foo`) *or* it can represent a sub-object of some - // existential type (e.g., `IBar`) in which case we cannot - // know the appropraite type/layout of sub-object to allocate. - // - RefPtr<ShaderObjectLayout> subObjectLayout; - if(slangBindingType != slang::BindingType::ExistentialValue) - { - ShaderObjectLayout::createForElementType(m_renderer, slangLeafTypeLayout->getElementTypeLayout(), subObjectLayout.writeRef()); - } - - SubObjectRangeInfo subObjectRange; - subObjectRange.bindingRangeIndex = bindingRangeIndex; - subObjectRange.layout = subObjectLayout; - - m_subObjectRanges.add(subObjectRange); - } - -#if 0 - SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount(); - for(SlangInt r = 0; r < subObjectRangeCount; ++r) - { - - // TODO: Still need a way to map the binding ranges for - // the sub-object over so that they can be used to - // set/get the sub-object as needed. - } -#endif - return SLANG_OK; - } - - SlangResult build(ShaderObjectLayout** outLayout) - { - RefPtr<ShaderObjectLayout> layout = new ShaderObjectLayout(); - SLANG_RETURN_ON_FAIL(layout->_init(this)); - - *outLayout = layout.detach(); - return SLANG_OK; - } - - Renderer* m_renderer = nullptr; - slang::TypeLayoutReflection* m_elementTypeLayout = nullptr; - }; - - static Result createForElementType(Renderer* renderer, slang::TypeLayoutReflection* elementType, ShaderObjectLayout** outLayout) - { - Builder builder(renderer); - builder.setElementTypeLayout(elementType); - return builder.build(outLayout); - } - - List<RefPtr<DescriptorSetInfo>> const& getDescriptorSets() { return m_descriptorSets; } - - List<BindingRangeInfo> const& getBindingRanges() { return m_bindingRanges; } - - Index getBindingRangeCount() { return m_bindingRanges.getCount(); } - - BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; } - - slang::TypeLayoutReflection* getElementTypeLayout() - { - return m_elementTypeLayout; - } - - Index getResourceViewCount() { return m_resourceViewCount; } - Index getSamplerCount() { return m_samplerCount; } - Index getCombinedTextureSamplerCount() { return m_combinedTextureSamplerCount; } - Index getSubObjectCount() { return m_subObjectCount; } - - SubObjectRangeInfo const& getSubObjectRange(Index index) { return m_subObjectRanges[index]; } - List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; } - - Renderer* getRenderer() - { - return m_renderer; - } - -protected: - Result _init(Builder const* builder) - { - auto renderer = builder->m_renderer; - m_renderer = renderer; - - m_elementTypeLayout = builder->m_elementTypeLayout; - m_bindingRanges = builder->m_bindingRanges; - - for(auto descriptorSetBuildInfo : builder->m_descriptorSetBuildInfos) - { - auto& slotRangeDescs = descriptorSetBuildInfo->slotRangeDescs; - DescriptorSetLayout::Desc desc; - desc.slotRangeCount = slotRangeDescs.getCount(); - desc.slotRanges = slotRangeDescs.getBuffer(); - - RefPtr<DescriptorSetLayout> descriptorSetLayout; - SLANG_RETURN_ON_FAIL(m_renderer->createDescriptorSetLayout(desc, descriptorSetLayout.writeRef())); - - RefPtr<DescriptorSetInfo> descriptorSetInfo = new DescriptorSetInfo(); - descriptorSetInfo->layout = descriptorSetLayout; - descriptorSetInfo->space = descriptorSetBuildInfo->space; - - m_descriptorSets.add(descriptorSetInfo); - } - - m_resourceViewCount = builder->m_resourceViewCount; - m_samplerCount = builder->m_samplerCount; - m_combinedTextureSamplerCount = builder->m_combinedTextureSamplerCount; - m_subObjectCount = builder->m_subObjectCount; - - m_subObjectRanges = builder->m_subObjectRanges; - - return SLANG_OK; - } - - Renderer* m_renderer; - List<RefPtr<DescriptorSetInfo>> m_descriptorSets; - List<BindingRangeInfo> m_bindingRanges; - slang::TypeLayoutReflection* m_elementTypeLayout; - Index m_resourceViewCount = 0; - Index m_samplerCount = 0; - Index m_combinedTextureSamplerCount = 0; - Index m_subObjectCount = 0; - List<SubObjectRangeInfo> m_subObjectRanges; -}; - -class EntryPointLayout : public ShaderObjectLayout -{ - typedef ShaderObjectLayout Super; -public: - - struct VaryingInputInfo - { - }; - - struct VaryingOutputInfo - { - }; - - struct Builder : Super::Builder - { - Builder(Renderer* renderer) - : Super::Builder(renderer) - {} - - Result build(EntryPointLayout** outLayout) - { - RefPtr<EntryPointLayout> layout = new EntryPointLayout(); - SLANG_RETURN_ON_FAIL(layout->_init(this)); - - *outLayout = layout.detach(); - return SLANG_OK; - } - - void _addEntryPointParam(slang::VariableLayoutReflection* entryPointParam) - { - auto slangStage = entryPointParam->getStage(); - auto typeLayout = entryPointParam->getTypeLayout(); - - SlangInt bindingRangeCount = typeLayout->getBindingRangeCount(); - for(SlangInt r = 0; r < bindingRangeCount; ++r) - { - slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r); - SlangInt count = typeLayout->getBindingRangeBindingCount(r); - - switch(slangBindingType) - { - default: - break; - - case slang::BindingType::VaryingInput: - { - VaryingInputInfo info; - - m_varyingInputs.add(info); - } - break; - - case slang::BindingType::VaryingOutput: - { - VaryingOutputInfo info; - m_varyingOutputs.add(info); - } - break; - } - } - } - - void addEntryPointParams(slang::EntryPointLayout* entryPointLayout) - { - m_slangEntryPointLayout = entryPointLayout; - - setElementTypeLayout(entryPointLayout->getTypeLayout()); - - m_stage = translateStage(entryPointLayout->getStage()); - _addEntryPointParam(entryPointLayout->getVarLayout()); - _addEntryPointParam(entryPointLayout->getResultVarLayout()); - } - - slang::EntryPointLayout* m_slangEntryPointLayout = nullptr; - - gfx::StageType m_stage; - List<VaryingInputInfo> m_varyingInputs; - List<VaryingOutputInfo> m_varyingOutputs; - }; - - Result _init(Builder const* builder) - { - auto renderer = builder->m_renderer; - - SLANG_RETURN_ON_FAIL(Super::_init(builder)); - - m_slangEntryPointLayout = builder->m_slangEntryPointLayout; - m_stage = builder->m_stage; - m_varyingInputs = builder->m_varyingInputs; - m_varyingOutputs = builder->m_varyingOutputs; - - return SLANG_OK; - } - - List<VaryingInputInfo> const& getVaryingInputs() { return m_varyingInputs; } - List<VaryingOutputInfo> const& getVaryingOutputs() { return m_varyingOutputs; } - - gfx::StageType getStage() const { return m_stage; } - - slang::EntryPointLayout* getSlangLayout() const { return m_slangEntryPointLayout; }; - - slang::EntryPointLayout* m_slangEntryPointLayout; - gfx::StageType m_stage; - List<VaryingInputInfo> m_varyingInputs; - List<VaryingOutputInfo> m_varyingOutputs; -}; - -class ProgramLayout : public ShaderObjectLayout -{ - typedef ShaderObjectLayout Super; -public: - - struct EntryPointInfo - { - RefPtr<EntryPointLayout> layout; - Index rangeOffset; - }; - - - struct Builder : Super::Builder - { - Builder(Renderer* renderer) - : Super::Builder(renderer) - {} - - Result build(ProgramLayout** outLayout) - { - RefPtr<ProgramLayout> layout = new ProgramLayout(); - SLANG_RETURN_ON_FAIL(layout->_init(this)); - - *outLayout = layout.detach(); - return SLANG_OK; - } - - void addGlobalParams(slang::VariableLayoutReflection* globalsLayout) - { - setElementTypeLayout(globalsLayout->getTypeLayout()); - } - - void addEntryPoint(EntryPointLayout* entryPointLayout) - { - EntryPointInfo info; - info.layout = entryPointLayout; - - if(m_descriptorSetBuildInfos.getCount()) - { - info.rangeOffset = m_descriptorSetBuildInfos[0]->slotRangeDescs.getCount(); - } - - auto slangEntryPointLayout = entryPointLayout->getSlangLayout(); - _addDescriptorSets(slangEntryPointLayout->getTypeLayout(), slangEntryPointLayout->getVarLayout()); - - m_entryPoints.add(info); - } - - List<EntryPointInfo> m_entryPoints; - }; - - Slang::Int getRenderTargetCount() - { - return m_renderTargetCount; - } - - PipelineLayout* getPipelineLayout() { return m_pipelineLayout; } - - Index findEntryPointIndex(gfx::StageType stage) - { - auto entryPointCount = m_entryPoints.getCount(); - for(Index i = 0; i < entryPointCount; ++i) - { - auto entryPoint = m_entryPoints[i]; - if(entryPoint.layout->getStage() == stage) - return i; - } - return -1; - } - - EntryPointInfo const& getEntryPoint(Index index) - { - return m_entryPoints[index]; - } - - List<EntryPointInfo> const& getEntryPoints() const { return m_entryPoints; } - -protected: - Result _init(Builder const* builder) - { - auto renderer = builder->m_renderer; - - SLANG_RETURN_ON_FAIL(Super::_init(builder)); - - m_entryPoints = builder->m_entryPoints; - - List<PipelineLayout::DescriptorSetDesc> pipelineDescriptorSets; - _addDescriptorSetsRec(this, pipelineDescriptorSets); - -#if 0 - _createInputLayout(builder); -#endif - - auto fragmentEntryPointIndex = findEntryPointIndex(gfx::StageType::Fragment); - if(fragmentEntryPointIndex != -1) - { - auto fragmentEntryPoint = getEntryPoint(fragmentEntryPointIndex); - m_renderTargetCount = fragmentEntryPoint.layout->getVaryingOutputs().getCount(); - } - - PipelineLayout::Desc pipelineLayoutDesc; - pipelineLayoutDesc.renderTargetCount = m_renderTargetCount; - pipelineLayoutDesc.descriptorSetCount = pipelineDescriptorSets.getCount(); - pipelineLayoutDesc.descriptorSets = pipelineDescriptorSets.getBuffer(); - - SLANG_RETURN_ON_FAIL(renderer->createPipelineLayout(pipelineLayoutDesc, m_pipelineLayout.writeRef())); - - return SLANG_OK; - } - - static void _addDescriptorSetsRec(ShaderObjectLayout* layout, List<PipelineLayout::DescriptorSetDesc>& ioPipelineDescriptorSets) - { - for(auto descriptorSetInfo : layout->getDescriptorSets()) - { - PipelineLayout::DescriptorSetDesc pipelineDescriptorSet; - pipelineDescriptorSet.layout = descriptorSetInfo->layout; - pipelineDescriptorSet.space = descriptorSetInfo->space; - - ioPipelineDescriptorSets.add(pipelineDescriptorSet); - } - - // TODO: next we need to recurse into the "sub-objects" of `layout` and - // add their descriptor sets as well. - } - -#if 0 - Result _createInputLayout(Builder const* builder) - { - auto renderer = builder->m_renderer; - - List<InputElementDesc> const& inputElements = builder->getInputElements(); - SLANG_RETURN_ON_FAIL(renderer->createInputLayout(inputElements.getBuffer(), inputElements.getCount(), m_inputLayout.writeRef())); - - return SLANG_OK; - } -#endif - - List<EntryPointInfo> m_entryPoints; - gfx::UInt m_renderTargetCount = 0; - - RefPtr<PipelineLayout> m_pipelineLayout; -}; - -class ShaderObject : public RefObject -{ -public: - static Result create(Renderer* renderer, ShaderObjectLayout* layout, ShaderObject** outShaderObject) - { - RefPtr<ShaderObject> object = new ShaderObject(); - SLANG_RETURN_ON_FAIL(object->init(renderer, layout)); - - *outShaderObject = object.detach(); - return SLANG_OK; - } - - Renderer* getRenderer() - { - return m_layout->getRenderer(); - } - - ShaderObjectLayout* getLayout() - { - return m_layout; - } - - slang::TypeLayoutReflection* getElementTypeLayout() - { - return m_layout->getElementTypeLayout(); - } - - SlangResult setData(ShaderOffset const& offset, void const* data, size_t size) - { - Renderer* renderer = getRenderer(); - - char* dest = (char*) renderer->map(m_buffer, MapFlavor::HostWrite); - memcpy(dest + offset.uniformOffset, data, size); - renderer->unmap(m_buffer); - - return SLANG_OK; - } - - SlangResult setObject(ShaderOffset const& offset, ShaderObject* object) - { - if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG; - if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG; - auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); - - // TODO: Is this reasonable to store the base index directly in the binding range? - m_objects[bindingRange.baseIndex + offset.bindingArrayIndex] = object; - -// auto& subObjectRange = m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex); -// m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex] = object; - -#if 0 - - SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0); - SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount()); - auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex]; - - descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer); - return SLANG_OK; -#else - return SLANG_E_NOT_IMPLEMENTED; -#endif - } - - SlangResult getObject(ShaderOffset const& offset, ShaderObject** outObject) - { - SLANG_ASSERT(outObject); - if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG; - if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG; - auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); - - *outObject = m_objects[bindingRange.baseIndex + offset.bindingArrayIndex]; - -// auto& subObjectRange = m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex); -// *outObject = m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex]; - - return SLANG_OK; - -#if 0 - SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0); - SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount()); - auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex]; - - descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer); - return SLANG_OK; -#endif - } - - ShaderObject* getObject(ShaderOffset const& offset) - { - ShaderObject* object = nullptr; - SLANG_RETURN_NULL_ON_FAIL(getObject(offset, &object)); - return object; - } - - SlangResult setResource(ShaderOffset const& offset, ResourceView* resourceView) - { - if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG; - if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG; - auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); - - m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = resourceView; - return SLANG_OK; - } - - SlangResult setSampler(ShaderOffset const& offset, SamplerState* sampler) - { - if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG; - if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG; - auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); - - m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] = sampler; - return SLANG_OK; - } - - SlangResult setCombinedTextureSampler(ShaderOffset const& offset, ResourceView* textureView, SamplerState* sampler) - { - if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG; - if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG; - auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex); - - auto& slot = m_combinedTextureSamplers[bindingRange.baseIndex + offset.bindingArrayIndex]; - slot.textureView = textureView; - slot.sampler = sampler; - return SLANG_OK; - } - -protected: - friend class ProgramVars; - - Result init(Renderer* renderer, ShaderObjectLayout* layout) - { - m_layout = layout; - - // If the layout tells us that there is any uniform data, - // then we need to allocate a constant buffer to hold that data. - // - // TODO: Do we need to allocate a shadow copy for use from - // the CPU? - // - // TODO: When/where do we bind this constant buffer into - // a descriptor set for later use? - // - size_t uniformSize = layout->getElementTypeLayout()->getSize(); - if(uniformSize) - { - BufferResource::Desc bufferDesc; - bufferDesc.init(uniformSize); - bufferDesc.cpuAccessFlags |= Resource::AccessFlag::Write; - SLANG_RETURN_ON_FAIL(renderer->createBufferResource(Resource::Usage::ConstantBuffer, bufferDesc, nullptr, m_buffer.writeRef())); - } - -#if 0 - // If the layout tells us there are any descriptor sets to - // allocate, then we do so now. - // - for(auto descriptorSetInfo : layout->getDescriptorSets()) - { - RefPtr<DescriptorSet> descriptorSet; - SLANG_RETURN_ON_FAIL(renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef())); - m_descriptorSets.add(descriptorSet); - } -#endif - - m_resourceViews.setCount(layout->getResourceViewCount()); - m_samplers.setCount(layout->getSamplerCount()); - m_combinedTextureSamplers.setCount(layout->getCombinedTextureSamplerCount()); - - // If the layout specifies that we have any sub-objects, then - // we need to size the array to account for them. - // - Index subObjectCount = layout->getSubObjectCount(); - m_objects.setCount(subObjectCount); - - for(auto subObjectRangeInfo : layout->getSubObjectRanges()) - { - RefPtr<ShaderObjectLayout> subObjectLayout = subObjectRangeInfo.layout; - - // In the case where the sub-object range represents an - // existential-type leaf field (e.g., an `IBar`), we - // cannot pre-allocate the objet(s) to go into that - // range, since we can't possibly know what to allocate - // at this point. - // - if(!subObjectLayout) - continue; - // - // Otherwise, we will allocate a sub-object to fill - // in each entry in this range, based on the layout - // information we already have. - - auto& bindingRangeInfo = layout->getBindingRange(subObjectRangeInfo.bindingRangeIndex); - for(Index i = 0; i < bindingRangeInfo.count; ++i) - { - RefPtr<ShaderObject> subObject; - SLANG_RETURN_ON_FAIL(ShaderObject::create(renderer, subObjectLayout, subObject.writeRef())); - m_objects[bindingRangeInfo.baseIndex + i] = subObject; - } - } - - return SLANG_OK; - } - - Result apply(Renderer* renderer, PipelineType pipelineType, PipelineLayout* pipelineLayout, Index& ioRootIndex) - { - ShaderObjectLayout* layout = m_layout; - - // Create the descritpor sets required by the layout... - // - List<RefPtr<DescriptorSet>> descriptorSets; - for(auto descriptorSetInfo : layout->getDescriptorSets()) - { - RefPtr<DescriptorSet> descriptorSet; - SLANG_RETURN_ON_FAIL(renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef())); - descriptorSets.add(descriptorSet); - } - - SLANG_RETURN_ON_FAIL(_bindIntoDescriptorSets(descriptorSets.getBuffer())); - - for(auto descriptorSet : descriptorSets) - { - renderer->setDescriptorSet(pipelineType, pipelineLayout, ioRootIndex++, descriptorSet); - } - - return SLANG_OK; - } - - Result _bindIntoDescriptorSet(DescriptorSet* descriptorSet, Index baseRangeIndex, Index subObjectRangeArrayIndex) - { - ShaderObjectLayout* layout = m_layout; - - if(m_buffer) - { - descriptorSet->setConstantBuffer(baseRangeIndex, subObjectRangeArrayIndex, m_buffer); - baseRangeIndex++; - } - - for(auto bindingRangeInfo : layout->getBindingRanges()) - { - switch(bindingRangeInfo.bindingType) - { - case slang::BindingType::VaryingInput: - case slang::BindingType::VaryingOutput: - continue; - - default: - break; - } - - SLANG_ASSERT(bindingRangeInfo.descriptorSetIndex == 0); - - auto count = bindingRangeInfo.count; - auto baseIndex = bindingRangeInfo.baseIndex; - - auto descriptorRangeIndex = baseRangeIndex + bindingRangeInfo.rangeIndexInDescriptorSet; - auto descriptorArrayBaseIndex = subObjectRangeArrayIndex * count; - - switch(bindingRangeInfo.bindingType) - { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - break; - - case slang::BindingType::ExistentialValue: - // - // TODO: If the existential value is one that "fits" into the storage available, - // then we should write its data directly into that area. Otherwise, we need - // to bind its content as "pending" data which will come after any other data - // beloning to the same set (that is, it's starting descriptorRangeIndex will - // need to be one after the number of ranges accounted for in the original type) - // - break; - - case slang::BindingType::CombinedTextureSampler: - for(Index i = 0; i < count; ++i) - { - auto& slot = m_combinedTextureSamplers[baseIndex + i]; - descriptorSet->setCombinedTextureSampler(descriptorRangeIndex, descriptorArrayBaseIndex + i, slot.textureView, slot.sampler); - } - break; - - case slang::BindingType::Sampler: - for(Index i = 0; i < count; ++i) - { - descriptorSet->setSampler(descriptorRangeIndex, descriptorArrayBaseIndex + i, m_samplers[baseIndex + i]); - } - break; - - default: - for(Index i = 0; i < count; ++i) - { - descriptorSet->setResource(descriptorRangeIndex, descriptorArrayBaseIndex + i, m_resourceViews[baseIndex + i]); - } - break; - } - } - - return SLANG_OK; - } - - public: - virtual Result _bindIntoDescriptorSets(RefPtr<DescriptorSet>* descriptorSets) - { - ShaderObjectLayout* layout = m_layout; - - if(m_buffer) - { - // TODO: look up binding infor for default constant buffer... - descriptorSets[0]->setConstantBuffer(0, 0, m_buffer); - } - - // Fill in the descriptor sets based on binding ranges - // - for(auto bindingRangeInfo : layout->getBindingRanges()) - { - DescriptorSet* descriptorSet = descriptorSets[bindingRangeInfo.descriptorSetIndex]; - auto rangeIndex = bindingRangeInfo.rangeIndexInDescriptorSet; - auto baseIndex = bindingRangeInfo.baseIndex; - auto count = bindingRangeInfo.count; - switch(bindingRangeInfo.bindingType) - { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - for(Index i = 0; i < count; ++i) - { - ShaderObject* subObject = m_objects[baseIndex + i]; - - subObject->_bindIntoDescriptorSet(descriptorSet, rangeIndex, i); - } - break; - - case slang::BindingType::CombinedTextureSampler: - for(Index i = 0; i < count; ++i) - { - auto& slot = m_combinedTextureSamplers[baseIndex + i]; - descriptorSet->setCombinedTextureSampler(rangeIndex, i, slot.textureView, slot.sampler); - } - break; - - case slang::BindingType::Sampler: - for(Index i = 0; i < count; ++i) - { - descriptorSet->setSampler(rangeIndex, i, m_samplers[baseIndex + i]); - } - break; - - case slang::BindingType::VaryingInput: - case slang::BindingType::VaryingOutput: - break; - - case slang::BindingType::ExistentialValue: - // Here we are binding as if existential value is the same - // as a constant buffer or parameter block, which will lead - // to incorrect results... - for(Index i = 0; i < count; ++i) - { - ShaderObject* subObject = m_objects[baseIndex + i]; - - subObject->_bindIntoDescriptorSet(descriptorSet, rangeIndex, i); - } - break; - - default: - for(Index i = 0; i < count; ++i) - { - descriptorSet->setResource(rangeIndex, i, m_resourceViews[baseIndex + i]); - } - break; - } - } - return SLANG_OK; - } - - - RefPtr<ShaderObjectLayout> m_layout = nullptr; - RefPtr<BufferResource> m_buffer; - - List<RefPtr<ResourceView>> m_resourceViews; - - List<RefPtr<SamplerState>> m_samplers; - - struct CombinedTextureSamplerSlot - { - RefPtr<ResourceView> textureView; - RefPtr<SamplerState> sampler; - }; - List<CombinedTextureSamplerSlot> m_combinedTextureSamplers; - -// List<RefPtr<DescriptorSet>> m_descriptorSets; - List<RefPtr<ShaderObject>> m_objects; -}; - -class EntryPointVars : public ShaderObject -{ - typedef ShaderObject Super; - -public: - static Result create(Renderer* renderer, EntryPointLayout* layout, EntryPointVars** outShaderObject) - { - RefPtr<EntryPointVars> object = new EntryPointVars(); - SLANG_RETURN_ON_FAIL(object->init(renderer, layout)); - - *outShaderObject = object.detach(); - return SLANG_OK; - } - - EntryPointLayout* getLayout() - { - return static_cast<EntryPointLayout*>(m_layout.Ptr()); - } - -protected: - Result init(Renderer* renderer, EntryPointLayout* layout) - { - SLANG_RETURN_ON_FAIL(Super::init(renderer, layout)); - return SLANG_OK; - } -}; - -class ProgramVars : public ShaderObject -{ - typedef ShaderObject Super; - -public: - static Result create(Renderer* renderer, ProgramLayout* layout, ProgramVars** outShaderObject) - { - RefPtr<ProgramVars> object = new ProgramVars(); - SLANG_RETURN_ON_FAIL(object->init(renderer, layout)); - - *outShaderObject = object.detach(); - return SLANG_OK; - } - - ProgramLayout* getLayout() - { - return static_cast<ProgramLayout*>(m_layout.Ptr()); - } - - void apply(Renderer* renderer, PipelineType pipelineType) - { - auto pipelineLayout = getLayout()->getPipelineLayout(); - - Index rootIndex = 0; - ShaderObject::apply(renderer, pipelineType, pipelineLayout, rootIndex); - -#if 0 - - Index descriptorSetCount = m_descriptorSets.getCount(); - for(Index descriptorSetIndex = 0; descriptorSetIndex < descriptorSetCount; ++descriptorSetIndex) - { - renderer->setDescriptorSet( - pipelineType, - pipelineLayout, - descriptorSetIndex, - m_descriptorSets[descriptorSetIndex]); - } -#endif - - // TODO: We also need to bind any descriptor sets that are - // part of sub-objects of this object. - } - - List<RefPtr<EntryPointVars>> const& getEntryPoints() const { return m_entryPoints; } - -protected: - - virtual Result _bindIntoDescriptorSets(RefPtr<DescriptorSet>* descriptorSets) - { - SLANG_RETURN_ON_FAIL(Super::_bindIntoDescriptorSets(descriptorSets)); - - auto entryPointCount = m_entryPoints.getCount(); - for( Index i = 0; i < entryPointCount; ++i ) - { - auto entryPoint = m_entryPoints[i]; - auto& entryPointInfo = getLayout()->getEntryPoint(i); - - SLANG_RETURN_ON_FAIL(entryPoint->_bindIntoDescriptorSet(descriptorSets[0], entryPointInfo.rangeOffset, 0)); - } - - return SLANG_OK; - } - - - Result init(Renderer* renderer, ProgramLayout* layout) - { - SLANG_RETURN_ON_FAIL(Super::init(renderer, layout)); - - for(auto entryPointInfo : layout->getEntryPoints()) - { - RefPtr<EntryPointVars> entryPoint; - SLANG_RETURN_ON_FAIL(EntryPointVars::create(renderer, entryPointInfo.layout, entryPoint.writeRef())); - m_entryPoints.add(entryPoint); - } - - return SLANG_OK; - } - - List<RefPtr<EntryPointVars>> m_entryPoints; -}; - - /// Represents a "pointer" to the storage for a shader parameter of a (dynamically) known type. - /// - /// A `ShaderCursor` serves as a pointer-like type for things stored inside a `ShaderObject`. - /// - /// A cursor that points to the entire content of a shader object can be formed as `ShaderCursor(someObject)`. - /// A cursor pointing to a structure field or array element can be formed from another cursor - /// using `getField` or `getElement` respectively. - /// - /// Given a cursor pointing to a value of some "primitive" type, we can set or get the value - /// using operations like `setResource`, `getResource`, etc. - /// - /// Because type information for shader parameters is being reflected dynamically, all type - /// checking for shader cursors occurs at runtime, and errors may occur when attempting to - /// set a parameter using a value of an inappropriate type. As much as possible, `ShaderCursor` - /// attempts to protect against these cases and return an error `Result` or an invalid - /// cursor, rather than allowing operations to proceed with incorrect types. - /// -struct ShaderCursor -{ - ShaderObject* m_baseObject = nullptr; - slang::TypeLayoutReflection* m_typeLayout = nullptr; - ShaderOffset m_offset; - - /// Get the type (layout) of the value being pointed at by the cursor - slang::TypeLayoutReflection* getTypeLayout() const - { - return m_typeLayout; - } - - /// Is this cursor valid (that is, does it seem to point to an actual location)? - /// - /// This check is equivalent to checking whether a pointer is null, so it is - /// a very weak sense of "valid." In particular, it is possible to form a - /// `ShaderCursor` for which `isValid()` is true, but attempting to get or - /// set the value would be an error (like dereferencing a garbage pointer). - /// - bool isValid() const - { - return m_baseObject != nullptr; - } - - Result getDereferenced(ShaderCursor& outCursor) const - { - switch(m_typeLayout->getKind()) - { - default: - return SLANG_E_INVALID_ARG; - - case slang::TypeReflection::Kind::ConstantBuffer: - case slang::TypeReflection::Kind::ParameterBlock: - { - ShaderObject* subObject = m_baseObject->getObject(m_offset); - outCursor = ShaderCursor(subObject); - return SLANG_OK; - } - - } - } - - ShaderCursor getDereferenced() - { - ShaderCursor result; - getDereferenced(result); - return result; - } - - /// Form a cursor pointing to the field with the given `name` within the value this cursor points at. - /// - /// If the operation succeeds, then the field cursor is written to `outCursor`. - Result getField(UnownedStringSlice const& name, ShaderCursor& outCursor) - { - // If this cursor is invalid, then can't possible fetch a field. - // - if(!isValid()) return SLANG_E_INVALID_ARG; - - // If the cursor is valid, we want to consider the type of data - // it is referencing. - // - switch(m_typeLayout->getKind()) - { - // The easy/expected case is when the value has a structure type. - // - case slang::TypeReflection::Kind::Struct: - { - // We start by looking up the index of a field matching `name`. - // - // If there is no such field, we have an error. - // - SlangInt fieldIndex = m_typeLayout->findFieldIndexByName(name.begin(), name.end()); - if(fieldIndex == -1) - return SLANG_E_INVALID_ARG; - - // Once we know the index of the field being referenced, - // we create a cursor to point at the field, based on - // the offset information already in this cursor, plus - // offsets derived from the field's layout. - // - slang::VariableLayoutReflection* fieldLayout = m_typeLayout->getFieldByIndex((unsigned int) fieldIndex); - ShaderCursor fieldCursor; - - // The field cursorwill point into the same parent object. - // - fieldCursor.m_baseObject = m_baseObject; - - // The type being pointed to is the tyep of the field. - // - fieldCursor.m_typeLayout = fieldLayout->getTypeLayout(); - - // The byte offset is the current offset plus the relative offset of the field. - // The offset in binding ranges is computed similarly. - // - fieldCursor.m_offset.uniformOffset = m_offset.uniformOffset + fieldLayout->getOffset(); - fieldCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex + m_typeLayout->getFieldBindingRangeOffset(fieldIndex); - - // The index of the field within any binding ranges will be the same - // as the index computed for the parent structure. - // - // Note: this case would arise for an array of structures with texture-type - // fields. Suppose we have: - // - // struct S { Texture2D t; Texture2D u; } - // S g[4]; - // - // In this scenario, `g` holds two binding ranges: - // - // * Range #0 comprises 4 textures, representing `g[...].t` - // * Range #1 comprises 4 textures, representing `g[...].u` - // - // A cursor for `g[2]` would have a `bindingRangeIndex` of zero but - // a `bindingArrayIndex` of 2, iindicating that we could end up - // referencing either range, but no matter what we know the index - // is 2. Thus when we form a cursor for `g[2].u` we want to - // apply the binding range offset to get a `bindingRangeIndex` of - // 1, while the `bindingArrayIndex` is unmodified. - // - // The result is that `g[2].u` is stored in range #1 at array index 2. - // - fieldCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex; - - outCursor = fieldCursor; - return SLANG_OK; - } - break; - - // In some cases the user might be trying to acess a field by name - // from a cursor that references a constant buffer or parameter block, - // and in these cases we want the access to Just Work. - // - case slang::TypeReflection::Kind::ConstantBuffer: - case slang::TypeReflection::Kind::ParameterBlock: - { - // We basically need to "dereference" the current cursor - // to go from a pointer to a constant buffer to a pointer - // to the *contents* of the constant buffer. - // - ShaderCursor d = getDereferenced(); - return d.getField(name, outCursor); - } - break; - } - - return SLANG_E_INVALID_ARG; - } - - ShaderCursor getField(UnownedStringSlice const& name) - { - ShaderCursor cursor; - getField(name, cursor); - return cursor; - } - - ShaderCursor getField(String const& name) - { - return getField(name.getUnownedSlice()); - } - - ShaderCursor getElement(Index index) - { - // TODO: need to auto-dereference various buffer types... - - if(m_typeLayout->getKind() == slang::TypeReflection::Kind::Array) - { - ShaderCursor elementCursor; - elementCursor.m_baseObject = m_baseObject; - elementCursor.m_typeLayout = m_typeLayout->getElementTypeLayout(); - elementCursor.m_offset.uniformOffset = m_offset.uniformOffset + index * m_typeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM); - elementCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex; - elementCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex*m_typeLayout->getElementCount() + index; - return elementCursor; - } - - return ShaderCursor(); - } - - static int _peek(UnownedStringSlice const& slice) - { - const char* b = slice.begin(); - const char* e = slice.end(); - if(b == e) return -1; - return *b; - } - - static int _get(UnownedStringSlice& slice) - { - const char* b = slice.begin(); - const char* e = slice.end(); - if(b == e) return -1; - auto result = *b++; - slice = UnownedStringSlice(b, e); - return result; - } - - static Result followPath(UnownedStringSlice const& path, ShaderCursor& ioCursor) - { - ShaderCursor cursor = ioCursor; - - enum - { - ALLOW_NAME = 0x1, - ALLOW_SUBSCRIPT = 0x2, - ALLOW_DOT = 0x4, - }; - int state = ALLOW_NAME | ALLOW_SUBSCRIPT; - - UnownedStringSlice rest = path; - for(;;) - { - int c = _peek(rest); - - if(c == -1) - break; - else if( c == '.' ) - { - if(!(state & ALLOW_DOT)) - return SLANG_E_INVALID_ARG; - - _get(rest); - state = ALLOW_NAME; - continue; - } - else if( c == '[' ) - { - if(!(state & ALLOW_SUBSCRIPT)) - return SLANG_E_INVALID_ARG; - - _get(rest); - Index index = 0; - while(_peek(rest) != ']') - { - int d = _get(rest); - if(d >= '0' && d <= '9') - { - index = index*10 + (d - '0'); - } - else - { - return SLANG_E_INVALID_ARG; - } - } - - if(_peek(rest) != ']') - return SLANG_E_INVALID_ARG; - _get(rest); - - cursor = cursor.getElement(index); - state = ALLOW_DOT | ALLOW_SUBSCRIPT; - continue; - } - else - { - const char* nameBegin = rest.begin(); - for(;;) - { - switch(_peek(rest)) - { - default: - _get(rest); - continue; - - case -1: - case '.': - case '[': - break; - } - break; - } - char const* nameEnd = rest.begin(); - UnownedStringSlice name(nameBegin, nameEnd); - cursor = cursor.getField(name); - state = ALLOW_DOT | ALLOW_SUBSCRIPT; - continue; - } - } - - ioCursor = cursor; - return SLANG_OK; - } - - static Result followPath(String const& path, ShaderCursor& ioCursor) - { - return followPath(path.getUnownedSlice(), ioCursor); - } - - ShaderCursor getPath(UnownedStringSlice const& path) - { - ShaderCursor result(*this); - followPath(path, result); - return result; - } - - - ShaderCursor getPath(String const& path) - { - ShaderCursor result(*this); - followPath(path, result); - return result; - } - - ShaderCursor() - {} - - ShaderCursor(ShaderObject* object) - : m_baseObject(object) - , m_typeLayout(object->getElementTypeLayout()) - {} - - SlangResult setData(void const* data, size_t size) - { - return m_baseObject->setData(m_offset, data, size); - } - - SlangResult setObject(ShaderObject* object) - { - return m_baseObject->setObject(m_offset, object); - } - - SlangResult setResource(ResourceView* resourceView) - { - return m_baseObject->setResource(m_offset, resourceView); - } - - SlangResult setSampler(SamplerState* sampler) - { - return m_baseObject->setSampler(m_offset, sampler); - } - - SlangResult setCombinedTextureSampler(ResourceView* textureView, SamplerState* sampler) - { - return m_baseObject->setCombinedTextureSampler(m_offset, textureView, sampler); - } -}; - SlangResult _assignVarsFromLayout( Renderer* renderer, - ProgramVars* shaderObject, + ShaderObject* shaderObject, ShaderInputLayout const& layout, ShaderOutputPlan& ioOutputPlan, slang::ProgramLayout* slangReflection) @@ -1676,9 +194,9 @@ SlangResult _assignVarsFromLayout( if(!entryCursor.isValid()) { - for(auto entryPoint : shaderObject->getEntryPoints()) + for(Index i = 0; i < shaderObject->getEntryPointCount(); i++) { - entryCursor = ShaderCursor(entryPoint).getPath(entry.name); + entryCursor = ShaderCursor(shaderObject->getEntryPoint(i)).getPath(entry.name); if(entryCursor.isValid()) break; } @@ -1877,11 +395,8 @@ SlangResult _assignVarsFromLayout( auto slangType = slangReflection->findTypeByName(typeName.getBuffer()); auto slangTypeLayout = slangReflection->getTypeLayout(slangType); - RefPtr<ShaderObjectLayout> shaderObjectLayout; - SLANG_RETURN_ON_FAIL(ShaderObjectLayout::createForElementType(renderer, slangTypeLayout, shaderObjectLayout.writeRef())); - - RefPtr<ShaderObject> shaderObject; - SLANG_RETURN_ON_FAIL(ShaderObject::create(renderer, shaderObjectLayout, shaderObject.writeRef())); + RefPtr<ShaderObjectLayout> shaderObjectLayout = renderer->createShaderObjectLayout(slangTypeLayout); + RefPtr<ShaderObject> shaderObject = renderer->createShaderObject(shaderObjectLayout); entryCursor.setObject(shaderObject); } @@ -1911,7 +426,7 @@ void LegacyRenderTestApp::applyBinding(PipelineType pipelineType) void ShaderObjectRenderTestApp::applyBinding(PipelineType pipelineType) { - m_programVars->apply(m_renderer.Ptr(), pipelineType); + m_renderer->bindRootShaderObject(pipelineType, m_programVars); } SlangResult LegacyRenderTestApp::initialize( @@ -2039,49 +554,19 @@ SlangResult ShaderObjectRenderTestApp::initialize( // If we are doing a non-pass-through compilation, then we will rely on // Slang's reflection API to tell us what the parameters of the program are. // - RefPtr<ProgramLayout> programLayout = nullptr; - - // Okay, we will use Slang reflection to determine what the parameters of the shader are. - // auto slangReflection = (slang::ProgramLayout*) spGetReflection(m_compilationOutput.output.getRequestForReflection()); - { - ProgramLayout::Builder builder(renderer); - builder.addGlobalParams(slangReflection->getGlobalParamsVarLayout()); - - // TODO: Also need to reflect entry points here. - - SlangInt entryPointCount = slangReflection->getEntryPointCount(); - for(SlangInt e = 0; e < entryPointCount; ++e) - { - auto slangEntryPoint = slangReflection->getEntryPointByIndex(e); - - EntryPointLayout::Builder entryPointBuilder(renderer); - entryPointBuilder.addEntryPointParams(slangEntryPoint); - - RefPtr<EntryPointLayout> entryPointLayout; - SLANG_RETURN_ON_FAIL(entryPointBuilder.build(entryPointLayout.writeRef())); - - builder.addEntryPoint(entryPointLayout); - } - - SLANG_RETURN_ON_FAIL(builder.build(programLayout.writeRef())); - } - - // The shape of the parameters will determine the pipeline layout that we use. - // - RefPtr<PipelineLayout> pipelineLayout = programLayout->getPipelineLayout(); + RefPtr<ShaderObjectLayout> programLayout = renderer->createRootShaderObjectLayout(slangReflection); // Once we have determined the layout of all the parameters we need to bind, // we will create a shader object to use for storing and binding those parameters. // - RefPtr<ProgramVars> programVars; - SLANG_RETURN_ON_FAIL(ProgramVars::create(renderer, programLayout, programVars.writeRef())); - m_programVars = programVars; + m_programVars = renderer->createRootShaderObject(programLayout); // Now we need to assign from the input parameter data that was parsed into // the program vars we allocated. // - SLANG_RETURN_ON_FAIL(_assignVarsFromLayout(renderer, programVars, m_compilationOutput.layout, m_outputPlan, slangReflection)); + SLANG_RETURN_ON_FAIL(_assignVarsFromLayout( + renderer, m_programVars, m_compilationOutput.layout, m_outputPlan, slangReflection)); m_renderer = renderer; @@ -2098,7 +583,7 @@ SlangResult ShaderObjectRenderTestApp::initialize( case Options::ShaderProgramType::Compute: { ComputePipelineStateDesc desc; - desc.pipelineLayout = pipelineLayout; + desc.rootShaderObjectLayout = programLayout.Ptr(); desc.program = m_shaderProgram; m_pipelineState = renderer->createComputePipelineState(desc); @@ -2132,10 +617,9 @@ SlangResult ShaderObjectRenderTestApp::initialize( SLANG_RETURN_ON_FAIL(renderer->createBufferResource(Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData, m_vertexBuffer.writeRef())); GraphicsPipelineStateDesc desc; - desc.pipelineLayout = pipelineLayout; + desc.rootShaderObjectLayout = programLayout.Ptr(); desc.program = m_shaderProgram; desc.inputLayout = inputLayout; - desc.renderTargetCount = programLayout->getRenderTargetCount(); m_pipelineState = renderer->createGraphicsPipelineState(desc); } |
