summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-02-09 22:00:15 -0800
committerGitHub <noreply@github.com>2024-02-09 22:00:15 -0800
commit20ab16178e45d07b4dc0104a7a98865d18440b62 (patch)
tree5314057a48d5ad2346fa808e4cfacff0991ce9b9 /tools
parentf44da6cc5c0f211c13bd1eb0743d79c7861ea64e (diff)
Support link-time constants. (#3564)
* Support link-time constants. * Fix. * Fix.
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx-unit-test/gfx-test-util.h2
-rw-r--r--tools/gfx-unit-test/link-time-constant.cpp156
-rw-r--r--tools/gfx-unit-test/link-time-constant.slang20
3 files changed, 177 insertions, 1 deletions
diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h
index 22b9b2fd3..501deeae0 100644
--- a/tools/gfx-unit-test/gfx-test-util.h
+++ b/tools/gfx-unit-test/gfx-test-util.h
@@ -8,7 +8,7 @@
namespace gfx_test
{
/// Helper function for print out diagnostic messages output by Slang compiler.
- void diagnoseIfNeeded(ISlangWriter* diagnosticWriter, slang::IBlob* diagnosticsBlob);
+ void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob);
/// Loads a compute shader module and produces a `gfx::IShaderProgram`.
Slang::Result loadComputeProgram(
diff --git a/tools/gfx-unit-test/link-time-constant.cpp b/tools/gfx-unit-test/link-time-constant.cpp
new file mode 100644
index 000000000..62cb294c1
--- /dev/null
+++ b/tools/gfx-unit-test/link-time-constant.cpp
@@ -0,0 +1,156 @@
+#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,
+ const char* shaderModuleName,
+ const char* entryPointName,
+ slang::ProgramLayout*& slangReflection,
+ const char* additionalModuleSource)
+ {
+ Slang::ComPtr<slang::ISession> slangSession;
+ SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
+ Slang::ComPtr<slang::IBlob> diagnosticsBlob;
+ slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
+
+ auto additionalModuleBlob = Slang::UnownedRawBlob::create(additionalModuleSource, strlen(additionalModuleSource));
+ slang::IModule* additionalModule = slangSession->loadModuleFromSource("linkedConstants", "path",
+ additionalModuleBlob);
+
+ ComPtr<slang::IEntryPoint> computeEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef()));
+
+ Slang::List<slang::IComponentType*> componentTypes;
+ componentTypes.add(module);
+ componentTypes.add(computeEntryPoint);
+ componentTypes.add(additionalModule);
+
+ 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 linkTimeConstantTestImpl(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, "link-time-constant", "computeMain", slangReflection,
+ R"(
+ export static const bool turnOnFeature = true;
+ export static const float constValue = 2.0;
+ )"));
+
+ 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>(2.0));
+ }
+
+ SLANG_UNIT_TEST(linkTimeConstantD3D12)
+ {
+ runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12);
+ }
+
+ SLANG_UNIT_TEST(linkTimeConstantVulkan)
+ {
+ runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan);
+ }
+
+}
diff --git a/tools/gfx-unit-test/link-time-constant.slang b/tools/gfx-unit-test/link-time-constant.slang
new file mode 100644
index 000000000..385932dd4
--- /dev/null
+++ b/tools/gfx-unit-test/link-time-constant.slang
@@ -0,0 +1,20 @@
+extern static const bool turnOnFeature;
+extern static const float constValue;
+
+// Main entry-point. Write some value into buffer depending on link
+// time constant.
+[shader("compute")]
+[numthreads(4, 1, 1)]
+void computeMain(
+ uint3 sv_dispatchThreadID: SV_DispatchThreadID,
+ uniform RWStructuredBuffer<float> buffer)
+{
+ if (turnOnFeature)
+ {
+ buffer[0] = constValue;
+ }
+ else
+ {
+ buffer[0] = -1.0;
+ }
+}