yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
43d0c2100
master
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{ 19LRESULT handled = ImGui_ImplWin32_WndProcHandler (hWnd ,msg ,wParam ,lParam ); 20if (handled ) 21return handled ; 22ImGuiIO & io = ImGui ::GetIO (); 23 24switch (msg ) 25 { 26case WM_LBUTTONDOWN : 27case WM_LBUTTONUP : 28if (io .WantCaptureMouse ) 29handled = 1 ; 30break ; 31 32case WM_KEYDOWN : 33case WM_KEYUP : 34if (io .WantCaptureKeyboard ) 35handled = 1 ; 36break ; 37 } 38 39return handled ; 40} 41#endif 42 43 44GUI ::GUI (Window * window ,IDevice * inDevice ,ICommandQueue * inQueue ) 45 :device (inDevice ),queue (inQueue ) 46{ 47ImGui ::CreateContext (); 48ImGuiIO & io = ImGui ::GetIO (); 49 50#ifdef _WIN32 51ImGui_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 59static const char * shaderCode = "cbuffer U { float4x4 mvp; }; \ 60Texture2D t; \ 61SamplerState s; \ 62struct AssembledVertex { \ 63float2 pos; \ 64float2 uv; \ 65float4 col; \ 66}; \ 67struct CoarseVertex { \ 68float4 col; \ 69float2 uv; \ 70}; \ 71struct VSOutput { \ 72CoarseVertex cv : U; \ 73float4 pos : SV_Position; \ 74}; \ 75void vertexMain( \ 76AssembledVertex i : U, \ 77out VSOutput o) \ 78{ \ 79o.cv.col = i.col; \ 80o.cv.uv = i.uv; \ 81o.pos = mul(mvp, \ 82float4(i.pos.xy, 0.f, 1.f)); \ 83} \ 84float4 fragmentMain( \ 85CoarseVertex i : U) \ 86: SV_target \ 87{ \ 88return i.col * t.Sample(s, i.uv); \ 89} \ 90" ; 91 92auto 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 98ShaderProgramDesc programDesc = {}; 99programDesc .slangGlobalScope = slangGlobalScope ; 100shaderProgram = device -> createShaderProgram (programDesc ); 101#endif 102 103InputElementDesc 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 }; 108inputLayout = device -> createInputLayout ( 109sizeof (ImDrawVert ), 110& inputElements [0 ], 111SLANG_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 116ColorTargetDesc colorTarget ; 117colorTarget .format = Format ::RGBA8Unorm ; 118colorTarget .enableBlend = true; 119colorTarget .color .srcFactor = BlendFactor ::SrcAlpha ; 120colorTarget .color .dstFactor = BlendFactor ::InvSrcAlpha ; 121colorTarget .alpha .srcFactor = BlendFactor ::InvSrcAlpha ; 122colorTarget .alpha .dstFactor = BlendFactor ::Zero ; 123 124RenderPipelineDesc pipelineDesc ; 125pipelineDesc .program = shaderProgram ; 126pipelineDesc .inputLayout = inputLayout ; 127pipelineDesc .targetCount = 1 ; 128pipelineDesc .targets = & colorTarget ; 129pipelineDesc .rasterizer .cullMode = CullMode ::None ; 130pipelineDesc .depthStencil .depthTestEnable = false; 131pipelineDesc .primitiveTopology = PrimitiveTopology ::TriangleList ; 132 133pipelineState = device -> createRenderPipeline (pipelineDesc ); 134#endif 135 136// Initialize the texture atlas 137unsigned char * pixels ; 138int width ,height ; 139io .Fonts -> GetTexDataAsRGBA32 (& pixels ,& width ,& height ); 140 141 { 142TextureDesc desc = {}; 143desc .type = TextureType ::Texture2D ; 144desc .format = Format ::RGBA8Unorm ; 145desc .arrayLength = 1 ; 146desc .size .width = width ; 147desc .size .height = height ; 148desc .size .depth = 1 ; 149desc .mipCount = 1 ; 150desc .usage = TextureUsage ::ShaderResource ; 151desc .defaultState = ResourceState ::ShaderResource ; 152 153SubresourceData initData = {}; 154initData .data = pixels ; 155initData .rowPitch = width * 4 * sizeof (unsigned char ); 156initData .slicePitch = initData .rowPitch * height ; 157 158auto texture = device -> createTexture (desc ,& initData ); 159 160TextureViewDesc viewDesc ; 161viewDesc .format = desc .format ; 162viewDesc .aspect = TextureAspect ::All ; 163auto textureView = device -> createTextureView (texture ,viewDesc ); 164 165io .Fonts -> TexID = (void * )textureView .detach (); 166 } 167 168 { 169SamplerDesc desc ; 170samplerState = device -> createSampler (desc ); 171 } 172} 173 174 175void GUI ::beginFrame () 176{ 177#ifdef _WIN32 178ImGui_ImplWin32_NewFrame (); 179#endif 180ImGui ::NewFrame (); 181} 182 183void GUI ::endFrame (ITexture * renderTarget ) 184{ 185ImGui ::Render (); 186 187ImDrawData * draw_data = ImGui ::GetDrawData (); 188auto vertexCount = draw_data -> TotalVtxCount ; 189auto indexCount = draw_data -> TotalIdxCount ; 190int commandListCount = draw_data -> CmdListsCount ; 191 192if (!vertexCount ) 193return ; 194if (!indexCount ) 195return ; 196if (!commandListCount ) 197return ; 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 203BufferDesc vertexBufferDesc ; 204vertexBufferDesc .size = vertexCount * sizeof (ImDrawVert ); 205vertexBufferDesc .usage = BufferUsage ::VertexBuffer |BufferUsage ::CopyDestination ; 206vertexBufferDesc .defaultState = ResourceState ::VertexBuffer ; 207vertexBufferDesc .memoryType = MemoryType ::Upload ; 208auto vertexBuffer = device -> createBuffer (vertexBufferDesc ); 209 210BufferDesc indexBufferDesc ; 211indexBufferDesc .size = indexCount * sizeof (ImDrawIdx ); 212indexBufferDesc .usage = BufferUsage ::IndexBuffer |BufferUsage ::CopyDestination ; 213indexBufferDesc .defaultState = ResourceState ::IndexBuffer ; 214indexBufferDesc .memoryType = MemoryType ::Upload ; 215auto indexBuffer = device -> createBuffer (indexBufferDesc ); 216 217// Upload vertex and index data 218 { 219void * vertexData ; 220device -> mapBuffer (vertexBuffer ,CpuAccessMode ::Write ,& vertexData ); 221size_t vertexOffset = 0 ; 222for (int ii = 0 ;ii < commandListCount ;++ ii ) 223 { 224const ImDrawList * commandList = draw_data -> CmdLists [ii ]; 225size_t dataSize = commandList -> VtxBuffer .Size * sizeof (ImDrawVert ); 226memcpy ((char * )vertexData + vertexOffset ,commandList -> VtxBuffer .Data ,dataSize ); 227vertexOffset += dataSize ; 228 } 229device -> unmapBuffer (vertexBuffer ); 230 231void * indexData ; 232device -> mapBuffer (indexBuffer ,CpuAccessMode ::Write ,& indexData ); 233size_t indexOffset = 0 ; 234for (int ii = 0 ;ii < commandListCount ;++ ii ) 235 { 236const ImDrawList * commandList = draw_data -> CmdLists [ii ]; 237size_t dataSize = commandList -> IdxBuffer .Size * sizeof (ImDrawIdx ); 238memcpy ((char * )indexData + indexOffset ,commandList -> IdxBuffer .Data ,dataSize ); 239indexOffset += dataSize ; 240 } 241device -> unmapBuffer (indexBuffer ); 242 } 243 244// Create constant buffer for projection matrix 245BufferDesc constantBufferDesc ; 246constantBufferDesc .size = sizeof (glm::mat4x4 ); 247constantBufferDesc .usage = BufferUsage ::ConstantBuffer |BufferUsage ::CopyDestination ; 248constantBufferDesc .defaultState = ResourceState ::ConstantBuffer ; 249constantBufferDesc .memoryType = MemoryType ::Upload ; 250auto constantBuffer = device -> createBuffer (constantBufferDesc ); 251 252 { 253float L = draw_data -> DisplayPos .x ; 254float R = draw_data -> DisplayPos .x + draw_data -> DisplaySize .x ; 255float T = draw_data -> DisplayPos .y ; 256float B = draw_data -> DisplayPos .y + draw_data -> DisplaySize .y ; 257float 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 264void * constantData ; 265device -> mapBuffer (constantBuffer ,CpuAccessMode ::Write ,& constantData ); 266memcpy (constantData ,mvp ,sizeof (mvp )); 267device -> unmapBuffer (constantBuffer ); 268 } 269 270// Record rendering commands 271auto commandEncoder = queue -> createCommandEncoder (); 272 273ComPtr < ITextureView > renderTargetView = device -> createTextureView (renderTarget , {}); 274RenderPassColorAttachment colorAttachment = {}; 275colorAttachment .view = renderTargetView ; 276colorAttachment .loadOp = LoadOp ::Load ; 277colorAttachment .storeOp = StoreOp ::Store ; 278 279RenderPassDesc renderPass = {}; 280renderPass .colorAttachments = & colorAttachment ; 281renderPass .colorAttachmentCount = 1 ; 282 283auto renderEncoder = commandEncoder -> beginRenderPass (renderPass ); 284 285RenderState renderState = {}; 286renderState .viewports [0 ]= Viewport ::fromSize (draw_data -> DisplaySize .x ,draw_data -> DisplaySize .y ); 287renderState .viewportCount = 1 ; 288renderState .vertexBuffers [0 ]= vertexBuffer ; 289renderState .vertexBufferCount = 1 ; 290renderState .indexBuffer = indexBuffer ; 291renderState .indexFormat = sizeof (ImDrawIdx )== 2 ?IndexFormat ::Uint16 :IndexFormat ::Uint32 ; 292 293auto rootObject = renderEncoder -> bindPipeline (pipelineState ); 294renderEncoder -> setRenderState (renderState ); 295 296uint32_t vertexOffset = 0 ; 297uint32_t indexOffset = 0 ; 298ImVec2 pos = draw_data -> DisplayPos ; 299for (int ii = 0 ;ii < commandListCount ;++ ii ) 300 { 301auto commandList = draw_data -> CmdLists [ii ]; 302auto commandCount = commandList -> CmdBuffer .Size ; 303for (int jj = 0 ;jj < commandCount ;jj ++ ) 304 { 305auto command = & commandList -> CmdBuffer [jj ]; 306if (auto userCallback = command -> UserCallback ) 307 { 308userCallback (commandList ,command ); 309 } 310else 311 { 312ScissorRect 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 318RenderState scissorState = renderState ; 319scissorState .scissorRects [0 ]= rect ; 320scissorState .scissorRectCount = 1 ; 321renderEncoder -> setRenderState (scissorState ); 322 323DrawArguments drawArgs = {}; 324drawArgs .vertexCount = command -> ElemCount ; 325drawArgs .startIndexLocation = indexOffset ; 326drawArgs .startVertexLocation = vertexOffset ; 327renderEncoder -> drawIndexed (drawArgs ); 328 } 329indexOffset += command -> ElemCount ; 330 } 331vertexOffset += commandList -> VtxBuffer .Size ; 332 } 333 334renderEncoder -> end (); 335queue -> submit (commandEncoder -> finish ()); 336#endif 337} 338 339GUI ::~GUI () 340{ 341auto & io = ImGui ::GetIO (); 342 343 { 344Slang ::ComPtr < ITextureView > textureView ; 345textureView .attach ((ITextureView * )io .Fonts -> TexID ); 346textureView = nullptr ; 347 } 348 349#ifdef _WIN32 350ImGui_ImplWin32_Shutdown (); 351#endif 352 353ImGui ::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