diff options
| author | Yong He <yonghe@outlook.com> | 2024-02-20 15:37:11 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-20 15:37:11 -0800 |
| commit | a62be597990966b9516995650baf750ee6a0146b (patch) | |
| tree | 1741b3d5b5859319f278aa6ab821a2f801fd8e08 | |
| parent | 4d20fd329956ac89408b1628a8291fea01bc9a6d (diff) | |
Support link time type specialization. (#3604)
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 1 | ||||
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters | 3 | ||||
| -rw-r--r-- | source/core/slang-list.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ast-decl.cpp | 15 | ||||
| -rw-r--r-- | source/slang/slang-ast-decl.h | 13 | ||||
| -rw-r--r-- | source/slang/slang-ast-dump.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-check-conformance.cpp | 53 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 40 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 14 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 5 | ||||
| -rw-r--r-- | tests/diagnostics/incomplete-type.slang | 11 | ||||
| -rw-r--r-- | tools/gfx-unit-test/link-time-type.cpp | 174 |
16 files changed, 338 insertions, 12 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj index 42e52b22d..e70470ef6 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj @@ -305,6 +305,7 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\instanced-draw-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-constant.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-options.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-type.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\precompiled-module-2.cpp" />
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters index ddc8b6bd3..9d2c70a92 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters @@ -71,6 +71,9 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-options.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-type.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/source/core/slang-list.h b/source/core/slang-list.h index 250b6dc49..c0fe28937 100644 --- a/source/core/slang-list.h +++ b/source/core/slang-list.h @@ -570,7 +570,7 @@ namespace Slang } template<typename T2> - int binarySearch(const T2& obj) + Index binarySearch(const T2& obj) { return binarySearch(obj, [](T & curObj, const T2 & thatObj)->int diff --git a/source/slang/slang-ast-decl.cpp b/source/slang/slang-ast-decl.cpp index 9dbd006a0..cd9c43410 100644 --- a/source/slang/slang-ast-decl.cpp +++ b/source/slang/slang-ast-decl.cpp @@ -136,4 +136,19 @@ InterfaceDecl* ThisTypeConstraintDecl::getInterfaceDecl() return as<InterfaceDecl>(parentDecl->parentDecl); } +void AggTypeDecl::addTag(TypeTag tag) +{ + typeTags = (TypeTag)((int)tag | (int)tag); +} + +bool AggTypeDecl::hasTag(TypeTag tag) +{ + return ((int)typeTags & (int)tag) != 0; +} + +void AggTypeDecl::unionTagsWith(TypeTag other) +{ + addTag(other); +} + } // namespace Slang diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index 5d8023eaf..7a4d46947 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -130,11 +130,24 @@ class ExtensionDecl : public AggTypeDeclBase TypeExp targetType; }; +enum class TypeTag +{ + None = 0, + Unsized = 1, + Incomplete = 2 +}; + // Declaration of a type that represents some sort of aggregate class AggTypeDecl : public AggTypeDeclBase { SLANG_ABSTRACT_AST_CLASS(AggTypeDecl) + TypeTag typeTags = TypeTag::None; + + void unionTagsWith(TypeTag other); + void addTag(TypeTag tag); + bool hasTag(TypeTag tag); + FilteredMemberList<VarDecl> getFields() { return getMembersOfType<VarDecl>(); diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp index 9c40fb12b..ccd9b9ee7 100644 --- a/source/slang/slang-ast-dump.cpp +++ b/source/slang/slang-ast-dump.cpp @@ -343,6 +343,10 @@ struct ASTDumpContext { m_writer->emit((int)v); } + void dump(TypeTag tag) + { + m_writer->emit((int)tag); + } void dump(const String& string) { dump(string.getUnownedSlice()); diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index c1984910c..d3529b963 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -1503,6 +1503,9 @@ namespace Slang // The type witnessesd by the witness table (a concrete type). Type* witnessedType; + // Whether or not this witness table is an extern declaration. + bool isExtern = false; + // Satisfying values of each requirement. List<KeyValuePair<Decl*, RequirementWitness>> m_requirements; diff --git a/source/slang/slang-check-conformance.cpp b/source/slang/slang-check-conformance.cpp index 4376b1135..726572d08 100644 --- a/source/slang/slang-check-conformance.cpp +++ b/source/slang/slang-check-conformance.cpp @@ -242,6 +242,59 @@ namespace Slang return isSubtype(type, m_astBuilder->getDiffInterfaceType()); } + bool SemanticsVisitor::doesTypeHaveTag(Type* type, TypeTag tag) + { + if (auto arrayType = as<ArrayExpressionType>(type)) + { + return doesTypeHaveTag(arrayType->getElementType(), tag); + } + if (auto modifiedType = as<ModifiedType>(type)) + { + return doesTypeHaveTag(modifiedType->getBase(), tag); + } + if (auto declRefType = as<DeclRefType>(type)) + { + if (auto aggTypeDecl = as<AggTypeDecl>(declRefType->getDeclRef())) + return aggTypeDecl.getDecl()->hasTag(tag); + } + return false; + } + + TypeTag SemanticsVisitor::getTypeTags(Type* type) + { + if (auto arrayType = as<ArrayExpressionType>(type)) + { + return getTypeTags(arrayType->getElementType()); + } + if (auto modifiedType = as<ModifiedType>(type)) + { + return getTypeTags(modifiedType->getBase()); + } + if (auto declRefType = as<DeclRefType>(type)) + { + if (auto aggTypeDecl = as<AggTypeDecl>(declRefType->getDeclRef())) + return aggTypeDecl.getDecl()->typeTags; + } + return TypeTag::None; + } + + + Type* SemanticsVisitor::getBufferElementType(Type* type) + { + if (auto arrType = as<ArrayExpressionType>(type)) + return getBufferElementType(arrType->getElementType()); + if (auto modifiedType = as<ModifiedType>(type)) + return getBufferElementType(modifiedType->getBase()); + if (auto constantBuffer = as<ConstantBufferType>(type)) + return constantBuffer->getElementType(); + if (auto structuredBuffer = as<HLSLStructuredBufferTypeBase>(type)) + return structuredBuffer->getElementType(); + if (auto storageBuffer = as<GLSLShaderStorageBufferType>(type)) + return storageBuffer->getElementType(); + return nullptr; + } + + SubtypeWitness* SemanticsVisitor::tryGetInterfaceConformanceWitness( Type* type, Type* interfaceType) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 3fb2725e2..dc888ccda 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -302,6 +302,8 @@ namespace Slang void visitFunctionDeclBase(FunctionDeclBase* funcDecl); void visitParamDecl(ParamDecl* paramDecl); + + void visitAggTypeDecl(AggTypeDecl* aggTypeDecl); }; template<typename VisitorType> @@ -1705,6 +1707,15 @@ namespace Slang } } + // Propagate type tags. + if (auto parentAggTypeDecl = as<AggTypeDecl>(getParentDecl(varDecl))) + { + if (auto varDeclRefType = as<DeclRefType>(varDecl->type.type)) + { + parentAggTypeDecl->unionTagsWith(getTypeTags(varDecl->type.type)); + } + } + checkVisibility(varDecl); } @@ -1722,11 +1733,20 @@ namespace Slang { addModifier(structDecl, m_astBuilder->create<NVAPIMagicModifier>()); } + + if (structDecl->hasModifier<ExternModifier>()) + { + structDecl->addTag(TypeTag::Incomplete); + } checkVisibility(structDecl); } void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl) { + if (classDecl->hasModifier<ExternModifier>()) + { + classDecl->addTag(TypeTag::Incomplete); + } checkVisibility(classDecl); } @@ -1812,6 +1832,13 @@ namespace Slang varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate); } } + if (auto elementType = getBufferElementType(varDecl->getType())) + { + if (doesTypeHaveTag(elementType, TypeTag::Incomplete)) + { + getSink()->diagnose(varDecl->type.exp->loc, Diagnostics::incompleteTypeCannotBeUsedInBuffer, elementType); + } + } maybeRegisterDifferentiableType(getASTBuilder(), varDecl->getType()); } @@ -4784,6 +4811,9 @@ namespace Slang SubtypeWitness* subIsSuperWitness, WitnessTable* witnessTable) { + if (witnessTable->isExtern) + return true; + if (auto supereclRefType = as<DeclRefType>(superType)) { auto superTypeDeclRef = supereclRefType->getDeclRef(); @@ -4896,6 +4926,7 @@ namespace Slang witnessTable = new WitnessTable(); witnessTable->baseType = superType; witnessTable->witnessedType = subType; + witnessTable->isExtern = parentDecl->hasModifier<ExternModifier>(); inheritanceDecl->witnessTable = witnessTable; } @@ -5179,6 +5210,7 @@ namespace Slang // order) is allowed to declare a base `class` type. // SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); + Index inheritanceClauseCounter = 0; for (auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) { @@ -6544,6 +6576,14 @@ namespace Slang } } + void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) + { + if (aggTypeDecl->hasTag(TypeTag::Incomplete) && aggTypeDecl->hasModifier<HLSLExportModifier>()) + { + getSink()->diagnose(aggTypeDecl->loc, Diagnostics::cannotExportIncompleteType, aggTypeDecl); + } + } + void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src) { dest->modifiers = src->modifiers; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 3af85b73d..ba8e2f4cd 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1957,6 +1957,12 @@ namespace Slang bool isTypeDifferentiable(Type* type); + bool doesTypeHaveTag(Type* type, TypeTag tag); + + TypeTag getTypeTags(Type* type); + + Type* getBufferElementType(Type* type); + /// Check whether `subType` is a sub-type of `superTypeDeclRef`, /// and return a witness to the sub-type relationship if it holds /// (return null otherwise). diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 9117eb6ec..a4e906ac9 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -1109,7 +1109,8 @@ namespace Slang case ASTNodeType::HLSLExportModifier: case ASTNodeType::ExternCppModifier: return as<VarDeclBase>(decl) || as<AggTypeDeclBase>(decl) || as<NamespaceDeclBase>(decl) || as<CallableDecl>(decl) - || as<TypeDefDecl>(decl) || as<PropertyDecl>(decl) || as<SyntaxDecl>(decl) || as<AttributeDecl>(decl); + || as<TypeDefDecl>(decl) || as<PropertyDecl>(decl) || as<SyntaxDecl>(decl) || as<AttributeDecl>(decl) + || as<InheritanceDecl>(decl); case ASTNodeType::ExportedModifier: return as<ImportDecl>(decl); diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index ac1f9aff9..722085744 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -438,6 +438,9 @@ DIAGNOSTIC(31155, Error, customDerivativeNotAllowedForMemberFunctionsOfDifferent DIAGNOSTIC(31200, Warning, deprecatedUsage, "$0 has been deprecated: $1") DIAGNOSTIC(31201, Error, modifierNotAllowed, "modifier '$0' is not allowed here.") DIAGNOSTIC(31202, Error, duplicateModifier, "modifier '$0' is redundant or conflicting with existing modifier '$1'") +DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'") +DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer") + // Enums DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'") diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 8531e4029..b560bb156 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -657,17 +657,11 @@ bool isFromStdLib(Decl* decl) bool isImportedDecl(IRGenContext* context, Decl* decl) { // If the declaration has the extern attribute then it must be imported - // from another module + // from another module. + // Note that `extern` declarations will have a mangled name that does not + // include the module name so the linking step can resolve them correctly. // - // The [__extern] attribute is a very special case feature (aka "a hack") that allows a symbol to be declared - // as if it is part of the current module for AST purposes, but then expects to be imported from another IR module. - // For that linkage to work, both the exporting and importing modules must have the same name (which would - // usually indicate that they are the same module). - // - // Note that in practice for matching during linking uses the fully qualified name - including module name. - // Thus using extern __attribute isn't useful for symbols that are imported via `import`, only symbols - // that notionally come from the same module but are split into separate compilations (as can be done with -module-name) - if (decl->findModifier<ExternAttribute>()) + if (decl->findModifier<ExternAttribute>() || decl->findModifier<ExternModifier>()) { return true; } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index e0ffba53c..b89b93138 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -3232,6 +3232,9 @@ namespace Slang inheritanceDecl->base = base; AddMember(decl, inheritanceDecl); + + if (parser->pendingModifiers->hasModifier<ExternModifier>()) + addModifier(inheritanceDecl, parser->astBuilder->create<ExternModifier>()); } while (AdvanceIf(parser, TokenType::Comma)); } @@ -4730,6 +4733,8 @@ namespace Slang // We allow for an inheritance clause on a `struct` // so that it can conform to interfaces. parseOptionalInheritanceClause(this, rs); + if (AdvanceIf(this, TokenType::Semicolon)) + return rs; parseDeclBody(this, rs); return rs; }); diff --git a/tests/diagnostics/incomplete-type.slang b/tests/diagnostics/incomplete-type.slang new file mode 100644 index 000000000..873673045 --- /dev/null +++ b/tests/diagnostics/incomplete-type.slang @@ -0,0 +1,11 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): + +extern struct ExtType; + +struct MyType +{ + ExtType arr[2]; +} + +// CHECK: ([[#@LINE+1]]): error 31204 +ConstantBuffer<MyType> buffer; diff --git a/tools/gfx-unit-test/link-time-type.cpp b/tools/gfx-unit-test/link-time-type.cpp new file mode 100644 index 000000000..0eda4487e --- /dev/null +++ b/tools/gfx-unit-test/link-time-type.cpp @@ -0,0 +1,174 @@ +#include "tools/unit-test/slang-unit-test.h" + +#include "slang-gfx.h" +#include "gfx-test-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "source/core/slang-basic.h" +#include "source/core/slang-blob.h" + +using namespace gfx; + +namespace gfx_test +{ + static Slang::Result loadProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + slang::ProgramLayout*& slangReflection) + { + const char* moduleInterfaceSrc = R"( + interface IFoo { [mutating] void setValue(float v); float getValue(); } + )"; + const char* module0Src = R"( + import ifoo; + extern struct Foo : IFoo; + + [numthreads(1,1,1)] + void computeMain(uniform RWStructuredBuffer<float> buffer) + { + Foo foo; + foo.setValue(3.0); + buffer[0] = foo.getValue(); + } + )"; + const char* module1Src = R"( + import ifoo; + export struct Foo : IFoo + { + float val; + [mutating] void setValue(float v) { val = v; } + float getValue() { return val + 1.0; } + }; + )"; + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + auto moduleInterfaceBlob = Slang::UnownedRawBlob::create(moduleInterfaceSrc, strlen(moduleInterfaceSrc)); + auto module0Blob = Slang::UnownedRawBlob::create(module0Src, strlen(module0Src)); + auto module1Blob = Slang::UnownedRawBlob::create(module1Src, strlen(module1Src)); + slang::IModule* moduleInterface = slangSession->loadModuleFromSource("ifoo", "ifoo.slang", + moduleInterfaceBlob); + slang::IModule* module0 = slangSession->loadModuleFromSource("module0", "path0", + module0Blob); + slang::IModule* module1 = slangSession->loadModuleFromSource("module1", "path1", + module1Blob); + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module0->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(moduleInterface); + componentTypes.add(module0); + componentTypes.add(module1); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; + } + + void linkTimeTypeTestImpl(IDevice* device, UnitTestContext* context) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT(device->createBufferResource( + bufferDesc, + (void*)initialData, + numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } + + compareComputeResult( + device, + numbersBuffer, + Slang::makeArray<float>(4.0)); + } + + SLANG_UNIT_TEST(linkTimeTypeD3D12) + { + runTestImpl(linkTimeTypeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + } + + SLANG_UNIT_TEST(linkTimeTypeVulkan) + { + runTestImpl(linkTimeTypeTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + } + +} |
