summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/hlsl.meta.slang66
-rw-r--r--source/slang/slang-ast-type.h4
-rw-r--r--source/slang/slang-check-decl.cpp26
-rw-r--r--source/slang/slang-emit.cpp8
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp94
-rw-r--r--source/slang/slang-ir-glsl-legalize.h1
-rw-r--r--source/slang/slang-ir-inst-defs.h5
-rw-r--r--source/slang/slang-ir-specialize-resources.cpp2
-rw-r--r--source/slang/slang-ir.cpp2
-rw-r--r--source/slang/slang-ir.h1
-rw-r--r--source/slang/slang-reflection-api.cpp4
-rw-r--r--source/slang/slang-type-layout.cpp7
12 files changed, 208 insertions, 12 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 9760f974a..1a112e1a9 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -20287,6 +20287,72 @@ struct ConstBufferPointer
}
}
+//
+// HLSL-like dynamic resources
+// https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_DynamicResources.html
+//
+// For Khronos targets, `__DynamicResource` can be used to declare "untyped" global bindings as
+// usual (e.g. unsized arrays for descriptor indexing), which will then be materialized into
+// new aliased bindings for each distinct cast type.
+//
+
+__magic_type(DynamicResourceType)
+__intrinsic_type($(kIROp_DynamicResourceType))
+struct __DynamicResource<let kind = __DynamicResourceKind.General>
+{
+ __intrinsic_op($(kIROp_CastDynamicResource))
+ T as<T : __IDynamicResourceCastable<kind>>();
+}
+interface __IDynamicResourceCastable<let kind = __DynamicResourceKind.General>
+{
+}
+
+enum __DynamicResourceKind
+{
+ General = 0, // CBV_SRV_UAV
+ Sampler = 1
+}
+
+__generic<T, Shape : __ITextureShape, let isArray : int, let isMS : int, let sampleCount : int, let access : int, let isShadow : int, let isCombined : int, let format : int>
+extension __TextureImpl<T, Shape, isArray, isMS, sampleCount, access, isShadow, isCombined, format> : __IDynamicResourceCastable<__DynamicResourceKind.General>
+{
+ __intrinsic_op($(kIROp_CastDynamicResource))
+ __implicit_conversion($(kConversionCost_GenericParamUpcast))
+ __init(__DynamicResource res);
+}
+
+${{{{
+const char* kDynamicResourceCastableTypes[] = {
+ "StructuredBuffer<T, L>", "RWStructuredBuffer<T, L>",
+ "AppendStructuredBuffer<T, L>", "ConsumeStructuredBuffer<T, L>", "RasterizerOrderedStructuredBuffer<T, L>",
+ "ByteAddressBuffer", "RWByteAddressBuffer", "RasterizerOrderedByteAddressBuffer",
+
+ "SamplerState", "SamplerComparisonState",
+
+ "ConstantBuffer<T>", "TextureBuffer<T>",
+};
+
+for (auto typeName : kDynamicResourceCastableTypes) {
+ auto kind = strstr(typeName, "Sampler") ? "Sampler" : "General";
+
+ if (strstr(typeName, "StructuredBuffer<T, L>"))
+ sb << "__generic<T, L : IBufferDataLayout = DefaultDataLayout>\n";
+ else if (strstr(typeName, "Buffer<T>"))
+ sb << "__generic<T>\n";
+}}}}
+
+extension $(typeName) : __IDynamicResourceCastable<__DynamicResourceKind.$(kind)>
+{
+ __intrinsic_op($(kIROp_CastDynamicResource))
+ __implicit_conversion($(kConversionCost_GenericParamUpcast))
+ __init(__DynamicResource res);
+}
+
+${{{{
+}
+}}}}
+
+
__glsl_version(450)
__glsl_extension(GL_ARB_shader_clock)
[require(glsl_spirv, GL_ARB_shader_clock)]
diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h
index b007ad854..0d1a89860 100644
--- a/source/slang/slang-ast-type.h
+++ b/source/slang/slang-ast-type.h
@@ -211,6 +211,10 @@ class PointerLikeType : public BuiltinGenericType
SLANG_AST_CLASS(PointerLikeType)
};
+class DynamicResourceType : public BuiltinType
+{
+ SLANG_AST_CLASS(DynamicResourceType)
+};
// HLSL buffer-type resources
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 23c10ddc2..969c87981 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -2037,10 +2037,11 @@ namespace Slang
if (overloadContext.bestCandidates[0].status != OverloadCandidate::Status::Applicable)
{
getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{});
- return;
}
-
- getSink()->diagnose(varDecl, Diagnostics::ambiguousDefaultInitializerForType, type);
+ else
+ {
+ getSink()->diagnose(varDecl, Diagnostics::ambiguousDefaultInitializerForType, type);
+ }
}
else if(overloadContext.bestCandidate)
{
@@ -2053,16 +2054,17 @@ namespace Slang
if (overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable)
{
getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{});
- return;
}
-
- // If we had a single best candidate *and* it was applicable,
- // then we use it to construct a new initial-value expression
- // for the variable, that will be used for all downstream
- // code generation.
- //
- varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate);
- getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{ *overloadContext.bestCandidate, 0});
+ else
+ {
+ // If we had a single best candidate *and* it was applicable,
+ // then we use it to construct a new initial-value expression
+ // for the variable, that will be used for all downstream
+ // code generation.
+ //
+ varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate);
+ getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{*overloadContext.bestCandidate, 0});
+ }
}
}
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 417bbf200..9e21ccbfd 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -244,6 +244,7 @@ struct RequiredLoweringPassSet
bool glslGlobalVar;
bool glslSSBO;
bool byteAddressBuffer;
+ bool dynamicResource;
};
// Scan the IR module and determine which lowering/legalization passes are needed based
@@ -347,6 +348,9 @@ void calcRequiredLoweringPassSet(RequiredLoweringPassSet& result, CodeGenContext
case kIROp_HLSLByteAddressBufferType:
result.byteAddressBuffer = true;
break;
+ case kIROp_DynamicResourceType:
+ result.dynamicResource = true;
+ break;
}
if (!result.generics || !result.existentialTypeLayout)
{
@@ -1166,6 +1170,10 @@ Result linkAndOptimizeIR(
if(isD3DTarget(targetRequest))
legalizeNonStructParameterToStructForHLSL(irModule);
+ // Create aliases for all dynamic resource parameters.
+ if(requiredLoweringPassSet.dynamicResource && isKhronosTarget(targetRequest))
+ legalizeDynamicResourcesForGLSL(codeGenContext, irModule);
+
legalizeExtractFromTextureAccess(irModule);
// Legalize `ImageSubscript` loads.
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index 6ff52688b..404111a85 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -3616,4 +3616,98 @@ void legalizeDispatchMeshPayloadForGLSL(IRModule* module)
});
}
+void legalizeDynamicResourcesForGLSL(CodeGenContext* context, IRModule* module)
+{
+ List<IRGlobalParam*> toRemove;
+
+ for (auto inst : module->getGlobalInsts())
+ {
+ auto param = as<IRGlobalParam>(inst);
+
+ if (!param)
+ continue;
+
+ // We are only interested in parameters involving `DynamicResource`, or arrays of it.
+ auto arrayType = as<IRArrayTypeBase>(param->getDataType());
+ auto type = arrayType ? arrayType->getElementType() : param->getDataType();
+
+ if (!as<IRDynamicResourceType>(type))
+ continue;
+
+ Dictionary<IRType*, IRGlobalParam*> aliasedParams;
+ IRBuilder builder(module);
+
+ auto getAliasedParam = [&](IRType* type)
+ {
+ IRGlobalParam* newParam;
+
+ if (!aliasedParams.tryGetValue(type, newParam))
+ {
+ newParam = builder.createGlobalParam(type);
+
+ for (auto decoration : param->getDecorations())
+ cloneDecoration(decoration, newParam);
+
+ aliasedParams[type] = newParam;
+ }
+ return newParam;
+ };
+
+ // Try to rewrite all uses leading to `CastDynamicResource`.
+ // Later, we will diagnose an error if the parameter still has uses.
+ traverseUsers(param, [&](IRInst* user)
+ {
+ if (user->getOp() == kIROp_CastDynamicResource && !arrayType)
+ {
+ builder.setInsertBefore(user);
+
+ user->replaceUsesWith(getAliasedParam(user->getDataType()));
+ user->removeAndDeallocate();
+ }
+ else if (user->getOp() == kIROp_GetElement && arrayType)
+ {
+ traverseUsers(user, [&](IRInst* elementUser)
+ {
+ if (elementUser->getOp() == kIROp_CastDynamicResource)
+ {
+ builder.setInsertBefore(elementUser);
+
+ auto paramType = builder.getArrayTypeBase(
+ arrayType->getOp(),
+ elementUser->getDataType(),
+ arrayType->getElementCount());
+
+ auto newAccess = builder.emitElementExtract(
+ paramType->getElementType(),
+ getAliasedParam(paramType),
+ user->getOperand(1));
+
+ elementUser->replaceUsesWith(newAccess);
+ elementUser->removeAndDeallocate();
+ }
+ });
+
+ if (!user->hasUses())
+ {
+ user->removeAndDeallocate();
+ }
+ }
+ });
+ toRemove.add(param);
+ }
+
+ // Remove unused parameters later to avoid invalidating iterator.
+ for (auto param : toRemove)
+ {
+ if (!param->hasUses())
+ {
+ param->removeAndDeallocate();
+ }
+ else
+ {
+ context->getSink()->diagnose(param->firstUse->getUser(), Diagnostics::ambiguousReference, param);
+ }
+ }
+}
+
} // namespace Slang
diff --git a/source/slang/slang-ir-glsl-legalize.h b/source/slang/slang-ir-glsl-legalize.h
index 8ec164a96..c9e6e3f26 100644
--- a/source/slang/slang-ir-glsl-legalize.h
+++ b/source/slang/slang-ir-glsl-legalize.h
@@ -25,4 +25,5 @@ void legalizeConstantBufferLoadForGLSL(IRModule* module);
void legalizeDispatchMeshPayloadForGLSL(IRModule* module);
+void legalizeDynamicResourcesForGLSL(CodeGenContext* context, IRModule* module);
}
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 2b5f35736..9899feba1 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -223,6 +223,9 @@ INST(Nop, nop, 0, 0)
INST(RayQueryType, RayQuery, 1, HOISTABLE)
INST(HitObjectType, HitObject, 0, HOISTABLE)
+// Opaque type that can be dynamically cast to other resource types.
+INST(DynamicResourceType, DynamicResource, 0, HOISTABLE)
+
// A user-defined structure declaration at the IR level.
// Unlike in the AST where there is a distinction between
// a `StructDecl` and a `DeclRefType` that refers to it,
@@ -403,6 +406,8 @@ INST(GetElementPtr, getElementPtr, 2, 0)
INST(GetOffsetPtr, getOffsetPtr, 2, 0)
INST(GetAddr, getAddr, 1, 0)
+INST(CastDynamicResource, castDynamicResource, 1, 0)
+
// Get an unowned NativeString from a String.
INST(getNativeStr, getNativeStr, 1, 0)
diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp
index 419477790..c4be278df 100644
--- a/source/slang/slang-ir-specialize-resources.cpp
+++ b/source/slang/slang-ir-specialize-resources.cpp
@@ -1246,6 +1246,8 @@ bool isIllegalGLSLParameterType(IRType* type)
return true;
if (as<IRHLSLStreamOutputType>(type))
return true;
+ if (as<IRDynamicResourceType>(type))
+ return true;
return false;
}
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index c6409a7e1..ba7376c46 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -8198,6 +8198,7 @@ namespace Slang
case kIROp_CastPtrToInt:
case kIROp_CastIntToPtr:
case kIROp_PtrCast:
+ case kIROp_CastDynamicResource:
case kIROp_AllocObj:
case kIROp_PackAnyValue:
case kIROp_UnpackAnyValue:
@@ -8638,6 +8639,7 @@ namespace Slang
case kIROp_CastPtrToBool:
case kIROp_CastPtrToInt:
case kIROp_PtrCast:
+ case kIROp_CastDynamicResource:
case kIROp_BitAnd:
case kIROp_BitNot:
case kIROp_BitOr:
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index cf9dfa84c..9a773a891 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1562,6 +1562,7 @@ SIMPLE_IR_TYPE(TextureBufferType, UniformParameterGroupType)
SIMPLE_IR_TYPE(GLSLInputParameterGroupType, VaryingParameterGroupType)
SIMPLE_IR_TYPE(GLSLOutputParameterGroupType, VaryingParameterGroupType)
SIMPLE_IR_TYPE(ParameterBlockType, UniformParameterGroupType)
+SIMPLE_IR_TYPE(DynamicResourceType, Type)
struct IRGLSLShaderStorageBufferType : IRBuiltinGenericType
{
diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp
index 8dc889c97..88caf67be 100644
--- a/source/slang/slang-reflection-api.cpp
+++ b/source/slang/slang-reflection-api.cpp
@@ -383,6 +383,10 @@ SLANG_API SlangTypeKind spReflectionType_GetKind(SlangReflectionType* inType)
{
return SLANG_TYPE_KIND_POINTER;
}
+ else if (const auto dynamicResourceType = as<DynamicResourceType>(type))
+ {
+ return SLANG_TYPE_KIND_DYNAMIC_RESOURCE;
+ }
// TODO: need a better way to handle this stuff...
#define CASE(TYPE) \
else if(as<TYPE>(type)) do { \
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index eca0d0ec3..f85fb2c5f 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -4389,6 +4389,13 @@ static TypeLayoutResult _createTypeLayout(
return result;
}
+ else if (as<DynamicResourceType>(type))
+ {
+ return createSimpleTypeLayout(
+ SimpleLayoutInfo(LayoutResourceKind::DescriptorTableSlot, 1),
+ type,
+ rules);
+ }
else if (auto declRefType = as<DeclRefType>(type))
{
auto declRef = declRefType->getDeclRef();