mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-13 18:50:58 +01:00
feedback fixes and added a example main
This commit is contained in:
parent
d99f628fb1
commit
8cab5258e5
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 <stdint.h> // 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 <SDL3/SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
#error This backend requires SDL 3.0.0+
|
||||
#endif
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
// 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<ImDrawVert*>(map);
|
||||
ImDrawIdx* idx_dst = reinterpret_cast<ImDrawIdx*>(reinterpret_cast<char*>(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
|
730
backends/imgui_impl_sdlgpu3.cpp
Normal file
730
backends/imgui_impl_sdlgpu3.cpp
Normal file
@ -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 <stdint.h> // 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 <SDL3/SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
#error This backend requires SDL 3.0.0+
|
||||
#endif
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
// 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<ImDrawVert*>(map);
|
||||
ImDrawIdx* idx_dst = reinterpret_cast<ImDrawIdx*>(reinterpret_cast<char*>(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
|
@ -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
|
73
examples/example_sdl3_sdlgpu3/Makefile
Normal file
73
examples/example_sdl3_sdlgpu3/Makefile
Normal file
@ -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)
|
220
examples/example_sdl3_sdlgpu3/main.cpp
Normal file
220
examples/example_sdl3_sdlgpu3/main.cpp
Normal file
@ -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 <stdio.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user