yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Gangzheng TongConvert gfx unit tests and examples to use slang-rhi (#7577)43d0c2100

master
5.1 KiB143 linesraw
1#include "core/slang-basic.h"
2#include "core/slang-blob.h"
3#include "gfx-test-util.h"
4#include "slang-rhi.h"
5#include "slang-rhi/shader-cursor.h"
6#include "unit-test/slang-unit-test.h"
7
8using namespace rhi;
9
10namespace gfx_test
11{
12static Slang::Result loadProgram(
13    rhi::IDevice* device,
14    Slang::ComPtr<rhi::IShaderProgram>& outShaderProgram,
15    const char* shaderModuleName,
16    const char* entryPointName,
17    slang::ProgramLayout*& slangReflection,
18    const char* additionalModuleSource)
19{
20    Slang::ComPtr<slang::ISession> slangSession;
21    SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
22    Slang::ComPtr<slang::IBlob> diagnosticsBlob;
23    slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef());
24    diagnoseIfNeeded(diagnosticsBlob);
25    if (!module)
26        return SLANG_FAIL;
27
28    auto additionalModuleBlob =
29        Slang::UnownedRawBlob::create(additionalModuleSource, strlen(additionalModuleSource));
30    slang::IModule* additionalModule =
31        slangSession->loadModuleFromSource("linkedConstants", "path", additionalModuleBlob);
32
33    ComPtr<slang::IEntryPoint> computeEntryPoint;
34    SLANG_RETURN_ON_FAIL(
35        module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef()));
36
37    Slang::List<slang::IComponentType*> componentTypes;
38    componentTypes.add(module);
39    componentTypes.add(computeEntryPoint);
40    componentTypes.add(additionalModule);
41
42    Slang::ComPtr<slang::IComponentType> composedProgram;
43    SlangResult result = slangSession->createCompositeComponentType(
44        componentTypes.getBuffer(),
45        componentTypes.getCount(),
46        composedProgram.writeRef(),
47        diagnosticsBlob.writeRef());
48    diagnoseIfNeeded(diagnosticsBlob);
49    SLANG_RETURN_ON_FAIL(result);
50
51    ComPtr<slang::IComponentType> linkedProgram;
52    result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef());
53    diagnoseIfNeeded(diagnosticsBlob);
54    SLANG_RETURN_ON_FAIL(result);
55
56    composedProgram = linkedProgram;
57    slangReflection = composedProgram->getLayout();
58
59    ShaderProgramDesc programDesc = {};
60    programDesc.slangGlobalScope = composedProgram.get();
61
62    auto shaderProgram = device->createShaderProgram(programDesc);
63
64    outShaderProgram = shaderProgram;
65    return SLANG_OK;
66}
67
68void linkTimeConstantTestImpl(IDevice* device, UnitTestContext* context)
69{
70    ComPtr<IShaderProgram> shaderProgram;
71    slang::ProgramLayout* slangReflection;
72    GFX_CHECK_CALL_ABORT(loadProgram(
73        device,
74        shaderProgram,
75        "link-time-constant",
76        "computeMain",
77        slangReflection,
78        R"(
79                export static const bool turnOnFeature = true;
80                export static const float constValue = 2.0;
81                export static const uint numthread = 2;
82                export static const int arraySize = 4;
83            )"));
84
85    SlangUInt threadGroupSizes[3];
86    slangReflection->findEntryPointByName("computeMain")
87        ->getComputeThreadGroupSize(3, threadGroupSizes);
88    SLANG_CHECK(threadGroupSizes[0] == 2 && threadGroupSizes[1] == 1 && threadGroupSizes[2] == 1);
89
90    ComputePipelineDesc pipelineDesc = {};
91    pipelineDesc.program = shaderProgram.get();
92    ComPtr<IComputePipeline> pipelineState;
93    GFX_CHECK_CALL_ABORT(device->createComputePipeline(pipelineDesc, pipelineState.writeRef()));
94
95    const int numberCount = 4;
96    float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f};
97    BufferDesc bufferDesc = {};
98    bufferDesc.size = numberCount * sizeof(float);
99    bufferDesc.format = rhi::Format::Undefined;
100    bufferDesc.elementSize = sizeof(float);
101    bufferDesc.usage = BufferUsage::ShaderResource | BufferUsage::UnorderedAccess |
102                       BufferUsage::CopyDestination | BufferUsage::CopySource;
103    bufferDesc.defaultState = ResourceState::UnorderedAccess;
104    bufferDesc.memoryType = MemoryType::DeviceLocal;
105
106    ComPtr<IBuffer> numbersBuffer;
107    GFX_CHECK_CALL_ABORT(
108        device->createBuffer(bufferDesc, (void*)initialData, numbersBuffer.writeRef()));
109
110    // We have done all the set up work, now it is time to start recording a command buffer for
111    // GPU execution.
112    {
113        auto queue = device->getQueue(QueueType::Graphics);
114        auto commandEncoder = queue->createCommandEncoder();
115        auto encoder = commandEncoder->beginComputePass();
116
117        auto rootObject = encoder->bindPipeline(pipelineState);
118
119        ShaderCursor entryPointCursor(
120            rootObject->getEntryPoint(0)); // get a cursor the the first entry-point.
121        // Bind buffer to the entry point.
122        entryPointCursor.getPath("buffer").setBinding(numbersBuffer);
123
124        encoder->dispatchCompute(1, 1, 1);
125        encoder->end();
126        queue->submit(commandEncoder->finish());
127        queue->waitOnHost();
128    }
129
130    compareComputeResult(device, numbersBuffer, std::array{2.0f});
131}
132
133SLANG_UNIT_TEST(linkTimeConstantD3D12)
134{
135    runTestImpl(linkTimeConstantTestImpl, unitTestContext, DeviceType::D3D12);
136}
137
138SLANG_UNIT_TEST(linkTimeConstantVulkan)
139{
140    runTestImpl(linkTimeConstantTestImpl, unitTestContext, DeviceType::Vulkan);
141}
142
143} // namespace gfx_test