From 8cab5258e5ea90d78d82c1f2657bb2b25e22175a Mon Sep 17 00:00:00 2001 From: Acclution <42910256+Acclution@users.noreply.github.com> Date: Thu, 19 Sep 2024 15:46:32 +0200 Subject: [PATCH] feedback fixes and added a example main --- backends/imgui_impl_sdl3.cpp | 2 +- backends/imgui_impl_sdl3.h | 2 +- backends/imgui_impl_sdlgpu.cpp | 730 ------------------ backends/imgui_impl_sdlgpu3.cpp | 730 ++++++++++++++++++ ...gui_impl_sdlgpu.h => imgui_impl_sdlgpu3.h} | 20 +- examples/example_sdl3_sdlgpu3/Makefile | 73 ++ examples/example_sdl3_sdlgpu3/main.cpp | 220 ++++++ 7 files changed, 1035 insertions(+), 742 deletions(-) delete mode 100644 backends/imgui_impl_sdlgpu.cpp create mode 100644 backends/imgui_impl_sdlgpu3.cpp rename backends/{imgui_impl_sdlgpu.h => imgui_impl_sdlgpu3.h} (67%) create mode 100644 examples/example_sdl3_sdlgpu3/Makefile create mode 100644 examples/example_sdl3_sdlgpu3/main.cpp diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index ad98ef9e1..03a72680b 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -592,7 +592,7 @@ bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere return ImGui_ImplSDL3_Init(window, renderer, nullptr, nullptr); } -bool ImGui_ImplSDL3_InitForSDLGpu(SDL_Window* window, SDL_GPUDevice* device) +bool ImGui_ImplSDL3_InitForSDLGPU3(SDL_Window* window, SDL_GPUDevice* device) { return ImGui_ImplSDL3_Init(window, nullptr, device, nullptr); } diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index da6de41b4..7e73ed8a9 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); -IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLGpu(SDL_Window* window, SDL_GPUDevice* device); +IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLGPU3(SDL_Window* window, SDL_GPUDevice* device); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window); IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame(); diff --git a/backends/imgui_impl_sdlgpu.cpp b/backends/imgui_impl_sdlgpu.cpp deleted file mode 100644 index 45f5d5ef1..000000000 --- a/backends/imgui_impl_sdlgpu.cpp +++ /dev/null @@ -1,730 +0,0 @@ -// dear imgui: Renderer Backend for SDL_GPU for SDL3 -// (Requires: SDL 3.0.0+) - -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) - -// Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as ImTextureID. Read the FAQ about ImTextureID! -// [ ] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// Missing features: -// [ ] Renderer: Multi-viewport support (multiple windows). - -// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - -// CHANGELOG -// 2024-09-19: Initial version. - -#include "imgui.h" -#ifndef IMGUI_DISABLE -#include "imgui_impl_sdlgpu.h" -#include // intptr_t - -// Clang warnings with -Weverything -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness -#endif - -// SDL -#include -#if !SDL_VERSION_ATLEAST(3, 0, 0) -#error This backend requires SDL 3.0.0+ -#endif -#include - -// SDL_GPUDevice data -struct ImGui_ImplSDLGpu_Data -{ - SDL_GPUDevice* Device; // Main viewport's renderer - SDL_Window* Window; - SDL_GPUTexture* FontTexture; - SDL_GPUSampler* FontSampler; - - SDL_GPUGraphicsPipeline* Pipeline; - SDL_GPUShader* ShaderModuleVert; - SDL_GPUShader* ShaderModuleFrag; - - size_t VertexBufferSize; - size_t IndexBufferSize; - SDL_GPUBuffer* VertexBuffer; - SDL_GPUBuffer* IndexBuffer; - - ImGui_ImplSDLGpu_Data() { memset((void*)this, 0, sizeof(*this)); } -}; - -//----------------------------------------------------------------------------- -// SHADERS -//----------------------------------------------------------------------------- - -// backends/vulkan/glsl_shader.vert, compiled with: -// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert -/* -#version 450 core -layout(location = 0) in vec2 aPos; -layout(location = 1) in vec2 aUV; -layout(location = 2) in vec4 aColor; -layout(set = 1, binding = 0) uniform UBO { vec2 uScale; vec2 uTranslate; }; - -out gl_PerVertex { vec4 gl_Position; }; -layout(location = 0) out struct { vec4 Color; vec2 UV; } Out; - -void main() -{ - Out.Color = aColor; - Out.UV = aUV; - gl_Position = vec4(aPos * uScale + uTranslate, 0, 1); -} -*/ -static uint32_t __glsl_shader_vert_spv[] = { - 0x07230203, 0x00010000, 0x0008000b, 0x0000002e, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x000a000f, 0x00000000, 0x00000004, 0x6e69616d, 0x00000000, 0x0000000b, 0x0000000f, 0x00000015, - 0x0000001b, 0x0000001c, 0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00030005, 0x00000009, 0x00000000, - 0x00050006, 0x00000009, 0x00000000, 0x6f6c6f43, 0x00000072, 0x00040006, 0x00000009, 0x00000001, 0x00005655, 0x00030005, 0x0000000b, 0x0074754f, - 0x00040005, 0x0000000f, 0x6c6f4361, 0x0000726f, 0x00030005, 0x00000015, 0x00565561, 0x00060005, 0x00000019, 0x505f6c67, 0x65567265, 0x78657472, - 0x00000000, 0x00060006, 0x00000019, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, 0x00030005, 0x0000001b, 0x00000000, 0x00040005, 0x0000001c, - 0x736f5061, 0x00000000, 0x00030005, 0x0000001e, 0x004f4255, 0x00050006, 0x0000001e, 0x00000000, 0x61635375, 0x0000656c, 0x00060006, 0x0000001e, - 0x00000001, 0x61725475, 0x616c736e, 0x00006574, 0x00030005, 0x00000020, 0x00000000, 0x00040047, 0x0000000b, 0x0000001e, 0x00000000, 0x00040047, - 0x0000000f, 0x0000001e, 0x00000002, 0x00040047, 0x00000015, 0x0000001e, 0x00000001, 0x00050048, 0x00000019, 0x00000000, 0x0000000b, 0x00000000, - 0x00030047, 0x00000019, 0x00000002, 0x00040047, 0x0000001c, 0x0000001e, 0x00000000, 0x00050048, 0x0000001e, 0x00000000, 0x00000023, 0x00000000, - 0x00050048, 0x0000001e, 0x00000001, 0x00000023, 0x00000008, 0x00030047, 0x0000001e, 0x00000002, 0x00040047, 0x00000020, 0x00000022, 0x00000001, - 0x00040047, 0x00000020, 0x00000021, 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, - 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040017, 0x00000008, 0x00000006, 0x00000002, 0x0004001e, 0x00000009, 0x00000007, 0x00000008, - 0x00040020, 0x0000000a, 0x00000003, 0x00000009, 0x0004003b, 0x0000000a, 0x0000000b, 0x00000003, 0x00040015, 0x0000000c, 0x00000020, 0x00000001, - 0x0004002b, 0x0000000c, 0x0000000d, 0x00000000, 0x00040020, 0x0000000e, 0x00000001, 0x00000007, 0x0004003b, 0x0000000e, 0x0000000f, 0x00000001, - 0x00040020, 0x00000011, 0x00000003, 0x00000007, 0x0004002b, 0x0000000c, 0x00000013, 0x00000001, 0x00040020, 0x00000014, 0x00000001, 0x00000008, - 0x0004003b, 0x00000014, 0x00000015, 0x00000001, 0x00040020, 0x00000017, 0x00000003, 0x00000008, 0x0003001e, 0x00000019, 0x00000007, 0x00040020, - 0x0000001a, 0x00000003, 0x00000019, 0x0004003b, 0x0000001a, 0x0000001b, 0x00000003, 0x0004003b, 0x00000014, 0x0000001c, 0x00000001, 0x0004001e, - 0x0000001e, 0x00000008, 0x00000008, 0x00040020, 0x0000001f, 0x00000002, 0x0000001e, 0x0004003b, 0x0000001f, 0x00000020, 0x00000002, 0x00040020, - 0x00000021, 0x00000002, 0x00000008, 0x0004002b, 0x00000006, 0x00000028, 0x00000000, 0x0004002b, 0x00000006, 0x00000029, 0x3f800000, 0x00050036, - 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x00000007, 0x00000010, 0x0000000f, 0x00050041, 0x00000011, - 0x00000012, 0x0000000b, 0x0000000d, 0x0003003e, 0x00000012, 0x00000010, 0x0004003d, 0x00000008, 0x00000016, 0x00000015, 0x00050041, 0x00000017, - 0x00000018, 0x0000000b, 0x00000013, 0x0003003e, 0x00000018, 0x00000016, 0x0004003d, 0x00000008, 0x0000001d, 0x0000001c, 0x00050041, 0x00000021, - 0x00000022, 0x00000020, 0x0000000d, 0x0004003d, 0x00000008, 0x00000023, 0x00000022, 0x00050085, 0x00000008, 0x00000024, 0x0000001d, 0x00000023, - 0x00050041, 0x00000021, 0x00000025, 0x00000020, 0x00000013, 0x0004003d, 0x00000008, 0x00000026, 0x00000025, 0x00050081, 0x00000008, 0x00000027, - 0x00000024, 0x00000026, 0x00050051, 0x00000006, 0x0000002a, 0x00000027, 0x00000000, 0x00050051, 0x00000006, 0x0000002b, 0x00000027, 0x00000001, - 0x00070050, 0x00000007, 0x0000002c, 0x0000002a, 0x0000002b, 0x00000028, 0x00000029, 0x00050041, 0x00000011, 0x0000002d, 0x0000001b, 0x0000000d, - 0x0003003e, 0x0000002d, 0x0000002c, 0x000100fd, 0x00010038}; - -// backends/vulkan/glsl_shader.frag, compiled with: -// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag -/* -#version 450 core -layout(location = 0) out vec4 fColor; -layout(set=2, binding=0) uniform sampler2D sTexture; -layout(location = 0) in struct { vec4 Color; vec2 UV; } In; -void main() -{ - fColor = In.Color * texture(sTexture, In.UV.st); -} -*/ -static uint32_t __glsl_shader_frag_spv[] = { - 0x07230203, 0x00010000, 0x0008000b, 0x0000001e, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000004, 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, 0x0000000d, 0x00030010, - 0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00040005, 0x00000009, 0x6c6f4366, - 0x0000726f, 0x00030005, 0x0000000b, 0x00000000, 0x00050006, 0x0000000b, 0x00000000, 0x6f6c6f43, 0x00000072, 0x00040006, 0x0000000b, 0x00000001, - 0x00005655, 0x00030005, 0x0000000d, 0x00006e49, 0x00050005, 0x00000016, 0x78655473, 0x65727574, 0x00000000, 0x00040047, 0x00000009, 0x0000001e, - 0x00000000, 0x00040047, 0x0000000d, 0x0000001e, 0x00000000, 0x00040047, 0x00000016, 0x00000022, 0x00000002, 0x00040047, 0x00000016, 0x00000021, - 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, - 0x00000004, 0x00040020, 0x00000008, 0x00000003, 0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, 0x00040017, 0x0000000a, 0x00000006, - 0x00000002, 0x0004001e, 0x0000000b, 0x00000007, 0x0000000a, 0x00040020, 0x0000000c, 0x00000001, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, - 0x00000001, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x00040020, 0x00000010, 0x00000001, - 0x00000007, 0x00090019, 0x00000013, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x00000014, - 0x00000013, 0x00040020, 0x00000015, 0x00000000, 0x00000014, 0x0004003b, 0x00000015, 0x00000016, 0x00000000, 0x0004002b, 0x0000000e, 0x00000018, - 0x00000001, 0x00040020, 0x00000019, 0x00000001, 0x0000000a, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x00050041, 0x00000010, 0x00000011, 0x0000000d, 0x0000000f, 0x0004003d, 0x00000007, 0x00000012, 0x00000011, 0x0004003d, 0x00000014, 0x00000017, - 0x00000016, 0x00050041, 0x00000019, 0x0000001a, 0x0000000d, 0x00000018, 0x0004003d, 0x0000000a, 0x0000001b, 0x0000001a, 0x00050057, 0x00000007, - 0x0000001c, 0x00000017, 0x0000001b, 0x00050085, 0x00000007, 0x0000001d, 0x00000012, 0x0000001c, 0x0003003e, 0x00000009, 0x0000001d, 0x000100fd, - 0x00010038}; - -// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts -// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple -// Dear ImGui contexts. -static ImGui_ImplSDLGpu_Data* ImGui_ImplSDLGpu_GetBackendData() -{ - return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGpu_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; -} - -static void ImGui_ImplSDLGpu_CreateShaderModules() -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - - SDL_GPUDriver driver = SDL_GetGPUDriver(bd->Device); - if(bd->ShaderModuleVert == nullptr) - { - SDL_GPUShaderCreateInfo vert_info{}; - vert_info.stage = SDL_GPU_SHADERSTAGE_VERTEX; - vert_info.entrypoint = "main"; - vert_info.num_uniform_buffers = 1; // UBO set 1 binding 0 - - if(driver == SDL_GPU_DRIVER_VULKAN) - { - vert_info.code_size = sizeof(__glsl_shader_vert_spv); - vert_info.code = (uint8_t*)__glsl_shader_vert_spv; - vert_info.format = SDL_GPU_SHADERFORMAT_SPIRV; - } - // TODO: Add other shader drivers here - - bd->ShaderModuleVert = SDL_CreateGPUShader(bd->Device, &vert_info); - if(bd->ShaderModuleVert == nullptr) - { - SDL_Log("error creating vertex shader module: %s", SDL_GetError()); - } - } - - if(bd->ShaderModuleFrag == nullptr) - { - SDL_GPUShaderCreateInfo frag_info{}; - frag_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT; - frag_info.entrypoint = "main"; - frag_info.num_samplers = 1; // sTexture set 0 binding 0 - - if(driver == SDL_GPU_DRIVER_VULKAN) - { - frag_info.code_size = sizeof(__glsl_shader_frag_spv); - frag_info.code = (uint8_t*)__glsl_shader_frag_spv; - frag_info.format = SDL_GPU_SHADERFORMAT_SPIRV; - } - // TODO: Add other shader drivers here - - bd->ShaderModuleFrag = SDL_CreateGPUShader(bd->Device, &frag_info); - if(bd->ShaderModuleFrag == nullptr) - { - SDL_Log("error creating fragment shader module: %s", SDL_GetError()); - } - } -} - -static void ImGui_ImplSDLGpu_DestroyRenderPipeline() -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - if(bd->Pipeline) - { - SDL_ReleaseGPUGraphicsPipeline(bd->Device, bd->Pipeline); - bd->Pipeline = nullptr; - } -} - -static void ImGui_ImplSDLGpu_CreateRenderPipeline() -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - - ImGui_ImplSDLGpu_CreateShaderModules(); - ImGui_ImplSDLGpu_DestroyRenderPipeline(); - - SDL_GPUGraphicsPipelineCreateInfo pipeline_info{}; - - SDL_GPUColorTargetDescription color_attachment_desc{}; - color_attachment_desc.blend_state.color_write_mask = - SDL_GPU_COLORCOMPONENT_R | SDL_GPU_COLORCOMPONENT_G | SDL_GPU_COLORCOMPONENT_B | SDL_GPU_COLORCOMPONENT_A; - color_attachment_desc.blend_state.enable_blend = true; - color_attachment_desc.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA; - color_attachment_desc.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - color_attachment_desc.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD; - color_attachment_desc.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE; - color_attachment_desc.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - color_attachment_desc.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD; - color_attachment_desc.format = SDL_GetGPUSwapchainTextureFormat(bd->Device, bd->Window); - - pipeline_info.target_info.num_color_targets = 1; - pipeline_info.target_info.color_target_descriptions = &color_attachment_desc; - pipeline_info.target_info.has_depth_stencil_target = false; - - pipeline_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1; - pipeline_info.multisample_state.sample_mask = 0xf; - - pipeline_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; - - pipeline_info.vertex_shader = bd->ShaderModuleVert; - pipeline_info.fragment_shader = bd->ShaderModuleFrag; - - pipeline_info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE; - pipeline_info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE; - pipeline_info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL; - - SDL_GPUVertexBufferDescription binding_desc[1]{}; - binding_desc[0].slot = 0; - binding_desc[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX; - binding_desc[0].instance_step_rate = 0; - binding_desc[0].pitch = sizeof(ImDrawVert); - - SDL_GPUVertexAttribute attribute_desc[3] = {}; - attribute_desc[0].location = 0; - attribute_desc[0].buffer_slot = binding_desc[0].slot; - attribute_desc[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; - attribute_desc[0].offset = offsetof(ImDrawVert, pos); - attribute_desc[1].location = 1; - attribute_desc[1].buffer_slot = binding_desc[0].slot; - attribute_desc[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; - attribute_desc[1].offset = offsetof(ImDrawVert, uv); - attribute_desc[2].location = 2; - attribute_desc[2].buffer_slot = binding_desc[0].slot; - attribute_desc[2].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM; - attribute_desc[2].offset = offsetof(ImDrawVert, col); - - pipeline_info.vertex_input_state.num_vertex_buffers = 1; - pipeline_info.vertex_input_state.vertex_buffer_descriptions = binding_desc; - pipeline_info.vertex_input_state.num_vertex_attributes = 3; - pipeline_info.vertex_input_state.vertex_attributes = attribute_desc; - - bd->Pipeline = SDL_CreateGPUGraphicsPipeline(bd->Device, &pipeline_info); - if(bd->Pipeline == nullptr) - { - SDL_Log("error creating graphics pipeline: %s", SDL_GetError()); - } -} - -static void ImGui_ImplSDLGpu_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, - SDL_GPURenderPass* render_pass, int fb_width, int fb_height) -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - - // Bind pipeline: - { - SDL_BindGPUGraphicsPipeline(render_pass, pipeline); - } - - // Bind Vertex And Index Buffer: - if(draw_data->TotalVtxCount > 0) - { - SDL_GPUBufferBinding buffer_binding{}; - buffer_binding.buffer = bd->VertexBuffer; - SDL_BindGPUVertexBuffers(render_pass, 0, &buffer_binding, 1); - - buffer_binding.buffer = bd->IndexBuffer; - SDL_BindGPUIndexBuffer(render_pass, &buffer_binding, - sizeof(ImDrawIdx) == 2 ? SDL_GPU_INDEXELEMENTSIZE_16BIT : SDL_GPU_INDEXELEMENTSIZE_32BIT); - - // vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); - } - - // Setup viewport: - { - SDL_GPUViewport viewport{}; - viewport.x = 0; - viewport.y = 0; - viewport.w = (float)fb_width; - viewport.h = (float)fb_height; - viewport.min_depth = 0.0f; - viewport.max_depth = 1.0f; - SDL_SetGPUViewport(render_pass, &viewport); - - SDL_Rect scissor{}; - scissor.x = 0; - scissor.y = 0; - scissor.w = viewport.w; - scissor.h = viewport.h; - SDL_SetGPUScissor(render_pass, &scissor); - } - - // Setup scale and translation: - // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos - // is (0,0) for single viewport apps. - { - float push_data[4]{}; - push_data[0] = 2.0f / draw_data->DisplaySize.x; // scale - push_data[1] = -2.0f / draw_data->DisplaySize.y; // scale - push_data[2] = -1.0f - draw_data->DisplayPos.x * push_data[0]; // translate - push_data[3] = 1.0f - draw_data->DisplayPos.y * push_data[1]; // translate - SDL_PushGPUVertexUniformData(command_buffer, 0, push_data, sizeof(float) * 4); - } -} - -// Functions -bool ImGui_ImplSDLGpu_Init(SDL_GPUDevice* device, SDL_Window* window) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - IM_ASSERT(device != nullptr && "SDL_Gpu not initialized!"); - - // Setup backend capabilities flags - ImGui_ImplSDLGpu_Data* bd = IM_NEW(ImGui_ImplSDLGpu_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_sdlgpu"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - - bd->Device = device; - bd->Window = window; - - return true; -} - -void ImGui_ImplSDLGpu_Shutdown() -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - - ImGui_ImplSDLGpu_DestroyDeviceObjects(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; - IM_DELETE(bd); -} - -void ImGui_ImplSDLGpu_NewFrame() -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLGpu_Init()?"); - - if(!bd->FontTexture) ImGui_ImplSDLGpu_CreateDeviceObjects(); -} - -void ImGui_ImplSDLGpu_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* cmd, SDL_GPUTexture* render_target) -{ - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - - // If there's a scale factor set by the user, use that instead - // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass - // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here. - float rsx = 1.0f; - float rsy = 1.0f; - // SDL_GetRenderScale(renderer, &rsx, &rsy); - ImVec2 render_scale; - render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; - render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; - - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); - int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); - if(fb_width == 0 || fb_height == 0) return; - - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = render_scale; - - // Copy over the vertices and indices - if(draw_data->TotalVtxCount > 0) - { - // Create or resize the vertex/index buffers - size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); - size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - if(bd->VertexBuffer == nullptr || bd->VertexBufferSize < vertex_size) - { - if(bd->VertexBuffer != nullptr) - { - SDL_ReleaseGPUBuffer(bd->Device, bd->VertexBuffer); - bd->VertexBuffer = nullptr; - } - SDL_GPUBufferCreateInfo info{}; - info.size = vertex_size; - info.usage = SDL_GPU_BUFFERUSAGE_VERTEX; - bd->VertexBuffer = SDL_CreateGPUBuffer(bd->Device, &info); - bd->VertexBufferSize = vertex_size; - SDL_SetGPUBufferName(bd->Device, bd->VertexBuffer, "ImguiVertexBuffer"); - } - if(bd->IndexBuffer == nullptr || bd->IndexBufferSize < index_size) - { - if(bd->IndexBuffer != nullptr) - { - SDL_ReleaseGPUBuffer(bd->Device, bd->IndexBuffer); - bd->IndexBuffer = nullptr; - } - SDL_GPUBufferCreateInfo info{}; - info.size = index_size; - info.usage = SDL_GPU_BUFFERUSAGE_INDEX; - bd->IndexBuffer = SDL_CreateGPUBuffer(bd->Device, &info); - bd->IndexBufferSize = index_size; - SDL_SetGPUBufferName(bd->Device, bd->IndexBuffer, "ImguiIndexBuffer"); - } - - // TODO: Reuse the transfer buffer? - SDL_GPUTransferBufferCreateInfo transfer_info{}; - transfer_info.size = vertex_size + index_size; - transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(bd->Device, &transfer_info); - - void* map = SDL_MapGPUTransferBuffer(bd->Device, transfer_buffer, false); - - // Upload vertex/index data into a single contiguous GPU buffer - ImDrawVert* vtx_dst = reinterpret_cast(map); - ImDrawIdx* idx_dst = reinterpret_cast(reinterpret_cast(map) + vertex_size); - - for(int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += cmd_list->VtxBuffer.Size; - idx_dst += cmd_list->IdxBuffer.Size; - } - SDL_UnmapGPUTransferBuffer(bd->Device, transfer_buffer); - - SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); - - SDL_GPUTransferBufferLocation vertex_location{}; - vertex_location.transfer_buffer = transfer_buffer; - vertex_location.offset = 0; - - SDL_GPUTransferBufferLocation index_location{}; - index_location.transfer_buffer = transfer_buffer; - index_location.offset = vertex_size; - - SDL_GPUBufferRegion vertex_region{}; - vertex_region.buffer = bd->VertexBuffer; - vertex_region.offset = 0; - vertex_region.size = vertex_size; - - SDL_GPUBufferRegion index_region{}; - index_region.buffer = bd->IndexBuffer; - index_region.offset = 0; - index_region.size = index_size; - - SDL_UploadToGPUBuffer(copy_pass, &vertex_location, &vertex_region, true); - SDL_UploadToGPUBuffer(copy_pass, &index_location, &index_region, true); - SDL_EndGPUCopyPass(copy_pass); - - SDL_ReleaseGPUTransferBuffer(bd->Device, transfer_buffer); - } - - SDL_GPUColorTargetInfo color_target_info{}; - color_target_info.texture = render_target; - color_target_info.load_op = SDL_GPU_LOADOP_LOAD; - color_target_info.store_op = SDL_GPU_STOREOP_STORE; - - SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(cmd, &color_target_info, 1, nullptr); - - ImGui_ImplSDLGpu_SetupRenderState(draw_data, bd->Pipeline, cmd, render_pass, fb_width, fb_height); - - // Render command lists - // (Because we merged all buffers into a single one, we maintain our own offset into them) - int global_vtx_offset = 0; - int global_idx_offset = 0; - for(int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for(int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if(pcmd->UserCallback != nullptr) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if(pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplSDLGpu_SetupRenderState(draw_data, bd->Pipeline, cmd, render_pass, fb_width, fb_height); - else - pcmd->UserCallback(cmd_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - - // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds - if(clip_min.x < 0.0f) - { - clip_min.x = 0.0f; - } - if(clip_min.y < 0.0f) - { - clip_min.y = 0.0f; - } - if(clip_max.x > fb_width) - { - clip_max.x = (float)fb_width; - } - if(clip_max.y > fb_height) - { - clip_max.y = (float)fb_height; - } - if(clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; - - // Apply scissor/clipping rectangle - SDL_Rect scissor; - scissor.x = (int32_t)(clip_min.x); - scissor.y = (int32_t)(clip_min.y); - scissor.w = (int32_t)(clip_max.x - clip_min.x); - scissor.h = (int32_t)(clip_max.y - clip_min.y); - - SDL_SetGPUScissor(render_pass, &scissor); - - // Bind DescriptorSet with font or user texture - SDL_GPUTextureSamplerBinding texture_binding{}; - texture_binding.sampler = bd->FontSampler; - texture_binding.texture = (SDL_GPUTexture*)pcmd->TextureId; - if(sizeof(ImTextureID) < sizeof(ImU64)) - { - // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures - // haven't been used. - IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontTexture); - texture_binding.texture = bd->FontTexture; - } - SDL_BindGPUFragmentSamplers(render_pass, 0, &texture_binding, 1); - - // Draw - SDL_DrawGPUIndexedPrimitives(render_pass, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, - pcmd->VtxOffset + global_vtx_offset, 0); - } - } - global_idx_offset += cmd_list->IdxBuffer.Size; - global_vtx_offset += cmd_list->VtxBuffer.Size; - } - - SDL_EndGPURenderPass(render_pass); -} - -// Called by Init/NewFrame/Shutdown -bool ImGui_ImplSDLGpu_CreateFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - - // Build texture atlas - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, - &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more - // likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level - // concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to - // allow point/nearest sampling) - SDL_GPUTextureCreateInfo info{}; - info.width = width; - info.height = height; - info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; - info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - info.sample_count = SDL_GPU_SAMPLECOUNT_1; - info.num_levels = 1; - info.type = SDL_GPU_TEXTURETYPE_2D; - info.layer_count_or_depth = 1; - bd->FontTexture = SDL_CreateGPUTexture(bd->Device, &info); - if(bd->FontTexture == nullptr) - { - SDL_Log("error creating texture: %s", SDL_GetError()); - return false; - } - - // First transfer the data to a transfer buffer - SDL_GPUTransferBufferCreateInfo transfer_create_info{}; - transfer_create_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - transfer_create_info.size = 4 * width * height; - SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(bd->Device, &transfer_create_info); - if(!transfer_buffer) - { - SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); - return false; - } - - void* map = SDL_MapGPUTransferBuffer(bd->Device, transfer_buffer, false); - SDL_memcpy(map, pixels, transfer_create_info.size); - SDL_UnmapGPUTransferBuffer(bd->Device, transfer_buffer); - - SDL_GPUTextureLocation location{}; - - auto* cmd = SDL_AcquireGPUCommandBuffer(bd->Device); - auto* copy_pass = SDL_BeginGPUCopyPass(cmd); - - SDL_GPUTextureTransferInfo transfer_info{}; - transfer_info.transfer_buffer = transfer_buffer; - transfer_info.pixels_per_row = width; - transfer_info.rows_per_layer = height; - transfer_info.offset = 0; - - SDL_GPUTextureRegion region{}; - region.texture = bd->FontTexture; - region.x = 0; - region.y = 0; - region.z = 0; - region.w = width; - region.h = height; - region.d = 1; - - SDL_UploadToGPUTexture(copy_pass, &transfer_info, ®ion, false); - SDL_EndGPUCopyPass(copy_pass); - - // Submit the commands - SDL_SubmitGPUCommandBuffer(cmd); - - // No need for the transfer buffer now - SDL_ReleaseGPUTransferBuffer(bd->Device, transfer_buffer); - - SDL_GPUSamplerCreateInfo sampler_info{}; - sampler_info.address_mode_u = sampler_info.address_mode_v = sampler_info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; - sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; - sampler_info.mag_filter = sampler_info.min_filter = SDL_GPU_FILTER_LINEAR; - - bd->FontSampler = SDL_CreateGPUSampler(bd->Device, &sampler_info); - if(!bd->FontSampler) - { - SDL_Log("error creating sampler: %s", SDL_GetError()); - return false; - } - - // SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND); - // SDL_SetTextureScaleMode(bd->FontTexture, SDL_SCALEMODE_LINEAR); - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); - - return true; -} - -void ImGui_ImplSDLGpu_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - if(bd->FontTexture) - { - io.Fonts->SetTexID(0); - - SDL_ReleaseGPUTexture(bd->Device, bd->FontTexture); - SDL_ReleaseGPUSampler(bd->Device, bd->FontSampler); - bd->FontTexture = nullptr; - bd->FontSampler = nullptr; - } -} - -bool ImGui_ImplSDLGpu_CreateDeviceObjects() -{ - ImGui_ImplSDLGpu_CreateRenderPipeline(); - return ImGui_ImplSDLGpu_CreateFontsTexture(); -} - -void ImGui_ImplSDLGpu_DestroyDeviceObjects() -{ - ImGui_ImplSDLGpu_DestroyRenderPipeline(); - ImGui_ImplSDLGpu_DestroyFontsTexture(); - - ImGui_ImplSDLGpu_Data* bd = ImGui_ImplSDLGpu_GetBackendData(); - if(bd->VertexBuffer) - { - SDL_ReleaseGPUBuffer(bd->Device, bd->VertexBuffer); - bd->VertexBuffer = nullptr; - } - - if(bd->IndexBuffer) - { - SDL_ReleaseGPUBuffer(bd->Device, bd->IndexBuffer); - bd->IndexBuffer = nullptr; - } - - if(bd->ShaderModuleVert) - { - SDL_ReleaseGPUShader(bd->Device, bd->ShaderModuleVert); - bd->ShaderModuleVert = nullptr; - } - - if(bd->ShaderModuleFrag) - { - SDL_ReleaseGPUShader(bd->Device, bd->ShaderModuleFrag); - bd->ShaderModuleFrag = nullptr; - } -} - -//----------------------------------------------------------------------------- - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -#endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp new file mode 100644 index 000000000..6633bd374 --- /dev/null +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -0,0 +1,730 @@ +// dear imgui: Renderer Backend for SDL_GPU for SDL3 +// (Requires: SDL 3.0.0+) + +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as ImTextureID. Read the FAQ about ImTextureID! +// [ ] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// Missing features: +// [ ] Renderer: Multi-viewport support (multiple windows). + +// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// CHANGELOG +// 2024-09-19: Initial version. + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_impl_sdlgpu3.h" +#include // intptr_t + +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + +// SDL +#include +#if !SDL_VERSION_ATLEAST(3, 0, 0) +#error This backend requires SDL 3.0.0+ +#endif +#include + +// SDL_GPUDevice data +struct ImGui_ImplSDLGPU3_Data +{ + SDL_GPUDevice* Device; // Main viewport's renderer + SDL_Window* Window; + SDL_GPUTexture* FontTexture; + SDL_GPUSampler* FontSampler; + + SDL_GPUGraphicsPipeline* Pipeline; + SDL_GPUShader* ShaderModuleVert; + SDL_GPUShader* ShaderModuleFrag; + + size_t VertexBufferSize; + size_t IndexBufferSize; + SDL_GPUBuffer* VertexBuffer; + SDL_GPUBuffer* IndexBuffer; + + ImGui_ImplSDLGPU3_Data() { memset((void*)this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// SHADERS +//----------------------------------------------------------------------------- + +// backends/vulkan/glsl_shader.vert, compiled with: +// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert +/* +#version 450 core +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aUV; +layout(location = 2) in vec4 aColor; +layout(set = 1, binding = 0) uniform UBO { vec2 uScale; vec2 uTranslate; }; + +out gl_PerVertex { vec4 gl_Position; }; +layout(location = 0) out struct { vec4 Color; vec2 UV; } Out; + +void main() +{ + Out.Color = aColor; + Out.UV = aUV; + gl_Position = vec4(aPos * uScale + uTranslate, 0, 1); +} +*/ +static uint32_t __glsl_shader_vert_spv[] = { + 0x07230203, 0x00010000, 0x0008000b, 0x0000002e, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x000a000f, 0x00000000, 0x00000004, 0x6e69616d, 0x00000000, 0x0000000b, 0x0000000f, 0x00000015, + 0x0000001b, 0x0000001c, 0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00030005, 0x00000009, 0x00000000, + 0x00050006, 0x00000009, 0x00000000, 0x6f6c6f43, 0x00000072, 0x00040006, 0x00000009, 0x00000001, 0x00005655, 0x00030005, 0x0000000b, 0x0074754f, + 0x00040005, 0x0000000f, 0x6c6f4361, 0x0000726f, 0x00030005, 0x00000015, 0x00565561, 0x00060005, 0x00000019, 0x505f6c67, 0x65567265, 0x78657472, + 0x00000000, 0x00060006, 0x00000019, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, 0x00030005, 0x0000001b, 0x00000000, 0x00040005, 0x0000001c, + 0x736f5061, 0x00000000, 0x00030005, 0x0000001e, 0x004f4255, 0x00050006, 0x0000001e, 0x00000000, 0x61635375, 0x0000656c, 0x00060006, 0x0000001e, + 0x00000001, 0x61725475, 0x616c736e, 0x00006574, 0x00030005, 0x00000020, 0x00000000, 0x00040047, 0x0000000b, 0x0000001e, 0x00000000, 0x00040047, + 0x0000000f, 0x0000001e, 0x00000002, 0x00040047, 0x00000015, 0x0000001e, 0x00000001, 0x00050048, 0x00000019, 0x00000000, 0x0000000b, 0x00000000, + 0x00030047, 0x00000019, 0x00000002, 0x00040047, 0x0000001c, 0x0000001e, 0x00000000, 0x00050048, 0x0000001e, 0x00000000, 0x00000023, 0x00000000, + 0x00050048, 0x0000001e, 0x00000001, 0x00000023, 0x00000008, 0x00030047, 0x0000001e, 0x00000002, 0x00040047, 0x00000020, 0x00000022, 0x00000001, + 0x00040047, 0x00000020, 0x00000021, 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, + 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040017, 0x00000008, 0x00000006, 0x00000002, 0x0004001e, 0x00000009, 0x00000007, 0x00000008, + 0x00040020, 0x0000000a, 0x00000003, 0x00000009, 0x0004003b, 0x0000000a, 0x0000000b, 0x00000003, 0x00040015, 0x0000000c, 0x00000020, 0x00000001, + 0x0004002b, 0x0000000c, 0x0000000d, 0x00000000, 0x00040020, 0x0000000e, 0x00000001, 0x00000007, 0x0004003b, 0x0000000e, 0x0000000f, 0x00000001, + 0x00040020, 0x00000011, 0x00000003, 0x00000007, 0x0004002b, 0x0000000c, 0x00000013, 0x00000001, 0x00040020, 0x00000014, 0x00000001, 0x00000008, + 0x0004003b, 0x00000014, 0x00000015, 0x00000001, 0x00040020, 0x00000017, 0x00000003, 0x00000008, 0x0003001e, 0x00000019, 0x00000007, 0x00040020, + 0x0000001a, 0x00000003, 0x00000019, 0x0004003b, 0x0000001a, 0x0000001b, 0x00000003, 0x0004003b, 0x00000014, 0x0000001c, 0x00000001, 0x0004001e, + 0x0000001e, 0x00000008, 0x00000008, 0x00040020, 0x0000001f, 0x00000002, 0x0000001e, 0x0004003b, 0x0000001f, 0x00000020, 0x00000002, 0x00040020, + 0x00000021, 0x00000002, 0x00000008, 0x0004002b, 0x00000006, 0x00000028, 0x00000000, 0x0004002b, 0x00000006, 0x00000029, 0x3f800000, 0x00050036, + 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x00000007, 0x00000010, 0x0000000f, 0x00050041, 0x00000011, + 0x00000012, 0x0000000b, 0x0000000d, 0x0003003e, 0x00000012, 0x00000010, 0x0004003d, 0x00000008, 0x00000016, 0x00000015, 0x00050041, 0x00000017, + 0x00000018, 0x0000000b, 0x00000013, 0x0003003e, 0x00000018, 0x00000016, 0x0004003d, 0x00000008, 0x0000001d, 0x0000001c, 0x00050041, 0x00000021, + 0x00000022, 0x00000020, 0x0000000d, 0x0004003d, 0x00000008, 0x00000023, 0x00000022, 0x00050085, 0x00000008, 0x00000024, 0x0000001d, 0x00000023, + 0x00050041, 0x00000021, 0x00000025, 0x00000020, 0x00000013, 0x0004003d, 0x00000008, 0x00000026, 0x00000025, 0x00050081, 0x00000008, 0x00000027, + 0x00000024, 0x00000026, 0x00050051, 0x00000006, 0x0000002a, 0x00000027, 0x00000000, 0x00050051, 0x00000006, 0x0000002b, 0x00000027, 0x00000001, + 0x00070050, 0x00000007, 0x0000002c, 0x0000002a, 0x0000002b, 0x00000028, 0x00000029, 0x00050041, 0x00000011, 0x0000002d, 0x0000001b, 0x0000000d, + 0x0003003e, 0x0000002d, 0x0000002c, 0x000100fd, 0x00010038}; + +// backends/vulkan/glsl_shader.frag, compiled with: +// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag +/* +#version 450 core +layout(location = 0) out vec4 fColor; +layout(set=2, binding=0) uniform sampler2D sTexture; +layout(location = 0) in struct { vec4 Color; vec2 UV; } In; +void main() +{ + fColor = In.Color * texture(sTexture, In.UV.st); +} +*/ +static uint32_t __glsl_shader_frag_spv[] = { + 0x07230203, 0x00010000, 0x0008000b, 0x0000001e, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000004, 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, 0x0000000d, 0x00030010, + 0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00040005, 0x00000009, 0x6c6f4366, + 0x0000726f, 0x00030005, 0x0000000b, 0x00000000, 0x00050006, 0x0000000b, 0x00000000, 0x6f6c6f43, 0x00000072, 0x00040006, 0x0000000b, 0x00000001, + 0x00005655, 0x00030005, 0x0000000d, 0x00006e49, 0x00050005, 0x00000016, 0x78655473, 0x65727574, 0x00000000, 0x00040047, 0x00000009, 0x0000001e, + 0x00000000, 0x00040047, 0x0000000d, 0x0000001e, 0x00000000, 0x00040047, 0x00000016, 0x00000022, 0x00000002, 0x00040047, 0x00000016, 0x00000021, + 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, + 0x00000004, 0x00040020, 0x00000008, 0x00000003, 0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, 0x00040017, 0x0000000a, 0x00000006, + 0x00000002, 0x0004001e, 0x0000000b, 0x00000007, 0x0000000a, 0x00040020, 0x0000000c, 0x00000001, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, + 0x00000001, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x00040020, 0x00000010, 0x00000001, + 0x00000007, 0x00090019, 0x00000013, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x00000014, + 0x00000013, 0x00040020, 0x00000015, 0x00000000, 0x00000014, 0x0004003b, 0x00000015, 0x00000016, 0x00000000, 0x0004002b, 0x0000000e, 0x00000018, + 0x00000001, 0x00040020, 0x00000019, 0x00000001, 0x0000000a, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x00050041, 0x00000010, 0x00000011, 0x0000000d, 0x0000000f, 0x0004003d, 0x00000007, 0x00000012, 0x00000011, 0x0004003d, 0x00000014, 0x00000017, + 0x00000016, 0x00050041, 0x00000019, 0x0000001a, 0x0000000d, 0x00000018, 0x0004003d, 0x0000000a, 0x0000001b, 0x0000001a, 0x00050057, 0x00000007, + 0x0000001c, 0x00000017, 0x0000001b, 0x00050085, 0x00000007, 0x0000001d, 0x00000012, 0x0000001c, 0x0003003e, 0x00000009, 0x0000001d, 0x000100fd, + 0x00010038}; + +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple +// Dear ImGui contexts. +static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; +} + +static void ImGui_ImplSDLGPU3_CreateShaderModules() +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + + SDL_GPUDriver driver = SDL_GetGPUDriver(bd->Device); + if(bd->ShaderModuleVert == nullptr) + { + SDL_GPUShaderCreateInfo vert_info{}; + vert_info.stage = SDL_GPU_SHADERSTAGE_VERTEX; + vert_info.entrypoint = "main"; + vert_info.num_uniform_buffers = 1; // UBO set 1 binding 0 + + if(driver == SDL_GPU_DRIVER_VULKAN) + { + vert_info.code_size = sizeof(__glsl_shader_vert_spv); + vert_info.code = (uint8_t*)__glsl_shader_vert_spv; + vert_info.format = SDL_GPU_SHADERFORMAT_SPIRV; + } + // TODO: Add other shader drivers here + + bd->ShaderModuleVert = SDL_CreateGPUShader(bd->Device, &vert_info); + if(bd->ShaderModuleVert == nullptr) + { + SDL_Log("error creating vertex shader module: %s", SDL_GetError()); + } + } + + if(bd->ShaderModuleFrag == nullptr) + { + SDL_GPUShaderCreateInfo frag_info{}; + frag_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT; + frag_info.entrypoint = "main"; + frag_info.num_samplers = 1; // sTexture set 0 binding 0 + + if(driver == SDL_GPU_DRIVER_VULKAN) + { + frag_info.code_size = sizeof(__glsl_shader_frag_spv); + frag_info.code = (uint8_t*)__glsl_shader_frag_spv; + frag_info.format = SDL_GPU_SHADERFORMAT_SPIRV; + } + // TODO: Add other shader drivers here + + bd->ShaderModuleFrag = SDL_CreateGPUShader(bd->Device, &frag_info); + if(bd->ShaderModuleFrag == nullptr) + { + SDL_Log("error creating fragment shader module: %s", SDL_GetError()); + } + } +} + +static void ImGui_ImplSDLGPU3_DestroyRenderPipeline() +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + if(bd->Pipeline) + { + SDL_ReleaseGPUGraphicsPipeline(bd->Device, bd->Pipeline); + bd->Pipeline = nullptr; + } +} + +static void ImGui_ImplSDLGPU3_CreateRenderPipeline() +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + + ImGui_ImplSDLGPU3_CreateShaderModules(); + ImGui_ImplSDLGPU3_DestroyRenderPipeline(); + + SDL_GPUGraphicsPipelineCreateInfo pipeline_info{}; + + SDL_GPUColorTargetDescription color_attachment_desc{}; + color_attachment_desc.blend_state.color_write_mask = + SDL_GPU_COLORCOMPONENT_R | SDL_GPU_COLORCOMPONENT_G | SDL_GPU_COLORCOMPONENT_B | SDL_GPU_COLORCOMPONENT_A; + color_attachment_desc.blend_state.enable_blend = true; + color_attachment_desc.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA; + color_attachment_desc.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + color_attachment_desc.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD; + color_attachment_desc.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE; + color_attachment_desc.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + color_attachment_desc.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD; + color_attachment_desc.format = SDL_GetGPUSwapchainTextureFormat(bd->Device, bd->Window); + + pipeline_info.target_info.num_color_targets = 1; + pipeline_info.target_info.color_target_descriptions = &color_attachment_desc; + pipeline_info.target_info.has_depth_stencil_target = false; + + pipeline_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1; + pipeline_info.multisample_state.sample_mask = 0xf; + + pipeline_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; + + pipeline_info.vertex_shader = bd->ShaderModuleVert; + pipeline_info.fragment_shader = bd->ShaderModuleFrag; + + pipeline_info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE; + pipeline_info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE; + pipeline_info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL; + + SDL_GPUVertexBufferDescription binding_desc[1]{}; + binding_desc[0].slot = 0; + binding_desc[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX; + binding_desc[0].instance_step_rate = 0; + binding_desc[0].pitch = sizeof(ImDrawVert); + + SDL_GPUVertexAttribute attribute_desc[3] = {}; + attribute_desc[0].location = 0; + attribute_desc[0].buffer_slot = binding_desc[0].slot; + attribute_desc[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; + attribute_desc[0].offset = offsetof(ImDrawVert, pos); + attribute_desc[1].location = 1; + attribute_desc[1].buffer_slot = binding_desc[0].slot; + attribute_desc[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; + attribute_desc[1].offset = offsetof(ImDrawVert, uv); + attribute_desc[2].location = 2; + attribute_desc[2].buffer_slot = binding_desc[0].slot; + attribute_desc[2].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM; + attribute_desc[2].offset = offsetof(ImDrawVert, col); + + pipeline_info.vertex_input_state.num_vertex_buffers = 1; + pipeline_info.vertex_input_state.vertex_buffer_descriptions = binding_desc; + pipeline_info.vertex_input_state.num_vertex_attributes = 3; + pipeline_info.vertex_input_state.vertex_attributes = attribute_desc; + + bd->Pipeline = SDL_CreateGPUGraphicsPipeline(bd->Device, &pipeline_info); + if(bd->Pipeline == nullptr) + { + SDL_Log("error creating graphics pipeline: %s", SDL_GetError()); + } +} + +static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, + SDL_GPURenderPass* render_pass, int fb_width, int fb_height) +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + + // Bind pipeline: + { + SDL_BindGPUGraphicsPipeline(render_pass, pipeline); + } + + // Bind Vertex And Index Buffer: + if(draw_data->TotalVtxCount > 0) + { + SDL_GPUBufferBinding buffer_binding{}; + buffer_binding.buffer = bd->VertexBuffer; + SDL_BindGPUVertexBuffers(render_pass, 0, &buffer_binding, 1); + + buffer_binding.buffer = bd->IndexBuffer; + SDL_BindGPUIndexBuffer(render_pass, &buffer_binding, + sizeof(ImDrawIdx) == 2 ? SDL_GPU_INDEXELEMENTSIZE_16BIT : SDL_GPU_INDEXELEMENTSIZE_32BIT); + + // vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); + } + + // Setup viewport: + { + SDL_GPUViewport viewport{}; + viewport.x = 0; + viewport.y = 0; + viewport.w = (float)fb_width; + viewport.h = (float)fb_height; + viewport.min_depth = 0.0f; + viewport.max_depth = 1.0f; + SDL_SetGPUViewport(render_pass, &viewport); + + SDL_Rect scissor{}; + scissor.x = 0; + scissor.y = 0; + scissor.w = viewport.w; + scissor.h = viewport.h; + SDL_SetGPUScissor(render_pass, &scissor); + } + + // Setup scale and translation: + // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos + // is (0,0) for single viewport apps. + { + float push_data[4]{}; + push_data[0] = 2.0f / draw_data->DisplaySize.x; // scale + push_data[1] = -2.0f / draw_data->DisplaySize.y; // scale + push_data[2] = -1.0f - draw_data->DisplayPos.x * push_data[0]; // translate + push_data[3] = 1.0f - draw_data->DisplayPos.y * push_data[1]; // translate + SDL_PushGPUVertexUniformData(command_buffer, 0, push_data, sizeof(float) * 4); + } +} + +// Functions +bool ImGui_ImplSDLGPU3_Init(SDL_GPUDevice* device, SDL_Window* window) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + IM_ASSERT(device != nullptr && "SDL_Gpu not initialized!"); + + // Setup backend capabilities flags + ImGui_ImplSDLGPU3_Data* bd = IM_NEW(ImGui_ImplSDLGPU3_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_sdlgpu3"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + + bd->Device = device; + bd->Window = window; + + return true; +} + +void ImGui_ImplSDLGPU3_Shutdown() +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplSDLGPU3_DestroyDeviceObjects(); + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + IM_DELETE(bd); +} + +void ImGui_ImplSDLGPU3_NewFrame() +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLGPU3_Init()?"); + + if(!bd->FontTexture) ImGui_ImplSDLGPU3_CreateDeviceObjects(); +} + +void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* cmd, SDL_GPUTexture* render_target) +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + + // If there's a scale factor set by the user, use that instead + // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass + // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here. + float rsx = 1.0f; + float rsy = 1.0f; + // SDL_GetRenderScale(renderer, &rsx, &rsy); + ImVec2 render_scale; + render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; + render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; + + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); + int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); + if(fb_width == 0 || fb_height == 0) return; + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = render_scale; + + // Copy over the vertices and indices + if(draw_data->TotalVtxCount > 0) + { + // Create or resize the vertex/index buffers + size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); + size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); + if(bd->VertexBuffer == nullptr || bd->VertexBufferSize < vertex_size) + { + if(bd->VertexBuffer != nullptr) + { + SDL_ReleaseGPUBuffer(bd->Device, bd->VertexBuffer); + bd->VertexBuffer = nullptr; + } + SDL_GPUBufferCreateInfo info{}; + info.size = vertex_size; + info.usage = SDL_GPU_BUFFERUSAGE_VERTEX; + bd->VertexBuffer = SDL_CreateGPUBuffer(bd->Device, &info); + bd->VertexBufferSize = vertex_size; + SDL_SetGPUBufferName(bd->Device, bd->VertexBuffer, "ImguiVertexBuffer"); + } + if(bd->IndexBuffer == nullptr || bd->IndexBufferSize < index_size) + { + if(bd->IndexBuffer != nullptr) + { + SDL_ReleaseGPUBuffer(bd->Device, bd->IndexBuffer); + bd->IndexBuffer = nullptr; + } + SDL_GPUBufferCreateInfo info{}; + info.size = index_size; + info.usage = SDL_GPU_BUFFERUSAGE_INDEX; + bd->IndexBuffer = SDL_CreateGPUBuffer(bd->Device, &info); + bd->IndexBufferSize = index_size; + SDL_SetGPUBufferName(bd->Device, bd->IndexBuffer, "ImguiIndexBuffer"); + } + + // TODO: Reuse the transfer buffer? + SDL_GPUTransferBufferCreateInfo transfer_info{}; + transfer_info.size = vertex_size + index_size; + transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(bd->Device, &transfer_info); + + void* map = SDL_MapGPUTransferBuffer(bd->Device, transfer_buffer, false); + + // Upload vertex/index data into a single contiguous GPU buffer + ImDrawVert* vtx_dst = reinterpret_cast(map); + ImDrawIdx* idx_dst = reinterpret_cast(reinterpret_cast(map) + vertex_size); + + for(int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; + } + SDL_UnmapGPUTransferBuffer(bd->Device, transfer_buffer); + + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); + + SDL_GPUTransferBufferLocation vertex_location{}; + vertex_location.transfer_buffer = transfer_buffer; + vertex_location.offset = 0; + + SDL_GPUTransferBufferLocation index_location{}; + index_location.transfer_buffer = transfer_buffer; + index_location.offset = vertex_size; + + SDL_GPUBufferRegion vertex_region{}; + vertex_region.buffer = bd->VertexBuffer; + vertex_region.offset = 0; + vertex_region.size = vertex_size; + + SDL_GPUBufferRegion index_region{}; + index_region.buffer = bd->IndexBuffer; + index_region.offset = 0; + index_region.size = index_size; + + SDL_UploadToGPUBuffer(copy_pass, &vertex_location, &vertex_region, true); + SDL_UploadToGPUBuffer(copy_pass, &index_location, &index_region, true); + SDL_EndGPUCopyPass(copy_pass); + + SDL_ReleaseGPUTransferBuffer(bd->Device, transfer_buffer); + } + + SDL_GPUColorTargetInfo color_target_info{}; + color_target_info.texture = render_target; + color_target_info.load_op = SDL_GPU_LOADOP_LOAD; + color_target_info.store_op = SDL_GPU_STOREOP_STORE; + + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(cmd, &color_target_info, 1, nullptr); + + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, bd->Pipeline, cmd, render_pass, fb_width, fb_height); + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + int global_vtx_offset = 0; + int global_idx_offset = 0; + for(int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for(int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if(pcmd->UserCallback != nullptr) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if(pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, bd->Pipeline, cmd, render_pass, fb_width, fb_height); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + + // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds + if(clip_min.x < 0.0f) + { + clip_min.x = 0.0f; + } + if(clip_min.y < 0.0f) + { + clip_min.y = 0.0f; + } + if(clip_max.x > fb_width) + { + clip_max.x = (float)fb_width; + } + if(clip_max.y > fb_height) + { + clip_max.y = (float)fb_height; + } + if(clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; + + // Apply scissor/clipping rectangle + SDL_Rect scissor; + scissor.x = (int32_t)(clip_min.x); + scissor.y = (int32_t)(clip_min.y); + scissor.w = (int32_t)(clip_max.x - clip_min.x); + scissor.h = (int32_t)(clip_max.y - clip_min.y); + + SDL_SetGPUScissor(render_pass, &scissor); + + // Bind DescriptorSet with font or user texture + SDL_GPUTextureSamplerBinding texture_binding{}; + texture_binding.sampler = bd->FontSampler; + texture_binding.texture = (SDL_GPUTexture*)pcmd->TextureId; + if(sizeof(ImTextureID) < sizeof(ImU64)) + { + // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures + // haven't been used. + IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontTexture); + texture_binding.texture = bd->FontTexture; + } + SDL_BindGPUFragmentSamplers(render_pass, 0, &texture_binding, 1); + + // Draw + SDL_DrawGPUIndexedPrimitives(render_pass, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, + pcmd->VtxOffset + global_vtx_offset, 0); + } + } + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; + } + + SDL_EndGPURenderPass(render_pass); +} + +// Called by Init/NewFrame/Shutdown +bool ImGui_ImplSDLGPU3_CreateFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + + // Build texture atlas + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, + &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more + // likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level + // concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + + // Upload texture to graphics system + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to + // allow point/nearest sampling) + SDL_GPUTextureCreateInfo info{}; + info.width = width; + info.height = height; + info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; + info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + info.sample_count = SDL_GPU_SAMPLECOUNT_1; + info.num_levels = 1; + info.type = SDL_GPU_TEXTURETYPE_2D; + info.layer_count_or_depth = 1; + bd->FontTexture = SDL_CreateGPUTexture(bd->Device, &info); + if(bd->FontTexture == nullptr) + { + SDL_Log("error creating texture: %s", SDL_GetError()); + return false; + } + + // First transfer the data to a transfer buffer + SDL_GPUTransferBufferCreateInfo transfer_create_info{}; + transfer_create_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + transfer_create_info.size = 4 * width * height; + SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(bd->Device, &transfer_create_info); + if(!transfer_buffer) + { + SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); + return false; + } + + void* map = SDL_MapGPUTransferBuffer(bd->Device, transfer_buffer, false); + SDL_memcpy(map, pixels, transfer_create_info.size); + SDL_UnmapGPUTransferBuffer(bd->Device, transfer_buffer); + + SDL_GPUTextureLocation location{}; + + auto* cmd = SDL_AcquireGPUCommandBuffer(bd->Device); + auto* copy_pass = SDL_BeginGPUCopyPass(cmd); + + SDL_GPUTextureTransferInfo transfer_info{}; + transfer_info.transfer_buffer = transfer_buffer; + transfer_info.pixels_per_row = width; + transfer_info.rows_per_layer = height; + transfer_info.offset = 0; + + SDL_GPUTextureRegion region{}; + region.texture = bd->FontTexture; + region.x = 0; + region.y = 0; + region.z = 0; + region.w = width; + region.h = height; + region.d = 1; + + SDL_UploadToGPUTexture(copy_pass, &transfer_info, ®ion, false); + SDL_EndGPUCopyPass(copy_pass); + + // Submit the commands + SDL_SubmitGPUCommandBuffer(cmd); + + // No need for the transfer buffer now + SDL_ReleaseGPUTransferBuffer(bd->Device, transfer_buffer); + + SDL_GPUSamplerCreateInfo sampler_info{}; + sampler_info.address_mode_u = sampler_info.address_mode_v = sampler_info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + sampler_info.mag_filter = sampler_info.min_filter = SDL_GPU_FILTER_LINEAR; + + bd->FontSampler = SDL_CreateGPUSampler(bd->Device, &sampler_info); + if(!bd->FontSampler) + { + SDL_Log("error creating sampler: %s", SDL_GetError()); + return false; + } + + // SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND); + // SDL_SetTextureScaleMode(bd->FontTexture, SDL_SCALEMODE_LINEAR); + + // Store our identifier + io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); + + return true; +} + +void ImGui_ImplSDLGPU3_DestroyFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + if(bd->FontTexture) + { + io.Fonts->SetTexID(0); + + SDL_ReleaseGPUTexture(bd->Device, bd->FontTexture); + SDL_ReleaseGPUSampler(bd->Device, bd->FontSampler); + bd->FontTexture = nullptr; + bd->FontSampler = nullptr; + } +} + +bool ImGui_ImplSDLGPU3_CreateDeviceObjects() +{ + ImGui_ImplSDLGPU3_CreateRenderPipeline(); + return ImGui_ImplSDLGPU3_CreateFontsTexture(); +} + +void ImGui_ImplSDLGPU3_DestroyDeviceObjects() +{ + ImGui_ImplSDLGPU3_DestroyRenderPipeline(); + ImGui_ImplSDLGPU3_DestroyFontsTexture(); + + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + if(bd->VertexBuffer) + { + SDL_ReleaseGPUBuffer(bd->Device, bd->VertexBuffer); + bd->VertexBuffer = nullptr; + } + + if(bd->IndexBuffer) + { + SDL_ReleaseGPUBuffer(bd->Device, bd->IndexBuffer); + bd->IndexBuffer = nullptr; + } + + if(bd->ShaderModuleVert) + { + SDL_ReleaseGPUShader(bd->Device, bd->ShaderModuleVert); + bd->ShaderModuleVert = nullptr; + } + + if(bd->ShaderModuleFrag) + { + SDL_ReleaseGPUShader(bd->Device, bd->ShaderModuleFrag); + bd->ShaderModuleFrag = nullptr; + } +} + +//----------------------------------------------------------------------------- + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu.h b/backends/imgui_impl_sdlgpu3.h similarity index 67% rename from backends/imgui_impl_sdlgpu.h rename to backends/imgui_impl_sdlgpu3.h index 70091bbf6..9cd23849f 100644 --- a/backends/imgui_impl_sdlgpu.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -18,7 +18,7 @@ // - Introduction, links and more at the top of imgui.cpp #pragma once -#include "imgui.h" // IMGUI_IMPL_API +#include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE struct SDL_GPUDevice; @@ -27,15 +27,15 @@ struct SDL_GPUCommandBuffer; struct SDL_GPUTexture; // Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplSDLGpu_Init(SDL_GPUDevice* device, SDL_Window* window); -IMGUI_IMPL_API void ImGui_ImplSDLGpu_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplSDLGpu_NewFrame(); -IMGUI_IMPL_API void ImGui_ImplSDLGpu_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* cmd, SDL_GPUTexture* render_target); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_Init(SDL_GPUDevice* device, SDL_Window* window); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* cmd, SDL_GPUTexture* render_target); // Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplSDLGpu_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLGpu_DestroyFontsTexture(); -IMGUI_IMPL_API bool ImGui_ImplSDLGpu_CreateDeviceObjects(); -IMGUI_IMPL_API void ImGui_ImplSDLGpu_DestroyDeviceObjects(); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyFontsTexture(); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); -#endif // #ifndef IMGUI_DISABLE +#endif // #ifndef IMGUI_DISABLE diff --git a/examples/example_sdl3_sdlgpu3/Makefile b/examples/example_sdl3_sdlgpu3/Makefile new file mode 100644 index 000000000..7e4cd8e82 --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/Makefile @@ -0,0 +1,73 @@ +# +# Cross Platform Makefile +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X +# +# You will need SDL3 (http://www.libsdl.org) which is still unreleased/unpackaged. + +#CXX = g++ +#CXX = clang++ + +EXE = example_sdl3_sdlgpu3 +IMGUI_DIR = ../.. +SOURCES = main.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlgpu3.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) +UNAME_S := $(shell uname -s) +LINUX_GL_LIBS = -lGL + +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = + +##--------------------------------------------------------------------- +## BUILD FLAGS PER PLATFORM +##--------------------------------------------------------------------- + +ifeq ($(UNAME_S), Linux) #LINUX + ECHO_MESSAGE = "Linux" + LIBS += -ldl `pkg-config sdl3 --libs` + + CXXFLAGS += `pkg-config sdl3 --cflags` + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(UNAME_S), Darwin) #APPLE + ECHO_MESSAGE = "Mac OS X" + LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` + LIBS += -L/usr/local/lib -L/opt/local/lib + + CXXFLAGS += `pkg-config sdl3 --cflags` + CXXFLAGS += -I/usr/local/include -I/opt/local/include + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(OS), Windows_NT) + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl3` + + CXXFLAGS += `pkg-config --cflags sdl3` + CFLAGS = $(CXXFLAGS) +endif + +##--------------------------------------------------------------------- +## BUILD RULES +##--------------------------------------------------------------------- + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +all: $(EXE) + @echo Build complete for $(ECHO_MESSAGE) + +$(EXE): $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +clean: + rm -f $(EXE) $(OBJS) diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp new file mode 100644 index 000000000..a55116546 --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -0,0 +1,220 @@ +// Dear ImGui: standalone example application for SDL3 + SDL_Renderer +// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// Important to understand: SDL_Renderer is an _optional_ component of SDL3. +// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. + +#include "imgui.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_sdlgpu3.h" +#include +#include +#include + +#define GPU_SUPPORTED_FORMATS (SDL_GPU_SHADERFORMAT_SPIRV) + +// Main code +int main(int, char**) +{ + // Setup SDL + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD)) + { + printf("Error: SDL_Init(): %s\n", SDL_GetError()); + return -1; + } + + // Create window with SDL_Renderer graphics context + Uint32 window_flags = SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", 1280, 720, window_flags); + if (window == nullptr) + { + printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); + return -1; + } + SDL_GPUDevice* device = SDL_CreateGPUDevice(GPU_SUPPORTED_FORMATS, true, nullptr); + if (device == nullptr) + { + printf("Error: SDL_CreateGPUDevice(): %s\n", SDL_GetError()); + return -1; + } + + if(!SDL_ClaimWindowForGPUDevice(device, window)) + { + printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError()); + return -1; + } + + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_ShowWindow(window); + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplSDL3_InitForSDLGPU3(window, device); + ImGui_ImplSDLGPU3_Init(device, window); + + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. + // - Read 'docs/FONTS.md' for more instructions and details. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //io.Fonts->AddFontDefault(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //IM_ASSERT(font != nullptr); + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop + bool done = false; +#ifdef __EMSCRIPTEN__ + // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. + // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. + io.IniFilename = nullptr; + EMSCRIPTEN_MAINLOOP_BEGIN +#else + while (!done) +#endif + { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. + // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL3_ProcessEvent(&event); + if (event.type == SDL_EVENT_QUIT) + done = true; + if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) + done = true; + } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } + + // Start the Dear ImGui frame + ImGui_ImplSDLGPU3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(m_gpu_device); + if(!cmd) + { + printf("Error: SDL_AcquireGPUCommandBuffer(): %s\n", SDL_GetError()); + continue; + } + + int width = 0, height = 0; + SDL_GPUTexture* swapchain = SDL_AcquireGPUSwapchainTexture(cmd, window, &width, &height); + if(!swapchain) + { + SDL_SubmitGPUCommandBuffer(cmd); + continue; + } + + SDL_GPUColorTargetInfo color_target_info{}; + color_target_info.texture = swapchain; + color_target_info.clear_color.r = 0.0f; + color_target_info.clear_color.g = 0.0f; + color_target_info.clear_color.b = 0.0f; + color_target_info.clear_color.a = 1.0f; + color_target_info.load_op = SDL_GPU_LOADOP_CLEAR; + color_target_info.store_op = SDL_GPU_STOREOP_STORE; + + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(cmd, &color_target_info, 1, NULL); + { + // Do custom rendering here + } + SDL_EndGPURenderPass(render_pass); + + ImGui_ImplSDLGPU3_RenderDrawData(ImGui::GetDrawData(), cmd, swapchain); + + SDL_SubmitGPUCommandBuffer(cmd); + } +#ifdef __EMSCRIPTEN__ + EMSCRIPTEN_MAINLOOP_END; +#endif + + // Cleanup + ImGui_ImplSDLGPU3_Shutdown(); + ImGui_ImplSDL3_Shutdown(); + ImGui::DestroyContext(); + + SDL_ReleaseWindowFromGPUDevice(device, window); + + SDL_DestroyGPUDevice(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + + return 0; +}