summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-emit-spirv-ops.h31
-rw-r--r--source/slang/slang-emit-spirv.cpp57
-rw-r--r--source/slang/slang-hlsl-to-vulkan-layout-options.cpp2
-rw-r--r--source/slang/slang-hlsl-to-vulkan-layout-options.h7
-rw-r--r--source/slang/slang-ir-inst-defs.h5
-rw-r--r--source/slang/slang-ir-insts.h20
-rw-r--r--source/slang/slang-ir-legalize-types.cpp57
-rw-r--r--source/slang/slang-ir-lower-append-consume-structured-buffer.cpp2
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp15
-rw-r--r--source/slang/slang-ir-util.cpp190
-rw-r--r--source/slang/slang-options.cpp8
11 files changed, 383 insertions, 11 deletions
diff --git a/source/slang/slang-emit-spirv-ops.h b/source/slang/slang-emit-spirv-ops.h
index 8840d033f..891372fa6 100644
--- a/source/slang/slang-emit-spirv-ops.h
+++ b/source/slang/slang-emit-spirv-ops.h
@@ -691,6 +691,35 @@ SpvInst* emitOpDecorateBuiltIn(
}
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpDecorate
+template<typename T>
+SpvInst* emitOpMemberDecorateString(
+ SpvInstParent* parent,
+ IRInst* inst,
+ const T& target,
+ const SpvLiteralInteger& index,
+ SpvDecoration decoration,
+ UnownedStringSlice text
+)
+{
+ static_assert(isSingular<T>);
+ return emitInst(parent, inst, SpvOpDecorate, target, index, decoration, text);
+}
+
+// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpDecorate
+template<typename T>
+SpvInst* emitOpDecorateString(
+ SpvInstParent* parent,
+ IRInst* inst,
+ const T& target,
+ SpvDecoration decoration,
+ UnownedStringSlice text
+)
+{
+ static_assert(isSingular<T>);
+ return emitInst(parent, inst, SpvOpDecorate, target, decoration, text);
+}
+
+// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpDecorate
template<typename T1, typename T2>
SpvInst* emitOpDecorateUniformId(
SpvInstParent* parent,
@@ -808,7 +837,7 @@ SpvInst* emitOpDecorateCounterBuffer(
{
static_assert(isSingular<T1>);
static_assert(isSingular<T2>);
- return emitInst(parent, inst, SpvOpDecorate, target, SpvDecorationCounterBuffer, counterBuffer);
+ return emitInst(parent, inst, SpvOpDecorateId, target, SpvDecorationCounterBuffer, counterBuffer);
}
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpDecorate
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 07f8a4cd2..a600d4b10 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1237,6 +1237,13 @@ struct SPIRVEmitContext
Dictionary<SpvTypeInstKey, SpvInst*> m_spvTypeInsts;
+ bool shouldEmitSPIRVReflectionInfo()
+ {
+ if (!m_targetRequest->getHLSLToVulkanLayoutOptions())
+ return false;
+ return m_targetRequest->getHLSLToVulkanLayoutOptions()->shouldEmitSPIRVReflectionInfo();
+ }
+
// Next, let's look at emitting some of the instructions
// that can occur at global scope.
@@ -1958,6 +1965,7 @@ struct SPIRVEmitContext
if (auto layout = getVarLayout(param))
emitVarLayout(param, varInst, layout);
maybeEmitName(varInst, param);
+ emitDecorations(param, getID(varInst));
return varInst;
}
@@ -2833,6 +2841,42 @@ struct SPIRVEmitContext
break;
// ...
}
+
+ if (shouldEmitSPIRVReflectionInfo())
+ {
+ switch (decoration->getOp())
+ {
+ default:
+ break;
+ case kIROp_SemanticDecoration:
+ {
+ emitOpDecorateString(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvDecorationUserSemantic,
+ cast<IRSemanticDecoration>(decoration)->getSemanticName());
+ }
+ break;
+ case kIROp_UserTypeNameDecoration:
+ {
+ ensureExtensionDeclaration(toSlice("SPV_GOOGLE_user_type"));
+ emitOpDecorateString(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvDecorationUserTypeGOOGLE,
+ cast<IRUserTypeNameDecoration>(decoration)->getUserTypeName()->getStringSlice());
+ }
+ break;
+ case kIROp_CounterBufferDecoration:
+ {
+ emitOpDecorateCounterBuffer(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ as<IRCounterBufferDecoration>(decoration)->getCounterBuffer());
+ }
+ break;
+ }
+ }
}
void emitLayoutDecorations(IRStructType* structType, SpvWord spvStructID)
@@ -2948,6 +2992,19 @@ struct SPIRVEmitContext
SpvLiteralInteger::from32(id),
SpvLiteralInteger::from32((int32_t)matrixStride));
}
+ if (shouldEmitSPIRVReflectionInfo())
+ {
+ if (auto semanticDecor = field->getKey()->findDecoration<IRSemanticDecoration>())
+ {
+ emitOpMemberDecorateString(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ spvStructID,
+ SpvLiteralInteger::from32(id),
+ SpvDecorationUserSemantic,
+ semanticDecor->getSemanticName());
+ }
+ }
id++;
}
}
diff --git a/source/slang/slang-hlsl-to-vulkan-layout-options.cpp b/source/slang/slang-hlsl-to-vulkan-layout-options.cpp
index d15b60f3b..36044e43a 100644
--- a/source/slang/slang-hlsl-to-vulkan-layout-options.cpp
+++ b/source/slang/slang-hlsl-to-vulkan-layout-options.cpp
@@ -92,7 +92,7 @@ Index HLSLToVulkanLayoutOptions::getShift(Kind kind, Index set) const
bool HLSLToVulkanLayoutOptions::hasState() const
{
return canInferBindings() || hasGlobalsBinding() || shouldInvertY() || getUseOriginalEntryPointName()
- || shouldUseGLLayout();
+ || shouldUseGLLayout() || shouldEmitSPIRVReflectionInfo();
}
HLSLToVulkanLayoutOptions::Binding HLSLToVulkanLayoutOptions::inferBinding(Kind kind, const Binding& inBinding) const
diff --git a/source/slang/slang-hlsl-to-vulkan-layout-options.h b/source/slang/slang-hlsl-to-vulkan-layout-options.h
index c88805412..97de2a610 100644
--- a/source/slang/slang-hlsl-to-vulkan-layout-options.h
+++ b/source/slang/slang-hlsl-to-vulkan-layout-options.h
@@ -121,6 +121,8 @@ public:
bool shouldUseGLLayout() const { return m_useGLLayout; }
+ bool shouldEmitSPIRVReflectionInfo() const { return m_emitSPIRVReflectionInfo; }
+
bool getUseOriginalEntryPointName() const { return m_useOriginalEntryPointName; }
/// Given an kind and a binding infer the vulkan binding.
@@ -153,6 +155,8 @@ public:
void setUseGLLayout(bool value) { m_useGLLayout = value; }
+ void setEmitSPIRVReflectionInfo(bool value) { m_emitSPIRVReflectionInfo = value; }
+
/// Ctor
HLSLToVulkanLayoutOptions();
@@ -185,6 +189,9 @@ protected:
/// If set, raw buffer load/stores will follow std430 layout.
bool m_useGLLayout = false;
+
+ /// If set, will emit SPIR-V reflection info.
+ bool m_emitSPIRVReflectionInfo = false;
};
} // namespace Slang
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 453fbf16d..ff0b815d4 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -853,6 +853,11 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(SemanticDecoration, semantic, 2, 0)
INST(PackOffsetDecoration, packoffset, 2, 0)
+ // Reflection metadata for a shader parameter that provides the original type name.
+ INST(UserTypeNameDecoration, UserTypeName, 1, 0)
+ // Reflection metadata for a shader parameter that refers to the associated counter buffer of a UAV.
+ INST(CounterBufferDecoration, CounterBuffer, 1, 0)
+
INST(RequireSPIRVDescriptorIndexingExtensionDecoration, RequireSPIRVDescriptorIndexingExtensionDecoration, 0, 0)
INST(SPIRVOpDecoration, spirvOpDecoration, 1, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 2a7852c1e..2d24efb43 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -1268,6 +1268,26 @@ struct IRPackOffsetDecoration : IRDecoration
IRIntLit* getComponentOffset() { return cast<IRIntLit>(getOperand(1)); }
};
+struct IRUserTypeNameDecoration : IRDecoration
+{
+ enum
+ {
+ kOp = kIROp_UserTypeNameDecoration
+ };
+ IR_LEAF_ISA(UserTypeNameDecoration)
+ IRStringLit* getUserTypeName() { return cast<IRStringLit>(getOperand(0)); }
+};
+
+struct IRCounterBufferDecoration : IRDecoration
+{
+ enum
+ {
+ kOp = kIROp_CounterBufferDecoration
+ };
+ IR_LEAF_ISA(CounterBufferDecoration)
+ IRInst* getCounterBuffer() { return getOperand(0); }
+};
+
struct IRStageAccessDecoration : public IRDecoration
{
IR_PARENT_ISA(StageAccessDecoration)
diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp
index bd5c45ff4..6c5ab1223 100644
--- a/source/slang/slang-ir-legalize-types.cpp
+++ b/source/slang/slang-ir-legalize-types.cpp
@@ -2518,6 +2518,24 @@ static LegalVal legalizeFunc(
return builder.build(irFunc);
}
+static void cloneDecorationToVar(IRInst* srcInst, IRInst* varInst)
+{
+ for (auto decoration : srcInst->getDecorations())
+ {
+ switch (decoration->getOp())
+ {
+ case kIROp_FormatDecoration:
+ case kIROp_UserTypeNameDecoration:
+ case kIROp_SemanticDecoration:
+ cloneDecoration(decoration, varInst);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
static LegalVal declareSimpleVar(
IRTypeLegalizationContext* context,
IROp op,
@@ -2601,16 +2619,17 @@ static LegalVal declareSimpleVar(
if( leafVar )
{
- for( auto decoration : leafVar->getDecorations() )
+ cloneDecorationToVar(leafVar, irVar);
+ if (as<IRStructKey>(leafVar))
{
- switch( decoration->getOp() )
+ // Find the struct field and clone any decorations on the field over.
+ for (auto use = leafVar->firstUse; use; use = use->nextUse)
{
- case kIROp_FormatDecoration:
- cloneDecoration(decoration, irVar);
- break;
-
- default:
- break;
+ if (auto field = as<IRStructField>(use->getUser()))
+ {
+ cloneDecorationToVar(field, irVar);
+ break;
+ }
}
}
}
@@ -3330,6 +3349,28 @@ static LegalVal declareVars(
tupleVal->elements.add(element);
}
+ if (tupleVal->elements.getCount() == 2 &&
+ tupleVal->elements[0].key &&
+ tupleVal->elements[0].key->findDecorationImpl(kIROp_CounterBufferDecoration))
+ {
+ // If this is a lowered struct from a structured buffer type that has an atomic counter,
+ // insert decorations to each element var to associate the element buffer with the atomic buffer.
+ // This decoration is inserted to all lowered structs in the slang-ir-lower-append-consume-structured-buffer
+ // pass.
+ //
+ if (tupleVal->elements[0].val.flavor == LegalVal::Flavor::simple &&
+ tupleVal->elements[1].val.flavor == LegalVal::Flavor::simple)
+ {
+ auto simpleElementVar = tupleVal->elements[0].val.getSimple();
+ auto simpleCounterVar = tupleVal->elements[1].val.getSimple();
+ IRBuilder builder(simpleElementVar);
+ builder.addDecoration(simpleElementVar, kIROp_CounterBufferDecoration, simpleCounterVar);
+ // Clone decorations from leafVar to both element and counter var.
+ cloneDecorationToVar(leafVar, simpleElementVar);
+ cloneDecorationToVar(leafVar, simpleCounterVar);
+ }
+ }
+
return LegalVal::tuple(tupleVal);
}
break;
diff --git a/source/slang/slang-ir-lower-append-consume-structured-buffer.cpp b/source/slang/slang-ir-lower-append-consume-structured-buffer.cpp
index ed04541ef..5a7c7ee1c 100644
--- a/source/slang/slang-ir-lower-append-consume-structured-buffer.cpp
+++ b/source/slang/slang-ir-lower-append-consume-structured-buffer.cpp
@@ -31,6 +31,8 @@ namespace Slang
auto counterBufferKey = builder.createStructKey();
builder.addNameHintDecoration(counterBufferKey, UnownedStringSlice("counter"));
+ builder.addDecoration(elementBufferKey, kIROp_CounterBufferDecoration, counterBufferKey);
+
auto elementBufferType = builder.getType(kIROp_HLSLRWStructuredBufferType, elementType);
auto counterBufferType = builder.getType(kIROp_HLSLRWStructuredBufferType, builder.getIntType());
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index d5b24dd31..c4b0a471a 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -496,6 +496,21 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
void processGlobalParam(IRGlobalParam* inst)
{
+ if (inst->getDataType())
+ {
+ // Preserve the original type name as a decoration before we do any type lowering.
+ // This is needed to implement -fspv-reflect, which allows the compiler to output the
+ // original user-friendly type name of each shader parameter as a SPIRV decoration.
+ //
+ StringBuilder sb;
+ getTypeNameHint(sb, inst->getDataType());
+ if (sb.getLength())
+ {
+ IRBuilder builder(inst);
+ builder.addDecoration(inst, kIROp_UserTypeNameDecoration, builder.getStringValue(sb.produceString().getUnownedSlice()));
+ }
+ }
+
// If the param is a texture, infer its format.
if (auto textureType = as<IRTextureTypeBase>(unwrapArray(inst->getDataType())))
{
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp
index 6afb6b719..b4a7b6b99 100644
--- a/source/slang/slang-ir-util.cpp
+++ b/source/slang/slang-ir-util.cpp
@@ -328,8 +328,196 @@ void getTypeNameHint(StringBuilder& sb, IRInst* type)
sb << "string";
break;
case kIROp_ArrayType:
- sb << "array_";
+ sb << "array<";
getTypeNameHint(sb, type->getOperand(0));
+ sb << ",";
+ getTypeNameHint(sb, as<IRArrayType>(type)->getElementCount());
+ sb << ">";
+ break;
+ case kIROp_UnsizedArrayType:
+ sb << "runtime_array<";
+ getTypeNameHint(sb, type->getOperand(0));
+ sb << ">";
+ break;
+ case kIROp_TextureType:
+ case kIROp_GLSLImageType:
+ {
+ auto textureType = as<IRResourceTypeBase>(type);
+ switch (textureType->getAccess())
+ {
+ case SLANG_RESOURCE_ACCESS_APPEND:
+ sb << "Append";
+ break;
+ case SLANG_RESOURCE_ACCESS_CONSUME:
+ sb << "Consume";
+ break;
+ case SLANG_RESOURCE_ACCESS_RASTER_ORDERED:
+ sb << "RasterizerOrdered";
+ break;
+ case SLANG_RESOURCE_ACCESS_WRITE:
+ sb << "RW";
+ break;
+ case SLANG_RESOURCE_ACCESS_FEEDBACK:
+ sb << "Feedback";
+ break;
+ case SLANG_RESOURCE_ACCESS_READ:
+ break;
+ }
+ if (textureType->isCombined())
+ {
+ switch (textureType->GetBaseShape())
+ {
+ case SLANG_TEXTURE_1D:
+ sb << "Sampler1D";
+ break;
+ case SLANG_TEXTURE_2D:
+ sb << "Sampler2D";
+ break;
+ case SLANG_TEXTURE_3D:
+ sb << "Sampler3D";
+ break;
+ case SLANG_TEXTURE_CUBE:
+ sb << "SamplerCube";
+ break;
+ case SLANG_TEXTURE_BUFFER:
+ sb << "SamplerBuffer";
+ break;
+ }
+ }
+ else
+ {
+ switch (textureType->GetBaseShape())
+ {
+ case SLANG_TEXTURE_1D:
+ sb << "Texture1D";
+ break;
+ case SLANG_TEXTURE_2D:
+ sb << "Texture2D";
+ break;
+ case SLANG_TEXTURE_3D:
+ sb << "Texture3D";
+ break;
+ case SLANG_TEXTURE_CUBE:
+ sb << "TextureCube";
+ break;
+ case SLANG_TEXTURE_BUFFER:
+ sb << "Buffer";
+ break;
+ }
+ }
+ if (textureType->isMultisample())
+ {
+ sb << "MS";
+ }
+ if (textureType->isArray())
+ {
+ sb << "Array";
+ }
+ if (textureType->isShadow())
+ {
+ sb << "Shadow";
+ }
+ }
+ break;
+ case kIROp_ParameterBlockType:
+ sb << "ParameterBlock<";
+ getTypeNameHint(sb, as<IRParameterBlockType>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_ConstantBufferType:
+ sb << "cbuffer<";
+ getTypeNameHint(sb, as<IRConstantBufferType>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_TextureBufferType:
+ sb << "tbuffer<";
+ getTypeNameHint(sb, as<IRTextureBufferType>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_GLSLShaderStorageBufferType:
+ sb << "StorageBuffer<";
+ getTypeNameHint(sb, as<IRGLSLShaderStorageBufferType>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_HLSLByteAddressBufferType:
+ sb << "ByteAddressBuffer";
+ break;
+ case kIROp_HLSLRWByteAddressBufferType:
+ sb << "RWByteAddressBuffer";
+ break;
+ case kIROp_HLSLRasterizerOrderedByteAddressBufferType:
+ sb << "RasterizerOrderedByteAddressBuffer";
+ break;
+ case kIROp_RaytracingAccelerationStructureType:
+ sb << "RayTracingAccelerationStructure";
+ break;
+ case kIROp_HitObjectType:
+ sb << "HitObject";
+ break;
+ case kIROp_HLSLConstBufferPointerType:
+ sb << "ConstantBufferPointer<";
+ getTypeNameHint(sb, as<IRHLSLConstBufferPointerType>(type)->getValueType());
+ sb << ">";
+ break;
+ case kIROp_HLSLStructuredBufferType:
+ sb << "StructuredBuffer<";
+ getTypeNameHint(sb, as<IRHLSLStructuredBufferTypeBase>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_HLSLRWStructuredBufferType:
+ sb << "RWStructuredBuffer<";
+ getTypeNameHint(sb, as<IRHLSLStructuredBufferTypeBase>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_HLSLAppendStructuredBufferType:
+ sb << "AppendStructuredBuffer<";
+ getTypeNameHint(sb, as<IRHLSLStructuredBufferTypeBase>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_HLSLConsumeStructuredBufferType:
+ sb << "ConsumeStructuredBuffer<";
+ getTypeNameHint(sb, as<IRHLSLStructuredBufferTypeBase>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_HLSLRasterizerOrderedStructuredBufferType:
+ sb << "RasterizerOrderedStructuredBuffer<";
+ getTypeNameHint(sb, as<IRHLSLStructuredBufferTypeBase>(type)->getElementType());
+ sb << ">";
+ break;
+ case kIROp_SamplerStateType:
+ sb << "SamplerState";
+ break;
+ case kIROp_SamplerComparisonStateType:
+ sb << "SamplerComparisonState";
+ break;
+ case kIROp_TextureFootprintType:
+ sb << "TextureFootprint";
+ break;
+ case kIROp_Specialize:
+ {
+ auto specialize = as<IRSpecialize>(type);
+ getTypeNameHint(sb, specialize->getBase());
+ sb << "<";
+ bool isFirst = true;
+ for (UInt i = 0; i < specialize->getArgCount(); i++)
+ {
+ auto arg = specialize->getArg(i);
+ if (!arg->getDataType())
+ continue;
+ if (arg->getDataType()->getOp() == kIROp_WitnessTableType)
+ continue;
+ if (!isFirst) sb << ",";
+ getTypeNameHint(sb, arg);
+ isFirst = false;
+ }
+ sb << ">";
+ }
+ break;
+ case kIROp_AttributedType:
+ getTypeNameHint(sb, as<IRAttributedType>(type)->getBaseType());
+ break;
+ case kIROp_RateQualifiedType:
+ getTypeNameHint(sb, as<IRRateQualifiedType>(type)->getValueType());
break;
case kIROp_VectorType:
getTypeNameHint(sb, type->getOperand(0));
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 7c442a9d2..c9527bf5e 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -95,6 +95,7 @@ enum class OptionKind
VulkanInvertY,
VulkanUseEntryPointName,
VulkanUseGLLayout,
+ VulkanEmitReflection,
GLSLForceScalarLayout,
EnableEffectAnnotations,
@@ -512,6 +513,7 @@ void initCommandOptions(CommandOptions& options)
{ OptionKind::VulkanInvertY, "-fvk-invert-y", nullptr, "Negates (additively inverts) SV_Position.y before writing to stage output."},
{ OptionKind::VulkanUseEntryPointName, "-fvk-use-entrypoint-name", nullptr, "Uses the entrypoint name from the source instead of 'main' in the spirv output."},
{ OptionKind::VulkanUseGLLayout, "-fvk-use-gl-layout", nullptr, "Use std430 layout instead of D3D buffer layout for raw buffer load/stores."},
+ { OptionKind::VulkanEmitReflection, "-fspv-reflect", nullptr, "Include reflection decorations in the resulting SPIRV for shader parameters."},
{ OptionKind::EnableEffectAnnotations,
"-enable-effect-annotations", nullptr,
"Enables support for legacy effect annotation syntax."},
@@ -2100,6 +2102,12 @@ SlangResult OptionsParser::_parse(
m_hlslToVulkanLayoutOptions->setUseGLLayout(true);
break;
}
+ case OptionKind::VulkanEmitReflection:
+ {
+ // -fvk-invert-y
+ m_hlslToVulkanLayoutOptions->setEmitSPIRVReflectionInfo(true);
+ break;
+ }
case OptionKind::Profile: SLANG_RETURN_ON_FAIL(_parseProfile(arg)); break;
case OptionKind::Capability:
{