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
10.5 KiB340 linesraw
1#if 0
2// Disabled: slang-rhi doesn't have resolveResource API.
3
4#include "core/slang-basic.h"
5#include "gfx-test-util.h"
6#include "unit-test/slang-unit-test.h"
7
8#include <slang-rhi.h>
9#include <slang-rhi/shader-cursor.h>
10
11#if SLANG_WINDOWS_FAMILY
12#include <d3d12.h>
13#endif
14
15using namespace Slang;
16using namespace rhi;
17
18namespace
19{
20using namespace gfx_test;
21
22struct Vertex
23{
24    float position[3];
25    float color[3];
26};
27
28static const int kVertexCount = 12;
29static const Vertex kVertexData[kVertexCount] = {
30    // Triangle 1
31    {{0, 0, 0.5}, {1, 0, 0}},
32    {{1, 1, 0.5}, {1, 0, 0}},
33    {{-1, 1, 0.5}, {1, 0, 0}},
34
35    // Triangle 2
36    {{-1, 1, 0.5}, {0, 1, 0}},
37    {{0, 0, 0.5}, {0, 1, 0}},
38    {{-1, -1, 0.5}, {0, 1, 0}},
39
40    // Triangle 3
41    {{-1, -1, 0.5}, {0, 0, 1}},
42    {{0, 0, 0.5}, {0, 0, 1}},
43    {{1, -1, 0.5}, {0, 0, 1}},
44
45    // Triangle 4
46    {{1, -1, 0.5}, {0, 0, 0}},
47    {{0, 0, 0.5}, {0, 0, 0}},
48    {{1, 1, 0.5}, {0, 0, 0}},
49};
50
51const int kWidth = 256;
52const int kHeight = 256;
53Format format = Format::RGBA32Float;
54
55ComPtr<IBuffer> createVertexBuffer(IDevice* device)
56{
57            BufferDesc vertexBufferDesc;
58        vertexBufferDesc.size = kVertexCount * sizeof(Vertex);
59        vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
60        vertexBufferDesc.usage = BufferUsage::VertexBuffer;
61    ComPtr<IBuffer> vertexBuffer = device->createBuffer(vertexBufferDesc, &kVertexData[0]);
62    SLANG_CHECK_ABORT(vertexBuffer != nullptr);
63    return vertexBuffer;
64}
65
66struct BaseResolveResourceTest
67{
68    IDevice* device;
69    UnitTestContext* context;
70
71    ComPtr<ITexture> msaaTexture;
72    ComPtr<ITexture> dstTexture;
73
74    ComPtr<IRenderPipeline> pipelineState;
75
76    ComPtr<IBuffer> vertexBuffer;
77
78    struct TextureInfo
79    {
80        Extent3D extent;
81        int numMipLevels;
82        int arraySize;
83        const SubresourceData* initData;
84    };
85
86    void init(IDevice* device, UnitTestContext* context)
87    {
88        this->device = device;
89        this->context = context;
90    }
91
92    void createRequiredResources(
93        TextureInfo msaaTextureInfo,
94        TextureInfo dstTextureInfo,
95        Format format)
96    {
97        VertexStreamDesc vertexStreams[] = {
98            {sizeof(Vertex), InputSlotClass::PerVertex, 0},
99        };
100
101        InputElementDesc inputElements[] = {
102            // Vertex buffer data
103            {"POSITION", 0, Format::RGB32Float, offsetof(Vertex, position), 0},
104            {"COLOR", 0, Format::RGB32Float, offsetof(Vertex, color), 0},
105        };
106
107        TextureDesc msaaTexDesc = {};
108        msaaTexDesc.type = TextureType::Texture2D;
109        msaaTexDesc.mipCount = dstTextureInfo.numMipLevels;
110        msaaTexDesc.arrayLength = dstTextureInfo.arraySize;
111        msaaTexDesc.size = dstTextureInfo.extent;
112        msaaTexDesc.defaultState = ResourceState::RenderTarget;
113        msaaTexDesc.usage = TextureUsage::RenderTarget;
114        msaaTexDesc.format = format;
115        msaaTexDesc.sampleCount = 4;
116
117        msaaTexture = device->createTexture(msaaTexDesc, msaaTextureInfo.initData);
118        SLANG_CHECK_ABORT(msaaTexture);
119
120        TextureDesc dstTexDesc = {};
121        dstTexDesc.type = TextureType::Texture2D;
122        dstTexDesc.mipCount = dstTextureInfo.numMipLevels;
123        dstTexDesc.arrayLength = dstTextureInfo.arraySize;
124        dstTexDesc.size = dstTextureInfo.extent;
125        dstTexDesc.defaultState = ResourceState::CopyDestination;
126        dstTexDesc.usage = TextureUsage::CopyDestination | TextureUsage::CopySource;
127        dstTexDesc.format = format;
128
129        dstTexture = device->createTexture(dstTexDesc, dstTextureInfo.initData);
130        SLANG_CHECK_ABORT(dstTexture);
131
132        InputLayoutDesc inputLayoutDesc = {};
133        inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements);
134        inputLayoutDesc.inputElements = inputElements;
135        inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams);
136        inputLayoutDesc.vertexStreams = vertexStreams;
137        auto inputLayout = device->createInputLayout(inputLayoutDesc);
138        SLANG_CHECK_ABORT(inputLayout != nullptr);
139
140        vertexBuffer = createVertexBuffer(device);
141
142        ComPtr<IShaderProgram> shaderProgram;
143        slang::ProgramLayout* slangReflection;
144        GFX_CHECK_CALL_ABORT(loadGraphicsProgram(
145            device,
146            shaderProgram,
147            "resolve-resource-shader",
148            "vertexMain",
149            "fragmentMain",
150            slangReflection));
151
152        ColorTargetDesc colorTarget = {};
153        colorTarget.format = format;
154        
155        RenderPipelineDesc pipelineDesc = {};
156        pipelineDesc.program = shaderProgram.get();
157        pipelineDesc.inputLayout = inputLayout;
158        pipelineDesc.targets = &colorTarget;
159        pipelineDesc.targetCount = 1;
160        pipelineDesc.primitiveTopology = PrimitiveTopology::TriangleList;
161        pipelineDesc.depthStencil.depthTestEnable = false;
162        pipelineDesc.depthStencil.depthWriteEnable = false;
163        pipelineState = device->createRenderPipeline(pipelineDesc);
164        SLANG_CHECK_ABORT(pipelineState);
165    }
166
167    void submitGPUWork(
168        SubresourceRange msaaSubresource,
169        SubresourceRange dstSubresource,
170        Extent3D extent)
171    {
172        auto queue = device->getQueue(QueueType::Graphics);
173
174        ComPtr<ICommandEncoder> encoder = queue->createCommandEncoder();
175        
176        // Create render target view
177        TextureViewDesc rtvDesc = {};
178        rtvDesc.format = format;
179        auto rtv = device->createTextureView(msaaTexture, rtvDesc);
180
181        RenderPassColorAttachment colorAttachment = {};
182        colorAttachment.view = rtv;
183        colorAttachment.loadOp = LoadOp::Clear;
184        colorAttachment.storeOp = StoreOp::Store;
185        float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
186        memcpy(colorAttachment.clearValue, clearColor, sizeof(clearColor));
187
188        RenderPassDesc passDesc = {};
189        passDesc.colorAttachments = &colorAttachment;
190        passDesc.colorAttachmentCount = 1;
191
192        auto renderEncoder = encoder->beginRenderPass(passDesc);
193        auto rootObject = renderEncoder->bindPipeline(pipelineState);
194
195        Viewport viewport = {};
196        viewport.maxZ = 1.0f;
197        viewport.extentX = kWidth;
198        viewport.extentY = kHeight;
199        
200        RenderState state = {};
201        state.viewports[0] = viewport;
202        state.viewportCount = 1;
203        state.vertexBuffers[0] = BufferOffsetPair(vertexBuffer, 0);
204        state.vertexBufferCount = 1;
205        renderEncoder->setRenderState(state);
206
207        DrawArguments drawArgs = {};
208        drawArgs.vertexCount = kVertexCount;
209        drawArgs.startVertexLocation = 0;
210        renderEncoder->draw(drawArgs);
211        renderEncoder->end();
212
213        // Note: slang-rhi doesn't have a direct resolveResource function
214        // For MSAA resolve, we would typically use a resolve render pass or blit operation
215        // For this test, we'll use a simple copy operation instead
216        encoder->copyTexture(
217            dstTexture,
218            dstSubresource,
219            Offset3D{0, 0, 0},
220            msaaTexture,
221            msaaSubresource,
222            Offset3D{0, 0, 0},
223            extent);
224        encoder->setTextureState(
225            dstTexture,
226            dstSubresource,
227            ResourceState::CopySource);
228            
229        queue->submit(encoder->finish());
230        queue->waitOnHost();
231    }
232
233    void checkTestResults(
234        int pixelCount,
235        int channelCount,
236        const int* testXCoords,
237        const int* testYCoords,
238        float* testResults)
239    {
240        // Read texture values back from four specific pixels located within the triangles
241        // and compare against expected values (because testing every single pixel will be too long
242        // and tedious and requires maintaining reference images).
243        ComPtr<ISlangBlob> resultBlob;
244        size_t rowPitch = 0;
245        size_t pixelSize = 0;
246        GFX_CHECK_CALL_ABORT(device->readTexture(
247            dstTexture,
248            0, // layer
249            0, // mip
250            resultBlob.writeRef(),
251            nullptr)); // SubresourceLayout output is optional
252        auto result = (float*)resultBlob->getBufferPointer();
253
254        int cursor = 0;
255        for (int i = 0; i < pixelCount; ++i)
256        {
257            auto x = testXCoords[i];
258            auto y = testYCoords[i];
259            auto pixelPtr = result + x * channelCount + y * rowPitch / sizeof(float);
260            for (int j = 0; j < channelCount; ++j)
261            {
262                testResults[cursor] = pixelPtr[j];
263                cursor++;
264            }
265        }
266
267        float expectedResult[] = {0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f,
268                                  1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f,
269                                  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f};
270        SLANG_CHECK(memcmp(testResults, expectedResult, 128) == 0);
271    }
272};
273
274struct ResolveResourceSimple : BaseResolveResourceTest
275{
276    void run()
277    {
278        Extent3D extent = {};
279        extent.width = kWidth;
280        extent.height = kHeight;
281        extent.depth = 1;
282
283        TextureInfo msaaTextureInfo = {extent, 1, 1, nullptr};
284        TextureInfo dstTextureInfo = {extent, 1, 1, nullptr};
285
286        createRequiredResources(msaaTextureInfo, dstTextureInfo, format);
287
288        SubresourceRange msaaSubresource = {};
289        msaaSubresource.layer = 0;
290        msaaSubresource.layerCount = 1;
291        msaaSubresource.mip = 0;
292        msaaSubresource.mipCount = 1;
293
294        SubresourceRange dstSubresource = {};
295        dstSubresource.layer = 0;
296        dstSubresource.layerCount = 1;
297        dstSubresource.mip = 0;
298        dstSubresource.mipCount = 1;
299
300        submitGPUWork(msaaSubresource, dstSubresource, extent);
301
302        const int kPixelCount = 8;
303        const int kChannelCount = 4;
304        int testXCoords[kPixelCount] = {64, 127, 191, 64, 191, 64, 127, 191};
305        int testYCoords[kPixelCount] = {64, 64, 64, 127, 127, 191, 191, 191};
306        float testResults[kPixelCount * kChannelCount];
307
308        checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults);
309    }
310};
311
312template<typename T>
313void resolveResourceTestImpl(IDevice* device, UnitTestContext* context)
314{
315    T test;
316    test.init(device, context);
317    test.run();
318}
319} // namespace
320
321namespace gfx_test
322{
323SLANG_UNIT_TEST(resolveResourceSimpleD3D12)
324{
325    runTestImpl(
326        resolveResourceTestImpl<ResolveResourceSimple>,
327        unitTestContext,
328        DeviceType::D3D12);
329}
330
331SLANG_UNIT_TEST(resolveResourceSimpleVulkan)
332{
333    runTestImpl(
334        resolveResourceTestImpl<ResolveResourceSimple>,
335        unitTestContext,
336        DeviceType::Vulkan);
337}
338} // namespace gfx_test
339
340#endif