From 7f8a9994d0bd99a171a1daa0bce46d92c02ccffd Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 21 May 2021 16:38:33 -0700 Subject: [gfx] Support StructuredBuffer. (#1851) Co-authored-by: T. Foley --- source/slang/slang-compiler.h | 28 +++++++--- source/slang/slang-emit-source-writer.cpp | 3 ++ source/slang/slang-emit-source-writer.h | 4 ++ source/slang/slang-emit.cpp | 6 +++ source/slang/slang-reflection-api.cpp | 32 +++++++++--- source/slang/slang.cpp | 85 ++++++++++++++++++------------- 6 files changed, 110 insertions(+), 48 deletions(-) (limited to 'source') diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 54c61bd75..603ee0bb5 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1199,14 +1199,10 @@ namespace Slang // TypeLayouts created on the fly by reflection API Dictionary> typeLayouts; - Dictionary parameterBlockTypes; - Dictionary>& getTypeLayouts() { return typeLayouts; } TypeLayout* getTypeLayout(Type* type); - TypeLayout* getParameterBlockLayout(Type* type); - private: Linkage* linkage = nullptr; CodeGenTarget format = CodeGenTarget::Unknown; @@ -1251,6 +1247,21 @@ namespace Slang const char* getBuildTagString(); struct TypeCheckingCache; + + struct ContainerTypeKey + { + slang::TypeReflection* elementType; + slang::ContainerType containerType; + bool operator==(ContainerTypeKey other) + { + return elementType == other.elementType && containerType == other.containerType; + } + Slang::HashCode getHashCode() + { + return Slang::combineHash( + Slang::getHashCode(elementType), Slang::getHashCode(containerType)); + } + }; /// A context for loading and re-using code modules. class Linkage : public RefObject, public slang::ISession @@ -1279,11 +1290,11 @@ namespace Slang SlangInt targetIndex = 0, slang::LayoutRules rules = slang::LayoutRules::Default, ISlangBlob** outDiagnostics = nullptr) override; - SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getParameterBlockLayout( + SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL getContainerType( slang::TypeReflection* elementType, - SlangInt targetIndex = 0, - slang::LayoutRules rules = slang::LayoutRules::Default, + slang::ContainerType containerType, ISlangBlob** outDiagnostics = nullptr) override; + SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL getDynamicType() override; SLANG_NO_THROW SlangResult SLANG_MCALL getTypeRTTIMangledName( slang::TypeReflection* type, ISlangBlob** outNameBlob) override; @@ -1348,6 +1359,9 @@ namespace Slang RefPtr m_astBuilder; + // Cache for container types. + Dictionary m_containerTypes; + // cache used by type checking, implemented in check.cpp TypeCheckingCache* getTypeCheckingCache(); void destroyTypeCheckingCache(); diff --git a/source/slang/slang-emit-source-writer.cpp b/source/slang/slang-emit-source-writer.cpp index 29a83a1fc..bed9a2dbc 100644 --- a/source/slang/slang-emit-source-writer.cpp +++ b/source/slang/slang-emit-source-writer.cpp @@ -330,6 +330,9 @@ void SourceWriter::_emitLineDirectiveAndUpdateSourceLocation(const HumaneSourceL void SourceWriter::_emitLineDirectiveIfNeeded(const HumaneSourceLoc& sourceLocation) { + if (m_supressLineDirective) + return; + // Don't do any of this work if the user has requested that we // not emit line directives. auto mode = getLineDirectiveMode(); diff --git a/source/slang/slang-emit-source-writer.h b/source/slang/slang-emit-source-writer.h index 64dc59801..294cfec18 100644 --- a/source/slang/slang-emit-source-writer.h +++ b/source/slang/slang-emit-source-writer.h @@ -47,6 +47,8 @@ public: void emitName(Name* name, const SourceLoc& loc); void emitName(Name* name); + void supressLineDirective() { m_supressLineDirective = true; } + void resumeLineDirective() { m_supressLineDirective = false; } /// Indent the text void indent(); @@ -102,6 +104,8 @@ protected: HumaneSourceLoc m_nextHumaneSourceLocation; bool m_needToUpdateSourceLocation = false; + + bool m_supressLineDirective = false; // Are we at the start of a line, so that we should indent // before writing any other text? diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index af870d02b..74b11079d 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -849,7 +849,13 @@ SlangResult emitEntryPointsSourceFromIR( } // There may be global-scope modifiers that we should emit now + // Supress emitting line directives when emitting preprocessor directives since + // these preprocessor directives may be required to appear in the first line + // of the output. An example is that the "#version" line in a GLSL source must + // appear before anything else. + sourceWriter.supressLineDirective(); sourceEmitter->emitPreprocessorDirectives(); + sourceWriter.resumeLineDirective(); RefObject* extensionTracker = sourceEmitter->getExtensionTracker(); diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index b74a019e3..22f34a41a 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -480,6 +480,10 @@ SLANG_API SlangReflectionType* spReflectionType_GetElementType(SlangReflectionTy { return convert(parameterGroupType->elementType); } + else if (auto structuredBufferType = as(type)) + { + return convert(structuredBufferType->elementType); + } else if( auto vectorType = as(type)) { return convert(vectorType->elementType); @@ -1485,7 +1489,7 @@ namespace Slang Index bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); SlangBindingType bindingType = SLANG_BINDING_TYPE_CONSTANT_BUFFER; Index spaceOffset = -1; - bool usesIndirectAllocation = false; + bool shouldAllocDescriptorSet = true; LayoutResourceKind kind = LayoutResourceKind::None; // TODO: It is unclear if this should be looking at the resource @@ -1515,13 +1519,14 @@ namespace Slang // Note: the only case where a parameter group should // reflect as consuming `Uniform` storage is on CPU/CUDA, // where that will be the only resource it contains. + case LayoutResourceKind::Uniform: + break; // // TODO: If we ever support targets that don't have // constant buffers at all, this logic would be questionable. // case LayoutResourceKind::RegisterSpace: - case LayoutResourceKind::Uniform: - usesIndirectAllocation = true; + shouldAllocDescriptorSet = false; break; } @@ -1591,7 +1596,7 @@ namespace Slang // because the physical storage for `C.a` is provided by the // memory allocation for `C` itself. - if( !usesIndirectAllocation ) + if (shouldAllocDescriptorSet) { // The logic here assumes that when a parameter group consumes // resources that must "leak" into the outer scope (including @@ -1737,8 +1742,8 @@ namespace Slang else { // Here we have the catch-all case that handles "leaf" fields - // that should never introduce a sub-object range, but might - // need to introduce a binding range and descriptor ranges. + // that might need to introduce a binding range and descriptor + // ranges. // // First, we want to determine what type of binding this // leaf field should map to, if any. We being by querying @@ -1839,12 +1844,13 @@ namespace Slang // TODO: Make some clear decisions about what should and should // not appear here. // - case LayoutResourceKind::Uniform: case LayoutResourceKind::RegisterSpace: case LayoutResourceKind::VaryingInput: case LayoutResourceKind::VaryingOutput: case LayoutResourceKind::HitAttributes: case LayoutResourceKind::RayPayload: + case LayoutResourceKind::ExistentialTypeParam: + case LayoutResourceKind::ExistentialObjectParam: continue; } @@ -1888,7 +1894,19 @@ namespace Slang bindingRange.descriptorRangeCount++; } + auto bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); + m_extendedInfo->m_bindingRanges.add(bindingRange); + + // For `StructuredBuffer` fields, we also make sure to report it as a sub-object range. + if (auto structuredBufferTypeLayout = as(typeLayout)) + { + TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange; + subObjectRange.bindingRangeIndex = bindingRangeIndex; + subObjectRange.offsetVarLayout = createOffsetVarLayout(typeLayout, path); + subObjectRange.spaceOffset = 0; + m_extendedInfo->m_subObjectRanges.add(subObjectRange); + } } } }; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 8479a0e99..9a109f9d7 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -896,35 +896,65 @@ SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL Linkage::getTypeLayout( return asExternal(typeLayout); } -SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL Linkage::getParameterBlockLayout( +SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getContainerType( slang::TypeReflection* inType, - SlangInt targetIndex, - slang::LayoutRules rules, + slang::ContainerType containerType, ISlangBlob** outDiagnostics) { auto type = asInternal(inType); - if (targetIndex < 0 || targetIndex >= targets.getCount()) - return nullptr; - - auto target = targets[targetIndex]; - - // TODO: We need a way to pass through the layout rules - // that the user requested (e.g., constant buffers vs. - // structured buffer rules). Right now the API only - // exposes a single case, so this isn't a big deal. - // - SLANG_UNUSED(rules); - - auto typeLayout = target->getParameterBlockLayout(type); + Type* containerTypeReflection = nullptr; + ContainerTypeKey key = {inType, containerType}; + if (!m_containerTypes.TryGetValue(key, containerTypeReflection)) + { + switch (containerType) + { + case slang::ContainerType::ConstantBuffer: + { + ConstantBufferType* cbType = getASTBuilder()->create(); + cbType->elementType = type; + containerTypeReflection = cbType; + } + break; + case slang::ContainerType::ParameterBlock: + { + ParameterBlockType* pbType = getASTBuilder()->create(); + pbType->elementType = type; + containerTypeReflection = pbType; + } + break; + case slang::ContainerType::StructuredBuffer: + { + HLSLStructuredBufferType* sbType = + getASTBuilder()->create(); + sbType->elementType = type; + containerTypeReflection = sbType; + } + break; + case slang::ContainerType::UnsizedArray: + { + ArrayExpressionType* arrType = getASTBuilder()->create(); + arrType->baseType = type; + arrType->arrayLength = nullptr; + containerTypeReflection = arrType; + } + break; + default: + containerTypeReflection = type; + break; + } + + m_containerTypes.Add(key, containerTypeReflection); + } - // TODO: We currently don't have a path for capturing - // errors that occur during layout (e.g., types that - // are invalid because of target-specific layout constraints). - // SLANG_UNUSED(outDiagnostics); - return asExternal(typeLayout); + return asExternal(containerTypeReflection); +} + +SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getDynamicType() +{ + return asExternal(getASTBuilder()->getSharedASTBuilder()->getDynamicType()); } SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::getTypeRTTIMangledName( @@ -1132,19 +1162,6 @@ TypeLayout* TargetRequest::getTypeLayout(Type* type) return result.Ptr(); } -TypeLayout* TargetRequest::getParameterBlockLayout(Type* type) -{ - ParameterBlockType* parameterBlockType = nullptr; - if (!parameterBlockTypes.TryGetValue(type, parameterBlockType)) - { - parameterBlockType = getLinkage()->getASTBuilder()->create(); - parameterBlockType->elementType = type; - parameterBlockTypes.Add(type, parameterBlockType); - } - return getTypeLayout(parameterBlockType); -} - - // // TranslationUnitRequest // -- cgit v1.2.3