summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slang.h269
-rw-r--r--source/slang/slang-reflection.cpp937
-rw-r--r--source/slang/slang-type-layout.h46
-rw-r--r--tests/bugs/bool-init.slang2
-rw-r--r--tests/bugs/bool-op.slang2
-rw-r--r--tests/bugs/gh-357.slang4
-rw-r--r--tests/bugs/gh-471.slang2
-rw-r--r--tests/bugs/gh-487.slang2
-rw-r--r--tests/bugs/gh-518.slang6
-rw-r--r--tests/bugs/gh-519.slang2
-rw-r--r--tests/bugs/gh-566.slang4
-rw-r--r--tests/bugs/gh-569.slang2
-rw-r--r--tests/bugs/gh-775.slang2
-rw-r--r--tests/bugs/gl-33.slang2
-rw-r--r--tests/bugs/glsl-static-const-array.slang2
-rw-r--r--tests/bugs/nested-generics-call.slang2
-rw-r--r--tests/bugs/nested-generics-method-call.slang2
-rw-r--r--tests/bugs/paren-insertion-bug.slang2
-rw-r--r--tests/bugs/static-method.slang2
-rw-r--r--tests/bugs/static-var.slang2
-rw-r--r--tests/bugs/texture2d-gather.hlsl4
-rw-r--r--tests/bugs/vec-compare.slang3
-rw-r--r--tests/bugs/while-in-generic.slang2
-rw-r--r--tests/compute/cbuffer-legalize.slang6
-rw-r--r--tests/compute/compile-time-loop.slang6
-rw-r--r--tests/compute/constexpr.slang7
-rw-r--r--tests/compute/discard-stmt.slang6
-rw-r--r--tests/compute/dump-repro.slang2
-rw-r--r--tests/compute/global-generic-value-param.slang4
-rw-r--r--tests/compute/global-type-param-array.slang5
-rw-r--r--tests/compute/global-type-param-in-entrypoint.slang5
-rw-r--r--tests/compute/global-type-param1.slang16
-rw-r--r--tests/compute/global-type-param2.slang16
-rw-r--r--tests/compute/half-calc.slang3
-rw-r--r--tests/compute/half-structured-buffer.slang3
-rw-r--r--tests/compute/interface-shader-param.slang2
-rw-r--r--tests/compute/interface-shader-param4.slang4
-rw-r--r--tests/compute/matrix-layout-structured-buffer.slang2
-rw-r--r--tests/compute/matrix-layout.hlsl4
-rw-r--r--tools/gfx/d3d11/render-d3d11.cpp327
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp532
-rw-r--r--tools/gfx/open-gl/render-gl.cpp124
-rw-r--r--tools/gfx/render.h24
-rw-r--r--tools/gfx/vulkan/render-vk.cpp138
-rw-r--r--tools/render-test/cpu-compute-util.cpp11
-rw-r--r--tools/render-test/cuda/cuda-compute-util.cpp12
-rw-r--r--tools/render-test/options.cpp4
-rw-r--r--tools/render-test/options.h6
-rw-r--r--tools/render-test/render-test-main.cpp2099
-rw-r--r--tools/render-test/shader-input-layout.cpp17
-rw-r--r--tools/render-test/shader-input-layout.h9
-rw-r--r--tools/render-test/shader-renderer-util.cpp2
-rw-r--r--tools/render-test/shader-renderer-util.h4
-rw-r--r--tools/render-test/slang-support.cpp60
-rw-r--r--tools/render-test/slang-support.h30
55 files changed, 3637 insertions, 1156 deletions
diff --git a/slang.h b/slang.h
index 587ae7289..4edf3dc54 100644
--- a/slang.h
+++ b/slang.h
@@ -1773,6 +1773,61 @@ extern "C"
SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT = SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT,
};
+ /** Types of API-managed bindings that a parameter might use.
+
+ `SlangBindingType` represents the distinct types of binding ranges that might be
+ understood by an underlying graphics API or cross-API abstraction layer.
+ Several of the enumeration cases here correspond to cases of `VkDescriptorType`
+ defined by the Vulkan API. Note however that the values of this enumeration
+ are not the same as those of any particular API.
+
+ The `SlangBindingType` enumeration is distinct from `SlangParameterCategory`
+ because `SlangParameterCategory` differentiates the types of parameters for
+ the purposes of layout, where the layout rules of some targets will treat
+ parameters of different types as occupying the same binding space for layout
+ (e.g., in SPIR-V both a `Texture2D` and `SamplerState` use the same space of
+ `binding` indices, and are not allowed to overlap), while those same types
+ map to different types of bindingsin the API (e.g., both textures and samplers
+ use different `VkDescriptorType` values).
+
+ When you want to answer "what register/binding did this parameter use?" you
+ should use `SlangParameterCategory`.
+
+ When you wnat to answer "what type of descriptor range should this parameter use?"
+ you should use `SlangBindingType`.
+ */
+ typedef SlangUInt32 SlangBindingType;
+ enum
+ {
+ SLANG_BINDING_TYPE_UNKNOWN = 0,
+
+ SLANG_BINDING_TYPE_SAMPLER,
+ SLANG_BINDING_TYPE_TEXTURE,
+ SLANG_BINDING_TYPE_CONSTANT_BUFFER,
+ SLANG_BINDING_TYPE_PARAMETER_BLOCK,
+ SLANG_BINDING_TYPE_TYPED_BUFFER,
+ SLANG_BINDING_TYPE_RAW_BUFFER,
+ SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER,
+ SLANG_BINDING_TYPE_INPUT_RENDER_TARGET,
+ SLANG_BINDING_TYPE_INLINE_UNIFORM_DATA,
+ SLANG_BINDING_TYPE_RAY_TRACTING_ACCELERATION_STRUCTURE,
+
+ SLANG_BINDING_TYPE_VARYING_INPUT,
+ SLANG_BINDING_TYPE_VARYING_OUTPUT,
+
+ SLANG_BINDING_TYPE_EXISTENTIAL_VALUE,
+ SLANG_BINDING_TYPE_PUSH_CONSTANT,
+
+ SLANG_BINDING_TYPE_MUTABLE_FLAG = 0x100,
+
+ SLANG_BINDING_TYPE_MUTABLE_TETURE = SLANG_BINDING_TYPE_TEXTURE | SLANG_BINDING_TYPE_MUTABLE_FLAG,
+ SLANG_BINDING_TYPE_MUTABLE_TYPED_BUFFER = SLANG_BINDING_TYPE_TYPED_BUFFER | SLANG_BINDING_TYPE_MUTABLE_FLAG,
+ SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER = SLANG_BINDING_TYPE_RAW_BUFFER | SLANG_BINDING_TYPE_MUTABLE_FLAG,
+
+ SLANG_BINDING_TYPE_BASE_MASK = 0x00FF,
+ SLANG_BINDING_TYPE_EXT_MASK = 0xFF00,
+ };
+
typedef SlangUInt32 SlangLayoutRules;
enum
{
@@ -1837,11 +1892,14 @@ extern "C"
// Type Layout Reflection
SLANG_API SlangReflectionType* spReflectionTypeLayout_GetType(SlangReflectionTypeLayout* type);
+ SLANG_API SlangTypeKind spReflectionTypeLayout_getKind(SlangReflectionTypeLayout* type);
SLANG_API size_t spReflectionTypeLayout_GetSize(SlangReflectionTypeLayout* type, SlangParameterCategory category);
SLANG_API int32_t spReflectionTypeLayout_getAlignment(SlangReflectionTypeLayout* type, SlangParameterCategory category);
SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetFieldByIndex(SlangReflectionTypeLayout* type, unsigned index);
+ SLANG_API SlangInt spReflectionTypeLayout_findFieldIndexByName(SlangReflectionTypeLayout* typeLayout, const char* nameBegin, const char* nameEnd);
+
SLANG_API size_t spReflectionTypeLayout_GetElementStride(SlangReflectionTypeLayout* type, SlangParameterCategory category);
SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout(SlangReflectionTypeLayout* type);
SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetElementVarLayout(SlangReflectionTypeLayout* type);
@@ -1860,6 +1918,39 @@ extern "C"
SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout(SlangReflectionTypeLayout* type);
+ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeCount(SlangReflectionTypeLayout* typeLayout);
+ SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangInt spReflectionTypeLayout_getFieldBindingRangeOffset(SlangReflectionTypeLayout* typeLayout, SlangInt fieldIndex);
+
+ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+
+ SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* typeLayout);
+ SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex);
+ SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex);
+ SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex);
+ SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex);
+ SLANG_API SlangBindingType spReflectionTypeLayout_getDescriptorSetDescriptorRangeType(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex);
+ SLANG_API SlangParameterCategory spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex);
+
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* typeLayout);
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex);
+
+#if 0
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* typeLayout);
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeObjectCount(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+ SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getSubObjectRangeTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index);
+
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex);
+ SLANG_API SlangBindingType spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingType(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject);
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject);
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeIndexOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject);
+ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject);
+#endif
+
// Variable Reflection
SLANG_API char const* spReflectionVariable_GetName(SlangReflectionVariable* var);
@@ -1979,9 +2070,14 @@ extern "C"
/// Count should *NOT* include terminating zero.
SLANG_API int spComputeStringHash(const char* chars, size_t count);
+ /// Get a type layout representing reflection information for the global-scope prameters.
SLANG_API SlangReflectionTypeLayout* spReflection_getGlobalParamsTypeLayout(
SlangReflection* reflection);
+ /// Get a variable layout representing reflection information for the global-scope prameters.
+ SLANG_API SlangReflectionVariableLayout* spReflection_getGlobalParamsVarLayout(
+ SlangReflection* reflection);
+
#ifdef __cplusplus
}
@@ -2198,6 +2294,35 @@ namespace slang
FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT,
};
+ enum class BindingType : SlangBindingType
+ {
+ Unknown = SLANG_BINDING_TYPE_UNKNOWN,
+
+ Sampler = SLANG_BINDING_TYPE_SAMPLER,
+ Texture = SLANG_BINDING_TYPE_TEXTURE,
+ ConstantBuffer = SLANG_BINDING_TYPE_CONSTANT_BUFFER,
+ ParameterBlock = SLANG_BINDING_TYPE_PARAMETER_BLOCK,
+ TypedBuffer = SLANG_BINDING_TYPE_TYPED_BUFFER,
+ RawBuffer = SLANG_BINDING_TYPE_RAW_BUFFER,
+ CombinedTextureSampler = SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER,
+ InputRenderTarget = SLANG_BINDING_TYPE_INPUT_RENDER_TARGET,
+ InlineUniformData = SLANG_BINDING_TYPE_INLINE_UNIFORM_DATA,
+ RayTracingAccelerationStructure = SLANG_BINDING_TYPE_RAY_TRACTING_ACCELERATION_STRUCTURE,
+ VaryingInput = SLANG_BINDING_TYPE_VARYING_INPUT,
+ VaryingOutput = SLANG_BINDING_TYPE_VARYING_OUTPUT,
+ ExistentialValue = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE,
+ PushConstant = SLANG_BINDING_TYPE_PUSH_CONSTANT,
+
+ MutableFlag = SLANG_BINDING_TYPE_MUTABLE_FLAG,
+
+ MutableTexture = SLANG_BINDING_TYPE_MUTABLE_TETURE,
+ MutableTypedBuffer = SLANG_BINDING_TYPE_MUTABLE_TYPED_BUFFER,
+ MutableRawBuffer = SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER,
+
+ BaseMask = SLANG_BINDING_TYPE_BASE_MASK,
+ ExtMask = SLANG_BINDING_TYPE_EXT_MASK,
+ };
+
struct TypeLayoutReflection
{
TypeReflection* getType()
@@ -2205,7 +2330,10 @@ namespace slang
return (TypeReflection*) spReflectionTypeLayout_GetType((SlangReflectionTypeLayout*) this);
}
- TypeReflection::Kind getKind() { return getType()->getKind(); }
+ TypeReflection::Kind getKind()
+ {
+ return (TypeReflection::Kind) spReflectionTypeLayout_getKind((SlangReflectionTypeLayout*) this);
+ }
size_t getSize(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM)
{
@@ -2227,6 +2355,11 @@ namespace slang
return (VariableLayoutReflection*) spReflectionTypeLayout_GetFieldByIndex((SlangReflectionTypeLayout*) this, index);
}
+ SlangInt findFieldIndexByName(char const* nameBegin, char const* nameEnd = nullptr)
+ {
+ return spReflectionTypeLayout_findFieldIndexByName((SlangReflectionTypeLayout*) this, nameBegin, nameEnd);
+ }
+
bool isArray() { return getType()->isArray(); }
TypeLayoutReflection* unwrapArray()
@@ -2343,6 +2476,136 @@ namespace slang
return (VariableLayoutReflection*) spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout(
(SlangReflectionTypeLayout*) this);
}
+
+ SlangInt getBindingRangeCount()
+ {
+ return spReflectionTypeLayout_getBindingRangeCount(
+ (SlangReflectionTypeLayout*) this);
+ }
+
+ BindingType getBindingRangeType(SlangInt index)
+ {
+ return (BindingType) spReflectionTypeLayout_getBindingRangeType(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+
+ SlangInt getBindingRangeBindingCount(SlangInt index)
+ {
+ return spReflectionTypeLayout_getBindingRangeBindingCount(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+
+ /*
+ SlangInt getBindingRangeIndexOffset(SlangInt index)
+ {
+ return spReflectionTypeLayout_getBindingRangeIndexOffset(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+
+ SlangInt getBindingRangeSpaceOffset(SlangInt index)
+ {
+ return spReflectionTypeLayout_getBindingRangeSpaceOffset(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+ */
+
+ SlangInt getFieldBindingRangeOffset(SlangInt fieldIndex)
+ {
+ return spReflectionTypeLayout_getFieldBindingRangeOffset(
+ (SlangReflectionTypeLayout*) this,
+ fieldIndex);
+ }
+
+ TypeLayoutReflection* getBindingRangeLeafTypeLayout(SlangInt index)
+ {
+ return (TypeLayoutReflection*) spReflectionTypeLayout_getBindingRangeLeafTypeLayout(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+
+ SlangInt getBindingRangeDescriptorSetIndex(SlangInt index)
+ {
+ return spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+
+ SlangInt getBindingRangeFirstDescriptorRangeIndex(SlangInt index)
+ {
+ return spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(
+ (SlangReflectionTypeLayout*) this,
+ index);
+ }
+
+
+ SlangInt getDescriptorSetCount()
+ {
+ return spReflectionTypeLayout_getDescriptorSetCount(
+ (SlangReflectionTypeLayout*) this);
+ }
+
+ SlangInt getDescriptorSetSpaceOffset(SlangInt setIndex)
+ {
+ return spReflectionTypeLayout_getDescriptorSetSpaceOffset(
+ (SlangReflectionTypeLayout*) this,
+ setIndex);
+ }
+
+ SlangInt getDescriptorSetDescriptorRangeCount(SlangInt setIndex)
+ {
+ return spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount(
+ (SlangReflectionTypeLayout*) this,
+ setIndex);
+ }
+
+ SlangInt getDescriptorSetDescriptorRangeIndexOffset(SlangInt setIndex, SlangInt rangeIndex)
+ {
+ return spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset(
+ (SlangReflectionTypeLayout*) this,
+ setIndex,
+ rangeIndex);
+ }
+
+ SlangInt getDescriptorSetDescriptorRangeDescriptorCount(SlangInt setIndex, SlangInt rangeIndex)
+ {
+ return spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount(
+ (SlangReflectionTypeLayout*) this,
+ setIndex,
+ rangeIndex);
+ }
+
+ BindingType getDescriptorSetDescriptorRangeType(SlangInt setIndex, SlangInt rangeIndex)
+ {
+ return (BindingType) spReflectionTypeLayout_getDescriptorSetDescriptorRangeType(
+ (SlangReflectionTypeLayout*) this,
+ setIndex,
+ rangeIndex);
+ }
+
+ ParameterCategory getDescriptorSetDescriptorRangeCategory(SlangInt setIndex, SlangInt rangeIndex)
+ {
+ return (ParameterCategory) spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory(
+ (SlangReflectionTypeLayout*) this,
+ setIndex,
+ rangeIndex);
+ }
+
+ SlangInt getSubObjectRangeCount()
+ {
+ return spReflectionTypeLayout_getSubObjectRangeCount(
+ (SlangReflectionTypeLayout*) this);
+ }
+
+ SlangInt getSubObjectRangeBindingRangeIndex(SlangInt subObjectRangeIndex)
+ {
+ return spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(
+ (SlangReflectionTypeLayout*) this,
+ subObjectRangeIndex);
+ }
};
struct Modifier
@@ -2653,6 +2916,10 @@ namespace slang
return (TypeLayoutReflection*) spReflection_getGlobalParamsTypeLayout((SlangReflection*) this);
}
+ VariableLayoutReflection* getGlobalParamsVarLayout()
+ {
+ return (VariableLayoutReflection*) spReflection_getGlobalParamsVarLayout((SlangReflection*) this);
+ }
};
typedef ISlangBlob IBlob;
diff --git a/source/slang/slang-reflection.cpp b/source/slang/slang-reflection.cpp
index fd76c5e0b..42355ca02 100644
--- a/source/slang/slang-reflection.cpp
+++ b/source/slang/slang-reflection.cpp
@@ -281,6 +281,11 @@ SLANG_API SlangTypeKind spReflectionType_GetKind(SlangReflectionType* inType)
{
return SLANG_TYPE_KIND_INTERFACE;
}
+ else if (declRef.is<FuncDecl>())
+ {
+ // This is a reference to an entry point
+ return SLANG_TYPE_KIND_STRUCT;
+ }
}
else if( auto specializedType = as<ExistentialSpecializedType>(type) )
{
@@ -673,6 +678,28 @@ SLANG_API SlangReflectionType* spReflectionTypeLayout_GetType(SlangReflectionTyp
return (SlangReflectionType*) typeLayout->type;
}
+SLANG_API SlangTypeKind spReflectionTypeLayout_getKind(SlangReflectionTypeLayout* inTypeLayout)
+{
+ if(!inTypeLayout) return SLANG_TYPE_KIND_NONE;
+
+ if( auto type = spReflectionTypeLayout_GetType(inTypeLayout) )
+ {
+ return spReflectionType_GetKind(type);
+ }
+
+ auto typeLayout = convert(inTypeLayout);
+ if( as<StructTypeLayout>(typeLayout) )
+ {
+ return SLANG_TYPE_KIND_STRUCT;
+ }
+ else if( as<ParameterGroupTypeLayout>(typeLayout) )
+ {
+ return SLANG_TYPE_KIND_CONSTANT_BUFFER;
+ }
+
+ return SLANG_TYPE_KIND_NONE;
+}
+
namespace
{
static size_t getReflectionSize(LayoutSize size)
@@ -723,6 +750,27 @@ SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetFieldByIndex(
return nullptr;
}
+SLANG_API SlangInt spReflectionTypeLayout_findFieldIndexByName(SlangReflectionTypeLayout* inTypeLayout, const char* nameBegin, const char* nameEnd)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return -1;
+
+ UnownedStringSlice name = nameEnd != nullptr ? UnownedStringSlice(nameBegin, nameEnd) : UnownedTerminatedStringSlice(nameBegin);
+
+ if(auto structTypeLayout = as<StructTypeLayout>(typeLayout))
+ {
+ Index fieldCount = structTypeLayout->fields.getCount();
+ for(Index f = 0; f < fieldCount; ++f)
+ {
+ auto field = structTypeLayout->fields[f];
+ if(getReflectionName(field->varDecl)->text.getUnownedSlice() == name)
+ return f;
+ }
+ }
+
+ return -1;
+}
+
SLANG_API size_t spReflectionTypeLayout_GetElementStride(SlangReflectionTypeLayout* inTypeLayout, SlangParameterCategory category)
{
auto typeLayout = convert(inTypeLayout);
@@ -920,6 +968,887 @@ SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSpecializedTy
}
}
+namespace Slang
+{
+ struct BindingRangePathLink
+ {
+ BindingRangePathLink(
+ BindingRangePathLink* parent,
+ VarLayout* var)
+ : parent(parent)
+ , var(var)
+ {}
+
+ BindingRangePathLink* parent;
+ VarLayout* var;
+ };
+
+
+ Int _calcIndexOffset(BindingRangePathLink* path, LayoutResourceKind kind)
+ {
+ Int result = 0;
+ for( auto link = path; link; link = link->parent )
+ {
+ if( auto resInfo = link->var->FindResourceInfo(kind) )
+ {
+ result += resInfo->index;
+ }
+ }
+ return result;
+ }
+
+ Int _calcSpaceOffset(BindingRangePathLink* path, LayoutResourceKind kind)
+ {
+ Int result = 0;
+ for( auto link = path; link; link = link->parent )
+ {
+ if( auto resInfo = link->var->FindResourceInfo(kind) )
+ {
+ result += resInfo->space;
+ }
+ }
+ return result;
+ }
+
+ SlangBindingType _calcResourceBindingType(
+ Type* type)
+ {
+ if( auto resourceType = as<ResourceType>(type) )
+ {
+ auto shape = resourceType->getBaseShape();
+
+ auto access = resourceType->getAccess();
+ auto mutableFlag = access != SLANG_RESOURCE_ACCESS_READ ? SLANG_BINDING_TYPE_MUTABLE_FLAG : 0;
+
+ switch( shape )
+ {
+ default:
+ return SLANG_BINDING_TYPE_TEXTURE | mutableFlag;
+
+ case SLANG_TEXTURE_BUFFER:
+ return SLANG_BINDING_TYPE_TYPED_BUFFER | mutableFlag;
+ }
+
+ }
+ else if( auto structuredBufferType = as<HLSLStructuredBufferTypeBase>(type) )
+ {
+ if( as<HLSLStructuredBufferType>(type) )
+ {
+ return SLANG_BINDING_TYPE_RAW_BUFFER;
+ }
+ else
+ {
+ return SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER;
+ }
+ }
+ else if( as<RaytracingAccelerationStructureType>(type) )
+ {
+ return SLANG_BINDING_TYPE_RAY_TRACTING_ACCELERATION_STRUCTURE;
+ }
+ else if( auto untypedBufferType = as<UntypedBufferResourceType>(type) )
+ {
+ if( as<HLSLByteAddressBufferType>(type) )
+ {
+ return SLANG_BINDING_TYPE_RAW_BUFFER;
+ }
+ else
+ {
+ return SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER;
+ }
+ }
+ else if( as<ConstantBufferType>(type) )
+ {
+ return SLANG_BINDING_TYPE_CONSTANT_BUFFER;
+ }
+ else
+ {
+ SLANG_UNEXPECTED("unhandled resource binding type");
+ }
+ }
+
+ SlangBindingType _calcResourceBindingType(
+ TypeLayout* typeLayout)
+ {
+ if(auto type = typeLayout->getType())
+ {
+ return _calcResourceBindingType(type);
+ }
+
+ if(as<ParameterGroupTypeLayout>(typeLayout))
+ {
+ return SLANG_BINDING_TYPE_CONSTANT_BUFFER;
+ }
+ else
+ {
+ SLANG_UNEXPECTED("unhandled resource binding type");
+ }
+ }
+
+
+ SlangBindingType _calcBindingType(
+ Slang::TypeLayout* typeLayout,
+ LayoutResourceKind kind)
+ {
+ switch( kind )
+ {
+ default:
+ return SLANG_BINDING_TYPE_UNKNOWN;
+
+ // Some cases of `LayoutResourceKind` can be mapped
+ // directly to a `BindingType` because there is only
+ // one case of types that have that resource kind.
+
+ #define CASE(FROM, TO) \
+ case LayoutResourceKind::FROM: return SLANG_BINDING_TYPE_##TO
+
+ CASE(ConstantBuffer, CONSTANT_BUFFER);
+ CASE(SamplerState, SAMPLER);
+ CASE(VaryingInput, VARYING_INPUT);
+ CASE(VaryingOutput, VARYING_OUTPUT);
+ CASE(ExistentialObjectParam, EXISTENTIAL_VALUE);
+ CASE(PushConstantBuffer, PUSH_CONSTANT);
+ // TODO: register space
+
+ #undef CASE
+
+ case LayoutResourceKind::ShaderResource:
+ case LayoutResourceKind::UnorderedAccess:
+ case LayoutResourceKind::DescriptorTableSlot:
+ return _calcResourceBindingType(typeLayout);
+ }
+ }
+
+ static DeclRefType* asInterfaceType(Type* type)
+ {
+ if(auto declRefType = as<DeclRefType>(type))
+ {
+ if(declRefType->declRef.as<InterfaceDecl>())
+ {
+ return declRefType;
+ }
+ }
+ return nullptr;
+ }
+
+ struct ExtendedTypeLayoutContext
+ {
+ TypeLayout* m_typeLayout;
+ TypeLayout::ExtendedInfo* m_extendedInfo;
+
+ Dictionary<Int, Int> m_mapSpaceToDescriptorSetIndex;
+
+ Int _findOrAddDescriptorSet(Int space)
+ {
+ Int index = 0;
+ if(m_mapSpaceToDescriptorSetIndex.TryGetValue(space, index))
+ return index;
+
+ index = m_extendedInfo->m_descriptorSets.getCount();
+ m_mapSpaceToDescriptorSetIndex.Add(space, index);
+
+ RefPtr<TypeLayout::ExtendedInfo::DescriptorSetInfo> descriptorSet = new TypeLayout::ExtendedInfo::DescriptorSetInfo();
+ m_extendedInfo->m_descriptorSets.add(descriptorSet);
+
+ return index;
+ }
+
+ void addRangesRec(TypeLayout* typeLayout, BindingRangePathLink* path, LayoutSize multiplier)
+ {
+ if( auto structTypeLayout = as<StructTypeLayout>(typeLayout) )
+ {
+ // For a structure type, we need to recursively
+ // add the ranges for each field.
+ //
+ // Along the way we will make sure to properly update
+ // the offset information on the fields so that
+ // they properly show their binding-range offset
+ // within the parent type.
+ //
+ Index structBindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
+ for( auto fieldVarLayout : structTypeLayout->fields )
+ {
+ Index fieldBindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
+ fieldVarLayout->bindingRangeOffset = fieldBindingRangeIndex - structBindingRangeIndex;
+
+ auto fieldTypeLayout = fieldVarLayout->getTypeLayout();
+
+
+ BindingRangePathLink fieldLink(path, fieldVarLayout);
+ addRangesRec(fieldTypeLayout, &fieldLink, multiplier);
+ }
+ return;
+ }
+ else if( auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout) )
+ {
+ // For an array, we need to recursively add the
+ // element type of the array, but with an adjusted
+ // `multiplier` to account for the element count.
+ //
+ auto elementTypeLayout = arrayTypeLayout->elementTypeLayout;
+ LayoutSize elementCount = LayoutSize::infinite();
+ if( auto arrayType = as<ArrayExpressionType>(arrayTypeLayout->type) )
+ {
+ if( auto elementCountVal = arrayType->arrayLength )
+ {
+ elementCount = LayoutSize::RawValue(getIntVal(elementCountVal));
+ }
+ }
+ addRangesRec(elementTypeLayout, path, multiplier * elementCount);
+ return;
+ }
+ else if( auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout))
+ {
+ // A parameter group (whether a `ConstantBuffer<>` or `ParameterBlock<>`
+ // introduces a separately-allocated "sub-object" in the application's
+ // layout for shader objects.
+ //
+ // We will represent the parameter group with a single sub-object
+ // binding range (and an associated sub-object range).
+ //
+ // We start out by looking at the resources consumed by the parameter group
+ // itself, to determine what kind of binding range to report it as.
+ //
+ Index bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
+ SlangBindingType bindingType = SLANG_BINDING_TYPE_CONSTANT_BUFFER;
+ Index spaceOffset = -1;
+ LayoutResourceKind kind = LayoutResourceKind::None;
+ for(auto& resInfo : parameterGroupTypeLayout->resourceInfos)
+ {
+ kind = resInfo.kind;
+ switch(kind)
+ {
+ default:
+ continue;
+
+ case LayoutResourceKind::ConstantBuffer:
+ case LayoutResourceKind::PushConstantBuffer:
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::DescriptorTableSlot:
+ break;
+ }
+
+ bindingType = _calcBindingType(typeLayout, kind);
+ spaceOffset = _calcSpaceOffset(path, kind);
+ break;
+ }
+
+ TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange;
+ bindingRange.leafTypeLayout = typeLayout;
+ bindingRange.bindingType = bindingType;
+ bindingRange.count = multiplier;
+ bindingRange.descriptorSetIndex = -1;
+ bindingRange.firstDescriptorRangeIndex = 0;
+ bindingRange.descriptorRangeCount = 0;
+
+ if( kind == LayoutResourceKind::PushConstantBuffer )
+ {
+ if(auto resInfo = parameterGroupTypeLayout->elementVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform))
+ {
+ bindingRange.count *= resInfo->count;
+ }
+ }
+
+ // Every parameter group will introduce a sub-object range,
+ // which will include bindings based on the type of data
+ // inside the sub-object.
+ //
+ TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange;
+ subObjectRange.bindingRangeIndex = bindingRangeIndex;
+
+ // It is possible that the sub-object has descriptor ranges
+ // that will need to be exposed upward, into the parent.
+ //
+ if( spaceOffset != -1 )
+ {
+ Int descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset);
+ auto descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex];
+ auto firstDescriptorRangeIndex = descriptorSet->descriptorRanges.getCount();
+
+ // TODO: We need to recursively add descriptor ranges (but not binding
+ // ranges!) for anything in the element type that "leaks" into
+ // the surrounding context.
+ //
+ switch(kind)
+ {
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::Uniform:
+ case LayoutResourceKind::None:
+ break;
+
+ default:
+ {
+ // This means we are in the constant-buffer-like case
+ // (even if the user wrote `ParameterBlock<T>`), and any
+ // resource usage inside the element type should "leak"
+ // out to the parent scope.
+ //
+ // It *also* means we should add a suitable descriptor
+ // range if one is required for the "container" type.
+ //
+ for(auto resInfo : parameterGroupTypeLayout->containerVarLayout->typeLayout->resourceInfos)
+ {
+ switch( resInfo.kind )
+ {
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::Uniform:
+ continue;
+
+ default:
+ break;
+ }
+
+ TypeLayout::ExtendedInfo::DescriptorRangeInfo descriptorRange;
+ descriptorRange.kind = resInfo.kind;
+ descriptorRange.bindingType = _calcBindingType(typeLayout, resInfo.kind);
+ descriptorRange.count = multiplier;
+ descriptorRange.indexOffset = _calcIndexOffset(path, resInfo.kind);
+
+ if( resInfo.kind == LayoutResourceKind::PushConstantBuffer )
+ {
+ if(auto uniformResInfo = parameterGroupTypeLayout->elementVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform))
+ {
+ descriptorRange.count *= uniformResInfo->count;
+ }
+ }
+
+ descriptorSet->descriptorRanges.add(descriptorRange);
+ }
+
+ // Now we need to recursively walk the element type and add all its
+ // descriptor ranges, so that they can be used for binding in
+ // the parent.
+ //
+ // We have this a bit by collecting both binding ranges and
+ // descriptor ranges, and then throwing away the binding ranges
+ // from the element type.
+ //
+ BindingRangePathLink elementPath(path, parameterGroupTypeLayout->elementVarLayout);
+
+ Index bindingRangeCountBefore = m_extendedInfo->m_bindingRanges.getCount();
+ Index subObjectRangeCountBefore = m_extendedInfo->m_subObjectRanges.getCount();
+
+ addRangesRec(parameterGroupTypeLayout->elementVarLayout->typeLayout, &elementPath, multiplier);
+
+ m_extendedInfo->m_bindingRanges.setCount(bindingRangeCountBefore);
+ m_extendedInfo->m_subObjectRanges.setCount(subObjectRangeCountBefore);
+ }
+ break;
+ }
+
+ auto descriptorRangeCount = descriptorSet->descriptorRanges.getCount() - firstDescriptorRangeIndex;
+ bindingRange.descriptorSetIndex = descriptorSetIndex;
+ bindingRange.firstDescriptorRangeIndex = firstDescriptorRangeIndex;
+ bindingRange.descriptorRangeCount = descriptorRangeCount;
+ }
+
+ m_extendedInfo->m_bindingRanges.add(bindingRange);
+ m_extendedInfo->m_subObjectRanges.add(subObjectRange);
+ return;
+ }
+ else if(asInterfaceType(typeLayout->type))
+ {
+ // An `interface` type should introduce a sub-object range,
+ // with no concrete descriptor ranges to store its value
+ // (since we don't know until runtime what type of
+ // value will be plugged in).
+ //
+
+ LayoutResourceKind kind = LayoutResourceKind::ExistentialObjectParam;
+ auto count = multiplier;
+ auto spaceOffset = _calcSpaceOffset(path, kind);
+
+ Int descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset);
+ auto descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex];
+
+ TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange;
+ bindingRange.leafTypeLayout = typeLayout;
+ bindingRange.bindingType = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE;
+ bindingRange.count = multiplier;
+ bindingRange.descriptorSetIndex = descriptorSetIndex;
+ bindingRange.firstDescriptorRangeIndex = descriptorSet->descriptorRanges.getCount();
+ bindingRange.descriptorRangeCount = 1;
+
+ TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange;
+ subObjectRange.bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
+
+ m_extendedInfo->m_bindingRanges.add(bindingRange);
+ m_extendedInfo->m_subObjectRanges.add(subObjectRange);
+ }
+ // TODO: We need to handle `interface` types here, because they are
+ // another case that introduces a "sub-object" for the purposes of
+ // application-side allocation.
+ //
+ // TODO: There are a few cases of "leaf" fields that might
+ // still result in multiple descriptors (or at least multiple
+ // `LayoutResourceKind`s) depending on the target.
+ //
+ // For eample, combined texture-sampler types should be treated
+ // as "leaf" fields for this code (since a portable engine would
+ // need to abstract over them), but would map to two descriptors
+ // on targets that don't actually support combining them.
+ else
+ {
+ Int resourceKindCount = typeLayout->resourceInfos.getCount();
+ if(resourceKindCount == 0)
+ {
+ // This is a field that consumes no resources, and as
+ // such does not need a binding or descriptor ranges
+ // allocated for it.
+ //
+ return;
+ }
+ else if(resourceKindCount == 1)
+ {
+ auto& resInfo = typeLayout->resourceInfos[0];
+ LayoutResourceKind kind = resInfo.kind;
+
+ if(kind == LayoutResourceKind::Uniform)
+ {
+ // We do not consider uniform resource usage
+ // in the ranges we compute.
+ //
+ // TODO: We may need to revise that rule for types that
+ // represent resources, even when one or more targets
+ // map those resource types to ordinary/uniform data.
+ //
+ return;
+ }
+
+ // This leaf field will map to a single binding range and,
+ // if it is appropriate, a single descriptor range.
+ //
+ auto bindingType = _calcBindingType(typeLayout, kind);
+ auto count = resInfo.count * multiplier;
+ auto indexOffset = _calcIndexOffset(path, kind);
+ auto spaceOffset = _calcSpaceOffset(path, kind);
+
+ Int descriptorSetIndex = -1;
+ Int firstDescriptorIndex = 0;
+ RefPtr<TypeLayout::ExtendedInfo::DescriptorSetInfo> descriptorSet;
+ switch( kind )
+ {
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::VaryingInput:
+ case LayoutResourceKind::VaryingOutput:
+ case LayoutResourceKind::HitAttributes:
+ case LayoutResourceKind::RayPayload:
+ // Resource kinds that represent "varying" input/output
+ // do not manifest as entries in API descriptor tables.
+ //
+ // TODO: Neither do root constants, if we are being
+ // precise. This API really needs to carefully match
+ // the semantics of the target platform/API in terms
+ // of what things are descriptor-bound and which are
+ // not, so that a user can easily allocate the platform-specific
+ // descriptor sets using this info.
+ //
+ // (That said, we are purposefully *not* breaking apart
+ // samplers and SRV/UAV/CBV stuff for our D3D reflection
+ // of descriptor sets. It seems like the policy here
+ // really requires careful thought)
+ //
+ // TODO: Maybe the best answer is to leave decomposition
+ // of stuff into descriptor sets up to the application
+ // layer? This is especially true if a common case would
+ // be an application that doesn't support arbitrary manual
+ // binding of parameters to register/spaces.
+ //
+ break;
+
+ default:
+ {
+ TypeLayout::ExtendedInfo::DescriptorRangeInfo descriptorRange;
+ descriptorRange.kind = kind;
+ descriptorRange.bindingType = bindingType;
+ descriptorRange.count = count;
+ descriptorRange.indexOffset = indexOffset;
+
+ descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset);
+ descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex];
+
+ firstDescriptorIndex = descriptorSet->descriptorRanges.getCount();
+ descriptorSet->descriptorRanges.add(descriptorRange);
+ }
+ break;
+ }
+
+
+ TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange;
+ bindingRange.leafTypeLayout = typeLayout;
+ bindingRange.bindingType = _calcBindingType(typeLayout, kind);
+ bindingRange.count = count;
+ bindingRange.descriptorSetIndex = descriptorSetIndex;
+ bindingRange.firstDescriptorRangeIndex = firstDescriptorIndex;
+ bindingRange.descriptorRangeCount = 1;
+
+ m_extendedInfo->m_bindingRanges.add(bindingRange);
+ }
+ else
+ {
+ // This type appears to be one that consumes multiple
+ // resource kinds, but was not handled by any of
+ // the special-case logic above. In such a case we
+ // are in trouble.
+ //
+ return;
+ }
+ }
+ }
+ };
+
+ TypeLayout::ExtendedInfo* getExtendedTypeLayout(TypeLayout* typeLayout)
+ {
+ if( !typeLayout->m_extendedInfo )
+ {
+ RefPtr<TypeLayout::ExtendedInfo> extendedInfo = new TypeLayout::ExtendedInfo;
+
+ ExtendedTypeLayoutContext context;
+ context.m_typeLayout = typeLayout;
+ context.m_extendedInfo = extendedInfo;
+
+ context.addRangesRec(typeLayout, nullptr, 1);
+
+ typeLayout->m_extendedInfo = extendedInfo;
+ }
+ return typeLayout->m_extendedInfo;
+ }
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeCount(SlangReflectionTypeLayout* inTypeLayout)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+ return extTypeLayout->m_bindingRanges.getCount();
+}
+
+SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return SLANG_BINDING_TYPE_UNKNOWN;
+
+ 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.bindingType;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(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];
+
+ auto count = bindingRange.count;
+ return count.isFinite() ? SlangInt(count.getFiniteValue()) : -1;
+}
+
+#if 0
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeIndexOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ return Slang::_findBindingRange(typeLayout, index).indexOffset;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeSpaceOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ return Slang::_findBindingRange(typeLayout, index).spaceOffset;
+}
+#endif
+
+SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+ if(index < 0) return 0;
+ if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0;
+ auto& bindingRange = extTypeLayout->m_bindingRanges[index];
+
+ return convert(bindingRange.leafTypeLayout);
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(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.descriptorSetIndex;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(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.firstDescriptorRangeIndex;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* inTypeLayout)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ return extTypeLayout->m_descriptorSets.getCount();
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(setIndex < 0) return 0;
+ if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0;
+ auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex];
+
+ return descriptorSet->spaceOffset;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(setIndex < 0) return 0;
+ if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0;
+ auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex];
+
+ return descriptorSet->descriptorRanges.getCount();
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(setIndex < 0) return 0;
+ if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0;
+ auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex];
+
+ if(rangeIndex < 0) return 0;
+ if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0;
+ auto& range = descriptorSet->descriptorRanges[rangeIndex];
+
+ return range.indexOffset;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(setIndex < 0) return 0;
+ if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0;
+ auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex];
+
+ if(rangeIndex < 0) return 0;
+ if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0;
+ auto& range = descriptorSet->descriptorRanges[rangeIndex];
+
+ auto count = range.count;
+ return count.isFinite() ? count.getFiniteValue() : -1;
+}
+
+SLANG_API SlangBindingType spReflectionTypeLayout_getDescriptorSetDescriptorRangeType(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(setIndex < 0) return 0;
+ if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0;
+ auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex];
+
+ if(rangeIndex < 0) return 0;
+ if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0;
+ auto& range = descriptorSet->descriptorRanges[rangeIndex];
+
+ return range.bindingType;
+}
+
+SLANG_API SlangParameterCategory spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(setIndex < 0) return 0;
+ if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0;
+ auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex];
+
+ if(rangeIndex < 0) return 0;
+ if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0;
+ auto& range = descriptorSet->descriptorRanges[rangeIndex];
+
+ return SlangParameterCategory(range.kind);
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* inTypeLayout)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ return extTypeLayout->m_subObjectRanges.getCount();
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if(subObjectRangeIndex < 0) return 0;
+ if(subObjectRangeIndex >= extTypeLayout->m_subObjectRanges.getCount()) return 0;
+
+ return extTypeLayout->m_subObjectRanges[subObjectRangeIndex].bindingRangeIndex;
+}
+
+
+#if 0
+SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeSubObjectRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ return Slang::_findBindingRange(typeLayout, index).subObjectRangeIndex;
+}
+#endif
+
+
+SLANG_API SlangInt spReflectionTypeLayout_getFieldBindingRangeOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt fieldIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ if( auto structTypeLayout = as<StructTypeLayout>(typeLayout) )
+ {
+ getExtendedTypeLayout(structTypeLayout);
+
+ return structTypeLayout->fields[fieldIndex]->bindingRangeOffset;
+ }
+
+ return 0;
+}
+
+#if 0
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* inTypeLayout)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ return Slang::_calcSubObjectRangeCount(typeLayout);
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeObjectCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto count = Slang::_findSubObjectRange(typeLayout, index).count;
+ return count.isFinite() ? SlangInt(count.getFiniteValue()) : -1;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ return Slang::_findSubObjectRange(typeLayout, index).bindingRangeIndex;
+}
+
+
+SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getSubObjectRangeTypeLayout(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ return convert(Slang::_findSubObjectRange(typeLayout, index).leafTypeLayout);
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex);
+ return Slang::_getSubObjectDescriptorRangeCount(subObjectRange);
+}
+
+SLANG_API SlangBindingType spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingType(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex);
+ return Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).bindingType;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex);
+ auto count = Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).count;
+ return count.isFinite() ? count.getFiniteValue() : -1;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeIndexOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex);
+ return Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).indexOffset;
+}
+
+SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeSpaceOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if(!typeLayout) return 0;
+
+ auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex);
+ return Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).spaceOffset;
+}
+#endif
// Variable Reflection
@@ -1427,6 +2356,14 @@ SLANG_API SlangReflectionParameter* spReflection_GetParameterByIndex(SlangReflec
return convert(globalStructLayout->fields[index].Ptr());
}
+SLANG_API SlangReflectionVariableLayout* spReflection_getGlobalParamsVarLayout(SlangReflection* inProgram)
+{
+ auto program = convert(inProgram);
+ if(!program) return nullptr;
+
+ return convert(program->parametersLayout);
+}
+
SLANG_API unsigned int spReflection_GetTypeParameterCount(SlangReflection * reflection)
{
auto program = convert(reflection);
diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h
index 1849b5736..c4df46fe0 100644
--- a/source/slang/slang-type-layout.h
+++ b/source/slang/slang-type-layout.h
@@ -405,6 +405,46 @@ public:
/// Otherwise, returns this type layout.
///
RefPtr<TypeLayout> unwrapArray();
+
+
+ /// Extended information about type layout, used for "flat" reflection API
+ struct ExtendedInfo : public RefObject
+ {
+ struct DescriptorRangeInfo
+ {
+ SlangBindingType bindingType;
+ LayoutResourceKind kind;
+ LayoutSize count;
+ Int indexOffset;
+ };
+
+ struct DescriptorSetInfo : public RefObject
+ {
+ Int spaceOffset;
+ List<DescriptorRangeInfo> descriptorRanges;
+ };
+
+ struct BindingRangeInfo
+ {
+ TypeLayout* leafTypeLayout;
+ SlangBindingType bindingType;
+ LayoutSize count;
+ Int descriptorSetIndex;
+ Int firstDescriptorRangeIndex;
+ Int descriptorRangeCount;
+ };
+
+ struct SubObjectRangeInfo
+ {
+ Int bindingRangeIndex;
+ };
+
+ List<RefPtr<DescriptorSetInfo>> m_descriptorSets;
+ List<BindingRangeInfo> m_bindingRanges;
+ List<SubObjectRangeInfo> m_subObjectRanges;
+ };
+
+ RefPtr<ExtendedInfo> m_extendedInfo;
};
typedef unsigned int VarLayoutFlags;
@@ -495,6 +535,12 @@ public:
void removeResourceUsage(LayoutResourceKind kind);
RefPtr<VarLayout> pendingVarLayout;
+
+ /// Offset in binding ranges within the parent type
+ ///
+ /// Note: only usable when extended layout information has been calculated.
+ ///
+ Index bindingRangeOffset = -1;
};
// type layout for a variable that has a constant-buffer type
diff --git a/tests/bugs/bool-init.slang b/tests/bugs/bool-init.slang
index 7484d450e..1e9627024 100644
--- a/tests/bugs/bool-init.slang
+++ b/tests/bugs/bool-init.slang
@@ -7,7 +7,7 @@ struct Thing
bool b;
};
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/bool-op.slang b/tests/bugs/bool-op.slang
index 1ce5d7c4f..c10c7e0dd 100644
--- a/tests/bugs/bool-op.slang
+++ b/tests/bugs/bool-op.slang
@@ -4,7 +4,7 @@
// Confirm operations that produce bools - such as comparisons, or && ||, ! work correctly
-//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
[numthreads(16, 1, 1)]
diff --git a/tests/bugs/gh-357.slang b/tests/bugs/gh-357.slang
index 7c2a87a41..90eba799b 100644
--- a/tests/bugs/gh-357.slang
+++ b/tests/bugs/gh-357.slang
@@ -1,5 +1,7 @@
//TEST(compute):COMPARE_COMPUTE:
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
+
//TEST_INPUT:type AssocImpl
diff --git a/tests/bugs/gh-471.slang b/tests/bugs/gh-471.slang
index a68ade010..adc50e799 100644
--- a/tests/bugs/gh-471.slang
+++ b/tests/bugs/gh-471.slang
@@ -1,5 +1,5 @@
//TEST(compute):COMPARE_COMPUTE:
-//TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):out,name outputBuffer
// Test that "operator comma" works as expected
diff --git a/tests/bugs/gh-487.slang b/tests/bugs/gh-487.slang
index a86c4061f..08ae8aa06 100644
--- a/tests/bugs/gh-487.slang
+++ b/tests/bugs/gh-487.slang
@@ -15,7 +15,7 @@ int test(int val)
return int(result);
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name gBuffer
RWStructuredBuffer<int> gBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/gh-518.slang b/tests/bugs/gh-518.slang
index 3f316c19e..8de61a94e 100644
--- a/tests/bugs/gh-518.slang
+++ b/tests/bugs/gh-518.slang
@@ -8,11 +8,11 @@
// Confirm that we can handle arrays of resources
// being passed to a function.
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name gBuffer
RWStructuredBuffer<int> gBuffer;
-//TEST_INPUT: Texture2D(size=4, content=one):
-//TEST_INPUT: Texture2D(size=4, content=one):
+//TEST_INPUT: Texture2D(size=4, content=one):name gTextures[0]
+//TEST_INPUT: Texture2D(size=4, content=one):name gTextures[1]
Texture2D gTextures[2];
float broken(Texture2D t[2])
diff --git a/tests/bugs/gh-519.slang b/tests/bugs/gh-519.slang
index 733864c85..207fa6d0a 100644
--- a/tests/bugs/gh-519.slang
+++ b/tests/bugs/gh-519.slang
@@ -29,7 +29,7 @@ int test(int val)
return tmp;
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name gBuffer
RWStructuredBuffer<int> gBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/gh-566.slang b/tests/bugs/gh-566.slang
index 5e5803aea..4c5fa1772 100644
--- a/tests/bugs/gh-566.slang
+++ b/tests/bugs/gh-566.slang
@@ -1,8 +1,8 @@
// legalize-struct-init.slang
//TEST(compute):COMPARE_COMPUTE:
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
-//TEST_INPUT:ubuffer(data=[4 3 2 1], stride=4):
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
+//TEST_INPUT:ubuffer(data=[4 3 2 1], stride=4):name inputBuffer
RWStructuredBuffer<uint> outputBuffer;
diff --git a/tests/bugs/gh-569.slang b/tests/bugs/gh-569.slang
index c0a65aaa8..21fbfa514 100644
--- a/tests/bugs/gh-569.slang
+++ b/tests/bugs/gh-569.slang
@@ -21,7 +21,7 @@ uint test(uint inVal)
return tmp + inVal;
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name gBuffer
RWStructuredBuffer<uint> gBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/gh-775.slang b/tests/bugs/gh-775.slang
index f98765bdb..867233919 100644
--- a/tests/bugs/gh-775.slang
+++ b/tests/bugs/gh-775.slang
@@ -17,7 +17,7 @@ int test(int inVal)
return int(dot(v, float4(1, 16, 256, 4096)));
}
-//TEST_INPUT:ubuffer(data=[9 9 9 9], stride=4):out
+//TEST_INPUT:ubuffer(data=[9 9 9 9], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer : register(u0);
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/gl-33.slang b/tests/bugs/gl-33.slang
index b459bf409..10c9ea208 100644
--- a/tests/bugs/gl-33.slang
+++ b/tests/bugs/gl-33.slang
@@ -13,7 +13,7 @@ int test(int val)
return b.next();
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name gBuffer
RWStructuredBuffer<int> gBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/glsl-static-const-array.slang b/tests/bugs/glsl-static-const-array.slang
index f4e953259..4d03d5ef8 100644
--- a/tests/bugs/glsl-static-const-array.slang
+++ b/tests/bugs/glsl-static-const-array.slang
@@ -7,7 +7,7 @@ static const int gData[4] =
0xA, 0xB, 0xC, 0xD,
};
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name gBuffer
RWStructuredBuffer<int> gBuffer;
[numthreads(4,1,1)]
diff --git a/tests/bugs/nested-generics-call.slang b/tests/bugs/nested-generics-call.slang
index 9a540a261..ba1566ec2 100644
--- a/tests/bugs/nested-generics-call.slang
+++ b/tests/bugs/nested-generics-call.slang
@@ -1,6 +1,6 @@
//TEST(compute):COMPARE_COMPUTE:
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<float> outputBuffer;
interface IBase
diff --git a/tests/bugs/nested-generics-method-call.slang b/tests/bugs/nested-generics-method-call.slang
index a127ed0da..fa0a983b9 100644
--- a/tests/bugs/nested-generics-method-call.slang
+++ b/tests/bugs/nested-generics-method-call.slang
@@ -1,6 +1,6 @@
//TEST(compute):COMPARE_COMPUTE:
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<float> outputBuffer;
interface IBase
diff --git a/tests/bugs/paren-insertion-bug.slang b/tests/bugs/paren-insertion-bug.slang
index 6c989d793..790934372 100644
--- a/tests/bugs/paren-insertion-bug.slang
+++ b/tests/bugs/paren-insertion-bug.slang
@@ -19,7 +19,7 @@ int test(float a)
}
-//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<uint> outputBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/static-method.slang b/tests/bugs/static-method.slang
index c728e9053..f95d40def 100644
--- a/tests/bugs/static-method.slang
+++ b/tests/bugs/static-method.slang
@@ -10,7 +10,7 @@ struct S
}
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer : register(u0);
int test(int t)
diff --git a/tests/bugs/static-var.slang b/tests/bugs/static-var.slang
index d130b6a7d..75662c7b5 100644
--- a/tests/bugs/static-var.slang
+++ b/tests/bugs/static-var.slang
@@ -7,7 +7,7 @@ int test(int inVal)
return inVal + kVal;
}
-//TEST_INPUT:ubuffer(data=[9 9 9 9], stride=4):out
+//TEST_INPUT:ubuffer(data=[9 9 9 9], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer : register(u0);
[numthreads(4, 1, 1)]
diff --git a/tests/bugs/texture2d-gather.hlsl b/tests/bugs/texture2d-gather.hlsl
index 2fc9424c5..6eb8b1af7 100644
--- a/tests/bugs/texture2d-gather.hlsl
+++ b/tests/bugs/texture2d-gather.hlsl
@@ -1,6 +1,6 @@
//TEST(smoke):COMPARE_HLSL_RENDER:
-//TEST_INPUT: Texture2D(size=16, content=chessboard, format=R_Float32):
-//TEST_INPUT: Sampler :
+//TEST_INPUT: Texture2D(size=16, content=chessboard, format=R_Float32):name g_texture
+//TEST_INPUT: Sampler :name g_sampler
Texture2D<float> g_texture : register(t0);
SamplerState g_sampler : register(s0);
diff --git a/tests/bugs/vec-compare.slang b/tests/bugs/vec-compare.slang
index 2b233f80f..7a6d8388d 100644
--- a/tests/bugs/vec-compare.slang
+++ b/tests/bugs/vec-compare.slang
@@ -2,8 +2,7 @@
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
-//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out
-
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
[numthreads(4,4,1)]
diff --git a/tests/bugs/while-in-generic.slang b/tests/bugs/while-in-generic.slang
index 7d2b8b255..4efa9a5d2 100644
--- a/tests/bugs/while-in-generic.slang
+++ b/tests/bugs/while-in-generic.slang
@@ -12,7 +12,7 @@ struct Context
return i;
}
};
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/compute/cbuffer-legalize.slang b/tests/compute/cbuffer-legalize.slang
index bbb08b565..416eded1e 100644
--- a/tests/compute/cbuffer-legalize.slang
+++ b/tests/compute/cbuffer-legalize.slang
@@ -1,8 +1,8 @@
//TEST(compute):COMPARE_COMPUTE:-cpu
-//TEST(compute):COMPARE_COMPUTE:
+//TEST(compute):COMPARE_COMPUTE:-shaderobj
-//TEST_INPUT:cbuffer(data=[1 2 3 4]):name=C.p.c
-//TEST_INPUT:Texture2D(size=4, content = one):name=C.p.t
+//TEST_INPUT: Uniform(data=[1 2 3 4]):name=C.p.c
+//TEST_INPUT: Texture2D(size=4, content = one):name=C.p.t
//TEST_INPUT: Sampler:name=C.p.s
//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
diff --git a/tests/compute/compile-time-loop.slang b/tests/compute/compile-time-loop.slang
index e081dfbd3..128e72895 100644
--- a/tests/compute/compile-time-loop.slang
+++ b/tests/compute/compile-time-loop.slang
@@ -1,8 +1,8 @@
//TEST(compute):COMPARE_RENDER_COMPUTE:
-//TEST_INPUT: Texture2D(size=4, content = one):
-//TEST_INPUT: Sampler:
-//TEST_INPUT: ubuffer(data=[0], stride=4):out
+//TEST_INPUT: Texture2D(size=4, content = one):name t
+//TEST_INPUT: Sampler:name s
+//TEST_INPUT: ubuffer(data=[0], stride=4):out, name outputBuffer
Texture2D t;
SamplerState s;
diff --git a/tests/compute/constexpr.slang b/tests/compute/constexpr.slang
index 247d3964d..cb14b1a9c 100644
--- a/tests/compute/constexpr.slang
+++ b/tests/compute/constexpr.slang
@@ -1,9 +1,10 @@
// constexpr.slang
//TEST(compute):COMPARE_COMPUTE_EX:-slang -gcompute
//DISABLED://TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -gcompute
-//TEST_INPUT: Texture2D(size=4, content = one):
-//TEST_INPUT: Sampler:
-//TEST_INPUT: ubuffer(data=[0 0], stride=4):out
+
+//TEST_INPUT: Texture2D(size=4, content = one):name tex
+//TEST_INPUT: Sampler:name samp
+//TEST_INPUT: ubuffer(data=[0 0], stride=4):out,name outputBuffer
// Note: Vulkan version of this test is disabled pending adding
// support for rendering tests to the harness.
diff --git a/tests/compute/discard-stmt.slang b/tests/compute/discard-stmt.slang
index 5a8210118..1af42c6a0 100644
--- a/tests/compute/discard-stmt.slang
+++ b/tests/compute/discard-stmt.slang
@@ -1,7 +1,7 @@
//TEST(compute):COMPARE_RENDER_COMPUTE:
-//TEST_INPUT: Texture2D(size=4, content = one):
-//TEST_INPUT: Sampler:
-//TEST_INPUT: ubuffer(data=[0 0], stride=4):out
+//TEST_INPUT: Texture2D(size=4, content = one):name tex
+//TEST_INPUT: Sampler:name samp
+//TEST_INPUT: ubuffer(data=[0 0], stride=4):out,name outputBuffer
Texture2D tex;
diff --git a/tests/compute/dump-repro.slang b/tests/compute/dump-repro.slang
index dd07574ad..90a9578fa 100644
--- a/tests/compute/dump-repro.slang
+++ b/tests/compute/dump-repro.slang
@@ -13,4 +13,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
int index = int(dispatchThreadID.x);
outputBuffer[index] = index * 2 + 1;
-} \ No newline at end of file
+}
diff --git a/tests/compute/global-generic-value-param.slang b/tests/compute/global-generic-value-param.slang
index 6214925c6..d2299e501 100644
--- a/tests/compute/global-generic-value-param.slang
+++ b/tests/compute/global-generic-value-param.slang
@@ -29,7 +29,7 @@ __generic_value_param kOffset : uint = 0;
// bit less trivial.
//
RWStructuredBuffer<uint> vals;
-//TEST_INPUT: ubuffer(data=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15], stride=4):
+//TEST_INPUT: ubuffer(data=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15], stride=4):name vals
// The core test function will use the `kOffset` value
// we declared above along with the input value (the
@@ -45,7 +45,7 @@ uint test(uint value)
// And finally we have the boilerplate cruft that almost
// all of our compute tests use.
-//TEST_INPUT: ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out
+//TEST_INPUT: ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<uint> outputBuffer;
[numthreads(16, 1, 1)]
diff --git a/tests/compute/global-type-param-array.slang b/tests/compute/global-type-param-array.slang
index ac514901f..f763f49fd 100644
--- a/tests/compute/global-type-param-array.slang
+++ b/tests/compute/global-type-param-array.slang
@@ -1,6 +1,7 @@
//TEST(compute):COMPARE_COMPUTE:
-//TEST_INPUT: cbuffer(data=[1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0], stride=4):
-//TEST_INPUT: ubuffer(data=[0], stride=4):out
+
+//TEST_INPUT: cbuffer(data=[1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0], stride=4):name impl
+//TEST_INPUT: ubuffer(data=[0], stride=4):out,name outputBuffer
//TEST_INPUT: type Pair<Arr<Base,1>, Pair<Arr<Base,2> , Base> >
RWStructuredBuffer<float> outputBuffer;
diff --git a/tests/compute/global-type-param-in-entrypoint.slang b/tests/compute/global-type-param-in-entrypoint.slang
index 06320ba0f..b2a1146d8 100644
--- a/tests/compute/global-type-param-in-entrypoint.slang
+++ b/tests/compute/global-type-param-in-entrypoint.slang
@@ -1,6 +1,7 @@
//TEST(compute):COMPARE_RENDER_COMPUTE:
-//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], stride=16):
-//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out
+
+//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], stride=16):name Uniforms
+//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
//TEST_INPUT: global_type VertImpl
interface IVertInterpolant
diff --git a/tests/compute/global-type-param1.slang b/tests/compute/global-type-param1.slang
index 5362af5e0..b5560e9d9 100644
--- a/tests/compute/global-type-param1.slang
+++ b/tests/compute/global-type-param1.slang
@@ -1,11 +1,13 @@
//TEST(smoke,compute):COMPARE_COMPUTE:
-//TEST_INPUT: cbuffer(data=[0.5 0 0 0 1.0], stride=4):
-//TEST_INPUT: cbuffer(data=[1.0], stride=4):
-//TEST_INPUT: Texture2D(size=4, content = zero):
-//TEST_INPUT: Texture2D(size=4, content = one):
-//TEST_INPUT: Sampler:
-//TEST_INPUT: Sampler:
-//TEST_INPUT: ubuffer(data=[0], stride=4):out
+
+
+//TEST_INPUT: ubuffer(data=[0], stride=4):out,name outputBufer
+//TEST_INPUT: cbuffer(data=[0.5 0 0 0 1.0], stride=4):name C
+//TEST_INPUT: cbuffer(data=[1.0], stride=4):name impl.base
+//TEST_INPUT: Texture2D(size=4, content = zero):name tex1
+//TEST_INPUT: Texture2D(size=4, content = one):name impl.tex
+//TEST_INPUT: Sampler:name sampler
+//TEST_INPUT: Sampler:name impl.sampler
//TEST_INPUT: type Impl
RWStructuredBuffer<float> outputBuffer;
diff --git a/tests/compute/global-type-param2.slang b/tests/compute/global-type-param2.slang
index d731e356a..39701f16f 100644
--- a/tests/compute/global-type-param2.slang
+++ b/tests/compute/global-type-param2.slang
@@ -1,11 +1,13 @@
//TEST(smoke,compute):COMPARE_COMPUTE:
-//TEST_INPUT: cbuffer(data=[0.5 0 0 0], stride=4):
-//TEST_INPUT: cbuffer(data=[1.0], stride=4):
-//TEST_INPUT: Texture2D(size=4, content = zero):
-//TEST_INPUT: Texture2D(size=4, content = one):
-//TEST_INPUT: Sampler:
-//TEST_INPUT: Sampler:
-//TEST_INPUT: ubuffer(data=[0], stride=4):out
+
+//TEST_INPUT: ubuffer(data=[0], stride=4):out,name outputBuffer
+//TEST_INPUT: cbuffer(data=[0.5 0 0 0], stride=4):name existingBuffer
+//__disabled__TEST_INPUT: object(type=Impl):name impl
+//TEST_INPUT: root_constants(data=[1.0], stride=4):name impl.base
+//TEST_INPUT: Texture2D(size=4, content = zero):name tex1
+//TEST_INPUT: Texture2D(size=4, content = one):name impl.tex
+//TEST_INPUT: Sampler:name sampler
+//TEST_INPUT: Sampler:name impl.sampler
//TEST_INPUT: type Impl
diff --git a/tests/compute/half-calc.slang b/tests/compute/half-calc.slang
index 7c94a0d4f..b9ed7c439 100644
--- a/tests/compute/half-calc.slang
+++ b/tests/compute/half-calc.slang
@@ -1,9 +1,10 @@
//DISABLE_TEST(compute):COMPARE_COMPUTE:-dx12 -compute -use-dxil -profile cs_6_2 -render-features half
//TEST(compute):COMPARE_COMPUTE:-vk -compute -profile cs_6_2 -render-features half
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+
// Test for doing a calculation using half
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<float> outputBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/compute/half-structured-buffer.slang b/tests/compute/half-structured-buffer.slang
index 08323913e..abccfb32a 100644
--- a/tests/compute/half-structured-buffer.slang
+++ b/tests/compute/half-structured-buffer.slang
@@ -2,8 +2,6 @@
//Disable on Dx12 for now - because writing to structured buffer produces unexpected results
//TEST_DISABLED(compute):COMPARE_COMPUTE:-dx12 -compute -use-dxil -profile cs_6_2 -render-features half
-//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=16):out
-
struct Thing
{
uint pos;
@@ -11,6 +9,7 @@ struct Thing
half4 color;
};
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=16):out,name outputBuffer
RWStructuredBuffer<Thing> outputBuffer;
[numthreads(4, 1, 1)]
diff --git a/tests/compute/interface-shader-param.slang b/tests/compute/interface-shader-param.slang
index dde7bf2a6..d4bc1d7fa 100644
--- a/tests/compute/interface-shader-param.slang
+++ b/tests/compute/interface-shader-param.slang
@@ -96,12 +96,14 @@ 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
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):
diff --git a/tests/compute/interface-shader-param4.slang b/tests/compute/interface-shader-param4.slang
index da57175e9..fe8e6b374 100644
--- a/tests/compute/interface-shader-param4.slang
+++ b/tests/compute/interface-shader-param4.slang
@@ -44,7 +44,7 @@ int test(
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=gOutputBuffer
RWStructuredBuffer<int> gOutputBuffer;
// Note: a constant buffer register/binding is always claimed
@@ -53,7 +53,7 @@ RWStructuredBuffer<int> gOutputBuffer;
// that gets plugged in will involve uniform/ordinary data
// or not.
//
-//TEST_INPUT:cbuffer(data=[0]):
+//TEST_INPUT:cbuffer(data=[0]):name=gStrategy
//
ConstantBuffer<IRandomNumberGenerationStrategy> gStrategy;
diff --git a/tests/compute/matrix-layout-structured-buffer.slang b/tests/compute/matrix-layout-structured-buffer.slang
index bb7dbb381..56112f959 100644
--- a/tests/compute/matrix-layout-structured-buffer.slang
+++ b/tests/compute/matrix-layout-structured-buffer.slang
@@ -26,7 +26,7 @@ int test(int val)
return tmp;
}
-//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=buffer
RWStructuredBuffer<int> buffer;
[numthreads(12, 1, 1)]
diff --git a/tests/compute/matrix-layout.hlsl b/tests/compute/matrix-layout.hlsl
index 0993a1bb2..a7a167926 100644
--- a/tests/compute/matrix-layout.hlsl
+++ b/tests/compute/matrix-layout.hlsl
@@ -23,13 +23,13 @@ struct S
int b;
};
-//TEST_INPUT:cbuffer(data=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]):
+//TEST_INPUT:cbuffer(data=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]):name=C0
cbuffer C0
{
S s;
};
-//TEST_INPUT:cbuffer(data=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]):
+//TEST_INPUT:cbuffer(data=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]):name=C1
cbuffer C1
{
diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp
index 30c982ab3..6a58501fd 100644
--- a/tools/gfx/d3d11/render-d3d11.cpp
+++ b/tools/gfx/d3d11/render-d3d11.cpp
@@ -1019,6 +1019,11 @@ Result D3D11Renderer::createBufferResource(Resource::Usage initialUsage, const B
}
}
+ if( bufferDesc.Usage == D3D11_USAGE_DYNAMIC )
+ {
+ bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE;
+ }
+
D3D11_SUBRESOURCE_DATA subResourceData = { 0 };
subResourceData.pSysMem = initData;
@@ -1394,7 +1399,7 @@ void* D3D11Renderer::map(BufferResource* bufferIn, MapFlavor flavor)
mapType = D3D11_MAP_WRITE_DISCARD;
break;
case MapFlavor::HostWrite:
- mapType = D3D11_MAP_WRITE;
+ mapType = D3D11_MAP_WRITE_NO_OVERWRITE;
break;
case MapFlavor::HostRead:
mapType = D3D11_MAP_READ;
@@ -2104,299 +2109,6 @@ Result D3D11Renderer::createDescriptorSet(DescriptorSetLayout* layout, Descripto
}
-#if 0
-BindingState* D3D11Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- assert(srcBinding.registerRange.isSingle());
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(srcBinding.resource && srcBinding.resource->isBuffer());
-
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& desc = buffer->getDesc();
-
- const int elemSize = bufferDesc.elementSize <= 0 ? 1 : bufferDesc.elementSize;
-
- if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
- viewDesc.Buffer.Flags = 0;
- viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
- viewDesc.Format = D3DUtil::getMapFormat(bufferDesc.format);
-
- if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown)
- {
- viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
- viewDesc.Format = DXGI_FORMAT_R32_TYPELESS;
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateUnorderedAccessView(buffer->m_buffer, &viewDesc, dstDetail.m_uav.writeRef()));
- }
- if (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource))
- {
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.ElementWidth = elemSize;
- viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
- viewDesc.Buffer.ElementOffset = 0;
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
- viewDesc.Format = DXGI_FORMAT_UNKNOWN;
-
- if (bufferDesc.elementSize == 0)
- {
- viewDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(buffer->m_buffer, &viewDesc, dstDetail.m_srv.writeRef()));
- }
- break;
- }
- case BindingType::Texture:
- case BindingType::CombinedTextureSampler:
- {
- assert(srcBinding.resource && srcBinding.resource->isTexture());
-
- TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
-
- const TextureResource::Desc& textureDesc = texture->getDesc();
-
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- viewDesc.Format = D3DUtil::getMapFormat(textureDesc.format);
-
- switch (texture->getType())
- {
- case Resource::Type::Texture1D:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
- viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1D.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
- viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture1DArray.FirstArraySlice = 0;
- viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1DArray.MostDetailedMip = 0;
- }
- break;
- }
- case Resource::Type::Texture2D:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2D.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
- viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture2DArray.FirstArraySlice = 0;
- viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2DArray.MostDetailedMip = 0;
- }
- break;
- }
- case Resource::Type::TextureCube:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
- viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCube.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
- viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCubeArray.MostDetailedMip = 0;
- viewDesc.TextureCubeArray.First2DArrayFace = 0;
- viewDesc.TextureCubeArray.NumCubes = textureDesc.arraySize;
- }
- break;
- }
- case Resource::Type::Texture3D:
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
- viewDesc.Texture3D.MipLevels = textureDesc.numMipLevels; // Old code fixed as one
- viewDesc.Texture3D.MostDetailedMip = 0;
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return nullptr;
- }
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(texture->m_resource, &viewDesc, dstDetail.m_srv.writeRef()));
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- D3D11_SAMPLER_DESC desc = {};
- desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
-
- if (samplerDesc.isCompareSampler)
- {
- desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
- desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
- desc.MinLOD = desc.MaxLOD = 0.0f;
- }
- else
- {
- desc.Filter = D3D11_FILTER_ANISOTROPIC;
- desc.MaxAnisotropy = 8;
- desc.MinLOD = 0.0f;
- desc.MaxLOD = 100.0f;
- }
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateSamplerState(&desc, dstDetail.m_samplerState.writeRef()));
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return nullptr;
- }
- }
- }
-
- // Done
- return bindingState.detach();
-}
-
-void D3D11Renderer::_applyBindingState(bool isCompute)
-{
- auto context = m_immediateContext.get();
-
- const auto& details = m_currentBindings->m_bindingDetails;
- const auto& bindings = m_currentBindings->getDesc().m_bindings;
-
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- switch (binding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(binding.resource && binding.resource->isBuffer());
- if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
- {
- ID3D11Buffer* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr())->m_buffer;
- if (isCompute)
- context->CSSetConstantBuffers(bindingIndex, 1, &buffer);
- else
- {
- context->VSSetConstantBuffers(bindingIndex, 1, &buffer);
- context->PSSetConstantBuffers(bindingIndex, 1, &buffer);
- }
- }
- else if (detail.m_uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(
- m_currentBindings->getDesc().m_numRenderTargets,
- m_renderTargetViews.getBuffer()->readRef(),
- m_depthStencilView,
- bindingIndex,
- 1,
- detail.m_uav.readRef(),
- nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- else
- {
- context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- }
- }
- break;
- }
- case BindingType::Texture:
- {
- if (detail.m_uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL,
- nullptr, nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- else
- {
- context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- }
- }
- break;
- }
- case BindingType::Sampler:
- {
- if (isCompute)
- context->CSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- else
- {
- context->PSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- context->VSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- }
- break;
- }
- default:
- {
- assert(!"Not implemented");
- return;
- }
- }
- }
-}
-
-void D3D11Renderer::setBindingState(BindingState* state)
-{
- m_currentBindings = static_cast<BindingStateImpl*>(state);
-}
-#endif
-
void D3D11Renderer::_flushGraphicsState()
{
auto pipelineType = int(PipelineType::Graphics);
@@ -2453,22 +2165,37 @@ void D3D11Renderer::DescriptorSetImpl::setResource(UInt range, UInt index, Resou
{
auto viewImpl = (ResourceViewImpl*)view;
auto& rangeInfo = m_layout->m_ranges[range];
+ auto flatIndex = rangeInfo.arrayIndex + index;
switch (rangeInfo.type)
{
case D3D11DescriptorSlotType::ShaderResourceView:
{
- assert(viewImpl->m_type == ResourceViewImpl::Type::SRV);
- auto srvImpl = (ShaderResourceViewImpl*)viewImpl;
- m_srvs[rangeInfo.arrayIndex + index] = srvImpl->m_srv;
+ if( viewImpl )
+ {
+ assert(viewImpl->m_type == ResourceViewImpl::Type::SRV);
+ auto srvImpl = (ShaderResourceViewImpl*)viewImpl;
+ m_srvs[flatIndex] = srvImpl->m_srv;
+ }
+ else
+ {
+ m_srvs[flatIndex] = nullptr;
+ }
}
break;
case D3D11DescriptorSlotType::UnorderedAccessView:
{
- assert(viewImpl->m_type == ResourceViewImpl::Type::UAV);
- auto uavImpl = (UnorderedAccessViewImpl*)viewImpl;
- m_uavs[rangeInfo.arrayIndex + index] = uavImpl->m_uav;
+ if( viewImpl )
+ {
+ assert(viewImpl->m_type == ResourceViewImpl::Type::UAV);
+ auto uavImpl = (UnorderedAccessViewImpl*)viewImpl;
+ m_uavs[flatIndex] = uavImpl->m_uav;
+ }
+ else
+ {
+ m_uavs[flatIndex] = nullptr;
+ }
}
break;
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index 0f23d8dd4..886754f0e 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -1082,270 +1082,6 @@ Result D3D12Renderer::captureTextureToSurface(D3D12Resource& resource, Surface&
}
}
-#if 0
-Result D3D12Renderer::calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut)
-{
- BindParameters bindParameters;
- _calcBindParameters(bindParameters);
-
- ComPtr<ID3D12RootSignature> rootSignature;
- ComPtr<ID3D12PipelineState> pipelineState;
-
- {
- D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc;
- rootSignatureDesc.NumParameters = bindParameters.m_paramIndex;
- rootSignatureDesc.pParameters = bindParameters.m_parameters;
- rootSignatureDesc.NumStaticSamplers = 0;
- rootSignatureDesc.pStaticSamplers = nullptr;
- rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
-
- ComPtr<ID3DBlob> signature;
- ComPtr<ID3DBlob> error;
- SLANG_RETURN_ON_FAIL(m_D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.writeRef(), error.writeRef()));
- SLANG_RETURN_ON_FAIL(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature.writeRef())));
- }
-
- {
- // Describe and create the compute pipeline state object
- D3D12_COMPUTE_PIPELINE_STATE_DESC computeDesc = {};
- computeDesc.pRootSignature = rootSignature;
- computeDesc.CS = { m_boundShaderProgram->m_computeShader.getBuffer(), m_boundShaderProgram->m_computeShader.Count() };
- SLANG_RETURN_ON_FAIL(m_device->CreateComputePipelineState(&computeDesc, IID_PPV_ARGS(pipelineState.writeRef())));
- }
-
- signatureOut.swap(rootSignature);
- pipelineStateOut.swap(pipelineState);
-
- return SLANG_OK;
-}
-#endif
-
-#if 0
-D3D12Renderer::RenderState* D3D12Renderer::findRenderState(PipelineType pipelineType)
-{
- switch (pipelineType)
- {
- case PipelineType::Compute:
- {
- // Check if current state is a match
- if (m_currentRenderState)
- {
- if (m_currentRenderState->m_bindingState == m_boundBindingState &&
- m_currentRenderState->m_shaderProgram == m_boundShaderProgram)
- {
- return m_currentRenderState;
- }
- }
-
- const int num = int(m_renderStates.Count());
- for (int i = 0; i < num; i++)
- {
- RenderState* renderState = m_renderStates[i];
- if (renderState->m_bindingState == m_boundBindingState &&
- renderState->m_shaderProgram == m_boundShaderProgram)
- {
- return renderState;
- }
- }
- break;
- }
- case PipelineType::Graphics:
- {
- if (m_currentRenderState)
- {
- if (m_currentRenderState->m_bindingState == m_boundBindingState &&
- m_currentRenderState->m_inputLayout == m_boundInputLayout &&
- m_currentRenderState->m_shaderProgram == m_boundShaderProgram &&
- m_currentRenderState->m_primitiveTopologyType == m_primitiveTopologyType)
- {
- return m_currentRenderState;
- }
- }
- // See if matches one in the list
- {
- const int num = int(m_renderStates.Count());
- for (int i = 0; i < num; i++)
- {
- RenderState* renderState = m_renderStates[i];
- if (renderState->m_bindingState == m_boundBindingState &&
- renderState->m_inputLayout == m_boundInputLayout &&
- renderState->m_shaderProgram == m_boundShaderProgram &&
- renderState->m_primitiveTopologyType == m_primitiveTopologyType)
- {
- // Okay we have a match
- return renderState;
- }
- }
- }
- break;
- }
- default: break;
- }
- return nullptr;
-}
-
-D3D12Renderer::RenderState* D3D12Renderer::calcRenderState()
-{
- if (!m_boundShaderProgram)
- {
- return nullptr;
- }
- m_currentRenderState = findRenderState(m_boundShaderProgram->m_pipelineType);
- if (m_currentRenderState)
- {
- return m_currentRenderState;
- }
-
- ComPtr<ID3D12RootSignature> rootSignature;
- ComPtr<ID3D12PipelineState> pipelineState;
-
- switch (m_boundShaderProgram->m_pipelineType)
- {
- case PipelineType::Compute:
- {
- if (SLANG_FAILED(calcComputePipelineState(rootSignature, pipelineState)))
- {
- return nullptr;
- }
- break;
- }
- case PipelineType::Graphics:
- {
- if (SLANG_FAILED(calcGraphicsPipelineState(rootSignature, pipelineState)))
- {
- return nullptr;
- }
- break;
- }
- default: return nullptr;
- }
-
- RenderState* renderState = new RenderState;
-
- renderState->m_primitiveTopologyType = m_primitiveTopologyType;
- renderState->m_bindingState = m_boundBindingState;
- renderState->m_inputLayout = m_boundInputLayout;
- renderState->m_shaderProgram = m_boundShaderProgram;
-
- renderState->m_rootSignature.swap(rootSignature);
- renderState->m_pipelineState.swap(pipelineState);
-
- m_renderStates.Add(renderState);
-
- m_currentRenderState = renderState;
-
- return renderState;
-}
-
-Result D3D12Renderer::_calcBindParameters(BindParameters& params)
-{
- int numConstantBuffers = 0;
- {
- if (m_boundBindingState)
- {
- const int numBoundConstantBuffers = numConstantBuffers;
-
- const BindingState::Desc& bindingStateDesc = m_boundBindingState->getDesc();
-
- const auto& bindings = bindingStateDesc.m_bindings;
- const auto& details = m_boundBindingState->m_bindingDetails;
-
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; i++)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- if (binding.bindingType == BindingType::Buffer)
- {
- assert(binding.resource && binding.resource->isBuffer());
- if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
- {
- // Make sure it's not overlapping the ones we just statically defined
- //assert(binding.m_binding < numBoundConstantBuffers);
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor;
- descriptor.ShaderRegister = bindingIndex;
- descriptor.RegisterSpace = 0;
-
- numConstantBuffers++;
- }
- }
-
- if (detail.m_srvIndex >= 0)
- {
- D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
-
- range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
- range.NumDescriptors = 1;
- range.BaseShaderRegister = bindingIndex;
- range.RegisterSpace = 0;
- range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
-
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable;
- table.NumDescriptorRanges = 1;
- table.pDescriptorRanges = &range;
- }
-
- if (detail.m_uavIndex >= 0)
- {
- D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
-
- range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
- range.NumDescriptors = 1;
- range.BaseShaderRegister = bindingIndex;
- range.RegisterSpace = 0;
- range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
-
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable;
- table.NumDescriptorRanges = 1;
- table.pDescriptorRanges = &range;
- }
- }
- }
- }
-
- // All the samplers are in one continuous section of the sampler heap
- if (m_boundBindingState && m_boundBindingState->m_samplerHeap.getUsedSize() > 0)
- {
- D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
-
- range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
- range.NumDescriptors = m_boundBindingState->m_samplerHeap.getUsedSize();
- range.BaseShaderRegister = 0;
- range.RegisterSpace = 0;
- range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
-
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable;
- table.NumDescriptorRanges = 1;
- table.pDescriptorRanges = &range;
- }
- return SLANG_OK;
-}
-#endif
-
Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter)
{
// TODO: we should only set some of this state as needed...
@@ -2952,176 +2688,6 @@ void D3D12Renderer::dispatchCompute(int x, int y, int z)
commandList->Dispatch(x, y, z);
}
-#if 0
-BindingState* D3D12Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
-
- SLANG_RETURN_NULL_ON_FAIL(bindingState->init(m_device));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& srcEntry = srcBindings[i];
- auto& dstDetail = dstDetails[i];
-
- const int bindingIndex = srcEntry.registerRange.getSingleIndex();
-
- switch (srcEntry.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(srcEntry.resource && srcEntry.resource->isBuffer());
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcEntry.resource.Ptr());
- const BufferResource::Desc& desc = bufferResource->getDesc();
-
- const size_t bufferSize = bufferDesc.sizeInBytes;
- const int elemSize = bufferDesc.elementSize <= 0 ? sizeof(uint32_t) : bufferDesc.elementSize;
-
- const bool createSrv = false;
-
- // NOTE! In this arrangement the buffer can either be a ConstantBuffer or a 'StorageBuffer'.
- // If it's a storage buffer then it has a 'uav'.
- // In neither circumstance is there an associated srv
- // This departs a little from dx11 code - in that it will create srv and uav for a storage buffer.
- if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- dstDetail.m_uavIndex = bindingState->m_viewHeap.allocate();
- if (dstDetail.m_uavIndex < 0)
- {
- return nullptr;
- }
-
- D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
-
- uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
- uavDesc.Format = D3DUtil::getMapFormat(bufferDesc.format);
-
- uavDesc.Buffer.StructureByteStride = elemSize;
-
- uavDesc.Buffer.FirstElement = 0;
- uavDesc.Buffer.NumElements = (UINT)(bufferSize / elemSize);
- uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
-
- if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown)
- {
- uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW;
- uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
-
- uavDesc.Buffer.StructureByteStride = 0;
- }
- else if( bufferDesc.format != Format::Unknown )
- {
- uavDesc.Buffer.StructureByteStride = 0;
- }
-
- m_device->CreateUnorderedAccessView(bufferResource->m_resource, nullptr, &uavDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_uavIndex));
- }
- if (createSrv && (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource)))
- {
- dstDetail.m_srvIndex = bindingState->m_viewHeap.allocate();
- if (dstDetail.m_srvIndex < 0)
- {
- return nullptr;
- }
-
- D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
-
- srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
- srvDesc.Format = DXGI_FORMAT_UNKNOWN;
- srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-
- srvDesc.Buffer.FirstElement = 0;
- srvDesc.Buffer.NumElements = (UINT)(bufferSize / elemSize);
- srvDesc.Buffer.StructureByteStride = elemSize;
- srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
-
- if (bufferDesc.elementSize == 0)
- {
- srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- m_device->CreateShaderResourceView(bufferResource->m_resource, &srvDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_srvIndex));
- }
-
- break;
- }
- case BindingType::Texture:
- {
- assert(srcEntry.resource && srcEntry.resource->isTexture());
-
- TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcEntry.resource.Ptr());
-
- dstDetail.m_srvIndex = bindingState->m_viewHeap.allocate();
- if (dstDetail.m_srvIndex < 0)
- {
- return nullptr;
- }
-
- {
- const D3D12_RESOURCE_DESC resourceDesc = textureResource->m_resource.getResource()->GetDesc();
- const DXGI_FORMAT pixelFormat = resourceDesc.Format;
-
- D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
- _initSrvDesc(textureResource->getType(), textureResource->getDesc(), resourceDesc, pixelFormat, srvDesc);
-
- // Create descriptor
- m_device->CreateShaderResourceView(textureResource->m_resource, &srvDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_srvIndex));
- }
-
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcEntry.descIndex];
-
- const int samplerIndex = bindingIndex;
- dstDetail.m_samplerIndex = samplerIndex;
- bindingState->m_samplerHeap.placeAt(samplerIndex);
-
- D3D12_SAMPLER_DESC desc = {};
- desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
- desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
-
- if (samplerDesc.isCompareSampler)
- {
- desc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
- desc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
- }
- else
- {
- desc.Filter = D3D12_FILTER_ANISOTROPIC;
- desc.MaxAnisotropy = 8;
- desc.MinLOD = 0.0f;
- desc.MaxLOD = 100.0f;
- }
-
- m_device->CreateSampler(&desc, bindingState->m_samplerHeap.getCpuHandle(samplerIndex));
-
- break;
- }
- case BindingType::CombinedTextureSampler:
- {
- assert(!"Not implemented");
- return nullptr;
- }
- }
- }
-
- return bindingState.detach();
-}
-
-void D3D12Renderer::setBindingState(BindingState* state)
-{
- m_boundBindingState = static_cast<BindingStateImpl*>(state);
-}
-#endif
-
void D3D12Renderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
{
auto dxDevice = m_renderer->m_device;
@@ -3525,10 +3091,10 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
// Finally, we will go through and fill in ready-to-go D3D
// register range information.
{
- UInt cbvCounter = 0;
- UInt srvCounter = 0;
- UInt uavCounter = 0;
- UInt samplerCounter = 0;
+ UInt cbvRegisterCounter = 0;
+ UInt srvRegisterCounter = 0;
+ UInt uavRegisterCounter = 0;
+ UInt samplerRegisterCounter = 0;
Int resourceRangeCounter = 0;
Int samplerRangeCounter = 0;
@@ -3548,7 +3114,6 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
Int dxRangeIndex = -1;
Int dxPairedSamplerRangeIndex = -1;
-
switch(rangeDesc.type)
{
default:
@@ -3586,7 +3151,12 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
// so that this range doesn't turn into a descriptor
// range in one of the D3D12 descriptor tables.
//
- UInt bindingIndex = cbvCounter; cbvCounter += bindingCount;
+ Int dxRegister = rangeDesc.binding;
+ if( dxRegister < 0 )
+ {
+ dxRegister = cbvRegisterCounter;
+ }
+ cbvRegisterCounter = dxRegister + bindingCount;
auto rootConstantRangeIndex = descriptorSetLayoutImpl->m_ranges[rr].arrayIndex;
auto rootParamIndex = descriptorSetLayoutImpl->m_rootConstantRanges[rootConstantRangeIndex].rootParamIndex;
@@ -3598,7 +3168,7 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
//
auto& dxRootParam = descriptorSetLayoutImpl->m_dxRootParameters[rootParamIndex];
dxRootParam.Constants.RegisterSpace = UINT(bindingSpace);
- dxRootParam.Constants.ShaderRegister = UINT(bindingIndex);
+ dxRootParam.Constants.ShaderRegister = UINT(dxRegister);
continue;
}
break;
@@ -3607,6 +3177,8 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
D3D12_DESCRIPTOR_RANGE& dxRange = descriptorSetLayoutImpl->m_dxRanges[dxRangeIndex];
memset(&dxRange, 0, sizeof(dxRange));
+ Int dxRegister = rangeDesc.binding;
+
switch(rangeDesc.type)
{
default:
@@ -3615,11 +3187,15 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::Sampler:
{
- UInt bindingIndex = samplerCounter; samplerCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = samplerRegisterCounter;
+ }
+ samplerRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3628,11 +3204,15 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::SampledImage:
case DescriptorSlotType::UniformTexelBuffer:
{
- UInt bindingIndex = srvCounter; srvCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = srvRegisterCounter;
+ }
+ srvRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3642,15 +3222,31 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
{
// The combined texture/sampler case basically just
// does the work of both the SRV and sampler cases above.
+ //
+ // TODO(tfoley): The current API for passing down an
+ // explicit register/binding can't handle the requirement
+ // that we specify *two* registers/bindings for the
+ // combined image/sampler case.
+ //
+ // Realistically, the `Renderer` implementation for
+ // targes that don't support combined texture/sampler
+ // bindings should just error out when a client attempts
+ // to create a descriptor set that uses them (rather than
+ // the current behavior which adds a lot of complexity
+ // in the name of trying to make them work).
{
// Here's the SRV logic:
-
- UInt bindingIndex = srvCounter; srvCounter += bindingCount;
+ Int srvRegister = dxRegister;
+ if( srvRegister < 0 )
+ {
+ srvRegister = srvRegisterCounter;
+ }
+ srvRegisterCounter = srvRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(srvRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3660,11 +3256,16 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
D3D12_DESCRIPTOR_RANGE& dxPairedSamplerRange = descriptorSetLayoutImpl->m_dxRanges[dxPairedSamplerRangeIndex];
memset(&dxPairedSamplerRange, 0, sizeof(dxPairedSamplerRange));
- UInt pairedSamplerBindingIndex = srvCounter; srvCounter += bindingCount;
+ Int samplerRegister = dxRegister;
+ if( samplerRegister < 0 )
+ {
+ samplerRegister = samplerRegisterCounter;
+ }
+ samplerRegisterCounter = samplerRegister + bindingCount;
dxPairedSamplerRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
dxPairedSamplerRange.NumDescriptors = UINT(bindingCount);
- dxPairedSamplerRange.BaseShaderRegister = UINT(pairedSamplerBindingIndex);
+ dxPairedSamplerRange.BaseShaderRegister = UINT(samplerRegister);
dxPairedSamplerRange.RegisterSpace = UINT(bindingSpace);
dxPairedSamplerRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3679,11 +3280,15 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::StorageBuffer:
case DescriptorSlotType::DynamicStorageBuffer:
{
- UInt bindingIndex = uavCounter; uavCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = uavRegisterCounter;
+ }
+ uavRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3692,15 +3297,23 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::UniformBuffer:
case DescriptorSlotType::DynamicUniformBuffer:
{
- UInt bindingIndex = cbvCounter; cbvCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = cbvRegisterCounter;
+ }
+ cbvRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
break;
+
+
+
+
}
}
}
@@ -3722,6 +3335,8 @@ Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, Pip
auto descriptorSetCount = desc.descriptorSetCount;
+ Int spaceCounter = 0;
+
// We are going to make two passes over the descriptor set layouts
// that are being used to build the pipeline layout. In the first
// pass we will collect all the descriptor ranges that have been
@@ -3740,7 +3355,12 @@ Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, Pip
// that comes from multiple spaces (e.g., if it contains an unbounded
// array).
//
- UInt bindingSpace = dd;
+ Int space = descriptorSetInfo.space;
+ if( space < 0 )
+ {
+ space = spaceCounter;
+ }
+ spaceCounter = space+1;
// Copy descriptor range information from the set layout into our
// temporary copy (this is required because the same set layout
@@ -3754,7 +3374,7 @@ Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, Pip
{
auto& range = ranges[rangeCount++];
range = setDescriptorRange;
- range.RegisterSpace = UINT(bindingSpace);
+ range.RegisterSpace = UINT(space);
// HACK: in order to deal with SM5.0 shaders, `u` registers
// in `space0` need to start with a number *after* the number
diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp
index caf8794c0..bf873212c 100644
--- a/tools/gfx/open-gl/render-gl.cpp
+++ b/tools/gfx/open-gl/render-gl.cpp
@@ -1151,130 +1151,6 @@ void GLRenderer::dispatchCompute(int x, int y, int z)
glDispatchCompute(x, y, z);
}
-#if 0
-BindingState* GLRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, this));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Texture:
- case BindingType::Buffer:
- {
- break;
- }
- case BindingType::CombinedTextureSampler:
- {
- assert(srcBinding.resource && srcBinding.resource->isTexture());
- TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- if (samplerDesc.isCompareSampler)
- {
- auto target = texture->m_target;
-
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- }
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- GLuint handle;
-
- glCreateSamplers(1, &handle);
- glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, GL_REPEAT);
-
- if (samplerDesc.isCompareSampler)
- {
- glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- }
- else
- {
- glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
- }
-
- dstDetail.m_samplerHandle = handle;
- break;
- }
- }
- }
-
- return bindingState.detach();
-}
-
-void GLRenderer::setBindingState(BindingState* stateIn)
-{
- BindingStateImpl* state = static_cast<BindingStateImpl*>(stateIn);
-
- const auto& bindingDesc = state->getDesc();
-
- const auto& details = state->m_bindingDetails;
- const auto& bindings = bindingDesc.m_bindings;
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- switch (binding.bindingType)
- {
- case BindingType::Buffer:
- {
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
- glBindBufferBase(buffer->m_target, bindingIndex, buffer->m_handle);
- break;
- }
- case BindingType::Sampler:
- {
- for (int index = binding.registerRange.index; index < binding.registerRange.index + binding.registerRange.size; ++index)
- {
- glBindSampler(index, detail.m_samplerHandle);
- }
- break;
- }
- case BindingType::Texture:
- case BindingType::CombinedTextureSampler:
- {
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- glActiveTexture(GL_TEXTURE0 + bindingIndex);
- glBindTexture(buffer->m_target, buffer->m_handle);
- break;
- }
- }
- }
-}
-#endif
-
void GLRenderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
{
auto resourceImpl = (BufferResourceImpl*) buffer;
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index 55beb5774..5ad338594 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -520,6 +520,8 @@ enum class DescriptorSlotType
DynamicStorageBuffer,
InputAttachment,
RootConstant,
+ InlineUniformBlock,
+ RayTracingAccelerationStructure,
};
class DescriptorSetLayout : public Slang::RefObject
@@ -530,6 +532,17 @@ public:
DescriptorSlotType type = DescriptorSlotType::Unknown;
UInt count = 1;
+ /// The underlying API-specific binding/register to use for this slot range.
+ ///
+ /// A value of `-1` indicates that the implementation should
+ /// automatically compute the binding/register to use
+ /// based on the preceeding slot range(s).
+ ///
+ /// Some implementations do not have a concept of bindings/regsiters
+ /// for slot ranges, and will ignore this field.
+ ///
+ Int binding = -1;
+
SlotRangeDesc()
{}
@@ -555,6 +568,17 @@ public:
{
DescriptorSetLayout* layout = nullptr;
+ /// The underlying API-specific space/set number to use for this set.
+ ///
+ /// A value of `-1` indicates that the implementation should
+ /// automatically compute the space/set to use basd on
+ /// the preceeding set(s)
+ ///
+ /// Some implementations do not have a concept of space/set numbers
+ /// for descriptor sets, and will ignore this field.
+ ///
+ Int space = -1;
+
DescriptorSetDesc()
{}
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 397d657a4..6f2411f24 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -2270,144 +2270,6 @@ static VkImageViewType _calcImageViewType(TextureResource::Type type, const Text
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
}
-#if 0
-BindingState* VKRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, &m_api));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- if (!srcBinding.resource || !srcBinding.resource->isBuffer())
- {
- assert(!"Needs to have a buffer resource set");
- return nullptr;
- }
-
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
-
- if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- // VkBufferView uav
-
- VkBufferViewCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO };
-
- info.format = VK_FORMAT_R32_SFLOAT;
- // TODO:
- // Not sure how to handle typeless?
- if (bufferResourceDesc.elementSize == 0)
- {
- info.format = VK_FORMAT_R32_SFLOAT; // DXGI_FORMAT_R32_TYPELESS ?
- }
-
- info.buffer = bufferResource->m_buffer.m_buffer;
- info.offset = 0;
- info.range = bufferResourceDesc.sizeInBytes;
-
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &dstDetail.m_uav));
- }
-
- // TODO: Setup views.
- // VkImageView srv
-
-
- break;
- }
- case BindingType::Sampler:
- {
- VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
-
- samplerInfo.magFilter = VK_FILTER_LINEAR;
- samplerInfo.minFilter = VK_FILTER_LINEAR;
-
- samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
-
- samplerInfo.anisotropyEnable = VK_FALSE;
- samplerInfo.maxAnisotropy = 1;
-
- samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
- samplerInfo.unnormalizedCoordinates = VK_FALSE;
- samplerInfo.compareEnable = VK_FALSE;
- samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
- samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
-
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &dstDetail.m_sampler));
-
- break;
- }
- case BindingType::Texture:
- {
- if (!srcBinding.resource || !srcBinding.resource->isTexture())
- {
- assert(!"Needs to have a texture resource set");
- return nullptr;
- }
-
- TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
- const TextureResource::Desc& texDesc = textureResource->getDesc();
-
- VkImageViewType imageViewType = _calcImageViewType(textureResource->getType(), texDesc);
- if (imageViewType == VK_IMAGE_VIEW_TYPE_MAX_ENUM)
- {
- assert(!"Invalid view type");
- return nullptr;
- }
- const VkFormat format = VulkanUtil::getVkFormat(texDesc.format);
- if (format == VK_FORMAT_UNDEFINED)
- {
- assert(!"Unhandled image format");
- return nullptr;
- }
-
- // Create the image view
-
- VkImageViewCreateInfo viewInfo = {};
- viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- viewInfo.image = textureResource->m_image;
- viewInfo.viewType = imageViewType;
- viewInfo.format = format;
- viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.subresourceRange.baseMipLevel = 0;
- viewInfo.subresourceRange.levelCount = 1;
- viewInfo.subresourceRange.baseArrayLayer = 0;
- viewInfo.subresourceRange.layerCount = 1;
-
- viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateImageView(m_device, &viewInfo, nullptr, &dstDetail.m_srv));
-
- break;
- }
- case BindingType::CombinedTextureSampler:
- {
- assert(!"not implemented");
- return nullptr;
- }
- }
- }
-
- return bindingState.detach();;
-}
-#endif
-
static VkDescriptorType translateDescriptorType(DescriptorSlotType type)
{
switch(type)
diff --git a/tools/render-test/cpu-compute-util.cpp b/tools/render-test/cpu-compute-util.cpp
index 72e44fb78..7c9103cb3 100644
--- a/tools/render-test/cpu-compute-util.cpp
+++ b/tools/render-test/cpu-compute-util.cpp
@@ -420,8 +420,9 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
Context& context,
ISlangSharedLibrary* sharedLib)
{
+ auto request = compilationAndLayout.output.getRequestForReflection();
Slang::ComPtr<slang::ISession> linkage;
- spCompileRequest_getSession(compilationAndLayout.output.request, linkage.writeRef());
+ spCompileRequest_getSession(request, linkage.writeRef());
auto& inputLayout = compilationAndLayout.layout;
for (auto& entry : inputLayout.entries)
{
@@ -433,7 +434,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
case RTTIDataEntryType::RTTIObject:
{
auto reflection =
- slang::ShaderReflection::get(compilationAndLayout.output.request);
+ slang::ShaderReflection::get(request);
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
ComPtr<ISlangBlob> outName;
linkage->getTypeRTTIMangledName(concreteType, outName.writeRef());
@@ -444,7 +445,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
break;
case RTTIDataEntryType::WitnessTable:
{
- auto reflection = slang::ShaderReflection::get(compilationAndLayout.output.request);
+ auto reflection = slang::ShaderReflection::get(request);
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
if (!concreteType)
return SLANG_FAIL;
@@ -503,7 +504,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
/* static */SlangResult CPUComputeUtil::calcBindings(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext)
{
- auto request = compilationAndLayout.output.request;
+ auto request = compilationAndLayout.output.getRequestForReflection();
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
const auto& sourcePath = compilationAndLayout.sourcePath;
@@ -684,7 +685,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
/* static */SlangResult CPUComputeUtil::calcExecuteInfo(ExecuteStyle style, ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context, ExecuteInfo& out)
{
- auto request = compilationAndLayout.output.request;
+ auto request = compilationAndLayout.output.getRequestForReflection();
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
slang::EntryPointReflection* entryPoint = nullptr;
diff --git a/tools/render-test/cuda/cuda-compute-util.cpp b/tools/render-test/cuda/cuda-compute-util.cpp
index cc84d4a00..ea7dab163 100644
--- a/tools/render-test/cuda/cuda-compute-util.cpp
+++ b/tools/render-test/cuda/cuda-compute-util.cpp
@@ -1000,7 +1000,7 @@ static SlangResult _invokeComputeProgram(
const uint32_t dispatchSize[3],
CUDAComputeUtil::Context& outContext)
{
- auto reflection = slang::ProgramLayout::get(outputAndLayout.output.request);
+ auto reflection = slang::ProgramLayout::get(outputAndLayout.output.getRequestForReflection());
auto& bindSet = outContext.m_bindSet;
auto& bindRoot = outContext.m_bindRoot;
@@ -1403,7 +1403,7 @@ static SlangResult _fillRuntimeHandlesInBuffers(
ScopeCUDAModule& cudaModule)
{
Slang::ComPtr<slang::ISession> linkage;
- spCompileRequest_getSession(compilationAndLayout.output.request, linkage.writeRef());
+ spCompileRequest_getSession(compilationAndLayout.output.getRequestForReflection(), linkage.writeRef());
auto& inputLayout = compilationAndLayout.layout;
for (auto& entry : inputLayout.entries)
{
@@ -1415,7 +1415,7 @@ static SlangResult _fillRuntimeHandlesInBuffers(
case RTTIDataEntryType::RTTIObject:
{
auto reflection =
- slang::ShaderReflection::get(compilationAndLayout.output.request);
+ slang::ShaderReflection::get(compilationAndLayout.output.getRequestForReflection());
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
ComPtr<ISlangBlob> outName;
linkage->getTypeRTTIMangledName(concreteType, outName.writeRef());
@@ -1431,7 +1431,7 @@ static SlangResult _fillRuntimeHandlesInBuffers(
case RTTIDataEntryType::WitnessTable:
{
auto reflection =
- slang::ShaderReflection::get(compilationAndLayout.output.request);
+ slang::ShaderReflection::get(compilationAndLayout.output.getRequestForReflection());
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
if (!concreteType)
return SLANG_FAIL;
@@ -1527,7 +1527,7 @@ static SlangResult _setUpArguments(
const uint32_t dispatchSize[3],
CUDAComputeUtil::Context& outContext)
{
- auto reflection = slang::ProgramLayout::get(outputAndLayout.output.request);
+ auto reflection = slang::ProgramLayout::get(outputAndLayout.output.getRequestForReflection());
auto& bindSet = outContext.m_bindSet;
auto& bindRoot = outContext.m_bindRoot;
@@ -1835,7 +1835,7 @@ SlangResult _loadAndInvokeKernel(
auto& bindSet = outContext.m_bindSet;
auto& bindRoot = outContext.m_bindRoot;
- auto request = outputAndLayout.output.request;
+ auto request = outputAndLayout.output.getRequestForReflection();
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
// Load cuda module first so its symbols may be queried and filled into argument buffers.
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index 797439cfa..100c353e0 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -250,6 +250,10 @@ static SlangResult _setRendererType(RendererType type, const char* arg, Slang::W
outOptions.nvapiExtnSlot = (*argCursor++);
}
+ else if (strcmp(arg, "-shaderobj") == 0)
+ {
+ outOptions.useShaderObjects = true;
+ }
else
{
// Lookup
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index ddb903a4a..646cf3a76 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -3,6 +3,10 @@
#include <stdint.h>
+#ifndef SLANG_HANDLE_RESULT_FAIL
+#define SLANG_HANDLE_RESULT_FAIL(x) assert(!"failure")
+#endif
+
#include "../../slang-com-helper.h"
#include "../../source/core/slang-writer.h"
@@ -63,6 +67,8 @@ struct Options
bool useDXIL = false;
bool onlyStartup = false;
+ bool useShaderObjects = false;
+
bool performanceProfile = false;
bool dontAddDefaultEntryPoints = false;
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index f6f3e4ce6..197ee2b46 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -67,60 +67,1865 @@ static void _outputProfileTime(uint64_t startTicks, uint64_t endTicks)
out.print("profile-time=%g\n", time);
}
-class RenderTestApp : public WindowListener
+class ProgramVars;
+
+struct ShaderOutputPlan
{
- public:
+ struct Item
+ {
+ Index inputLayoutEntryIndex;
+ RefPtr<Resource> resource;
+ };
+ List<Item> items;
+};
+
+class RenderTestApp : public WindowListener
+{
+public:
// WindowListener
virtual Result update(Window* window) SLANG_OVERRIDE;
- // At initialization time, we are going to load and compile our Slang shader
- // code, and then create the API objects we need for rendering.
- Result initialize(SlangSession* session, Renderer* renderer, const Options& options, const ShaderCompilerUtil::Input& input);
+ // At initialization time, we are going to load and compile our Slang shader
+ // code, and then create the API objects we need for rendering.
+ virtual Result initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input) = 0;
void runCompute();
void renderFrame();
void finalize();
- BindingStateImpl* getBindingState() const { return m_bindingState; }
-
- Result writeBindingOutput(BindRoot* bindRoot, const char* fileName);
+ virtual void applyBinding(PipelineType pipelineType) = 0;
+ virtual void setProjectionMatrix() = 0;
+ virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) = 0;
Result writeScreen(const char* filename);
- protected:
- /// Called in initialize
- Result _initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input);
+protected:
+ /// Called in initialize
+ Result _initializeShaders(
+ SlangSession* session,
+ Renderer* renderer,
+ Options::ShaderProgramType shaderType,
+ const ShaderCompilerUtil::Input& input);
uint64_t m_startTicks;
- // variables for state to be used for rendering...
- uintptr_t m_constantBufferSize;
+ // variables for state to be used for rendering...
+ uintptr_t m_constantBufferSize;
- RefPtr<Renderer> m_renderer;
+ RefPtr<Renderer> m_renderer;
- RefPtr<BufferResource> m_constantBuffer;
- RefPtr<InputLayout> m_inputLayout;
- RefPtr<BufferResource> m_vertexBuffer;
- RefPtr<ShaderProgram> m_shaderProgram;
- RefPtr<PipelineState> m_pipelineState;
- RefPtr<BindingStateImpl> m_bindingState;
+ RefPtr<InputLayout> m_inputLayout;
+ RefPtr<BufferResource> m_vertexBuffer;
+ RefPtr<ShaderProgram> m_shaderProgram;
+ RefPtr<PipelineState> m_pipelineState;
ShaderCompilerUtil::OutputAndLayout m_compilationOutput;
- ShaderInputLayout m_shaderInputLayout; ///< The binding layout
- int m_numAddedConstantBuffers; ///< Constant buffers can be added to the binding directly. Will be added at the end.
+ ShaderInputLayout m_shaderInputLayout; ///< The binding layout
Options m_options;
};
-SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer, const Options& options, const ShaderCompilerUtil::Input& input)
+class LegacyRenderTestApp : public RenderTestApp
+{
+public:
+ virtual void applyBinding(PipelineType pipelineType) SLANG_OVERRIDE;
+ virtual void setProjectionMatrix() SLANG_OVERRIDE;
+ virtual Result initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input) SLANG_OVERRIDE;
+
+ BindingStateImpl* getBindingState() const { return m_bindingState; }
+
+ virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) override;
+
+protected:
+ uintptr_t m_constantBufferSize;
+ RefPtr<BufferResource> m_constantBuffer;
+ RefPtr<BindingStateImpl> m_bindingState;
+ int m_numAddedConstantBuffers; ///< Constant buffers can be added to the binding directly. Will be added at the end.
+};
+
+class ShaderObjectRenderTestApp : public RenderTestApp
+{
+public:
+ virtual void applyBinding(PipelineType pipelineType) SLANG_OVERRIDE;
+ virtual void setProjectionMatrix() SLANG_OVERRIDE;
+ virtual Result initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input) SLANG_OVERRIDE;
+ virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) override;
+
+protected:
+ RefPtr<ProgramVars> 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,
+ ShaderInputLayout const& layout,
+ ShaderOutputPlan& ioOutputPlan,
+ slang::ProgramLayout* slangReflection)
+{
+ ShaderCursor rootCursor = ShaderCursor(shaderObject);
+
+ const int textureBindFlags = Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource;
+
+ Index entryCount = layout.entries.getCount();
+ for(Index entryIndex = 0; entryIndex < entryCount; ++entryIndex)
+ {
+ auto& entry = layout.entries[entryIndex];
+ if(entry.name.getLength() == 0)
+ {
+ StdWriters::getError().print("error: entries in `ShaderInputLayout` must include a name\n");
+ return SLANG_E_INVALID_ARG;
+ }
+
+ auto entryCursor = rootCursor.getPath(entry.name);
+
+ if(!entryCursor.isValid())
+ {
+ for(auto entryPoint : shaderObject->getEntryPoints())
+ {
+ entryCursor = ShaderCursor(entryPoint).getPath(entry.name);
+ if(entryCursor.isValid())
+ break;
+ }
+ }
+
+
+ if(!entryCursor.isValid())
+ {
+ StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", entry.name.begin());
+ return SLANG_E_INVALID_ARG;
+ }
+
+ RefPtr<Resource> resource;
+ switch(entry.type)
+ {
+ case ShaderInputType::Uniform:
+ {
+ const size_t bufferSize = entry.bufferData.getCount() * sizeof(uint32_t);
+
+ ShaderCursor dataCursor = entryCursor;
+ switch(dataCursor.getTypeLayout()->getKind())
+ {
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ dataCursor = dataCursor.getDereferenced();
+ break;
+
+ default:
+ break;
+
+ }
+
+ dataCursor.setData(entry.bufferData.getBuffer(), bufferSize);
+ }
+ break;
+
+ case ShaderInputType::Buffer:
+ {
+ const InputBufferDesc& srcBuffer = entry.bufferDesc;
+ const size_t bufferSize = entry.bufferData.getCount() * sizeof(uint32_t);
+
+ switch(srcBuffer.type)
+ {
+ case InputBufferType::ConstantBuffer:
+ {
+ // A `cbuffer` input line actually represents the data we
+ // want to write *into* the buffer, and shouldn't
+ // allocate a buffer itself.
+ //
+ entryCursor.getDereferenced().setData(entry.bufferData.getBuffer(), bufferSize);
+ }
+ break;
+
+ case InputBufferType::RootConstantBuffer:
+ {
+ // A `root_constants` input line actually represents the data we
+ // want to write *into* the buffer, and shouldn't
+ // allocate a buffer itself.
+ //
+ // Note: we are not doing `.getDereferenced()` here because the
+ // `root_constant` line should be referring to a parameter value
+ // inside the root-constant range, and not the range/buffer itself.
+ //
+ entryCursor.setData(entry.bufferData.getBuffer(), bufferSize);
+ }
+ break;
+
+ default:
+ {
+
+ RefPtr<BufferResource> bufferResource;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBufferResource(entry.bufferDesc, entry.isOutput, bufferSize, entry.bufferData.getBuffer(), renderer, bufferResource));
+ resource = bufferResource;
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::UnorderedAccess;
+ viewDesc.format = srcBuffer.format;
+ auto bufferView = renderer->createBufferView(
+ bufferResource,
+ viewDesc);
+ entryCursor.setResource(bufferView);
+ }
+ break;
+ }
+
+#if 0
+ switch(srcBuffer.type)
+ {
+ case InputBufferType::ConstantBuffer:
+ descriptorSet->setConstantBuffer(rangeIndex, 0, bufferResource);
+ break;
+
+ case InputBufferType::StorageBuffer:
+ {
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::UnorderedAccess;
+ viewDesc.format = srcBuffer.format;
+ auto bufferView = renderer->createBufferView(
+ bufferResource,
+ viewDesc);
+ descriptorSet->setResource(rangeIndex, 0, bufferView);
+ }
+ break;
+ }
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = bufferResource;
+ outputBindings.add(binding);
+ }
+#endif
+ }
+ break;
+
+ case ShaderInputType::CombinedTextureSampler:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(entry.textureDesc, textureBindFlags, renderer, texture));
+ resource = texture;
+
+ auto sampler = _createSamplerState(renderer, entry.samplerDesc);
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(
+ texture,
+ viewDesc);
+
+ entryCursor.setCombinedTextureSampler(textureView, sampler);
+
+#if 0
+ descriptorSet->setCombinedTextureSampler(rangeIndex, 0, textureView, sampler);
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = texture;
+ outputBindings.add(binding);
+ }
+#endif
+ }
+ break;
+
+ case ShaderInputType::Texture:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(entry.textureDesc, textureBindFlags, renderer, texture));
+ resource = texture;
+
+ // TODO: support UAV textures...
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(
+ texture,
+ viewDesc);
+
+ if (!textureView)
+ {
+ return SLANG_FAIL;
+ }
+
+ entryCursor.setResource(textureView);
+
+#if 0
+ descriptorSet->setResource(rangeIndex, 0, textureView);
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = texture;
+ outputBindings.add(binding);
+ }
+#endif
+ }
+ break;
+
+ case ShaderInputType::Sampler:
+ {
+ auto sampler = _createSamplerState(renderer, entry.samplerDesc);
+
+ entryCursor.setSampler(sampler);
+#if 0
+ descriptorSet->setSampler(rangeIndex, 0, sampler);
+#endif
+ }
+ break;
+
+ case ShaderInputType::Object:
+ {
+ auto typeName = entry.objectDesc.typeName;
+ 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()));
+
+ entryCursor.setObject(shaderObject);
+ }
+ break;
+
+ default:
+ assert(!"Unhandled type");
+ return SLANG_FAIL;
+ }
+
+ if(entry.isOutput)
+ {
+ ShaderOutputPlan::Item item;
+ item.inputLayoutEntryIndex = entryIndex;
+ item.resource = resource;
+ ioOutputPlan.items.add(item);
+ }
+
+ }
+ return SLANG_OK;
+}
+
+void LegacyRenderTestApp::applyBinding(PipelineType pipelineType)
+{
+ m_bindingState->apply(m_renderer.Ptr(), pipelineType);
+}
+
+void ShaderObjectRenderTestApp::applyBinding(PipelineType pipelineType)
+{
+ m_programVars->apply(m_renderer.Ptr(), pipelineType);
+}
+
+SlangResult LegacyRenderTestApp::initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input)
{
m_options = options;
SLANG_RETURN_ON_FAIL(_initializeShaders(session, renderer, options.shaderType, input));
m_numAddedConstantBuffers = 0;
- m_renderer = renderer;
+ m_renderer = renderer;
// TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
m_constantBufferSize = 16 * sizeof(float);
@@ -129,16 +1934,17 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
constantBufferDesc.init(m_constantBufferSize);
constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
- m_constantBuffer = renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc);
+ m_constantBuffer =
+ renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc);
if (!m_constantBuffer)
return SLANG_FAIL;
//! Hack -> if doing a graphics test, add an extra binding for our dynamic constant buffer
//
- // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s binding always being specified
- // in the test file
+ // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s
+ // binding always being specified in the test file
RefPtr<BufferResource> addedConstantBuffer;
- switch(m_options.shaderType)
+ switch (m_options.shaderType)
{
default:
break;
@@ -151,7 +1957,8 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
}
BindingStateImpl* bindingState = nullptr;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(
+ m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
m_bindingState = bindingState;
// Do other initialization that doesn't depend on the source language.
@@ -159,24 +1966,25 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
// Input Assembler (IA)
const InputElementDesc inputElements[] = {
- { "A", 0, Format::RGB_Float32, offsetof(Vertex, position) },
- { "A", 1, Format::RGB_Float32, offsetof(Vertex, color) },
- { "A", 2, Format::RG_Float32, offsetof(Vertex, uv) },
+ {"A", 0, Format::RGB_Float32, offsetof(Vertex, position)},
+ {"A", 1, Format::RGB_Float32, offsetof(Vertex, color)},
+ {"A", 2, Format::RG_Float32, offsetof(Vertex, uv)},
};
m_inputLayout = renderer->createInputLayout(inputElements, SLANG_COUNT_OF(inputElements));
- if(!m_inputLayout)
+ if (!m_inputLayout)
return SLANG_FAIL;
BufferResource::Desc vertexBufferDesc;
vertexBufferDesc.init(kVertexCount * sizeof(Vertex));
- m_vertexBuffer = renderer->createBufferResource(Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData);
- if(!m_vertexBuffer)
+ m_vertexBuffer = renderer->createBufferResource(
+ Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData);
+ if (!m_vertexBuffer)
return SLANG_FAIL;
{
- switch(m_options.shaderType)
+ switch (m_options.shaderType)
{
default:
assert(!"unexpected test shader type");
@@ -211,6 +2019,134 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
return m_pipelineState ? SLANG_OK : SLANG_FAIL;
}
+SlangResult ShaderObjectRenderTestApp::initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input)
+{
+ m_options = options;
+
+ // We begin by compiling the shader file and entry points that specified via the options.
+ //
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, options, input, m_compilationOutput));
+ m_shaderInputLayout = m_compilationOutput.layout;
+
+ // Once the shaders have been compiled we load them via the underlying API.
+ //
+ SLANG_RETURN_ON_FAIL(renderer->createProgram(m_compilationOutput.output.desc, m_shaderProgram.writeRef()));
+
+ // 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();
+
+ // 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;
+
+ // 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));
+
+ m_renderer = renderer;
+
+ // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
+// m_constantBufferSize = 16 * sizeof(float);
+
+ {
+ switch(m_options.shaderType)
+ {
+ default:
+ assert(!"unexpected test shader type");
+ return SLANG_FAIL;
+
+ case Options::ShaderProgramType::Compute:
+ {
+ ComputePipelineStateDesc desc;
+ desc.pipelineLayout = pipelineLayout;
+ desc.program = m_shaderProgram;
+
+ m_pipelineState = renderer->createComputePipelineState(desc);
+ }
+ break;
+
+ case Options::ShaderProgramType::Graphics:
+ case Options::ShaderProgramType::GraphicsCompute:
+ {
+ // TODO: We should conceivably be able to match up the "available" vertex
+ // attributes, as defined by the vertex stream(s) on the model being
+ // renderer, with the "required" vertex attributes as defiend on the
+ // shader.
+ //
+ // For now we just create a fixed input layout for all graphics tests
+ // since at present they all draw the same single triangle with a
+ // fixed/known set of attributes.
+ //
+ const InputElementDesc inputElements[] = {
+ { "A", 0, Format::RGB_Float32, offsetof(Vertex, position) },
+ { "A", 1, Format::RGB_Float32, offsetof(Vertex, color) },
+ { "A", 2, Format::RG_Float32, offsetof(Vertex, uv) },
+ };
+
+ RefPtr<InputLayout> inputLayout;
+ SLANG_RETURN_ON_FAIL(renderer->createInputLayout(inputElements, SLANG_COUNT_OF(inputElements), inputLayout.writeRef()));
+
+ BufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.init(kVertexCount * sizeof(Vertex));
+
+ SLANG_RETURN_ON_FAIL(renderer->createBufferResource(Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData, m_vertexBuffer.writeRef()));
+
+ GraphicsPipelineStateDesc desc;
+ desc.pipelineLayout = pipelineLayout;
+ desc.program = m_shaderProgram;
+ desc.inputLayout = inputLayout;
+ desc.renderTargetCount = programLayout->getRenderTargetCount();
+
+ m_pipelineState = renderer->createGraphicsPipelineState(desc);
+ }
+ break;
+ }
+ }
+
+ // If success must have a pipeline state
+ return m_pipelineState ? SLANG_OK : SLANG_FAIL;
+}
+
Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
{
SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, m_options, input, m_compilationOutput));
@@ -219,16 +2155,36 @@ Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* render
return m_shaderProgram ? SLANG_OK : SLANG_FAIL;
}
-void RenderTestApp::renderFrame()
+
+void LegacyRenderTestApp::setProjectionMatrix()
{
auto mappedData = m_renderer->map(m_constantBuffer, MapFlavor::WriteDiscard);
- if(mappedData)
+ if (mappedData)
{
- const ProjectionStyle projectionStyle = RendererUtil::getProjectionStyle(m_renderer->getRendererType());
+ const ProjectionStyle projectionStyle =
+ RendererUtil::getProjectionStyle(m_renderer->getRendererType());
RendererUtil::getIdentityProjection(projectionStyle, (float*)mappedData);
- m_renderer->unmap(m_constantBuffer);
+ m_renderer->unmap(m_constantBuffer);
}
+}
+
+void ShaderObjectRenderTestApp::setProjectionMatrix()
+{
+ const ProjectionStyle projectionStyle =
+ RendererUtil::getProjectionStyle(m_renderer->getRendererType());
+
+ float projectionMatrix[16];
+ RendererUtil::getIdentityProjection(projectionStyle, projectionMatrix);
+ ShaderCursor(m_programVars)
+ .getField("Uniforms")
+ .getDereferenced()
+ .setData(projectionMatrix, sizeof(projectionMatrix));
+}
+
+void RenderTestApp::renderFrame()
+{
+ setProjectionMatrix();
auto pipelineType = PipelineType::Graphics;
@@ -237,7 +2193,7 @@ void RenderTestApp::renderFrame()
m_renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList);
m_renderer->setVertexBuffer(0, m_vertexBuffer, sizeof(Vertex));
- m_bindingState->apply(m_renderer, pipelineType);
+ applyBinding(pipelineType);
m_renderer->draw(3);
}
@@ -246,7 +2202,7 @@ void RenderTestApp::runCompute()
{
auto pipelineType = PipelineType::Compute;
m_renderer->setPipelineState(pipelineType, m_pipelineState);
- m_bindingState->apply(m_renderer, pipelineType);
+ applyBinding(pipelineType);
m_startTicks = ProcessUtil::getClockTick();
@@ -257,7 +2213,7 @@ void RenderTestApp::finalize()
{
}
-Result RenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
+Result LegacyRenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
{
// Submit the work
m_renderer->submitGpuWork();
@@ -304,6 +2260,51 @@ Result RenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileNam
return SLANG_OK;
}
+Result ShaderObjectRenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
+{
+ // Submit the work
+ m_renderer->submitGpuWork();
+ // Wait until everything is complete
+ m_renderer->waitForGpu();
+
+ FILE * f = fopen(fileName, "wb");
+ if (!f)
+ {
+ return SLANG_FAIL;
+ }
+ FileWriter writer(f, WriterFlags(0));
+
+ for(auto outputItem : m_outputPlan.items)
+ {
+ auto& inputEntry = m_shaderInputLayout.entries[outputItem.inputLayoutEntryIndex];
+ assert(inputEntry.isOutput);
+
+ auto resource = outputItem.resource;
+ if (resource && resource->isBuffer())
+ {
+ BufferResource* bufferResource = static_cast<BufferResource*>(resource.Ptr());
+ const size_t bufferSize = bufferResource->getDesc().sizeInBytes;
+
+ unsigned int* ptr = (unsigned int*)m_renderer->map(bufferResource, MapFlavor::HostRead);
+ if (!ptr)
+ {
+ return SLANG_FAIL;
+ }
+
+ const SlangResult res = ShaderInputLayout::writeBinding(bindRoot, inputEntry, ptr, bufferSize, &writer);
+
+ m_renderer->unmap(bufferResource);
+
+ SLANG_RETURN_ON_FAIL(res);
+ }
+ else
+ {
+ printf("invalid output type at %d.\n", int(outputItem.inputLayoutEntryIndex));
+ }
+ }
+ return SLANG_OK;
+}
+
Result RenderTestApp::writeScreen(const char* filename)
{
@@ -338,6 +2339,7 @@ Result RenderTestApp::update(Window* window)
if (m_options.performanceProfile)
{
+#if 0
// It might not be enough on some APIs to 'waitForGpu' to mean the computation has completed. Let's lock an output
// buffer to be sure
if (m_bindingState->outputBindings.getCount() > 0)
@@ -360,6 +2362,7 @@ Result RenderTestApp::update(Window* window)
m_renderer->unmap(bufferResource);
}
}
+#endif
// Note we don't do the same with screen rendering -> as that will do a lot of work, which may swamp any computation
// so can only really profile compute shaders at the moment
@@ -373,7 +2376,7 @@ Result RenderTestApp::update(Window* window)
{
if (m_options.shaderType == Options::ShaderProgramType::Compute || m_options.shaderType == Options::ShaderProgramType::GraphicsCompute)
{
- auto request = m_compilationOutput.output.request;
+ auto request = m_compilationOutput.output.getRequestForReflection();
auto slangReflection = (slang::ShaderReflection*) spGetReflection(request);
BindSet bindSet;
@@ -629,7 +2632,7 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
{
// Get the shared library -> it contains the executable code, we need to keep around if we recompile
ComPtr<ISlangSharedLibrary> sharedLibrary;
- SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(compilationAndLayout.output.request, 0, 0, sharedLibrary.writeRef()));
+ SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(compilationAndLayout.output.getRequestForKernels(), 0, 0, sharedLibrary.writeRef()));
// This is a hack to work around, reflection when compiling straight C/C++ code. In that case the code is just passed
// straight through to the C++ compiler so no reflection. In these tests though we should have conditional code
@@ -780,7 +2783,11 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
}
{
- RefPtr<RenderTestApp> app(new RenderTestApp);
+ RefPtr<RenderTestApp> app;
+ if (options.useShaderObjects)
+ app = new ShaderObjectRenderTestApp();
+ else
+ app = new LegacyRenderTestApp();
SLANG_RETURN_ON_FAIL(app->initialize(session, renderer, options, input));
window->show();
return window->runLoop(app);
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 6c6f67c86..5f43b254d 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -140,11 +140,19 @@ namespace renderer_test
entry.type = ShaderInputType::Buffer;
entry.bufferDesc.type = InputBufferType::ConstantBuffer;
}
+ else if (parser.LookAhead("object"))
+ {
+ entry.type = ShaderInputType::Object;
+ }
else if (parser.LookAhead("root_constants"))
{
entry.type = ShaderInputType::Buffer;
entry.bufferDesc.type = InputBufferType::RootConstantBuffer;
}
+ else if (parser.LookAhead("Uniform"))
+ {
+ entry.type = ShaderInputType::Uniform;
+ }
else if (parser.LookAhead("ubuffer"))
{
entry.type = ShaderInputType::Buffer;
@@ -226,6 +234,10 @@ namespace renderer_test
numRenderTargets = parser.ReadInt();
continue;
}
+ else
+ {
+ throw TextFormatException(String("Invalid input syntax at line ") + String(parser.NextToken().Position.Line));
+ }
parser.ReadToken();
// parse options
if (parser.LookAhead("("))
@@ -510,6 +522,11 @@ namespace renderer_test
parser.Read("=");
entry.textureDesc.mipMapCount = int(parser.ReadInt());
}
+ else if( word == "type" )
+ {
+ parser.Read("=");
+ entry.objectDesc.typeName = parser.ReadWord();
+ }
if (parser.LookAhead(","))
parser.Read(",");
diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h
index 97796d7f6..437da820b 100644
--- a/tools/render-test/shader-input-layout.h
+++ b/tools/render-test/shader-input-layout.h
@@ -17,7 +17,8 @@ using namespace gfx;
enum class ShaderInputType
{
- Buffer, Texture, Sampler, CombinedTextureSampler, Array
+ Buffer, Texture, Sampler, CombinedTextureSampler, Array, Uniform,
+ Object,
};
enum class InputTextureContent
@@ -81,6 +82,11 @@ struct BindlessHandleDataEntry
Slang::String name;
};
+struct InputObjectDesc
+{
+ Slang::String typeName;
+};
+
class ShaderInputLayoutEntry
{
public:
@@ -92,6 +98,7 @@ public:
InputBufferDesc bufferDesc;
InputSamplerDesc samplerDesc;
ArrayDesc arrayDesc;
+ InputObjectDesc objectDesc;
bool isOutput = false;
bool onlyCPULikeBinding = false; ///< If true, only use on targets that have 'uniform' or 'CPU like' binding, like CPU and CUDA
bool isBindlessObject = false; ///< If true, this is a bindless object with no associated binding point in the shader.
diff --git a/tools/render-test/shader-renderer-util.cpp b/tools/render-test/shader-renderer-util.cpp
index b2911ffd5..5e77cf1fd 100644
--- a/tools/render-test/shader-renderer-util.cpp
+++ b/tools/render-test/shader-renderer-util.cpp
@@ -149,7 +149,7 @@ static SamplerState::Desc _calcSamplerDesc(const InputSamplerDesc& srcDesc)
return dstDesc;
}
-static RefPtr<SamplerState> _createSamplerState(
+RefPtr<SamplerState> _createSamplerState(
Renderer* renderer,
const InputSamplerDesc& srcDesc)
{
diff --git a/tools/render-test/shader-renderer-util.h b/tools/render-test/shader-renderer-util.h
index 872f21768..76f3b6d87 100644
--- a/tools/render-test/shader-renderer-util.h
+++ b/tools/render-test/shader-renderer-util.h
@@ -47,6 +47,10 @@ struct BindingStateImpl : public Slang::RefObject
int m_numRenderTargets = 1;
};
+RefPtr<SamplerState> _createSamplerState(
+ Renderer* renderer,
+ const InputSamplerDesc& srcDesc);
+
/// Utility class containing functions that construct items on the renderer using the ShaderInputLayout representation
struct ShaderRendererUtil
{
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 78c730cab..baa745b14 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -20,7 +20,7 @@ static const char fragmentEntryPointName[] = "fragmentMain";
static const char computeEntryPointName[] = "computeMain";
static const char rtEntryPointName[] = "raygenMain";
-static gfx::StageType _translateStage(SlangStage slangStage)
+gfx::StageType translateStage(SlangStage slangStage)
{
switch(slangStage)
{
@@ -50,12 +50,12 @@ static gfx::StageType _translateStage(SlangStage slangStage)
}
}
-/* static */ SlangResult ShaderCompilerUtil::compileProgram(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
+/* static */ SlangResult ShaderCompilerUtil::_compileProgramImpl(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
{
out.reset();
SlangCompileRequest* slangRequest = spCreateCompileRequest(session);
- out.request = slangRequest;
+ out.m_requestForKernels = slangRequest;
out.session = session;
// Parse all the extra args
@@ -215,7 +215,7 @@ static gfx::StageType _translateStage(SlangStage slangStage)
size_t codeSize = 0;
char const* code = (char const*) spGetEntryPointCode(slangRequest, int(ee), &codeSize);
- auto gfxStage = _translateStage(actualEntryPoint.slangStage);
+ auto gfxStage = translateStage(actualEntryPoint.slangStage);
ShaderProgram::KernelDesc kernelDesc;
kernelDesc.stage = gfxStage;
@@ -231,6 +231,58 @@ static gfx::StageType _translateStage(SlangStage slangStage)
return SLANG_OK;
}
+/* static */ SlangResult ShaderCompilerUtil::compileProgram(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
+{
+ if( input.passThrough == SLANG_PASS_THROUGH_NONE )
+ {
+ return _compileProgramImpl(session, options, input, request, out);
+ }
+ else
+ {
+ bool canUseSlangForPrecompile = false;
+ switch (input.passThrough)
+ {
+ case SLANG_PASS_THROUGH_DXC:
+ case SLANG_PASS_THROUGH_FXC:
+ canUseSlangForPrecompile = true;
+ break;
+ default:
+ break;
+ }
+ // If we are doing a HLSL pass-through compilation, then we can't rely
+ // on the downstream compiler for the reflection information that
+ // will drive all of our parameter binding. As such, we will first
+ // compile with Slang to get reflection information, and then
+ // compile in another pass using the desired downstream compiler
+ // so that we can get the refleciton information we need.
+ //
+ Output slangOutput;
+ if (canUseSlangForPrecompile)
+ {
+ ShaderCompilerUtil::Input slangInput = input;
+ slangInput.sourceLanguage = SLANG_SOURCE_LANGUAGE_SLANG;
+ slangInput.passThrough = SLANG_PASS_THROUGH_NONE;
+ // TODO: we want to pass along a flag to skip codegen...
+
+
+ SLANG_RETURN_ON_FAIL(_compileProgramImpl(session, options, slangInput, request, slangOutput));
+ }
+
+ // Now we have what we need to be able to do the downstream compile better.
+ //
+ // TODO: We should be able to use the output from the Slang compilation
+ // to fill in the actual entry points to be used for this compilation,
+ // so that discovery of entry points via `[shader(...)]` attributes will work.
+ //
+ SLANG_RETURN_ON_FAIL(_compileProgramImpl(session, options, input, request, out));
+
+ out.m_extraRequestForReflection = slangOutput.getRequestForReflection();
+ slangOutput.m_requestForKernels = nullptr;
+
+ return SLANG_OK;
+ }
+}
+
/* static */SlangResult ShaderCompilerUtil::readSource(const String& inSourcePath, List<char>& outSourceText)
{
// Read in the source code
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index 5e38c8c69..a0a7ef276 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -10,6 +10,8 @@
namespace renderer_test {
+gfx::StageType translateStage(SlangStage slangStage);
+
struct ShaderCompilerUtil
{
struct Input
@@ -42,19 +44,21 @@ struct ShaderCompilerUtil
}
kernelDescs.clear();
- if (request && session)
+ if (m_requestForKernels && session)
+ {
+ spDestroyCompileRequest(m_requestForKernels);
+ }
+ if (m_extraRequestForReflection && session)
{
- spDestroyCompileRequest(request);
+ spDestroyCompileRequest(m_extraRequestForReflection);
}
session = nullptr;
- request = nullptr;
+ m_requestForKernels = nullptr;
+ m_extraRequestForReflection = nullptr;
}
~Output()
{
- if (request && session)
- {
- spDestroyCompileRequest(request);
- }
+ reset();
}
Slang::Index findKernelDescIndex(gfx::StageType stage) const
@@ -71,7 +75,16 @@ struct ShaderCompilerUtil
List<ShaderProgram::KernelDesc> kernelDescs;
ShaderProgram::Desc desc;
- SlangCompileRequest* request = nullptr;
+
+ /// Compile request that owns the lifetime of compiled kernel code.
+ SlangCompileRequest* m_requestForKernels = nullptr;
+
+ /// Compile request that owns the lifetime of reflection information.
+ SlangCompileRequest* m_extraRequestForReflection = nullptr;
+
+ SlangCompileRequest* getRequestForKernels() const { return m_requestForKernels; }
+ SlangCompileRequest* getRequestForReflection() const { return m_extraRequestForReflection ? m_extraRequestForReflection : m_requestForKernels; }
+
SlangSession* session = nullptr;
};
@@ -87,6 +100,7 @@ struct ShaderCompilerUtil
static SlangResult readSource(const Slang::String& inSourcePath, List<char>& outSourceText);
+ static SlangResult _compileProgramImpl(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out);
static SlangResult compileProgram(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out);
};