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
12.2 KiB367 linesraw
1// gui.cpp
2#include "gui.h"
3
4#ifdef _WIN32
5#include <examples/imgui_impl_win32.h>
6#include <windows.h>
7IMGUI_IMPL_API LRESULT
8ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
9#endif
10
11using namespace rhi;
12
13namespace platform
14{
15
16#ifdef _WIN32
17LRESULT CALLBACK guiWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
18{
19    LRESULT handled = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);
20    if (handled)
21        return handled;
22    ImGuiIO& io = ImGui::GetIO();
23
24    switch (msg)
25    {
26    case WM_LBUTTONDOWN:
27    case WM_LBUTTONUP:
28        if (io.WantCaptureMouse)
29            handled = 1;
30        break;
31
32    case WM_KEYDOWN:
33    case WM_KEYUP:
34        if (io.WantCaptureKeyboard)
35            handled = 1;
36        break;
37    }
38
39    return handled;
40}
41#endif
42
43
44GUI::GUI(Window* window, IDevice* inDevice, ICommandQueue* inQueue)
45    : device(inDevice), queue(inQueue)
46{
47    ImGui::CreateContext();
48    ImGuiIO& io = ImGui::GetIO();
49
50#ifdef _WIN32
51    ImGui_ImplWin32_Init((HWND)window->getNativeHandle().handleValues[0]);
52#endif
53
54    // Let's do the initialization work required for our graphics API
55    // abstraction layer, so that we can pipe all IMGUI rendering
56    // through the same interface as other work.
57    //
58
59    static const char* shaderCode = "cbuffer U { float4x4 mvp; };           \
60    Texture2D t;                            \
61    SamplerState s;                         \
62    struct AssembledVertex {                \
63        float2 pos;                         \
64        float2 uv;                          \
65        float4 col;                         \
66    };                                      \
67    struct CoarseVertex {                   \
68        float4 col;                         \
69        float2 uv;                          \
70    };                                      \
71    struct VSOutput {                       \
72        CoarseVertex cv : U;                \
73        float4 pos : SV_Position;           \
74    };                                      \
75    void vertexMain(                        \
76        AssembledVertex i : U,              \
77        out VSOutput    o)                  \
78    {                                       \
79        o.cv.col = i.col;                   \
80        o.cv.uv = i.uv;                     \
81        o.pos = mul(mvp,                    \
82            float4(i.pos.xy, 0.f, 1.f));    \
83    }                                       \
84    float4 fragmentMain(                    \
85        CoarseVertex     i : U)             \
86        : SV_target                         \
87    {                                       \
88        return i.col * t.Sample(s, i.uv);   \
89    }                                       \
90    ";
91
92    auto slangSession = inDevice->getSlangSession();
93
94    // TODO: create slang program.
95    // For now, we'll proceed without a proper shader program
96    // This is a limitation that would need to be addressed for full functionality
97#if 0
98    ShaderProgramDesc programDesc = {};
99    programDesc.slangGlobalScope = slangGlobalScope;
100    shaderProgram = device->createShaderProgram(programDesc);
101#endif
102
103    InputElementDesc inputElements[] = {
104        {"U", 0, Format::RG32Float, offsetof(ImDrawVert, pos)},
105        {"U", 1, Format::RG32Float, offsetof(ImDrawVert, uv)},
106        {"U", 2, Format::RGBA8Unorm, offsetof(ImDrawVert, col)},
107    };
108    inputLayout = device->createInputLayout(
109        sizeof(ImDrawVert),
110        &inputElements[0],
111        SLANG_COUNT_OF(inputElements));
112
113    // For now, skip pipeline creation since we don't have a shader program
114    // This would need to be completed for full functionality
115#if 0
116    ColorTargetDesc colorTarget;
117    colorTarget.format = Format::RGBA8Unorm;
118    colorTarget.enableBlend = true;
119    colorTarget.color.srcFactor = BlendFactor::SrcAlpha;
120    colorTarget.color.dstFactor = BlendFactor::InvSrcAlpha;
121    colorTarget.alpha.srcFactor = BlendFactor::InvSrcAlpha;
122    colorTarget.alpha.dstFactor = BlendFactor::Zero;
123
124    RenderPipelineDesc pipelineDesc;
125    pipelineDesc.program = shaderProgram;
126    pipelineDesc.inputLayout = inputLayout;
127    pipelineDesc.targetCount = 1;
128    pipelineDesc.targets = &colorTarget;
129    pipelineDesc.rasterizer.cullMode = CullMode::None;
130    pipelineDesc.depthStencil.depthTestEnable = false;
131    pipelineDesc.primitiveTopology = PrimitiveTopology::TriangleList;
132
133    pipelineState = device->createRenderPipeline(pipelineDesc);
134#endif
135
136    // Initialize the texture atlas
137    unsigned char* pixels;
138    int width, height;
139    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
140
141    {
142        TextureDesc desc = {};
143        desc.type = TextureType::Texture2D;
144        desc.format = Format::RGBA8Unorm;
145        desc.arrayLength = 1;
146        desc.size.width = width;
147        desc.size.height = height;
148        desc.size.depth = 1;
149        desc.mipCount = 1;
150        desc.usage = TextureUsage::ShaderResource;
151        desc.defaultState = ResourceState::ShaderResource;
152
153        SubresourceData initData = {};
154        initData.data = pixels;
155        initData.rowPitch = width * 4 * sizeof(unsigned char);
156        initData.slicePitch = initData.rowPitch * height;
157
158        auto texture = device->createTexture(desc, &initData);
159
160        TextureViewDesc viewDesc;
161        viewDesc.format = desc.format;
162        viewDesc.aspect = TextureAspect::All;
163        auto textureView = device->createTextureView(texture, viewDesc);
164
165        io.Fonts->TexID = (void*)textureView.detach();
166    }
167
168    {
169        SamplerDesc desc;
170        samplerState = device->createSampler(desc);
171    }
172}
173
174
175void GUI::beginFrame()
176{
177#ifdef _WIN32
178    ImGui_ImplWin32_NewFrame();
179#endif
180    ImGui::NewFrame();
181}
182
183void GUI::endFrame(ITexture* renderTarget)
184{
185    ImGui::Render();
186
187    ImDrawData* draw_data = ImGui::GetDrawData();
188    auto vertexCount = draw_data->TotalVtxCount;
189    auto indexCount = draw_data->TotalIdxCount;
190    int commandListCount = draw_data->CmdListsCount;
191
192    if (!vertexCount)
193        return;
194    if (!indexCount)
195        return;
196    if (!commandListCount)
197        return;
198
199        // For now, skip rendering since we don't have a complete pipeline
200        // This would need shader program creation to work properly
201#if 0
202    // Create vertex and index buffers for this frame
203    BufferDesc vertexBufferDesc;
204    vertexBufferDesc.size = vertexCount * sizeof(ImDrawVert);
205    vertexBufferDesc.usage = BufferUsage::VertexBuffer | BufferUsage::CopyDestination;
206    vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
207    vertexBufferDesc.memoryType = MemoryType::Upload;
208    auto vertexBuffer = device->createBuffer(vertexBufferDesc);
209
210    BufferDesc indexBufferDesc;
211    indexBufferDesc.size = indexCount * sizeof(ImDrawIdx);
212    indexBufferDesc.usage = BufferUsage::IndexBuffer | BufferUsage::CopyDestination;
213    indexBufferDesc.defaultState = ResourceState::IndexBuffer;
214    indexBufferDesc.memoryType = MemoryType::Upload;
215    auto indexBuffer = device->createBuffer(indexBufferDesc);
216
217    // Upload vertex and index data
218    {
219        void* vertexData;
220        device->mapBuffer(vertexBuffer, CpuAccessMode::Write, &vertexData);
221        size_t vertexOffset = 0;
222        for (int ii = 0; ii < commandListCount; ++ii)
223        {
224            const ImDrawList* commandList = draw_data->CmdLists[ii];
225            size_t dataSize = commandList->VtxBuffer.Size * sizeof(ImDrawVert);
226            memcpy((char*)vertexData + vertexOffset, commandList->VtxBuffer.Data, dataSize);
227            vertexOffset += dataSize;
228        }
229        device->unmapBuffer(vertexBuffer);
230
231        void* indexData;
232        device->mapBuffer(indexBuffer, CpuAccessMode::Write, &indexData);
233        size_t indexOffset = 0;
234        for (int ii = 0; ii < commandListCount; ++ii)
235        {
236            const ImDrawList* commandList = draw_data->CmdLists[ii];
237            size_t dataSize = commandList->IdxBuffer.Size * sizeof(ImDrawIdx);
238            memcpy((char*)indexData + indexOffset, commandList->IdxBuffer.Data, dataSize);
239            indexOffset += dataSize;
240        }
241        device->unmapBuffer(indexBuffer);
242    }
243
244    // Create constant buffer for projection matrix
245    BufferDesc constantBufferDesc;
246    constantBufferDesc.size = sizeof(glm::mat4x4);
247    constantBufferDesc.usage = BufferUsage::ConstantBuffer | BufferUsage::CopyDestination;
248    constantBufferDesc.defaultState = ResourceState::ConstantBuffer;
249    constantBufferDesc.memoryType = MemoryType::Upload;
250    auto constantBuffer = device->createBuffer(constantBufferDesc);
251
252    {
253        float L = draw_data->DisplayPos.x;
254        float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
255        float T = draw_data->DisplayPos.y;
256        float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
257        float mvp[4][4] = {
258            {2.0f / (R - L), 0.0f, 0.0f, 0.0f},
259            {0.0f, 2.0f / (T - B), 0.0f, 0.0f},
260            {0.0f, 0.0f, 0.5f, 0.0f},
261            {(R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f},
262        };
263
264        void* constantData;
265        device->mapBuffer(constantBuffer, CpuAccessMode::Write, &constantData);
266        memcpy(constantData, mvp, sizeof(mvp));
267        device->unmapBuffer(constantBuffer);
268    }
269
270    // Record rendering commands
271    auto commandEncoder = queue->createCommandEncoder();
272    
273    ComPtr<ITextureView> renderTargetView = device->createTextureView(renderTarget, {});
274    RenderPassColorAttachment colorAttachment = {};
275    colorAttachment.view = renderTargetView;
276    colorAttachment.loadOp = LoadOp::Load;
277    colorAttachment.storeOp = StoreOp::Store;
278
279    RenderPassDesc renderPass = {};
280    renderPass.colorAttachments = &colorAttachment;
281    renderPass.colorAttachmentCount = 1;
282
283    auto renderEncoder = commandEncoder->beginRenderPass(renderPass);
284
285    RenderState renderState = {};
286    renderState.viewports[0] = Viewport::fromSize(draw_data->DisplaySize.x, draw_data->DisplaySize.y);
287    renderState.viewportCount = 1;
288    renderState.vertexBuffers[0] = vertexBuffer;
289    renderState.vertexBufferCount = 1;
290    renderState.indexBuffer = indexBuffer;
291    renderState.indexFormat = sizeof(ImDrawIdx) == 2 ? IndexFormat::Uint16 : IndexFormat::Uint32;
292
293    auto rootObject = renderEncoder->bindPipeline(pipelineState);
294    renderEncoder->setRenderState(renderState);
295
296    uint32_t vertexOffset = 0;
297    uint32_t indexOffset = 0;
298    ImVec2 pos = draw_data->DisplayPos;
299    for (int ii = 0; ii < commandListCount; ++ii)
300    {
301        auto commandList = draw_data->CmdLists[ii];
302        auto commandCount = commandList->CmdBuffer.Size;
303        for (int jj = 0; jj < commandCount; jj++)
304        {
305            auto command = &commandList->CmdBuffer[jj];
306            if (auto userCallback = command->UserCallback)
307            {
308                userCallback(commandList, command);
309            }
310            else
311            {
312                ScissorRect rect = {
313                    (uint32_t)(command->ClipRect.x - pos.x),
314                    (uint32_t)(command->ClipRect.y - pos.y),
315                    (uint32_t)(command->ClipRect.z - pos.x),
316                    (uint32_t)(command->ClipRect.w - pos.y)};
317                
318                RenderState scissorState = renderState;
319                scissorState.scissorRects[0] = rect;
320                scissorState.scissorRectCount = 1;
321                renderEncoder->setRenderState(scissorState);
322
323                DrawArguments drawArgs = {};
324                drawArgs.vertexCount = command->ElemCount;
325                drawArgs.startIndexLocation = indexOffset;
326                drawArgs.startVertexLocation = vertexOffset;
327                renderEncoder->drawIndexed(drawArgs);
328            }
329            indexOffset += command->ElemCount;
330        }
331        vertexOffset += commandList->VtxBuffer.Size;
332    }
333    
334    renderEncoder->end();
335    queue->submit(commandEncoder->finish());
336#endif
337}
338
339GUI::~GUI()
340{
341    auto& io = ImGui::GetIO();
342
343    {
344        Slang::ComPtr<ITextureView> textureView;
345        textureView.attach((ITextureView*)io.Fonts->TexID);
346        textureView = nullptr;
347    }
348
349#ifdef _WIN32
350    ImGui_ImplWin32_Shutdown();
351#endif
352
353    ImGui::DestroyContext();
354}
355
356} // namespace platform
357
358#include <imgui.cpp>
359#include <imgui_draw.cpp>
360#include <imgui_widgets.cpp>
361#ifdef _WIN32
362  // imgui_impl_win32 defines these, so make sure it doesn't error because
363// they're already there
364#undef WIN32_LEAN_AND_MEAN
365#undef NOMINMAX
366#include <examples/imgui_impl_win32.cpp>
367#endif