summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-02-20 15:37:11 -0800
committerGitHub <noreply@github.com>2024-02-20 15:37:11 -0800
commita62be597990966b9516995650baf750ee6a0146b (patch)
tree1741b3d5b5859319f278aa6ab821a2f801fd8e08
parent4d20fd329956ac89408b1628a8291fea01bc9a6d (diff)
Support link time type specialization. (#3604)
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj1
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters3
-rw-r--r--source/core/slang-list.h2
-rw-r--r--source/slang/slang-ast-decl.cpp15
-rw-r--r--source/slang/slang-ast-decl.h13
-rw-r--r--source/slang/slang-ast-dump.cpp4
-rw-r--r--source/slang/slang-ast-support-types.h3
-rw-r--r--source/slang/slang-check-conformance.cpp53
-rw-r--r--source/slang/slang-check-decl.cpp40
-rw-r--r--source/slang/slang-check-impl.h6
-rw-r--r--source/slang/slang-check-modifier.cpp3
-rw-r--r--source/slang/slang-diagnostic-defs.h3
-rw-r--r--source/slang/slang-lower-to-ir.cpp14
-rw-r--r--source/slang/slang-parser.cpp5
-rw-r--r--tests/diagnostics/incomplete-type.slang11
-rw-r--r--tools/gfx-unit-test/link-time-type.cpp174
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);
+ }
+
+}