summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slang.h7
-rw-r--r--source/slang/slang-reflection-api.cpp38
-rw-r--r--source/slang/slang.cpp4
-rw-r--r--tests/bugs/gh-357.slang2
-rw-r--r--tests/compute/assoctype-generic-arg.slang4
-rw-r--r--tests/compute/global-generic-value-param.slang2
-rw-r--r--tests/compute/global-type-param-in-entrypoint.slang2
-rw-r--r--tests/compute/global-type-param.slang2
-rw-r--r--tests/compute/int-generic.slang2
-rw-r--r--tests/compute/interface-assoc-type-param.slang4
-rw-r--r--tests/compute/interface-func-param-in-struct.slang6
-rw-r--r--tests/compute/interface-shader-param-in-struct.slang26
-rw-r--r--tests/compute/interface-shader-param.slang33
-rw-r--r--tests/compute/parameter-block.slang7
-rw-r--r--tests/disabled-tests.txt41
-rw-r--r--tools/gfx-util/shader-cursor.cpp50
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp466
-rw-r--r--tools/render-test/render-test-main.cpp28
-rw-r--r--tools/render-test/shader-input-layout.cpp11
-rw-r--r--tools/render-test/slang-support.cpp4
20 files changed, 471 insertions, 268 deletions
diff --git a/slang.h b/slang.h
index da4b359c4..97e860275 100644
--- a/slang.h
+++ b/slang.h
@@ -1993,6 +1993,7 @@ extern "C"
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt index);
SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* typeLayout);
SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex);
@@ -2608,6 +2609,12 @@ namespace slang
index);
}
+ SlangInt getBindingRangeDescriptorRangeCount(SlangInt index)
+ {
+ return spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
SlangInt getDescriptorSetCount()
{
diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp
index 2031b4a0f..6f022cc90 100644
--- a/source/slang/slang-reflection-api.cpp
+++ b/source/slang/slang-reflection-api.cpp
@@ -1326,6 +1326,7 @@ namespace Slang
Index bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
SlangBindingType bindingType = SLANG_BINDING_TYPE_CONSTANT_BUFFER;
Index spaceOffset = -1;
+ bool usesIndirectAllocation = false;
LayoutResourceKind kind = LayoutResourceKind::None;
// TODO: It is unclear if this should be looking at the resource
@@ -1333,12 +1334,25 @@ namespace Slang
//
for(auto& resInfo : parameterGroupTypeLayout->resourceInfos)
{
+ if( spaceOffset == -1 )
+ {
+ spaceOffset = _calcSpaceOffset(path, kind);
+ }
+
kind = resInfo.kind;
switch(kind)
{
default:
continue;
+ case LayoutResourceKind::ConstantBuffer:
+ case LayoutResourceKind::PushConstantBuffer:
+ case LayoutResourceKind::DescriptorTableSlot:
+ break;
+
+ // Certain cases indicate a parameter block that
+ // actually involves indirection.
+ //
// Note: the only case where a parameter group should
// reflect as consuming `Uniform` storage is on CPU/CUDA,
// where that will be the only resource it contains.
@@ -1346,18 +1360,19 @@ namespace Slang
// TODO: If we ever support targets that don't have
// constant buffers at all, this logic would be questionable.
//
- case LayoutResourceKind::ConstantBuffer:
- case LayoutResourceKind::PushConstantBuffer:
case LayoutResourceKind::RegisterSpace:
- case LayoutResourceKind::DescriptorTableSlot:
case LayoutResourceKind::Uniform:
+ usesIndirectAllocation = true;
break;
}
bindingType = _calcBindingType(typeLayout, kind);
- spaceOffset = _calcSpaceOffset(path, kind);
break;
}
+ if(spaceOffset == -1)
+ {
+ spaceOffset = 0;
+ }
TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange;
bindingRange.leafTypeLayout = typeLayout;
@@ -1419,7 +1434,7 @@ namespace Slang
// because the physical storage for `C.a` is provided by the
// memory allocation for `C` itself.
- if( spaceOffset != -1 )
+ if( !usesIndirectAllocation )
{
// The logic here assumes that when a parameter group consumes
// resources that must "leak" into the outer scope (including
@@ -1848,6 +1863,19 @@ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeInd
return bindingRange.firstDescriptorRangeIndex;
}
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+ if(index < 0) return 0;
+ if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0;
+ auto& bindingRange = extTypeLayout->m_bindingRanges[index];
+
+ return bindingRange.descriptorRangeCount;
+}
+
SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* inTypeLayout)
{
auto typeLayout = convert(inTypeLayout);
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 8c6bf403e..c48701575 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -2832,7 +2832,9 @@ SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::specialize(
auto specializationParamCount = getSpecializationParamCount();
if( specializationArgCount != specializationParamCount )
{
- // TODO: diagnose
+ sink.diagnose(SourceLoc(), Diagnostics::mismatchSpecializationArguments,
+ specializationParamCount,
+ specializationArgCount);
sink.getBlobIfNeeded(outDiagnostics);
return SLANG_FAIL;
}
diff --git a/tests/bugs/gh-357.slang b/tests/bugs/gh-357.slang
index 522cabd7c..4bd76b800 100644
--- a/tests/bugs/gh-357.slang
+++ b/tests/bugs/gh-357.slang
@@ -1,4 +1,4 @@
-//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
diff --git a/tests/compute/assoctype-generic-arg.slang b/tests/compute/assoctype-generic-arg.slang
index 1015ef775..cf71d7cde 100644
--- a/tests/compute/assoctype-generic-arg.slang
+++ b/tests/compute/assoctype-generic-arg.slang
@@ -1,5 +1,5 @@
-//TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj
-//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
//TEST_INPUT:type AssocImpl
diff --git a/tests/compute/global-generic-value-param.slang b/tests/compute/global-generic-value-param.slang
index dd1b091c1..3cd97da59 100644
--- a/tests/compute/global-generic-value-param.slang
+++ b/tests/compute/global-generic-value-param.slang
@@ -1,6 +1,6 @@
// global-generic-value-param.slang
-//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
// This is a basic test of support for global generic
// value parameters: explicit named parameters at global
diff --git a/tests/compute/global-type-param-in-entrypoint.slang b/tests/compute/global-type-param-in-entrypoint.slang
index 24ee113f5..326fc73d1 100644
--- a/tests/compute/global-type-param-in-entrypoint.slang
+++ b/tests/compute/global-type-param-in-entrypoint.slang
@@ -1,4 +1,4 @@
-//TEST(compute):COMPARE_RENDER_COMPUTE: -shaderobj
+//DISABLED_TEST(compute):COMPARE_RENDER_COMPUTE: -shaderobj
//TEST_INPUT: cbuffer(data=[1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0]):name Uniforms
//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
diff --git a/tests/compute/global-type-param.slang b/tests/compute/global-type-param.slang
index 7a3e31187..6ec957d9d 100644
--- a/tests/compute/global-type-param.slang
+++ b/tests/compute/global-type-param.slang
@@ -1,4 +1,4 @@
-//TEST(smoke,compute):COMPARE_COMPUTE: -shaderobj
+//DISABLED_TEST(smoke,compute):COMPARE_COMPUTE: -shaderobj
//TEST_INPUT:type Wrapper<Impl>
diff --git a/tests/compute/int-generic.slang b/tests/compute/int-generic.slang
index 7d693e42b..1c67591b7 100644
--- a/tests/compute/int-generic.slang
+++ b/tests/compute/int-generic.slang
@@ -1,4 +1,4 @@
-//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
//TEST_INPUT:type Material<1,2>
diff --git a/tests/compute/interface-assoc-type-param.slang b/tests/compute/interface-assoc-type-param.slang
index 4e6df4eb5..b315dd5f9 100644
--- a/tests/compute/interface-assoc-type-param.slang
+++ b/tests/compute/interface-assoc-type-param.slang
@@ -1,7 +1,7 @@
// Tests using associated types through an existential-struct-typed param.
-//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
-//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
[anyValueSize(8)]
interface IInterface
diff --git a/tests/compute/interface-func-param-in-struct.slang b/tests/compute/interface-func-param-in-struct.slang
index c32254cb5..9e3e6c201 100644
--- a/tests/compute/interface-func-param-in-struct.slang
+++ b/tests/compute/interface-func-param-in-struct.slang
@@ -1,7 +1,7 @@
// Tests specializing a function with existential-struct-typed param.
-//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
-//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
[anyValueSize(8)]
interface IInterface
@@ -31,8 +31,6 @@ void compute(uint tid, Params p)
gOutputBuffer[tid] = p.obj[0].eval();
}
-//TEST_INPUT: entryPointExistentialType Impl
-
[numthreads(4, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID,
//TEST_INPUT:ubuffer(data=[0 0 0 0 1 0], stride=4):name=params.obj
diff --git a/tests/compute/interface-shader-param-in-struct.slang b/tests/compute/interface-shader-param-in-struct.slang
index 1098b4077..62aa093ed 100644
--- a/tests/compute/interface-shader-param-in-struct.slang
+++ b/tests/compute/interface-shader-param-in-struct.slang
@@ -4,7 +4,6 @@
// inside of structure types to make sure that works
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
-
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -profile sm_6_0 -use-dxil
//DISABLED_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
@@ -42,7 +41,7 @@ int test(
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:set gOutputBuffer = out ubuffer(data=[0 0 0 0], stride=4)
RWStructuredBuffer<int> gOutputBuffer;
// Note: even though `C` doesn't include any
@@ -52,7 +51,8 @@ RWStructuredBuffer<int> gOutputBuffer;
// that it *will* contain uniform/ordinary data
// after specialization.
//
-//TEST_INPUT:cbuffer(data=[0 0 0 0 0 0 0 0]):
+//TEST_INPUT:set C = new{ new MyStrategy{ ubuffer(data=[1 2 4 8], stride=4) } }
+//TEST_INPUT: globalExistentialType MyStrategy
cbuffer C
{
IRandomNumberGenerationStrategy gStrategy;
@@ -64,23 +64,10 @@ struct Stuff
int extra;
}
-// Note: the data for global-scope existential parameters
-// is being introduced *before* the entry point declaration,
-// because the default policy used by `slangc` (which the
-// render test also uses) is to specialize the parameters at
-// the global scope (producing a new layout) and then compose
-// that specialized global scope with the entry point.
-//
-// (The net result is that data related to global-scope
-// specialization always precedes the data for entry point
-// parameters in these tests today)
-//
-//TEST_INPUT: globalExistentialType MyStrategy
-//TEST_INPUT:ubuffer(data=[1 2 4 8], stride=4):
-
[numthreads(4, 1, 1)]
void computeMain(
-//TEST_INPUT:root_constants(data=[0 0 0 0 0 0 0 0 256]):
+//TEST_INPUT:set stuff = { new MyModifier{ ubuffer(data=[16 32 64 128], stride=4) }, 256 }
+//TEST_INPUT: entryPointExistentialType MyModifier
uniform Stuff stuff,
uint3 dispatchThreadID : SV_DispatchThreadID)
@@ -129,6 +116,3 @@ struct MyModifier : IModifier
return val ^ localModifiers[val & 3];
}
}
-
-//TEST_INPUT: entryPointExistentialType MyModifier
-//TEST_INPUT:ubuffer(data=[16 32 64 128], stride=4):
diff --git a/tests/compute/interface-shader-param.slang b/tests/compute/interface-shader-param.slang
index e57ff1bc6..e7c6ceb6a 100644
--- a/tests/compute/interface-shader-param.slang
+++ b/tests/compute/interface-shader-param.slang
@@ -3,11 +3,11 @@
// Test using interface tops as top-level shader parameters
// (whether global, or on an entry point).
-//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
-//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -profile sm_6_0 -use-dxil
-//DISABLED_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
-//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -profile sm_6_0 -use-dxil
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
// First we will define some fake interfaces for testing.
// Let's pretend we are doing some kind of random number
@@ -70,43 +70,27 @@ int test(
return modifiedVal;
}
-// The global-scope parameters for this example include
-// some `uniform` parameters, and that will trigger
-// the allocation of a global-scope constant buffer to
-// hold them. Slang's layout rules mean that the buffer
-// will be allocated before any other global-scope parameters.
-//
-// In this example, the buffer will not be needed after specialization,
-// but we need to declare/allocate it here so that the application
-// creates a descriptor table/set that matches what the shader
-// signature expects.
-//
-//TEST_INPUT:cbuffer(data=[0], stride=4):name=gStrategy
-
-
-
// Now we'll define a shader entry point that will use
// these interfaces to define its behavior.
//
// We'll start with the buffer for writing the test output.
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=gOutputBuffer
+//TEST_INPUT:set gOutputBuffer = out ubuffer(data=[0 0 0 0], stride=4)
RWStructuredBuffer<int> gOutputBuffer;
// Now we'll define a global shader parameter for the
// random number generation strategy.
//
-//__disabled__TEST_INPUT:object(type=MyStrategy):name=gStrategy
+//TEST_INPUT:set gStrategy = new MyStrategy{}
uniform IRandomNumberGenerationStrategy gStrategy;
// The other parameter (for the modifier) will be attached
// the entry point instead, so that we are testing both
// cases.
//
-//__disabled__TEST_INPUT:object(type=MyModifier):name=modifier
[numthreads(4, 1, 1)]
void computeMain(
-//TEST_INPUT:root_constants(data=[0], stride=4):
+//TEST_INPUT:set modifier = new MyModifier{}
uniform IModifier modifier,
uint3 dispatchThreadID : SV_DispatchThreadID)
{
@@ -150,6 +134,3 @@ struct MyModifier : IModifier
return val * 16;
}
}
-
-//TEST_INPUT: globalExistentialType MyStrategy
-//TEST_INPUT: entryPointExistentialType MyModifier
diff --git a/tests/compute/parameter-block.slang b/tests/compute/parameter-block.slang
index b1f861236..f7fa718de 100644
--- a/tests/compute/parameter-block.slang
+++ b/tests/compute/parameter-block.slang
@@ -3,10 +3,6 @@
//TEST(compute):COMPARE_COMPUTE:-vk -shaderobj
//TEST(compute):COMPARE_COMPUTE:-shaderobj
-
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=block0.buffer
-//TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):name=block1.buffer
-
// Ensure that Slang `ParameterBlock` type is lowered
// to HLSL in the fashion that we expect.
@@ -15,7 +11,10 @@ struct P
RWStructuredBuffer<int> buffer;
};
+//TEST_INPUT: set block0 = new{ out ubuffer(data=[0 0 0 0], stride=4) }
ParameterBlock<P> block0;
+
+//TEST_INPUT: set block1 = new{ ubuffer(data=[0 1 2 3], stride=4) }
ParameterBlock<P> block1;
[numthreads(4, 1, 1)]
diff --git a/tests/disabled-tests.txt b/tests/disabled-tests.txt
index ffc9736db..ea1a2330e 100644
--- a/tests/disabled-tests.txt
+++ b/tests/disabled-tests.txt
@@ -9,15 +9,53 @@ Test that don't work with shader objects in render-test
The following tests were disabled because they had been running on non `-shaderobj` code paths that have since been removed.
These tests will need to be re-enabled together with changes to the shader object implementation, or removed entirely if they no longer test useful functionality.
+### `ConstantBuffer<ISomething>`
+
+These tests rely on details of how a `ConstantBuffer<ISomething>` or `ParameterBlock<ISomething>` gets laid out.
+We need to fix the compiler and shader object implementation to agree that a `ConstantBuffer<ISomething>`
+should compile as `exists T : ISomething . ConstantBuffer<T>` and *not* `ConstantBuffer<exists T : ISomething . T>`
+like it currently does.
+(The reason for this choice is that we want a shader object created from `SomeConcreteType`, where `SomeConcreteType : ISomething`, to be directly usable for a `ConstantBuffer<ISomething>` parameter with its existing buffer allocation.)
+
* compute/dynamic-dispatch-12.slang
+
+### `StructuredBuffer<ISomething>`
+
+These tests require support for structured buffers where the element type either is an interface type or transitively contains one.
+
* compute/dynamic-dispatch-13.slang
* compute/dynamic-dispatch-14.slang
* compute/dynamic-dispatch-bindless-texture.slang
-* compute/global-type-param2.slang
+* compute/interface-func-param-in-struct.slang
+* compute/interface-assoc-type-param.slang
+
+### Generic Specialization Parameters
+
+These tests make use of generic specialization parameters in ways that don't easily align with the implementation approach that is more focused on existential parameters.
+They should either be ported to use existentials directly (at which point we potentially get rid of support for generic specialization at global or entry-point scope?) or we should refine the implementation of generic specialization to be consistent with existential specialization.
+
* compute/global-type-param-array.slang
* compute/global-type-param1.slang
+* compute/global-type-param2.slang
+* bugs/gh-357.slang
+* compute/assoctype-generic-arg.slang
+* compute/global-generic-value-param.slang
+* compute/global-type-param-in-entrypoint.slang
+* compute/global-type-param.slang
+* compute/int-generic.slang
+
+### Static Specialization
+
+These tests rely on the ability of the static specialization path to provide locations for data that doesn't "fit" into the fixed-size payload of an existential-type field/value.
+They will need to wait until the shader object implementation(s) are updated to support that case.
+
* compute/interface-shader-param-in-struct.slang
* compute/interface-shader-param-legalization.slang
+
+### Uncategorized
+
+These tests need to be binned according to what features they need.
+
* compute/interface-shader-param.slang
* compute/performance-profile.slang
* compute/rewriter-parameter-block-complex.hlsl
@@ -40,4 +78,3 @@ These tests will need to be re-enabled together with changes to the shader objec
* render/tess.hlsl
* render/unused-discard.hlsl
* compute/interface-param-partial-specialize.slang
-* compute/array-existential-parameter.slang
diff --git a/tools/gfx-util/shader-cursor.cpp b/tools/gfx-util/shader-cursor.cpp
index c2c34f5a5..b188901ec 100644
--- a/tools/gfx-util/shader-cursor.cpp
+++ b/tools/gfx-util/shader-cursor.cpp
@@ -145,19 +145,45 @@ Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCurso
ShaderCursor ShaderCursor::getElement(SlangInt index) const
{
// TODO: need to auto-dereference various buffer types...
-
- if (m_typeLayout->getKind() == slang::TypeReflection::Kind::Array)
+ switch( m_typeLayout->getKind() )
{
- 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;
+ case 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;
+ }
+ break;
+
+ case slang::TypeReflection::Kind::Struct:
+ {
+ // The logic here is similar to `getField()` except that we don't
+ // need to look up the field index based on a name first.
+ //
+ auto fieldIndex = index;
+ slang::VariableLayoutReflection* fieldLayout =
+ m_typeLayout->getFieldByIndex((unsigned int)fieldIndex);
+ if(!fieldLayout)
+ return ShaderCursor();
+
+ ShaderCursor fieldCursor;
+ fieldCursor.m_baseObject = m_baseObject;
+ fieldCursor.m_typeLayout = fieldLayout->getTypeLayout();
+ fieldCursor.m_offset.uniformOffset = m_offset.uniformOffset + fieldLayout->getOffset();
+ fieldCursor.m_offset.bindingRangeIndex =
+ m_offset.bindingRangeIndex + m_typeLayout->getFieldBindingRangeOffset(fieldIndex);
+ fieldCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex;
+
+ return fieldCursor;
+ }
+ break;
}
return ShaderCursor();
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index 6b818f100..891077a8b 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -1059,83 +1059,88 @@ public:
}
}
+ /// Stores offset information to apply to the reflected register/space for a descriptor range.
+ ///
struct BindingRegisterOffset
{
- // The index to the physical descriptor set that stores the binding.
- uint32_t descriptorSetIndex;
-
- uint32_t spaceOffset; // The `space` index as specified in shader.
- uint32_t textureOffset; // `t` registers
- uint32_t samplerOffset; // `s` registers
- uint32_t constantBufferOffset; // `b` registers
- uint32_t uavOffset; // `u` registers
- void set(D3D12_DESCRIPTOR_RANGE_TYPE type, uint32_t value)
+ uint32_t spaceOffset = 0; // The `space` index as specified in shader.
+
+ /// An offset to apply for each D3D12 register class, as given
+ /// by a `D3D12_DESCRIPTOR_RANGE_TYPE`.
+ ///
+ /// Note that the `D3D12_DESCRIPTOR_RANGE_TYPE` enumeration has
+ /// values between 0 and 3, inclusive.
+ ///
+ uint32_t offsetForRangeType[4] = {0, 0, 0, 0};
+
+ uint32_t& operator[](D3D12_DESCRIPTOR_RANGE_TYPE type)
{
- switch (type)
- {
- case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
- constantBufferOffset = value;
- return;
- case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
- uavOffset = value;
- return;
- case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
- textureOffset = value;
- return;
- case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
- samplerOffset = value;
- return;
- default:
- break;
- }
+ return offsetForRangeType[int(type)];
}
- uint32_t get(D3D12_DESCRIPTOR_RANGE_TYPE type)
+
+ uint32_t operator[](D3D12_DESCRIPTOR_RANGE_TYPE type) const
{
- switch (type)
- {
- case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
- return constantBufferOffset;
- case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
- return uavOffset;
- case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
- return textureOffset;
- case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
- return samplerOffset;
- default:
- return 0;
- }
+ return offsetForRangeType[int(type)];
}
};
- void addDescriptorRange(
- slang::TypeLayoutReflection* typeLayout,
- D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
- Index bindingRangeIndex,
- BindingRegisterOffset* offset,
- BindingRegisterOffset* newOffset)
+ /// Add a new descriptor set to the layout being computed.
+ ///
+ /// Note that a "descriptor set" in the layout may amount to
+ /// zero, one, or two different descriptor *tables* in the
+ /// final D3D12 root signature. Each descriptor set may
+ /// contain zero or more view ranges (CBV/SRV/UAV) and zero
+ /// or more sampler ranges. It maps to a view descriptor table
+ /// if the number of view ranges is non-zero and to a sampler
+ /// descriptor table if the number of sampler ranges is non-zero.
+ ///
+ uint32_t addDescriptorSet()
+ {
+ auto result = (uint32_t) m_descriptorSets.getCount();
+ m_descriptorSets.add(DescriptorSetLayout{});
+ return result;
+ }
+
+ /// Add one descriptor range as specified in Slang reflection information to the layout.
+ ///
+ /// The layout information is taken from `typeLayout` for the descriptor
+ /// range with the given `descriptorRangeIndex` within the logical
+ /// descriptor set (reflected by Slang) with the given `logicalDescriptorSetIndex`.
+ ///
+ /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of
+ /// the descriptor set that the range should be added to.
+ ///
+ /// The `offset` encodes information about space and/or register offsets that
+ /// should be applied to descrptor ranges.
+ ///
+ /// This operation can fail if the given descriptor range encodes a range that
+ /// doesn't map to anything directly supported by D3D12. Higher-level routines
+ /// will often want to ignore such failures.
+ ///
+ Result addDescriptorRange(
+ slang::TypeLayoutReflection* typeLayout,
+ Index physicalDescriptorSetIndex,
+ BindingRegisterOffset const& offset,
+ Index logicalDescriptorSetIndex,
+ Index descriptorRangeIndex)
{
+ auto& descriptorSet = m_descriptorSets[physicalDescriptorSetIndex];
+
+ auto bindingType = typeLayout->getDescriptorSetDescriptorRangeType(logicalDescriptorSetIndex, descriptorRangeIndex);
+ auto count = typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(logicalDescriptorSetIndex, descriptorRangeIndex);
+ auto index = typeLayout->getDescriptorSetDescriptorRangeIndexOffset(logicalDescriptorSetIndex, descriptorRangeIndex);
+ auto space = typeLayout->getDescriptorSetSpaceOffset(logicalDescriptorSetIndex);
+
+ D3D12_DESCRIPTOR_RANGE_TYPE rangeType;
+ SLANG_RETURN_ON_FAIL(translateDescriptorRangeType(bindingType, &rangeType));
+
D3D12_DESCRIPTOR_RANGE range = {};
range.RangeType = rangeType;
- auto descriptorRangeIndex =
- typeLayout->getBindingRangeFirstDescriptorRangeIndex(bindingRangeIndex);
- auto relativeSpaceIndex =
- (uint32_t)typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex);
- auto space = offset->spaceOffset + relativeSpaceIndex;
- // Update descriptor range descs in current descriptor set.
- auto& descriptorSet = m_descriptorSets[offset->descriptorSetIndex];
- range.NumDescriptors =
- (UINT)typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(
- relativeSpaceIndex, descriptorRangeIndex);
- range.BaseShaderRegister =
- (UINT)typeLayout->getDescriptorSetDescriptorRangeIndexOffset(
- relativeSpaceIndex, descriptorRangeIndex) +
- offset->get(range.RangeType);
- newOffset->set(
- range.RangeType,
- Math::Max(range.BaseShaderRegister + 1, newOffset->get(range.RangeType)));
+ range.NumDescriptors = (UINT) count;
+ range.BaseShaderRegister = (UINT) index + offset[rangeType];
+ range.RegisterSpace = (UINT) space;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
- range.RegisterSpace = space;
if (range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER)
{
descriptorSet.m_samplerRanges.add(range);
@@ -1146,110 +1151,204 @@ public:
descriptorSet.m_resourceRanges.add(range);
descriptorSet.m_resourceCount += range.NumDescriptors;
}
+
+ return SLANG_OK;
}
- void addObject(slang::TypeLayoutReflection* typeLayout, BindingRegisterOffset* offset)
+ /// Add one binding range to the computed layout.
+ ///
+ /// The layout information is taken from `typeLayout` for the binding
+ /// range with the given `bindingRangeIndex`.
+ ///
+ /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of
+ /// the descriptor set that the range should be added to.
+ ///
+ /// The `offset` encodes information about space and/or register offsets that
+ /// should be applied to descrptor ranges.
+ ///
+ /// Note that a single binding range may encompass zero or more descriptor ranges.
+ ///
+ void addBindingRange(
+ slang::TypeLayoutReflection* typeLayout,
+ Index physicalDescriptorSetIndex,
+ BindingRegisterOffset const& offset,
+ Index bindingRangeIndex)
{
- typeLayout = _unwrapParameterGroups(typeLayout);
- SlangInt bindingRangeCount = typeLayout->getBindingRangeCount();
- // `register` and `space` index offset of future sub-objects.
- BindingRegisterOffset subObjectOffset = *offset;
- for (SlangInt i = 0; i < bindingRangeCount; i++)
+ auto logicalDescriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex);
+ auto firstDescriptorRangeIndex = typeLayout->getBindingRangeFirstDescriptorRangeIndex(bindingRangeIndex);
+ Index descriptorRangeCount = typeLayout->getBindingRangeDescriptorRangeCount(bindingRangeIndex);
+ for( Index i = 0; i < descriptorRangeCount; ++i )
+ {
+ auto descriptorRangeIndex = firstDescriptorRangeIndex + i;
+
+ // Note: we ignore the `Result` returned by `addDescriptorRange()` because we
+ // want to silently skip any ranges that represent kinds of bindings that
+ // don't actually exist in D3D12.
+ //
+ addDescriptorRange(typeLayout, physicalDescriptorSetIndex, offset, logicalDescriptorSetIndex, descriptorRangeIndex);
+ }
+ }
+
+ /// Add binding ranges and parameter blocks to the root signature.
+ ///
+ /// The layout information is taken from `varLayout` which should
+ /// be a layout for either a program or an entry point.
+ ///
+ /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of
+ /// the descriptor set that binding ranges not belonging to nested
+ /// parameter blocks should be added to.
+ ///
+ /// This routine will use absolute offset information computed from `varLayout`
+ /// to apply appropriate space/register offsets to the bindings and parameter
+ /// blocks inside the layout.
+ ///
+ void addBindingRangesAndParameterBlocks(
+ slang::VariableLayoutReflection* varLayout,
+ Index physicalDescriptorSetIndex)
+ {
+ BindingRegisterOffset offset;
+ offset.spaceOffset = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_REGISTER_SPACE);
+ offset[D3D12_DESCRIPTOR_RANGE_TYPE_CBV] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER);
+ offset[D3D12_DESCRIPTOR_RANGE_TYPE_SRV] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE);
+ offset[D3D12_DESCRIPTOR_RANGE_TYPE_UAV] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS);
+ offset[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SAMPLER_STATE);
+
+ addBindingRangesAndParameterBlocks(varLayout->getTypeLayout(), physicalDescriptorSetIndex, offset);
+ }
+
+ /// Add binding ranges and parameter blocks to the root signature.
+ ///
+ /// The layout information is taken from `typeLayout` which should
+ /// be a layout for either a program or an entry point.
+ ///
+ /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of
+ /// the descriptor set that binding ranges not belonging to nested
+ /// parameter blocks should be added to.
+ ///
+ /// The `offset` encodes information about space and/or register offsets that
+ /// should be applied to descrptor ranges.
+ ///
+ void addBindingRangesAndParameterBlocks(
+ slang::TypeLayoutReflection* typeLayout,
+ Index physicalDescriptorSetIndex,
+ BindingRegisterOffset const& offset)
+ {
+ // Our first task is to add the binding ranges for stuff that is
+ // directly contained in `typeLayout` rather than via sub-objects.
+ //
+ // Our goal is to have the descriptors for directly-contained views/samplers
+ // always be contiguous in CPU and GPU memory, so that we can write
+ // to them easily with a single operaiton.
+ //
+ Index bindingRangeCount = typeLayout->getBindingRangeCount();
+ for (Index bindingRangeIndex = 0; bindingRangeIndex < bindingRangeCount; bindingRangeIndex++)
{
- auto bindingType = typeLayout->getBindingRangeType(i);
- D3D12_DESCRIPTOR_RANGE_TYPE rangeType;
- if (translateDescriptorRangeType(bindingType, &rangeType) != SLANG_OK)
+ // We will look at the type of each binding range and intentionally
+ // skip those that represent sub-objects.
+ //
+ auto bindingType = typeLayout->getBindingRangeType(bindingRangeIndex);
+ switch(bindingType)
{
- // Ignore all descriptor ranges that does not map directly into a
- // d3d descriptor.
+ case slang::BindingType::ConstantBuffer:
+ case slang::BindingType::ParameterBlock:
+ case slang::BindingType::ExistentialValue:
continue;
+
+ default:
+ break;
}
- // The CBV descriptor range, along with any additional descriptor ranges associated
- // with the constant buffer binding range, will be appended to the end of this object's
- // descriptor table, so we skip them now.
- if (bindingType == slang::BindingType::ConstantBuffer)
- continue;
- addDescriptorRange(typeLayout, rangeType, i, offset, &subObjectOffset);
+
+ // For binding ranges that don't represent sub-objects, we will add
+ // all of the descriptor ranges they encompass to the root signature.
+ //
+ addBindingRange(typeLayout, physicalDescriptorSetIndex, offset, bindingRangeIndex);
}
- auto subObjectCount = typeLayout->getSubObjectRangeCount();
- for (SlangInt i = 0; i < subObjectCount; i++)
+
+ // Next we need to recurse on the various sub-objects that the type might contain.
+ //
+ Index subObjectCount = typeLayout->getSubObjectRangeCount();
+ for (Index subObjectRangeIndex = 0; subObjectRangeIndex < subObjectCount; subObjectRangeIndex++)
{
- auto rangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(i);
- switch (typeLayout->getBindingRangeType(rangeIndex))
+ // There are a few different concerns being tackled at once here, which depend on
+ // the type of each sub-object range.
+ //
+ auto bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(subObjectRangeIndex);
+ auto bindingType = typeLayout->getBindingRangeType(bindingRangeIndex);
+ switch (bindingType)
{
case slang::BindingType::ConstantBuffer:
{
- auto subObjectType = typeLayout->getBindingRangeLeafTypeLayout(rangeIndex);
- auto subObjectElementType = _unwrapParameterGroups(subObjectType);
- if (subObjectElementType->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0)
- {
- addDescriptorRange(
- typeLayout,
- D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
- rangeIndex,
- offset,
- &subObjectOffset);
- }
- addObject(subObjectType, &subObjectOffset);
+ // Constant buffer ranges (for `ConstantBuffer<ConcreteType>`) will "leak" their
+ // binding ranges into the surrounding type, so we can add them here like any other
+ // binding range.
+ //
+ // Note: It would be valid to allow `slang::BindingType::ConstantBuffer` to be handled
+ // in the earlier loop, but that would mean that descriptor ranges coming directly
+ // from the fields of `typeLayout` could be broken up with ranges coming from constant-buffer
+ // sub-objects. By moving the handling of constant buffers to this later loop, we
+ // guarantee that the descritpors used by non-sub-object binding ranges are all
+ // contiguous.
+ //
+ addBindingRange(typeLayout, physicalDescriptorSetIndex, offset, bindingRangeIndex);
}
break;
+
case slang::BindingType::ParameterBlock:
{
- BindingRegisterOffset newOffset = {};
- newOffset.descriptorSetIndex = (uint32_t)m_descriptorSets.getCount();
- m_descriptorSets.add(DescriptorSetLayout{});
- newOffset.spaceOffset =
- offset->spaceOffset +
- (uint32_t)typeLayout->getBindingRangeDescriptorSetIndex(rangeIndex);
- auto subObjectType =
- typeLayout->getBindingRangeLeafTypeLayout(rangeIndex);
- addObject(subObjectType, &newOffset);
+ // A parameter block (`ParameterBlock<ConcreteType>`) will always map to a distinct
+ // descriptor set, and its contained view/sampler binding ranges will be bound
+ // through that set.
+ //
+ auto blockPhysicalDescriptorSetIndex = addDescriptorSet();
+
+ // We will need to recursively add the binding ranges implied by the type of
+ // the parameter block.
+ //
+ auto blockTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex);
+
+ // One important detail is that the `blockTypeLayout` does not know the base register
+ // space that the contents of the block should use. All descriptor ranges stored in
+ // that layout will by default use a space offset of zero.
+ //
+ // We need to compute the space offset to apply when recursing into that block type
+ // based on the binding range we are processing here.
+ //
+ auto blockLogicalDescriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex);
+ auto blockSpaceOffset = typeLayout->getDescriptorSetSpaceOffset(blockLogicalDescriptorSetIndex);
+
+ // The space offset for this binding range should be added to any additional space
+ // offset that was being passed down from above this layer.
+ //
+ // Any other offset information (register offsets) should be ignored at this point,
+ // because `register` offsets from outside of the block don't affect layout within
+ // the block.
+ //
+ BindingRegisterOffset blockOffset;
+ blockOffset.spaceOffset = offset.spaceOffset + (uint32_t) blockSpaceOffset;
+
+ // Once we have all the details worked out, we can write the binding ranges for the
+ // block's type into the newly-allocated descriptor set.
+ //
+ // Note: there is an important subtlety going on here. We are passing in the type
+ // `blockTypeLayout` which corresponds to `ParameterBlock<ConcreteType>` and *not* to
+ // `ConcreteType` alone. Because of that detail, the binding/descriptor ranges will
+ // include any "default constant buffer" range that needed to be allocated based
+ // on `ConcreteType`.
+ //
+ // TODO: validate that this logic is right.
+ //
+ addBindingRangesAndParameterBlocks(blockTypeLayout, blockPhysicalDescriptorSetIndex, blockOffset);
}
break;
- }
- }
- *offset = subObjectOffset;
- }
-
- static BindingRegisterOffset getOffsetFromVarLayout(
- slang::VariableLayoutReflection* varLayout)
- {
- BindingRegisterOffset offset;
- offset.descriptorSetIndex = 0;
- offset.spaceOffset =
- (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_REGISTER_SPACE);
- offset.samplerOffset =
- (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SAMPLER_STATE);
- offset.textureOffset =
- (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE);
- offset.constantBufferOffset =
- (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER);
- offset.uavOffset =
- (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS);
- return offset;
- }
- void addObject(
- slang::TypeLayoutReflection* typeLayout,
- slang::VariableLayoutReflection* varLayout)
- {
- auto offset = getOffsetFromVarLayout(varLayout);
- addObject(typeLayout, &offset);
- }
+ case slang::BindingType::ExistentialValue:
+ // TODO: Need to handle this case here.
+ break;
- void addEntryPoint(slang::EntryPointReflection* entryPoint)
- {
- BindingRegisterOffset offset = getOffsetFromVarLayout(entryPoint->getVarLayout());
- if (entryPoint->hasDefaultConstantBuffer())
- {
- addDescriptorRange(
- entryPoint->getTypeLayout(),
- D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
- 0,
- &offset,
- &offset);
+ default:
+ break;
+ }
}
- addObject(entryPoint->getTypeLayout(), &offset);
}
D3D12_ROOT_SIGNATURE_DESC& build(
@@ -1307,19 +1406,46 @@ public:
ID3D12RootSignature** outRootSignature,
List<DescriptorSetInfo>& outRootDescriptorSetInfos)
{
+ // We are going to build up the root signature by adding
+ // binding/descritpor ranges and nested parameter blocks
+ // based on the computed layout information for `program`.
+ //
RootSignatureDescBuilder builder;
- builder.m_descriptorSets.add(DescriptorSetLayout{});
-
auto layout = program->getLayout();
- auto globalParamLayout = layout->getGlobalParamsTypeLayout();
- auto globalVarLayout = layout->getGlobalParamsVarLayout();
- builder.addObject(globalParamLayout, globalVarLayout);
+ // The layout information computed by Slang breaks up shader
+ // parameters into what we can think of as "logical" descriptor
+ // sets based on whether or not parameters have the same `space`.
+ //
+ // We want to basically ignore that decomposition and generate a
+ // single descriptor set to hold all top-level parameters, and only
+ // generate distinct descriptor sets when the shader has opted in
+ // via explicit parameter blocks.
+ //
+ // To achieve this goal, we will manually allocate a default descriptor
+ // set for root parameters in our signature, and then recursively
+ // add all the binding/descriptor ranges implied by the global-scope
+ // parameters.
+ //
+ auto rootDescriptorSetIndex = builder.addDescriptorSet();
+ builder.addBindingRangesAndParameterBlocks(layout->getGlobalParamsVarLayout(), rootDescriptorSetIndex);
for (SlangUInt i = 0; i < layout->getEntryPointCount(); i++)
{
+ // Entry-point parameters should also be added to the default root
+ // descriptor set.
+ //
+ // We add the parameters using the "variable layout" for the entry point
+ // and not just its type layout, to ensure that any offset information is
+ // applied correctly to the `register` and `space` information for entry-point
+ // parameters.
+ //
+ // Note: When we start to support DXR we will need to handle entry-point parameters
+ // differently because they will need to map to local root signatures rather than
+ // being included in the global root signature as is being done here.
+ //
auto entryPoint = layout->getEntryPointByIndex(i);
- builder.addEntryPoint(entryPoint);
+ builder.addBindingRangesAndParameterBlocks(entryPoint->getVarLayout(), rootDescriptorSetIndex);
}
auto& rootSignatureDesc = builder.build(outRootDescriptorSetInfos);
@@ -2034,21 +2160,13 @@ public:
SLANG_RETURN_ON_FAIL(_writeOrdinaryData(
encoder, m_ordinaryDataBuffer, 0, specializedOrdinaryDataSize, specializedLayout));
- return SLANG_OK;
- }
-
- /// Bind the buffer for ordinary/uniform data, if needed
- Result _bindOrdinaryDataBufferIfNeeded(PipelineCommandEncoder* encoder)
- {
- // We start by ensuring that the buffer is created, if it is needed.
- //
- SLANG_RETURN_ON_FAIL(_ensureOrdinaryDataBufferCreatedIfNeeded(encoder));
-
- // If we did indeed need/create a buffer, then we must bind it
- // into root binding state.
- //
- if (m_ordinaryDataBuffer)
{
+ // We also create and store a descriptor for our root constant buffer
+ // into the descriptor table allocation that was reserved for them.
+ //
+ // We always know that the ordinary data buffer will be the first descriptor
+ // in the table of resource views.
+ //
auto descriptorTable = m_descriptorSet.m_resourceTable;
D3D12_CONSTANT_BUFFER_VIEW_DESC viewDesc = {};
viewDesc.BufferLocation =
@@ -2067,7 +2185,7 @@ public:
virtual Result bindObject(PipelineCommandEncoder* encoder, RootBindingState* bindingState)
{
ShaderObjectLayoutImpl* layout = getLayout();
- SLANG_RETURN_ON_FAIL(_bindOrdinaryDataBufferIfNeeded(encoder));
+ SLANG_RETURN_ON_FAIL(_ensureOrdinaryDataBufferCreatedIfNeeded(encoder));
uint32_t descTableIndex = bindingState->rootParamIndex;
auto& descSet = m_descriptorSet;
if (descSet.m_resourceCount)
@@ -2677,7 +2795,10 @@ public:
// Submit - setting for graphics
{
GraphicsSubmitter submitter(m_d3dCmdList);
- _bindRenderState(&submitter);
+ if(SLANG_FAILED(_bindRenderState(&submitter)))
+ {
+ assert(!"Failed to bind render state");
+ }
}
m_d3dCmdList->IASetPrimitiveTopology(m_primitiveTopology);
@@ -2844,7 +2965,10 @@ public:
// Submit binding for compute
{
ComputeSubmitter submitter(m_d3dCmdList);
- _bindRenderState(&submitter);
+ if(SLANG_FAILED(_bindRenderState(&submitter)))
+ {
+ assert(!"Failed to bind render state");
+ }
}
m_d3dCmdList->Dispatch(x, y, z);
}
@@ -3238,7 +3362,7 @@ Result D3D12Device::PipelineCommandEncoder::_bindRenderState(Submitter* submitte
submitter->setRootSignature(programImpl->m_rootObjectLayout->m_rootSignature);
ShortList<DescriptorTable, kMaxDescriptorSetCount> descriptorTables;
RefPtr<ShaderObjectLayoutImpl> specializedRootLayout;
- rootObjectImpl->getSpecializedLayout(specializedRootLayout.writeRef());
+ SLANG_RETURN_ON_FAIL(rootObjectImpl->getSpecializedLayout(specializedRootLayout.writeRef()));
RootShaderObjectLayoutImpl* rootLayoutImpl =
static_cast<RootShaderObjectLayoutImpl*>(specializedRootLayout.Ptr());
for (auto& descSet : rootLayoutImpl->m_gpuDescriptorSetInfos)
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index 27311d67a..db51339f1 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -274,19 +274,25 @@ struct AssignValsFromLayoutContext
if(field.name.getLength() == 0)
{
- StdWriters::getError().print("error: entries in `ShaderInputLayout` must include a name\n");
- return SLANG_E_INVALID_ARG;
+ // If no name was given, assume by-indexing matching is requested
+ auto fieldCursor = dstCursor.getElement(fieldIndex);
+ if(!fieldCursor.isValid())
+ {
+ StdWriters::getError().print("error: could not find shader parameter at index %d\n", (int)fieldIndex);
+ return SLANG_E_INVALID_ARG;
+ }
+ SLANG_RETURN_ON_FAIL(assign(fieldCursor, field.val));
}
-
- auto fieldCursor = dstCursor.getPath(field.name.getBuffer());
-
- if(!fieldCursor.isValid())
+ else
{
- StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", field.name.begin());
- return SLANG_E_INVALID_ARG;
+ auto fieldCursor = dstCursor.getPath(field.name.getBuffer());
+ if(!fieldCursor.isValid())
+ {
+ StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", field.name.begin());
+ return SLANG_E_INVALID_ARG;
+ }
+ SLANG_RETURN_ON_FAIL(assign(fieldCursor, field.val));
}
-
- assign(fieldCursor, field.val);
}
return SLANG_OK;
}
@@ -329,7 +335,7 @@ struct AssignValsFromLayoutContext
ComPtr<IShaderObject> shaderObject = device->createShaderObject(slangType);
- assign(ShaderCursor(shaderObject), srcVal->contentVal);
+ SLANG_RETURN_ON_FAIL(assign(ShaderCursor(shaderObject), srcVal->contentVal));
dstCursor.setObject(shaderObject);
return SLANG_OK;
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index c5f1cb6dd..4febc4bd5 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -504,10 +504,17 @@ namespace renderer_test
val->contentVal = parseValExpr(parser);
return val;
}
+ else if( parser.AdvanceIf("out") )
+ {
+ auto val = parseValExpr(parser);
+ val->isOutput = true;
+ return val;
+ }
else
{
- // TODO: other named cases
- throw ShaderInputLayoutFormatException(String("Unexpected '") + parser.NextToken().Content + String("' at line") + String(parser.NextToken().Position.Line));
+ // We assume that any other word is introducing one of the other
+ // cases for a parse-able value.
+ return parseVal(parser);
}
}
break;
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index aca354763..840b0d3e2 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -135,6 +135,10 @@ void ShaderCompilerUtil::Output::reset()
{
spSetPassThrough(slangRequest, input.passThrough);
}
+ else
+ {
+ spSetCompileFlags(slangRequest, SLANG_COMPILE_FLAG_NO_CODEGEN);
+ }
// Process any additional command-line options specified for Slang using
// the `-xslang <arg>` option to `render-test`.