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.2 KiB144 linesraw
1#include "core/slang-basic.h"
2#include "core/slang-blob.h"
3#include "core/slang-memory-file-system.h"
4#include "gfx-test-util.h"
5#include "slang-rhi.h"
6#include "slang-rhi/shader-cursor.h"
7#include "unit-test/slang-unit-test.h"
8
9using namespace rhi;
10
11namespace gfx_test
12{
13static Slang::Result precompileProgram(
14    IDevice* device,
15    ISlangMutableFileSystem* fileSys,
16    const char* shaderModuleName)
17{
18    Slang::ComPtr<slang::ISession> slangSession;
19    SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
20    slang::SessionDesc sessionDesc = {};
21    auto searchPaths = getSlangSearchPaths();
22    sessionDesc.searchPathCount = searchPaths.getCount();
23    sessionDesc.searchPaths = searchPaths.getBuffer();
24    auto globalSession = slangSession->getGlobalSession();
25    globalSession->createSession(sessionDesc, slangSession.writeRef());
26
27    Slang::ComPtr<slang::IBlob> diagnosticsBlob;
28    slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef());
29    diagnoseIfNeeded(diagnosticsBlob);
30    if (!module)
31        return SLANG_FAIL;
32
33    // Write loaded modules to memory file system.
34    for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++)
35    {
36        auto module = slangSession->getLoadedModule(i);
37        auto path = module->getFilePath();
38        if (path)
39        {
40            auto name = module->getName();
41            ComPtr<ISlangBlob> outBlob;
42            module->serialize(outBlob.writeRef());
43            fileSys->saveFileBlob((Slang::String(name) + ".slang-module").getBuffer(), outBlob);
44        }
45    }
46    return SLANG_OK;
47}
48
49void precompiledModuleTestImpl(IDevice* device, UnitTestContext* context)
50{
51    // First, load and compile the slang source.
52    ComPtr<ISlangMutableFileSystem> memoryFileSystem =
53        ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem());
54
55    ComPtr<IShaderProgram> shaderProgram;
56    slang::ProgramLayout* slangReflection;
57    GFX_CHECK_CALL_ABORT(precompileProgram(device, memoryFileSystem.get(), "precompiled-module"));
58
59    // Next, load the precompiled slang program.
60    Slang::ComPtr<slang::ISession> slangSession;
61    device->getSlangSession(slangSession.writeRef());
62    slang::SessionDesc sessionDesc = {};
63    sessionDesc.targetCount = 1;
64    slang::TargetDesc targetDesc = {};
65    switch (device->getInfo().deviceType)
66    {
67    case DeviceType::D3D12:
68        targetDesc.format = SLANG_DXIL;
69        targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1");
70        break;
71    case DeviceType::Vulkan:
72        targetDesc.format = SLANG_SPIRV;
73        targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460");
74        break;
75    }
76    sessionDesc.targets = &targetDesc;
77    sessionDesc.fileSystem = memoryFileSystem.get();
78    auto globalSession = slangSession->getGlobalSession();
79    globalSession->createSession(sessionDesc, slangSession.writeRef());
80    GFX_CHECK_CALL_ABORT(loadComputeProgram(
81        device,
82        slangSession,
83        shaderProgram,
84        "precompiled-module",
85        "computeMain",
86        slangReflection));
87
88    ComputePipelineDesc pipelineDesc = {};
89    pipelineDesc.program = shaderProgram.get();
90    ComPtr<IComputePipeline> pipelineState;
91    GFX_CHECK_CALL_ABORT(device->createComputePipeline(pipelineDesc, pipelineState.writeRef()));
92
93    const int numberCount = 4;
94    float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f};
95    BufferDesc bufferDesc = {};
96    bufferDesc.size = numberCount * sizeof(float);
97    bufferDesc.format = Format::Undefined;
98    bufferDesc.elementSize = sizeof(float);
99    bufferDesc.usage = BufferUsage::ShaderResource | BufferUsage::UnorderedAccess |
100                       BufferUsage::CopyDestination | BufferUsage::CopySource;
101    bufferDesc.defaultState = ResourceState::UnorderedAccess;
102    bufferDesc.memoryType = MemoryType::DeviceLocal;
103
104    ComPtr<IBuffer> numbersBuffer;
105    GFX_CHECK_CALL_ABORT(
106        device->createBuffer(bufferDesc, (void*)initialData, numbersBuffer.writeRef()));
107
108    // We have done all the set up work, now it is time to start recording a command buffer for
109    // GPU execution.
110    {
111        auto queue = device->getQueue(QueueType::Graphics);
112        auto commandEncoder = queue->createCommandEncoder();
113        {
114            auto encoder = commandEncoder->beginComputePass();
115            auto rootObject = encoder->bindPipeline(pipelineState);
116
117            ShaderCursor entryPointCursor(
118                rootObject->getEntryPoint(0)); // get a cursor the the first entry-point.
119            // Bind buffer directly to the entry point.
120            entryPointCursor.getPath("buffer").setBinding(Binding(numbersBuffer));
121
122            encoder->dispatchCompute(1, 1, 1);
123            encoder->end();
124        }
125
126        auto commandBuffer = commandEncoder->finish();
127        queue->submit(commandBuffer);
128        queue->waitOnHost();
129    }
130
131    compareComputeResult(device, numbersBuffer, std::array{3.0f, 3.0f, 3.0f, 3.0f});
132}
133
134SLANG_UNIT_TEST(precompiledModuleD3D12)
135{
136    runTestImpl(precompiledModuleTestImpl, unitTestContext, DeviceType::D3D12);
137}
138
139SLANG_UNIT_TEST(precompiledModuleVulkan)
140{
141    runTestImpl(precompiledModuleTestImpl, unitTestContext, DeviceType::Vulkan);
142}
143
144} // namespace gfx_test