diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2017-11-13 14:17:09 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-11-13 14:17:09 -0800 |
| commit | c9d94248dc73fe41c344b0a23230e597f7b94a2c (patch) | |
| tree | 07330bef7fc8685f5615212de33250bb32adc918 | |
| parent | c9368fe3ec8f8d8bc58947ddb1b5fd2caa4bd70a (diff) | |
Parameter block work (#276)
* Don't auto-enable IR use for compute tests
The `COMPARE_COMPUTE` and `COMPARE_RENDER_COMPUTE` test fixtures were set up to always enable the `-use-ir` flag on Slang, which precludes having any tests that confirm functionality on the old non-IR path (which is still required by our main customer).
This change adds the `-xslang -use-ir` flags explicitly to any compute test cases that left them out, and makes the fixture no longer add it by default.
* Continue building out parameter block support
The initial front-end logic for parameter blocks was already added, but they are still missing a bunch of functionality. This change addresses some of the known issues:
- Bug fix: don't try to emit HLSL `register` bindings for variables that consume whole register spaces/sets
- Overhaul type layout logic so that it can make decisions based on a given code generation target (currently passed in as a `TargetRequest`), which allows us to decide whether or not a parameter block should get its own register set on a per-target basis.
- Always use a register space/set for Vulkan
- Never use a register space/set for HLSL SM 5.0 and lower
- By default, don't use register spaces/sets for HLSL output
- Add a command-line flag and some "target flags" to enable register-space usage for D3D targets
- Hackily add initial support for parameter blocks in the AST-to-AST path
- This just blindly lowers `ParameterBlock<T>` to `T`, which shouldn't quite work
- A more complete overhaul will probably need to wait until the AST-to-AST legalization is changed to use the `LegalType`s from the IR legalization pass.
- Add a compute-based test case to actually run code using parameter blocks
- This file runs test cases both with and without the IR
| -rw-r--r-- | slang.h | 28 | ||||
| -rw-r--r-- | source/slang/compiler.h | 6 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 121 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 16 | ||||
| -rw-r--r-- | source/slang/lower.cpp | 14 | ||||
| -rw-r--r-- | source/slang/options.cpp | 12 | ||||
| -rw-r--r-- | source/slang/parameter-binding.cpp | 103 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 22 | ||||
| -rw-r--r-- | source/slang/type-layout.cpp | 433 | ||||
| -rw-r--r-- | source/slang/type-layout.h | 83 | ||||
| -rw-r--r-- | tests/bindings/multiple-parameter-blocks.slang | 2 | ||||
| -rw-r--r-- | tests/bindings/parameter-blocks.slang | 2 | ||||
| -rw-r--r-- | tests/compute/break-stmt.slang | 2 | ||||
| -rw-r--r-- | tests/compute/continue-stmt.slang | 2 | ||||
| -rw-r--r-- | tests/compute/discard-stmt.slang | 2 | ||||
| -rw-r--r-- | tests/compute/parameter-block.slang | 28 | ||||
| -rw-r--r-- | tests/compute/parameter-block.slang.1.expected.txt | 4 | ||||
| -rw-r--r-- | tests/compute/parameter-block.slang.expected.txt | 4 | ||||
| -rw-r--r-- | tests/compute/select-expr.slang | 2 | ||||
| -rw-r--r-- | tests/compute/simple.slang | 2 | ||||
| -rw-r--r-- | tests/compute/textureSamplingTest.slang | 2 | ||||
| -rw-r--r-- | tools/slang-test/main.cpp | 1 |
22 files changed, 625 insertions, 266 deletions
@@ -136,6 +136,16 @@ extern "C" }; /*! + @brief Flags to control code generation behavior of a compilation target */ + typedef unsigned int SlangTargetFlags; + enum + { + /* When compiling for a D3D Shader Model 5.1 or higher target, allocate + distinct register spaces for parameter blocks. */ + SLANG_TARGET_FLAG_PARAMETER_BLOCKS_USE_REGISTER_SPACES = 1 << 4, + }; + + /*! @brief Options to control emission of `#line` directives */ typedef unsigned int SlangLineDirectiveMode; @@ -249,10 +259,20 @@ extern "C" /*! @brief Add a code-generation target to be used. */ - SLANG_API void spAddCodeGenTarget( + SLANG_API int spAddCodeGenTarget( SlangCompileRequest* request, SlangCompileTarget target); + SLANG_API void spSetTargetProfile( + SlangCompileRequest* request, + int targetIndex, + SlangProfileID profile); + + SLANG_API void spSetTargetFlags( + SlangCompileRequest* request, + int targetIndex, + SlangTargetFlags flags); + /*! @brief Set the container format to be used for binary output. */ @@ -564,7 +584,9 @@ extern "C" SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT, SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT, SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER, - SLANG_PAREMTER_CATEGORY_PARAMETER_BLOCK, + + // HLSL register `space`, Vulkan GLSL `set` + SLANG_PARAMETER_CATEGORY_REGISTER_SPACE, // SLANG_PARAMETER_CATEGORY_COUNT, @@ -825,7 +847,7 @@ namespace slang DescriptorTableSlot = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT, SpecializationConstant = SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT, PushConstantBuffer = SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER, - ParameterBlock = SLANG_PAREMTER_CATEGORY_PARAMETER_BLOCK, + RegisterSpace = SLANG_PARAMETER_CATEGORY_REGISTER_SPACE, }; struct TypeLayoutReflection diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 7a045d23c..f42f36c1f 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -176,8 +176,10 @@ namespace Slang class TargetRequest : public RefObject { public: - CompileRequest* compileRequest; - CodeGenTarget target; + CompileRequest* compileRequest; + CodeGenTarget target; + SlangTargetFlags targetFlags = 0; + Slang::Profile targetProfile = Slang::Profile::Unknown; // The resulting reflection layout information RefPtr<ProgramLayout> layout; diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 039aea27d..a8cd11af4 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -3425,75 +3425,84 @@ struct EmitVisitor // Keyword to use in the uniform case (`register` for globals, `packoffset` inside a `cbuffer`) char const* uniformSemanticSpelling = "register") { - if( info.kind == LayoutResourceKind::Uniform ) + switch(info.kind) { - size_t offset = info.index; + case LayoutResourceKind::Uniform: + { + size_t offset = info.index; - // The HLSL `c` register space is logically grouped in 16-byte registers, - // while we try to traffic in byte offsets. That means we need to pick - // a register number, based on the starting offset in 16-byte register - // units, and then a "component" within that register, based on 4-byte - // offsets from there. We cannot support more fine-grained offsets than that. + // The HLSL `c` register space is logically grouped in 16-byte registers, + // while we try to traffic in byte offsets. That means we need to pick + // a register number, based on the starting offset in 16-byte register + // units, and then a "component" within that register, based on 4-byte + // offsets from there. We cannot support more fine-grained offsets than that. - Emit(": "); - Emit(uniformSemanticSpelling); - Emit("(c"); + Emit(": "); + Emit(uniformSemanticSpelling); + Emit("(c"); - // Size of a logical `c` register in bytes - auto registerSize = 16; + // Size of a logical `c` register in bytes + auto registerSize = 16; - // Size of each component of a logical `c` register, in bytes - auto componentSize = 4; + // Size of each component of a logical `c` register, in bytes + auto componentSize = 4; - size_t startRegister = offset / registerSize; - Emit(int(startRegister)); + size_t startRegister = offset / registerSize; + Emit(int(startRegister)); - size_t byteOffsetInRegister = offset % registerSize; + size_t byteOffsetInRegister = offset % registerSize; - // If this field doesn't start on an even register boundary, - // then we need to emit additional information to pick the - // right component to start from - if (byteOffsetInRegister != 0) - { - // The value had better occupy a whole number of components. - SLANG_RELEASE_ASSERT(byteOffsetInRegister % componentSize == 0); + // If this field doesn't start on an even register boundary, + // then we need to emit additional information to pick the + // right component to start from + if (byteOffsetInRegister != 0) + { + // The value had better occupy a whole number of components. + SLANG_RELEASE_ASSERT(byteOffsetInRegister % componentSize == 0); - size_t startComponent = byteOffsetInRegister / componentSize; + size_t startComponent = byteOffsetInRegister / componentSize; - static const char* kComponentNames[] = {"x", "y", "z", "w"}; - Emit("."); - Emit(kComponentNames[startComponent]); - } - Emit(")"); - } - else - { - Emit(": register("); - switch( info.kind ) - { - case LayoutResourceKind::ConstantBuffer: - Emit("b"); - break; - case LayoutResourceKind::ShaderResource: - Emit("t"); - break; - case LayoutResourceKind::UnorderedAccess: - Emit("u"); - break; - case LayoutResourceKind::SamplerState: - Emit("s"); - break; - default: - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled HLSL register type"); - break; + static const char* kComponentNames[] = {"x", "y", "z", "w"}; + Emit("."); + Emit(kComponentNames[startComponent]); + } + Emit(")"); } - Emit(info.index); - if(info.space) + break; + + case LayoutResourceKind::RegisterSpace: + // ignore + break; + + default: { - Emit(", space"); - Emit(info.space); + Emit(": register("); + switch( info.kind ) + { + case LayoutResourceKind::ConstantBuffer: + Emit("b"); + break; + case LayoutResourceKind::ShaderResource: + Emit("t"); + break; + case LayoutResourceKind::UnorderedAccess: + Emit("u"); + break; + case LayoutResourceKind::SamplerState: + Emit("s"); + break; + default: + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled HLSL register type"); + break; + } + Emit(info.index); + if(info.space) + { + Emit(", space"); + Emit(info.space); + } + Emit(")"); } - Emit(")"); } } diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index 5b42407c2..5b08acee8 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -660,13 +660,13 @@ static LegalVal declareSimpleVar( // those to all the nested resource infos. for (auto vv = varChain; vv; vv = vv->next) { - auto parentSpaceInfo = vv->varLayout->findOrAddResourceInfo(LayoutResourceKind::ParameterBlock); + auto parentSpaceInfo = vv->varLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace); if (!parentSpaceInfo) continue; for (auto& rr : varLayout->resourceInfos) { - if (rr.kind == LayoutResourceKind::ParameterBlock) + if (rr.kind == LayoutResourceKind::RegisterSpace) { rr.index += parentSpaceInfo->index; } @@ -827,21 +827,13 @@ static void legalizeGlobalVar( RefPtr<VarLayout> varLayout = findVarLayout(irGlobalVar); RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr; - // If we've decided to do implicit deref on the type, - // then go ahead and declare a value of the pointed-to type. - LegalType maybeSimpleType = legalValueType; - while (maybeSimpleType.flavor == LegalType::Flavor::implicitDeref) - { - maybeSimpleType = maybeSimpleType.getImplicitDeref()->valueType; - } - - switch (maybeSimpleType.flavor) + switch (legalValueType.flavor) { case LegalType::Flavor::simple: // Easy case: the type is usable as-is, and we // should just do that. irGlobalVar->type = context->session->getPtrType( - maybeSimpleType.getSimple()); + legalValueType.getSimple()); break; default: diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index ccf302027..a15104d6a 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -797,6 +797,20 @@ struct LoweringVisitor lowerType(type->valueType)); } + RefPtr<Type> visitParameterBlockType(ParameterBlockType* type) + { + // TODO: When doing AST-to-AST lowering, we want to lower + // a `ParameterBlock<T>` just like a `ConstantBuffer<T>`. + // + // HACK: for now we will try to simply lower the type + // directly to its stated element type, and see how + // that works. + + return lowerType(type->getElementType()); +// return getSession()->getConstantBufferType( +// lowerType(type->getElementType()); + } + RefPtr<Type> transformSyntaxField(Type* type) { return lowerType(type); diff --git a/source/slang/options.cpp b/source/slang/options.cpp index 7eea3fecc..452e7c439 100644 --- a/source/slang/options.cpp +++ b/source/slang/options.cpp @@ -80,6 +80,7 @@ struct OptionsParser int profileOptionCount = 0; SlangCompileFlags flags = 0; + SlangTargetFlags targetFlags = 0; struct RawOutputPath { @@ -279,6 +280,10 @@ struct OptionsParser { requestImpl->shouldSkipCodegen = true; } + else if(argStr == "-parameter-blocks-use-register-spaces" ) + { + targetFlags |= SLANG_TARGET_FLAG_PARAMETER_BLOCKS_USE_REGISTER_SPACES; + } else if (argStr == "-backend" || argStr == "-target") { String name = tryReadCommandLineArgument(arg, &argCursor, argEnd); @@ -729,6 +734,13 @@ struct OptionsParser } } + // If the user specifed and per-compilation-target flags, make sure + // to apply them here. + if(targetFlags) + { + spSetTargetFlags(compileRequest, 0, targetFlags); + } + // Next, we want to make sure that entry points get attached to the appropriate translation // unit that will provide them. { diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index 05b9d924e..fa015186b 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -188,6 +188,13 @@ struct SharedParameterBindingContext // The base compile request CompileRequest* compileRequest; + // The target request that is triggering layout + // + // TODO: We should eventually strip this down to + // just the subset of fields on the target that + // can influence layout decisions. + TargetRequest* targetRequest; + LayoutRulesFamilyImpl* defaultLayoutRules; // All shader parameters we've discovered so far, and started to lay out... @@ -208,6 +215,8 @@ struct SharedParameterBindingContext // Which register spaces have been claimed so far? UsedRanges usedSpaces; + + TargetRequest* getTargetRequest() { return targetRequest; } }; static DiagnosticSink* getSink(SharedParameterBindingContext* shared) @@ -225,8 +234,9 @@ struct ParameterBindingContext // All the shared state needs to be available SharedParameterBindingContext* shared; - // The layout rules to use while computing usage... - LayoutRulesFamilyImpl* layoutRules; + // The type layout context to use when computing + // the resource usage of shader parameters. + TypeLayoutContext layoutContext; // A dictionary to accellerate looking up parameters by name Dictionary<Name*, ParameterInfo*> mapNameToParameterInfo; @@ -236,6 +246,9 @@ struct ParameterBindingContext // The source language we are trying to use SourceLanguage sourceLanguage; + + TargetRequest* getTargetRequest() { return shared->getTargetRequest(); } + LayoutRulesFamilyImpl* getRulesFamily() { return layoutContext.getRulesFamily(); } }; static DiagnosticSink* getSink(ParameterBindingContext* context) @@ -475,7 +488,8 @@ getTypeLayoutForGlobalShaderParameter_GLSL( ParameterBindingContext* context, VarDeclBase* varDecl) { - auto rules = context->layoutRules; + auto layoutContext = context->layoutContext; + auto rules = layoutContext.getRulesFamily(); auto type = varDecl->getType(); // A GLSL shader parameter will be marked with @@ -489,36 +503,56 @@ getTypeLayoutForGlobalShaderParameter_GLSL( // We want to check for a constant-buffer type with a `push_constant` layout // qualifier before we move on to anything else. - if (varDecl->HasModifier<GLSLPushConstantLayoutModifier>() && type->As<ConstantBufferType>()) - return CreateTypeLayout(type, rules->getPushConstantBufferRules()); + if( varDecl->HasModifier<GLSLPushConstantLayoutModifier>() && type->As<ConstantBufferType>() ) + { + return CreateTypeLayout( + layoutContext.with(rules->getPushConstantBufferRules()), + type); + } // TODO(tfoley): We have multiple variations of // the `uniform` modifier right now, and that // needs to get fixed... - if(varDecl->HasModifier<HLSLUniformModifier>() || type->As<ConstantBufferType>()) - return CreateTypeLayout(type, rules->getConstantBufferRules()); + if( varDecl->HasModifier<HLSLUniformModifier>() || type->As<ConstantBufferType>() ) + { + return CreateTypeLayout( + layoutContext.with(rules->getConstantBufferRules()), + type); + } - if(varDecl->HasModifier<GLSLBufferModifier>() || type->As<GLSLShaderStorageBufferType>()) - return CreateTypeLayout(type, rules->getShaderStorageBufferRules()); + if( varDecl->HasModifier<GLSLBufferModifier>() || type->As<GLSLShaderStorageBufferType>() ) + { + return CreateTypeLayout( + layoutContext.with(rules->getShaderStorageBufferRules()), + type); + } if (auto effectiveVaryingInputType = tryGetEffectiveTypeForGLSLVaryingInput(context, varDecl)) { // We expect to handle these elsewhere SLANG_DIAGNOSE_UNEXPECTED(getSink(context), varDecl, "GLSL varying input"); - return CreateTypeLayout(effectiveVaryingInputType, rules->getVaryingInputRules()); + return CreateTypeLayout( + layoutContext.with(rules->getVaryingInputRules()), + effectiveVaryingInputType); } if (auto effectiveVaryingOutputType = tryGetEffectiveTypeForGLSLVaryingOutput(context, varDecl)) { // We expect to handle these elsewhere SLANG_DIAGNOSE_UNEXPECTED(getSink(context), varDecl, "GLSL varying output"); - return CreateTypeLayout(effectiveVaryingOutputType, rules->getVaryingOutputRules()); + return CreateTypeLayout( + layoutContext.with(rules->getVaryingOutputRules()), + effectiveVaryingOutputType); } // A `const` global with a `layout(constant_id = ...)` modifier // is a declaration of a specialization constant. - if(varDecl->HasModifier<GLSLConstantIDLayoutModifier>()) - return CreateTypeLayout(type, rules->getSpecializationConstantRules()); + if( varDecl->HasModifier<GLSLConstantIDLayoutModifier>() ) + { + return CreateTypeLayout( + layoutContext.with(rules->getSpecializationConstantRules()), + type); + } // GLSL says that an "ordinary" global variable // is just a (thread local) global and not a @@ -531,7 +565,8 @@ getTypeLayoutForGlobalShaderParameter_HLSL( ParameterBindingContext* context, VarDeclBase* varDecl) { - auto rules = context->layoutRules; + auto layoutContext = context->layoutContext; + auto rules = layoutContext.getRulesFamily(); auto type = varDecl->getType(); // HLSL `static` modifier indicates "thread local" @@ -546,7 +581,9 @@ getTypeLayoutForGlobalShaderParameter_HLSL( // An "ordinary" global variable is implicitly a uniform // shader parameter. - return CreateTypeLayout(type, rules->getConstantBufferRules()); + return CreateTypeLayout( + layoutContext.with(rules->getConstantBufferRules()), + type); } // Determine how to lay out a global variable that might be @@ -983,7 +1020,7 @@ static void completeBindingsForParameter( // a parameter wants to claim an entire register // space to itself (for a parameter block), since // that can't be handled like other resources. - if (kind == LayoutResourceKind::ParameterBlock) + if (kind == LayoutResourceKind::RegisterSpace) { // We need to snag a register space of our own. @@ -991,6 +1028,11 @@ static void completeBindingsForParameter( bindingInfo.count = count; bindingInfo.index = space; + + // TODO: what should we store as the "space" for + // an allocation of register spaces? Either zero + // or `space` makes sense, but it isn't clear + // which is a better choice. bindingInfo.space = 0; continue; @@ -1158,8 +1200,10 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter( // We also need to track this as an ordinary varying output from the stage, // since that is how GLSL will want to see it. - auto rules = context->layoutRules->getVaryingOutputRules(); - SimpleLayoutInfo layout = GetLayout(type, rules); + auto rules = context->getRulesFamily()->getVaryingOutputRules(); + SimpleLayoutInfo layout = GetLayout( + context->layoutContext.with(rules), + type); typeLayout->addResourceUsage(layout.kind, layout.size); } } @@ -1179,15 +1223,19 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter( if (state.directionMask & kEntryPointParameterDirection_Input) { - auto rules = context->layoutRules->getVaryingInputRules(); - SimpleLayoutInfo layout = GetLayout(type, rules); + auto rules = context->getRulesFamily()->getVaryingInputRules(); + SimpleLayoutInfo layout = GetLayout( + context->layoutContext.with(rules), + type); typeLayout->addResourceUsage(layout.kind, layout.size); } if (state.directionMask & kEntryPointParameterDirection_Output) { - auto rules = context->layoutRules->getVaryingOutputRules(); - SimpleLayoutInfo layout = GetLayout(type, rules); + auto rules = context->getRulesFamily()->getVaryingOutputRules(); + SimpleLayoutInfo layout = GetLayout( + context->layoutContext.with(rules), + type); typeLayout->addResourceUsage(layout.kind, layout.size); } } @@ -1610,11 +1658,11 @@ void generateParameterBindings( CompileRequest* compileReq = targetReq->compileRequest; // Try to find rules based on the selected code-generation target - auto rules = GetLayoutRulesFamilyImpl(targetReq->target); + auto layoutContext = getInitialLayoutContextForTarget(targetReq); // If there was no target, or there are no rules for the target, // then bail out here. - if (!rules) + if (!layoutContext.rules) return; RefPtr<ProgramLayout> programLayout = new ProgramLayout; @@ -1623,7 +1671,7 @@ void generateParameterBindings( // of generating parameter bindings SharedParameterBindingContext sharedContext; sharedContext.compileRequest = compileReq; - sharedContext.defaultLayoutRules = rules; + sharedContext.defaultLayoutRules = layoutContext.getRulesFamily(); sharedContext.programLayout = programLayout; // Create a sub-context to collect parameters that get @@ -1631,7 +1679,7 @@ void generateParameterBindings( ParameterBindingContext context; context.shared = &sharedContext; context.translationUnit = nullptr; - context.layoutRules = sharedContext.defaultLayoutRules; + context.layoutContext = layoutContext; // Walk through AST to discover all the parameters collectParameters(&context, compileReq); @@ -1698,7 +1746,7 @@ void generateParameterBindings( // For legacy GLSL targets, we'd probably need a distinct resource // kind and set of rules here, since legacy uniforms are not the // same as the contents of a constant buffer. - auto globalScopeRules = context.layoutRules->getConstantBufferRules(); + auto globalScopeRules = context.getRulesFamily()->getConstantBufferRules(); RefPtr<StructTypeLayout> globalScopeStructLayout = new StructTypeLayout(); globalScopeStructLayout->rules = globalScopeRules; @@ -1746,6 +1794,7 @@ void generateParameterBindings( if( anyGlobalUniforms ) { auto globalConstantBufferLayout = createParameterGroupTypeLayout( + layoutContext, nullptr, globalScopeRules, globalScopeRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer), diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index fe24fbd19..17f8ea96d 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -746,12 +746,30 @@ SLANG_API void spSetCodeGenTarget( req->addTarget(Slang::CodeGenTarget(target)); } -SLANG_API void spAddCodeGenTarget( +SLANG_API int spAddCodeGenTarget( SlangCompileRequest* request, SlangCompileTarget target) { auto req = REQ(request); - req->addTarget(Slang::CodeGenTarget(target)); + return (int) req->addTarget(Slang::CodeGenTarget(target)); +} + +SLANG_API void spSetTargetProfile( + SlangCompileRequest* request, + int targetIndex, + SlangProfileID profile) +{ + auto req = REQ(request); + req->targets[targetIndex]->targetProfile = profile; +} + +SLANG_API void spSetTargetFlags( + SlangCompileRequest* request, + int targetIndex, + SlangTargetFlags flags) +{ + auto req = REQ(request); + req->targets[targetIndex]->targetFlags = flags; } SLANG_API void spSetOutputContainerFormat( diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp index 9f2aee922..8fa790dd8 100644 --- a/source/slang/type-layout.cpp +++ b/source/slang/type-layout.cpp @@ -616,20 +616,9 @@ LayoutRulesImpl* GetLayoutRulesImpl(LayoutRule rule) } } -LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(LayoutRulesFamily rule) +LayoutRulesFamilyImpl* getDefaultLayoutRulesFamilyForTarget(TargetRequest* targetReq) { - switch (rule) - { - case LayoutRulesFamily::HLSL: return &kHLSLLayoutRulesFamilyImpl; - case LayoutRulesFamily::GLSL: return &kGLSLLayoutRulesFamilyImpl; - default: - return nullptr; - } -} - -LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(CodeGenTarget target) -{ - switch (target) + switch (targetReq->target) { case CodeGenTarget::HLSL: case CodeGenTarget::DXBytecode: @@ -648,6 +637,24 @@ LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(CodeGenTarget target) } } +TypeLayoutContext getInitialLayoutContextForTarget(TargetRequest* targetReq) +{ + LayoutRulesFamilyImpl* rulesFamily = getDefaultLayoutRulesFamilyForTarget(targetReq); + + TypeLayoutContext context; + context.targetReq = targetReq; + context.rules = nullptr; + context.matrixLayoutMode = MatrixLayoutMode::kMatrixLayoutMode_RowMajor; + + if( rulesFamily ) + { + context.rules = rulesFamily->getConstantBufferRules(); + context.matrixLayoutMode = rulesFamily->getDefaultMatrixLayoutMode(); + } + + return context; +} + static int GetElementCount(RefPtr<IntVal> val) { @@ -718,10 +725,17 @@ static SimpleLayoutInfo getParameterGroupLayoutInfo( } else if (type->As<ParameterBlockType>()) { - // TODO(tfoley): Should a parameter block *always* consume at least - // one `set`/`space`, or should we hold back and just allocate this - // if it actually contains anything? - return SimpleLayoutInfo(LayoutResourceKind::ParameterBlock, 1); + // Note: we default to consuming zero register spces here, because + // a parameter block might not contain anything (or all it contains + // is other blocks), and so it won't get a space allocated. + // + // This choice *also* means that in the case where we don't actually + // want to allocate register spaces to blocks at all, we haven't + // committed to that choice here. + // + // TODO: wouldn't it be any different to just allocate this + // as an empty `SimpleLayoutInfo` of any other kind? + return SimpleLayoutInfo(LayoutResourceKind::RegisterSpace, 0); } // TODO: the vertex-input and fragment-output cases should @@ -742,31 +756,118 @@ static SimpleLayoutInfo getParameterGroupLayoutInfo( } } -struct TypeLayoutContext +RefPtr<TypeLayout> createTypeLayout( + TypeLayoutContext const& context, + Type* type, + SimpleLayoutInfo offset); + +static bool isOpenGLTarget(TargetRequest*) { - // The layout rules to use (e.g., we compute - // layout differently in a `cbuffer` vs. the - // parameter list of a fragment shader). - LayoutRulesImpl* rules; + // We aren't officially supporting OpenGL right now + return false; +} - // Whether to lay out matrices column-major - // or row-major. - MatrixLayoutMode matrixLayoutMode; -}; +static bool isD3DTarget(TargetRequest* targetReq) +{ + switch( targetReq->target ) + { + case CodeGenTarget::HLSL: + case CodeGenTarget::DXBytecode: + case CodeGenTarget::DXBytecodeAssembly: + case CodeGenTarget::DXIL: + case CodeGenTarget::DXILAssembly: + return true; -RefPtr<TypeLayout> createTypeLayout( - TypeLayoutContext* context, - Type* type, - SimpleLayoutInfo offset); + default: + return false; + } +} + +static bool isD3D11Target(TargetRequest*) +{ + // We aren't officially supporting D3D11 right now + return false; +} + +static bool isD3D12Target(TargetRequest* targetReq) +{ + // We are currently only officially supporting D3D12 + return isD3DTarget(targetReq); +} + + +static bool isSM5OrEarlier(TargetRequest* targetReq) +{ + if(!isD3DTarget(targetReq)) + return false; + + auto profile = targetReq->targetProfile; + + if(profile.getFamily() == ProfileFamily::DX) + { + if(profile.GetVersion() <= ProfileVersion::DX_5_0) + return true; + } + + return false; +} + +static bool isVulkanTarget(TargetRequest* targetReq) +{ + switch( targetReq->target ) + { + default: + return false; + + case CodeGenTarget::GLSL: + case CodeGenTarget::SPIRV: + case CodeGenTarget::SPIRVAssembly: + break; + } + + // For right now, any GLSL-related target is assumed + // to be a Vulkan target. + + return true; +} + +static bool shouldAllocateRegisterSpaceForParameterBlock( + TypeLayoutContext const& context) +{ + auto targetReq = context.targetReq; + + // We *never* want to use register spaces/sets under + // OpenGL, D3D11, or for Shader Model 5.0 or earlier. + if(isOpenGLTarget(targetReq) || isD3D11Target(targetReq) || isSM5OrEarlier(targetReq)) + return false; + + // If we know that we are targetting Vulkan, then + // the only way to effectively use parameter blocks + // is by using descriptor sets. + if(isVulkanTarget(targetReq)) + return true; + + // If none of the above passed, then it seems like we + // are generating code for D3D12, and using SM5.1 or later. + // We will use a register space for parameter blocks *if* + // the target options tell us to: + if( isD3D12Target(targetReq) ) + { + if(targetReq->targetFlags & SLANG_TARGET_FLAG_PARAMETER_BLOCKS_USE_REGISTER_SPACES) + return true; + } + + return false; +} RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( - TypeLayoutContext* context, + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, SimpleLayoutInfo parameterGroupInfo, RefPtr<TypeLayout> elementTypeLayout) { - auto parameterGroupRules = context->rules; + auto parameterGroupRules = context.rules; auto typeLayout = new ParameterGroupTypeLayout(); @@ -780,9 +881,8 @@ createParameterGroupTypeLayout( // originally (which should be a single binding "slot" // and hence no uniform data). // - typeLayout->uniformAlignment = parameterGroupInfo.alignment; - SLANG_RELEASE_ASSERT(!typeLayout->FindResourceInfo(LayoutResourceKind::Uniform)); - SLANG_RELEASE_ASSERT(typeLayout->uniformAlignment == 1); + SLANG_RELEASE_ASSERT(parameterGroupInfo.kind != LayoutResourceKind::Uniform); + typeLayout->uniformAlignment = 1; // TODO(tfoley): There is a subtle question here of whether // a constant buffer declaration that then contains zero @@ -801,59 +901,125 @@ createParameterGroupTypeLayout( parameterGroupInfo.size); } - // The layout rules for a constant buffer, vs. a "parameter block" - // are different, with respect to how they expose layout information - // for underlying resources. - // - // A parameter block should *not* expose the fine-grained resource - // prameters it contains, and should only expose a total number - // of `space`s or `set`s that it consumes. - if (parameterGroupInfo.kind == LayoutResourceKind::ParameterBlock) - { - // Iterate over element types, but *only* accumulate usage - // info for types that consume whole register sets/spaces. - for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + // There are several different cases that need to be handled here, + // depending on whether we have a `ParameterBlock`, a `ConstantBuffer`, + // or some other kind of parameter group. Furthermore, in the + // `ParameterBlock` case, we need to deal with differnet layout + // rules depending on whether a block should map to a register `space` + // in HLSL or not. + + // Check if we are working with a parameter block... + auto parameterBlockType = parameterGroupType->As<ParameterBlockType>(); + + // Check if we have a parameter block *and* it should be + // allocated into its own register space(s) + bool ownRegisterSpace = false; + if (parameterBlockType) + { + if( shouldAllocateRegisterSpaceForParameterBlock(context) ) { - if(elementResourceInfo.kind != LayoutResourceKind::ParameterBlock) - break; + ownRegisterSpace = true; + } - typeLayout->addResourceUsage(elementResourceInfo); + // If the parameter block contains any uniform data, then we + // had better allocate a constant buffer for it. + bool anyUniformData = false; + if(auto elementUniformInfo = elementTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) ) + { + if( elementUniformInfo->count != 0 ) + { + // We have a non-zero number of bytes of uniform data here. + anyUniformData = true; + } } - } - else - { - // In the ordinary case (e.g., a constant buffer) then we need - // to make sure that any resources nested in the element type - // get counted against the container type, so that we can - // allocate registers to it directly. - for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + + if( anyUniformData ) + { + typeLayout->addResourceUsage(LayoutResourceKind::ConstantBuffer, 1); + } + + // Next, if we are going to allocate whole register space(s) to the + // parameter block, check if it actually needs one (it might be empty, + // or only contain other parameter blocks). + if( ownRegisterSpace ) { - // Skip uniform data, since that is encapsualted behind the constant buffer - if(elementResourceInfo.kind == LayoutResourceKind::Uniform) - break; + bool needsARegisterSpace = false; + for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + { + if(elementResourceInfo.kind != LayoutResourceKind::RegisterSpace) + { + needsARegisterSpace = true; + break; + } + } - typeLayout->addResourceUsage(elementResourceInfo); + if( needsARegisterSpace ) + { + typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, 1); + } } } + // The layout for the element type was computed without any knowledge + // of what resources the parent type was going to consume; we now + // need to go through and offset that any starting locations (e.g., + // in nested `StructTypeLayout`s) based on what we allocated to + // the parent. + + // TODO(tfoley): actually implement that! + // Now we will (possibly) accumulate the resources used by the element + // type into the resources used by the parameter group. The reason + // this is "possibly" is because, e.g., a `ConstantBuffer<Foo>` should + // not report itself as consuming `sizeof(Foo)` bytes of uniform data, + // or else it would mess up layout for any type that contains the + // constant buffer. Similarly, a parameter block that consumes whole + // register `space`s shouldn't report its fine-grained resource + // usage inside those spces. + for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + { + switch( elementResourceInfo.kind ) + { + case LayoutResourceKind::RegisterSpace: + // Register spaces consumed by the element type should be + // reflected in the resource usage of the parent type. + typeLayout->addResourceUsage(elementResourceInfo); + break; + + case LayoutResourceKind::Uniform: + // Uniform resource usages will always be hidden. + break; + + default: + // All other register types should be hidden *if* we + // are allocating a whole register space, and exposed + // otherwise. + if( ownRegisterSpace ) + { + // don't expose internal register/binding use outside + } + else + { + typeLayout->addResourceUsage(elementResourceInfo); + } + break; + } + } + return typeLayout; } RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, LayoutRulesImpl* parameterGroupRules, SimpleLayoutInfo parameterGroupInfo, RefPtr<TypeLayout> elementTypeLayout) { - TypeLayoutContext context; - context.rules = parameterGroupRules; - context.matrixLayoutMode = parameterGroupRules->getDefaultMatrixLayoutMode(); - return createParameterGroupTypeLayout( - &context, + context.with(parameterGroupRules).with(parameterGroupRules->getDefaultMatrixLayoutMode()), parameterGroupType, parameterGroupInfo, elementTypeLayout); @@ -861,12 +1027,12 @@ createParameterGroupTypeLayout( RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( - TypeLayoutContext* context, + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, RefPtr<Type> elementType, LayoutRulesImpl* elementTypeRules) { - auto parameterGroupRules = context->rules; + auto parameterGroupRules = context.rules; // First compute resource usage of the block itself. // For now we assume that the layout of the block can @@ -891,10 +1057,8 @@ createParameterGroupTypeLayout( // the elements of the block use the same resource kind consumed // by the block itself. - TypeLayoutContext elementContext = *context; - elementContext.rules = elementTypeRules; auto elementTypeLayout = createTypeLayout( - &elementContext, + context.with(elementTypeRules), elementType, info); @@ -942,10 +1106,10 @@ LayoutRulesImpl* getParameterBufferElementTypeLayoutRules( RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( - TypeLayoutContext* context, + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType) { - auto parameterGroupRules = context->rules; + auto parameterGroupRules = context.rules; // Determine the layout rules to use for the contents of the block auto elementTypeRules = getParameterBufferElementTypeLayoutRules( @@ -964,11 +1128,12 @@ createParameterGroupTypeLayout( // Create a type layout for a structured buffer type. RefPtr<StructuredBufferTypeLayout> createStructuredBufferTypeLayout( - ShaderParameterKind kind, - RefPtr<Type> structuredBufferType, - RefPtr<TypeLayout> elementTypeLayout, - LayoutRulesImpl* rules) + TypeLayoutContext const& context, + ShaderParameterKind kind, + RefPtr<Type> structuredBufferType, + RefPtr<TypeLayout> elementTypeLayout) { + auto rules = context.rules; auto info = rules->GetObjectLayout(kind); auto typeLayout = new StructuredBufferTypeLayout(); @@ -997,50 +1162,50 @@ createStructuredBufferTypeLayout( // Create a type layout for a structured buffer type. RefPtr<StructuredBufferTypeLayout> createStructuredBufferTypeLayout( - ShaderParameterKind kind, - RefPtr<Type> structuredBufferType, - RefPtr<Type> elementType, - LayoutRulesImpl* rules) + TypeLayoutContext const& context, + ShaderParameterKind kind, + RefPtr<Type> structuredBufferType, + RefPtr<Type> elementType) { - // TODO(tfoley): need to compute the layout for the constant - // buffer's contents... + // TODO(tfoley): we should be looking up the appropriate rules + // via the `LayoutRulesFamily` in use here... auto structuredBufferLayoutRules = GetLayoutRulesImpl( LayoutRule::HLSLStructuredBuffer); // Create and save type layout for the buffer contents. auto elementTypeLayout = CreateTypeLayout( - elementType.Ptr(), - structuredBufferLayoutRules); + context.with(structuredBufferLayoutRules), + elementType.Ptr()); return createStructuredBufferTypeLayout( + context, kind, structuredBufferType, - elementTypeLayout, - rules); + elementTypeLayout); } SimpleLayoutInfo GetLayoutImpl( - TypeLayoutContext* context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout, - SimpleLayoutInfo offset); + TypeLayoutContext const& context, + Type* type, + RefPtr<TypeLayout>* outTypeLayout, + SimpleLayoutInfo offset); SimpleLayoutInfo GetLayoutImpl( - TypeLayoutContext* context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout) + TypeLayoutContext const& context, + Type* type, + RefPtr<TypeLayout>* outTypeLayout) { return GetLayoutImpl(context, type, outTypeLayout, SimpleLayoutInfo()); } SimpleLayoutInfo GetLayoutImpl( - TypeLayoutContext* context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout, - Decl* declForModifiers) + TypeLayoutContext const& context, + Type* type, + RefPtr<TypeLayout>* outTypeLayout, + Decl* declForModifiers) { - TypeLayoutContext subContext = *context; + TypeLayoutContext subContext = context; if (declForModifiers) { @@ -1054,16 +1219,16 @@ SimpleLayoutInfo GetLayoutImpl( // layout, such as GLSL `std140`. } - return GetLayoutImpl(&subContext, type, outTypeLayout, SimpleLayoutInfo()); + return GetLayoutImpl(subContext, type, outTypeLayout, SimpleLayoutInfo()); } SimpleLayoutInfo GetLayoutImpl( - TypeLayoutContext* context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout, - SimpleLayoutInfo offset) + TypeLayoutContext const& context, + Type* type, + RefPtr<TypeLayout>* outTypeLayout, + SimpleLayoutInfo offset) { - auto rules = context->rules; + auto rules = context.rules; if (auto parameterGroupType = type->As<ParameterGroupType>()) { @@ -1176,10 +1341,10 @@ SimpleLayoutInfo GetLayoutImpl( if (outTypeLayout) \ { \ *outTypeLayout = createStructuredBufferTypeLayout( \ + context, \ ShaderParameterKind::KIND, \ type_##TYPE, \ - type_##TYPE->elementType.Ptr(), \ - rules); \ + type_##TYPE->elementType.Ptr()); \ } \ return info; \ } while(0) @@ -1225,7 +1390,7 @@ SimpleLayoutInfo GetLayoutImpl( { return GetSimpleLayoutImpl( rules->GetVectorLayout( - GetLayout(vecType->elementType.Ptr(), rules), + GetLayout(context, vecType->elementType.Ptr()), (size_t) GetIntVal(vecType->elementCount)), type, rules, @@ -1245,7 +1410,7 @@ SimpleLayoutInfo GetLayoutImpl( // size_t rowCount = (size_t) GetIntVal(matType->getRowCount()); size_t colCount = (size_t) GetIntVal(matType->getColumnCount()); - if (context->matrixLayoutMode == kMatrixLayoutMode_ColumnMajor) + if (context.matrixLayoutMode == kMatrixLayoutMode_ColumnMajor) { size_t tmp = rowCount; rowCount = colCount; @@ -1253,7 +1418,7 @@ SimpleLayoutInfo GetLayoutImpl( } auto info = rules->GetMatrixLayout( - GetLayout(matType->getElementType(), rules), + GetLayout(context, matType->getElementType()), rowCount, colCount); @@ -1265,7 +1430,7 @@ SimpleLayoutInfo GetLayoutImpl( typeLayout->type = type; typeLayout->rules = rules; typeLayout->uniformAlignment = info.alignment; - typeLayout->mode = context->matrixLayoutMode; + typeLayout->mode = context.matrixLayoutMode; typeLayout->addResourceUsage(info.kind, info.size); } @@ -1459,19 +1624,17 @@ SimpleLayoutInfo GetLayoutImpl( outTypeLayout); } -SimpleLayoutInfo GetLayout(Type* inType, LayoutRulesImpl* rules) +SimpleLayoutInfo GetLayout( + TypeLayoutContext const& context, + Type* inType) { - TypeLayoutContext context; - context.rules = rules; - context.matrixLayoutMode = rules->getDefaultMatrixLayoutMode(); - - return GetLayoutImpl(&context, inType, nullptr); + return GetLayoutImpl(context, inType, nullptr); } RefPtr<TypeLayout> createTypeLayout( - TypeLayoutContext* context, - Type* type, - SimpleLayoutInfo offset) + TypeLayoutContext const& context, + Type* type, + SimpleLayoutInfo offset) { RefPtr<TypeLayout> typeLayout; GetLayoutImpl(context, type, &typeLayout, offset); @@ -1479,8 +1642,8 @@ RefPtr<TypeLayout> createTypeLayout( } RefPtr<TypeLayout> createTypeLayout( - TypeLayoutContext* context, - Type* type) + TypeLayoutContext const& context, + Type* type) { RefPtr<TypeLayout> typeLayout; GetLayoutImpl(context, type, &typeLayout, SimpleLayoutInfo()); @@ -1488,28 +1651,20 @@ RefPtr<TypeLayout> createTypeLayout( } RefPtr<TypeLayout> CreateTypeLayout( - Type* type, - LayoutRulesImpl* rules, - SimpleLayoutInfo offset) + TypeLayoutContext const& context, + Type* type, + SimpleLayoutInfo offset) { - TypeLayoutContext context; - context.rules = rules; - context.matrixLayoutMode = rules->getDefaultMatrixLayoutMode(); - RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(&context, type, &typeLayout, offset); + GetLayoutImpl(context, type, &typeLayout, offset); return typeLayout; } -RefPtr<TypeLayout> CreateTypeLayout(Type* type, LayoutRulesImpl* rules) -{ - return CreateTypeLayout(type, rules, SimpleLayoutInfo()); -} - -SimpleLayoutInfo GetLayout(Type* type, LayoutRule rule) +RefPtr<TypeLayout> CreateTypeLayout( + TypeLayoutContext const& context, + Type* type) { - LayoutRulesImpl* rulesImpl = GetLayoutRulesImpl(rule); - return GetLayout(type, rulesImpl); + return CreateTypeLayout(context, type, SimpleLayoutInfo()); } } // namespace Slang diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h index 257bfa310..363b01486 100644 --- a/source/slang/type-layout.h +++ b/source/slang/type-layout.h @@ -28,11 +28,13 @@ enum class LayoutRule HLSLStructuredBuffer, }; +#if 0 enum class LayoutRulesFamily { HLSL, GLSL, }; +#endif // Layout appropriate to "just memory" scenarios, // such as laying out the members of a constant buffer. @@ -559,43 +561,92 @@ struct LayoutRulesFamilyImpl virtual MatrixLayoutMode getDefaultMatrixLayoutMode() = 0; }; -LayoutRulesImpl* GetLayoutRulesImpl(LayoutRule rule); -LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(LayoutRulesFamily rule); -LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(CodeGenTarget target); +struct TypeLayoutContext +{ + // The layout rules to use (e.g., we compute + // layout differently in a `cbuffer` vs. the + // parameter list of a fragment shader). + LayoutRulesImpl* rules; -SimpleLayoutInfo GetLayout(Type* type, LayoutRulesImpl* rules); + // The target request that is triggering layout + TargetRequest* targetReq; -SimpleLayoutInfo GetLayout(Type* type, LayoutRule rule = LayoutRule::Std430); + // Whether to lay out matrices column-major + // or row-major. + MatrixLayoutMode matrixLayoutMode; -RefPtr<TypeLayout> CreateTypeLayout(Type* type, LayoutRulesImpl* rules); -RefPtr<TypeLayout> CreateTypeLayout(Type* type, LayoutRulesImpl* rules, SimpleLayoutInfo offset); + LayoutRulesImpl* getRules() { return rules; } + LayoutRulesFamilyImpl* getRulesFamily() { return rules->getLayoutRulesFamily(); } -// + TypeLayoutContext with(LayoutRulesImpl* inRules) const + { + TypeLayoutContext result = *this; + result.rules = inRules; + return result; + } -struct TypeLayoutContext; + TypeLayoutContext with(MatrixLayoutMode inMatrixLayoutMode) const + { + TypeLayoutContext result = *this; + result.matrixLayoutMode = inMatrixLayoutMode; + return result; + } +}; + + +// Get an appropriate set of layout rules (packaged up +// as a `TypeLayoutContext`) to perform type layout +// for the given target. +TypeLayoutContext getInitialLayoutContextForTarget( + TargetRequest* targetReq); + +// Get the "simple" layout for a type accordinging to a given set of layout +// rules. Note that a "simple" layout can only consume one `LayoutResourceKind`, +// and so this operation may not correctly capture the full resource usage +// of a type. +SimpleLayoutInfo GetLayout( + TypeLayoutContext const& context, + Type* type); + +// Create a full type-layout object for a type, +// according to the layout rules in `context`. +RefPtr<TypeLayout> CreateTypeLayout( + TypeLayoutContext const& context, + Type* type); + +// Create a full type layout for a type, while applying the given "simple" +// layout information as an offset to any `VarLayout`s created along +// the way. +RefPtr<TypeLayout> CreateTypeLayout( + TypeLayoutContext const& context, + Type* type, + SimpleLayoutInfo offset); + +// // Create a type layout for a parameter block type. RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( - TypeLayoutContext* context, + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType); RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( - TypeLayoutContext* context, + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, RefPtr<Type> elementType, LayoutRulesImpl* elementTypeRules); RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( - TypeLayoutContext* context, + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, SimpleLayoutInfo parameterGroupInfo, RefPtr<TypeLayout> elementTypeLayout); RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( + TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, LayoutRulesImpl* parameterGroupRules, SimpleLayoutInfo parameterGroupInfo, @@ -604,10 +655,10 @@ createParameterGroupTypeLayout( // Create a type layout for a structured buffer type. RefPtr<StructuredBufferTypeLayout> createStructuredBufferTypeLayout( - ShaderParameterKind kind, - RefPtr<Type> structuredBufferType, - RefPtr<Type> elementType, - LayoutRulesImpl* rules); + TypeLayoutContext const& context, + ShaderParameterKind kind, + RefPtr<Type> structuredBufferType, + RefPtr<Type> elementType); // diff --git a/tests/bindings/multiple-parameter-blocks.slang b/tests/bindings/multiple-parameter-blocks.slang index 0fdf7d429..093d2ea43 100644 --- a/tests/bindings/multiple-parameter-blocks.slang +++ b/tests/bindings/multiple-parameter-blocks.slang @@ -1,4 +1,4 @@ -//TEST:COMPARE_HLSL:-no-mangle -use-ir -target dxbc-assembly -profile ps_5_1 -entry main +//TEST:COMPARE_HLSL:-no-mangle -use-ir -target dxbc-assembly -profile ps_5_1 -entry main -parameter-blocks-use-register-spaces // Confirm that Slang `ParameterBlock<T>` generates // parameter bindings like we expect. diff --git a/tests/bindings/parameter-blocks.slang b/tests/bindings/parameter-blocks.slang index cd916f144..38f99d105 100644 --- a/tests/bindings/parameter-blocks.slang +++ b/tests/bindings/parameter-blocks.slang @@ -1,4 +1,4 @@ -//TEST:COMPARE_HLSL:-no-mangle -use-ir -target dxbc-assembly -profile ps_5_1 -entry main +//TEST:COMPARE_HLSL:-no-mangle -use-ir -target dxbc-assembly -profile ps_5_1 -entry main -parameter-blocks-use-register-spaces // Confirm that Slang `ParameterBlock<T>` generates // parameter bindings like we expect. diff --git a/tests/compute/break-stmt.slang b/tests/compute/break-stmt.slang index 02f5f9fa9..3f438da54 100644 --- a/tests/compute/break-stmt.slang +++ b/tests/compute/break-stmt.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_COMPUTE: +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir //TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):dxbinding(0),glbinding(0),out // Test that `break` from a loop works. diff --git a/tests/compute/continue-stmt.slang b/tests/compute/continue-stmt.slang index 9adb5a4a6..800511290 100644 --- a/tests/compute/continue-stmt.slang +++ b/tests/compute/continue-stmt.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_COMPUTE: +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir //TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):dxbinding(0),glbinding(0),out // Test that `break` from a loop works. diff --git a/tests/compute/discard-stmt.slang b/tests/compute/discard-stmt.slang index 18ffc39e2..5f861ed96 100644 --- a/tests/compute/discard-stmt.slang +++ b/tests/compute/discard-stmt.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_RENDER_COMPUTE: +//TEST(compute):COMPARE_RENDER_COMPUTE:-xslang -use-ir //TEST_INPUT: Texture2D(size=4, content = one) : dxbinding(0),glbinding(0) //TEST_INPUT: Sampler : dxbinding(0),glbinding(0) //TEST_INPUT: ubuffer(data=[0 0], stride=4):dxbinding(1),glbinding(0),out diff --git a/tests/compute/parameter-block.slang b/tests/compute/parameter-block.slang new file mode 100644 index 000000000..d10a1e9c2 --- /dev/null +++ b/tests/compute/parameter-block.slang @@ -0,0 +1,28 @@ +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir +//TEST(compute):COMPARE_COMPUTE: + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out +//TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):dxbinding(1),glbinding(1) + +// Ensure that Slang `ParameterBlock` type is lowered +// to HLSL in the fashion that we expect. + +struct P +{ + RWStructuredBuffer<int> buffer; +}; + +ParameterBlock<P> block0; +ParameterBlock<P> block1; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + uint tid = dispatchThreadID.x; + + int inVal = block1.buffer[tid]; + + int outVal = inVal; + + block0.buffer[tid] = outVal; +}
\ No newline at end of file diff --git a/tests/compute/parameter-block.slang.1.expected.txt b/tests/compute/parameter-block.slang.1.expected.txt new file mode 100644 index 000000000..bc856dafa --- /dev/null +++ b/tests/compute/parameter-block.slang.1.expected.txt @@ -0,0 +1,4 @@ +0 +1 +2 +3 diff --git a/tests/compute/parameter-block.slang.expected.txt b/tests/compute/parameter-block.slang.expected.txt new file mode 100644 index 000000000..bc856dafa --- /dev/null +++ b/tests/compute/parameter-block.slang.expected.txt @@ -0,0 +1,4 @@ +0 +1 +2 +3 diff --git a/tests/compute/select-expr.slang b/tests/compute/select-expr.slang index d90708ab9..4d9abfd35 100644 --- a/tests/compute/select-expr.slang +++ b/tests/compute/select-expr.slang @@ -1,4 +1,4 @@ -//TEST(smoke,compute):COMPARE_COMPUTE: +//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir //TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out diff --git a/tests/compute/simple.slang b/tests/compute/simple.slang index 8f53a79b2..b2f1417cf 100644 --- a/tests/compute/simple.slang +++ b/tests/compute/simple.slang @@ -1,4 +1,4 @@ -//TEST(smoke,compute):COMPARE_COMPUTE: +//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir //TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out // This is a basic test for Slang compute shader. diff --git a/tests/compute/textureSamplingTest.slang b/tests/compute/textureSamplingTest.slang index 1aa267b89..b1255f6c5 100644 --- a/tests/compute/textureSamplingTest.slang +++ b/tests/compute/textureSamplingTest.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_RENDER_COMPUTE: +//TEST(compute):COMPARE_RENDER_COMPUTE:-xslang -use-ir //TEST_INPUT: Texture1D(size=4, content = one) : dxbinding(0),glbinding(0) //TEST_INPUT: Texture2D(size=4, content = one) : dxbinding(1),glbinding(1) //TEST_INPUT: Texture3D(size=4, content = one) : dxbinding(2),glbinding(2) diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp index 292b98137..0210b2558 100644 --- a/tools/slang-test/main.cpp +++ b/tools/slang-test/main.cpp @@ -1137,7 +1137,6 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S spawner.pushArgument("-o"); auto actualOutputFile = outputStem + ".actual.txt"; spawner.pushArgument(actualOutputFile); - spawner.pushArgument("-xslang -use-ir"); // clear the stale actual output file first. This will allow us to detect error if render-test fails and outputs nothing. File::WriteAllText(actualOutputFile, ""); |
