From a1e05521e942c1611bef1aafe1631506c85f1148 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Apr 2026 17:24:41 +0200 Subject: [PATCH 01/10] Backends: GLFW: added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2. (#9003) Since we ship GLFW 3.2 binaries for Windows this makes our examples a little better behaving by default. Ideally we'd use ImGui_ImplWin32_GetDpiScaleForHwnd() and ImGui_ImplWin32_GetDpiScaleForMonitor() but they are too much code to copy. --- backends/imgui_impl_glfw.cpp | 11 +++++++++++ docs/CHANGELOG.txt | 2 ++ 2 files changed, 13 insertions(+) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 27f5fe90a..37e933cf5 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -29,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-04-21: Added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2. // 2026-03-25: Mouse cursor is properly restored if changed by user app/code while using glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange. Amend change from 2025-12-10. // 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. @@ -948,6 +949,16 @@ static void ImGui_ImplGlfw_UpdateGamepads() #undef MAP_ANALOG } +// For GFLW 3.2 + Windows: include a simplified non-monitor aware version of ImGui_ImplWin32_GetDpiScaleForMonitor(). +// This is merely a band-aid to make using GLFW 3.2 a little bit nicer, but prefer to use GLFW 3.3+ or the full correct functions from the Win32 backend. +#if !GLFW_HAS_PER_MONITOR_DPI && defined(_WIN32) && !defined(NOGDI) +float ImGui_ImplWin32_GetLegacyDpiScale() { const HDC dc = ::GetDC(nullptr); UINT xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); ::ReleaseDC(nullptr, dc); return xdpi / 96.0f; } +void glfwGetWindowContentScale(GLFWwindow*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); } +void glfwGetMonitorContentScale(GLFWmonitor*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); } +#undef GLFW_HAS_PER_MONITOR_DPI +#define GLFW_HAS_PER_MONITOR_DPI 1 +#endif + // - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend. // - Apple platforms use FramebufferScale so we always return 1.0f. // - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a907de658..20fd49c66 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -103,6 +103,8 @@ Other Changes: - Minor optimization: reduce redudant label scanning in common widgets. - Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). - Backends: + - GLFW: added a Win32-specific implementation of `ImGui_ImplGlfw_GetContentScaleXXXX` + functions for legacy GLFW 3.2. (#9003) - Metal: avoid redundant vertex buffer bind in `SetupRenderState()`, which leads to validation issue. (#9343) [@Hunam6] - Metal: use a dedicated `bufferCacheLock` to avoid crashing when `bufferCache` is From 2d131ef5b718d518ea5144c086794efc2380ff5a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Apr 2026 22:07:03 +0200 Subject: [PATCH 02/10] Backends: Vulkan: renaming and moving code around to reduce diff in upcoming change. Should be no-op. --- backends/imgui_impl_vulkan.cpp | 74 ++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index dc49ac1f7..c74f4bcbf 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -278,7 +278,7 @@ struct ImGui_ImplVulkan_Data ImVector PipelineRenderingCreateInfoColorAttachmentFormats; // Deep copy of format array // Texture management - VkSampler TexSamplerLinear; + VkSampler SamplerLinear; VkCommandPool TexCommandPool; VkCommandBuffer TexCommandBuffer; @@ -753,7 +753,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) } // Create the Descriptor Set - backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSamplerLinear, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->SamplerLinear, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); // Store identifiers tex->SetTexID((ImTextureID)backend_tex->DescriptorSet); @@ -1048,43 +1048,31 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc return pipeline; } +static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDescriptorSetLayout* p_layout, VkDescriptorType descriptor_type) +{ + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + + VkDescriptorSetLayoutBinding binding[1] = {}; + binding[0].descriptorType = descriptor_type; + binding[0].descriptorCount = 1; + binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.bindingCount = 1; + info.pBindings = binding; + VkResult err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, p_layout); + check_vk_result(err); +} + bool ImGui_ImplVulkan_CreateDeviceObjects() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; VkResult err; - if (!bd->TexSamplerLinear) - { - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. - VkSamplerCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - info.magFilter = VK_FILTER_LINEAR; - info.minFilter = VK_FILTER_LINEAR; - info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.minLod = -1000; - info.maxLod = 1000; - info.maxAnisotropy = 1.0f; - err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->TexSamplerLinear); - check_vk_result(err); - } - if (!bd->DescriptorSetLayout) - { - VkDescriptorSetLayoutBinding binding[1] = {}; - binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - binding[0].descriptorCount = 1; - binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.bindingCount = 1; - info.pBindings = binding; - err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayout); - check_vk_result(err); - } + ImGui_ImplVulkan_CreateDescriptorSetLayout(&bd->DescriptorSetLayout, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); if (v->DescriptorPoolSize != 0) { @@ -1096,11 +1084,29 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() pool_info.maxSets = v->DescriptorPoolSize; pool_info.poolSizeCount = 1; pool_info.pPoolSizes = &pool_size; - err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool); check_vk_result(err); } + // Create sampler + // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. + if (!bd->SamplerLinear) + { + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.minLod = -1000; + info.maxLod = 1000; + info.maxAnisotropy = 1.0f; + err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerLinear); + check_vk_result(err); + } + if (!bd->PipelineLayout) { // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix @@ -1191,7 +1197,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; } if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; } - if (bd->TexSamplerLinear) { vkDestroySampler(v->Device, bd->TexSamplerLinear, v->Allocator); bd->TexSamplerLinear = VK_NULL_HANDLE; } + if (bd->SamplerLinear) { vkDestroySampler(v->Device, bd->SamplerLinear, v->Allocator); bd->SamplerLinear = VK_NULL_HANDLE; } if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } From 382b99c334c6f3bc7e0c548a1ae231d6402d319b Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Apr 2026 22:32:01 +0200 Subject: [PATCH 03/10] PlotHistogram: add comments. (#9372) --- imgui_widgets.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d26e407da..cb6e09dc8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8869,9 +8869,7 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)( // - PlotHistogram() //------------------------------------------------------------------------- // Plot/Graph widgets are not very good. -// Consider writing your own, or using a third-party one, see: -// - ImPlot https://github.com/epezent/implot -// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions +// Consider using ImPlot (https://github.com/epezent/implot) which is much better! //------------------------------------------------------------------------- int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg) @@ -9018,6 +9016,7 @@ void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); } +// Plot Histogram (the data provided _is_ histogram data. it doesn't compute the histogram of your data) void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) { ImGuiPlotArrayGetterData data(values, stride); From a5fd597be3d282df20520ef8b95e3d6af81fb213 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Apr 2026 14:23:42 +0200 Subject: [PATCH 04/10] Backends: Vulkan: minor changes. --- backends/imgui_impl_vulkan.cpp | 42 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index c74f4bcbf..f6ea891c7 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -481,9 +481,7 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); // Bind pipeline: - { - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - } + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); // Bind Vertex And Index Buffer: if (draw_data->TotalVtxCount > 0) @@ -495,27 +493,23 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline } // Setup viewport: - { - VkViewport viewport; - viewport.x = 0; - viewport.y = 0; - viewport.width = (float)fb_width; - viewport.height = (float)fb_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(command_buffer, 0, 1, &viewport); - } + VkViewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = (float)fb_width; + viewport.height = (float)fb_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(command_buffer, 0, 1, &viewport); // 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 constants[4]; - constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale - constants[1] = 2.0f / draw_data->DisplaySize.y; - constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate - constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1]; - vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); - } + float constants[4]; + constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale + constants[1] = 2.0f / draw_data->DisplaySize.y; + constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate + constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1]; + vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); } // Render function @@ -589,9 +583,6 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm vkUnmapMemory(v->Device, rb->IndexBufferMemory); } - // Setup desired Vulkan state - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - // Setup render state structure (for callbacks and custom texture bindings) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplVulkan_RenderState render_state; @@ -600,6 +591,9 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm render_state.PipelineLayout = bd->PipelineLayout; platform_io.Renderer_RenderState = &render_state; + // Setup desired Vulkan state + ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); + // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) From 0453ae96e8f165e08155c957a99d87daffce2bc9 Mon Sep 17 00:00:00 2001 From: yaz0r <363511+yaz0r@users.noreply.github.com> Date: Tue, 9 Sep 2025 00:21:45 -0700 Subject: [PATCH 05/10] (Breaking) Backends: Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (WIP) (#914) --- backends/imgui_impl_vulkan.cpp | 196 ++++++++++++++++++++----- backends/imgui_impl_vulkan.h | 5 +- backends/vulkan/glsl_shader.frag | 5 +- backends/vulkan/glsl_shader.frag.u32 | 30 ++++ examples/example_glfw_vulkan/main.cpp | 3 +- examples/example_sdl2_vulkan/main.cpp | 3 +- examples/example_sdl3_vulkan/main.cpp | 3 +- examples/example_win32_vulkan/main.cpp | 19 ++- 8 files changed, 223 insertions(+), 41 deletions(-) create mode 100644 backends/vulkan/glsl_shader.frag.u32 diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f6ea891c7..4750dedb2 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -269,7 +269,8 @@ struct ImGui_ImplVulkan_Data VkDeviceSize BufferMemoryAlignment; VkDeviceSize NonCoherentAtomSize; VkPipelineCreateFlags PipelineCreateFlags; - VkDescriptorSetLayout DescriptorSetLayout; + VkDescriptorSetLayout DescriptorSetLayoutTexture; + VkDescriptorSetLayout DescriptorSetLayoutSampler; VkPipelineLayout PipelineLayout; VkPipeline Pipeline; // pipeline for main render pass (created by app) VkShaderModule ShaderModuleVert; @@ -279,6 +280,9 @@ struct ImGui_ImplVulkan_Data // Texture management VkSampler SamplerLinear; + VkSampler SamplerNearest; + VkDescriptorSet SamplerLinearDS; + VkDescriptorSet SamplerNearestDS; VkCommandPool TexCommandPool; VkCommandBuffer TexCommandBuffer; @@ -375,30 +379,34 @@ void main() */ static uint32_t __glsl_shader_frag_spv[] = { - 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x07230203,0x00010000,0x0008000b,0x00000023,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,0x00000000,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, + 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000015,0x7865545f,0x65727574, + 0x00000000,0x00050005,0x00000019,0x6d61535f,0x72656c70,0x00000000,0x00040047,0x00000009, + 0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,0x00000000,0x00040047,0x00000015, + 0x00000022,0x00000000,0x00040047,0x00000015,0x00000021,0x00000000,0x00040047,0x00000019, + 0x00000022,0x00000001,0x00040047,0x00000019,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,0x00040020, + 0x00000014,0x00000000,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000000,0x0002001a, + 0x00000017,0x00040020,0x00000018,0x00000000,0x00000017,0x0004003b,0x00000018,0x00000019, + 0x00000000,0x0003001b,0x0000001b,0x00000013,0x0004002b,0x0000000e,0x0000001d,0x00000001, + 0x00040020,0x0000001e,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,0x0000000f, + 0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000013,0x00000016,0x00000015, + 0x0004003d,0x00000017,0x0000001a,0x00000019,0x00050056,0x0000001b,0x0000001c,0x00000016, + 0x0000001a,0x00050041,0x0000001e,0x0000001f,0x0000000d,0x0000001d,0x0004003d,0x0000000a, + 0x00000020,0x0000001f,0x00050057,0x00000007,0x00000021,0x0000001c,0x00000020,0x00050085, + 0x00000007,0x00000022,0x00000012,0x00000021,0x0003003e,0x00000009,0x00000022,0x000100fd, 0x00010038 }; @@ -510,6 +518,9 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1]; vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); + + // use linear sampler by default + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } // Render function @@ -618,6 +629,16 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm pcmd->UserCallback(draw_list, pcmd); last_desc_set = VK_NULL_HANDLE; } + /*else if (pcmd->UserCallback == ImDrawCallback_SetSamplerLinear) + { // Bind Sampler + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); + + } + else if (pcmd->UserCallback == ImDrawCallback_SetSamplerNearest) + { + // Bind Sampler + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); + }*/ else { // Project scissor/clipping rectangles into framebuffer space @@ -747,7 +768,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) } // Create the Descriptor Set - backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->SamplerLinear, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); // Store identifiers tex->SetTexID((ImTextureID)backend_tex->DescriptorSet); @@ -1065,12 +1086,40 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; VkResult err; - if (!bd->DescriptorSetLayout) - ImGui_ImplVulkan_CreateDescriptorSetLayout(&bd->DescriptorSetLayout, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + if (!bd->DescriptorSetLayoutTexture) + { + VkDescriptorSetLayoutBinding binding[1] = {}; + binding[0].binding = 0; + binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + binding[0].descriptorCount = 1; + binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.bindingCount = 1; + info.pBindings = binding; + err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayoutTexture); + check_vk_result(err); + } + + if (!bd->DescriptorSetLayoutSampler) + { + VkDescriptorSetLayoutBinding binding[1] = {}; + binding[0].binding = 0; + binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + binding[0].descriptorCount = 1; + binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.bindingCount = 1; + info.pBindings = binding; + err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayoutSampler); + check_vk_result(err); + } if (v->DescriptorPoolSize != 0) { - IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE); + // TODO: need to account for the samplers too + IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE); VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -1082,10 +1131,9 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - // Create sampler - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. if (!bd->SamplerLinear) { + // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = VK_FILTER_LINEAR; @@ -1101,6 +1149,87 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } + if (!bd->SamplerNearest) + { + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_NEAREST; + info.minFilter = VK_FILTER_NEAREST; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.minLod = -1000; + info.maxLod = 1000; + info.maxAnisotropy = 1.0f; + err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerNearest); + check_vk_result(err); + } + + if (!bd->SamplerLinearDS) + { + VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; + + // Create Descriptor Set: + VkDescriptorSet descriptor_set; + { + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &bd->DescriptorSetLayoutSampler; + VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); + check_vk_result(err); + } + + // Update the Descriptor Set: + { + VkDescriptorImageInfo desc_image[1] = {}; + desc_image[0].sampler = bd->SamplerLinear; + VkWriteDescriptorSet sampler_write_desc[1] = {}; + sampler_write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + sampler_write_desc[0].dstSet = descriptor_set; + sampler_write_desc[0].descriptorCount = 1; + sampler_write_desc[0].dstBinding = 0; + sampler_write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + sampler_write_desc[0].pImageInfo = desc_image; + vkUpdateDescriptorSets(v->Device, 1, sampler_write_desc, 0, nullptr); + } + bd->SamplerLinearDS = descriptor_set; + } + + if (!bd->SamplerNearestDS) + { + VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; + + // Create Descriptor Set: + VkDescriptorSet descriptor_set; + { + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &bd->DescriptorSetLayoutSampler; + VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); + check_vk_result(err); + } + + // Update the Descriptor Set: + { + VkDescriptorImageInfo desc_image[1] = {}; + desc_image[0].sampler = bd->SamplerNearest; + VkWriteDescriptorSet sampler_write_desc[1] = {}; + sampler_write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + sampler_write_desc[0].dstSet = descriptor_set; + sampler_write_desc[0].descriptorCount = 1; + sampler_write_desc[0].dstBinding = 0; + sampler_write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + sampler_write_desc[0].pImageInfo = desc_image; + vkUpdateDescriptorSets(v->Device, 1, sampler_write_desc, 0, nullptr); + } + bd->SamplerNearestDS = descriptor_set; + } + if (!bd->PipelineLayout) { // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix @@ -1108,10 +1237,10 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].offset = sizeof(float) * 0; push_constants[0].size = sizeof(float) * 4; - VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout }; + VkDescriptorSetLayout set_layout[2] = { bd->DescriptorSetLayoutTexture, bd->DescriptorSetLayoutSampler }; VkPipelineLayoutCreateInfo layout_info = {}; layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; + layout_info.setLayoutCount = 2; layout_info.pSetLayouts = set_layout; layout_info.pushConstantRangeCount = 1; layout_info.pPushConstantRanges = push_constants; @@ -1192,9 +1321,11 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; } if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; } if (bd->SamplerLinear) { vkDestroySampler(v->Device, bd->SamplerLinear, v->Allocator); bd->SamplerLinear = VK_NULL_HANDLE; } + if (bd->SamplerNearest) { vkDestroySampler(v->Device, bd->SamplerNearest, v->Allocator); bd->SamplerNearest = VK_NULL_HANDLE; } if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } - if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } + if (bd->DescriptorSetLayoutTexture) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutTexture, v->Allocator); bd->DescriptorSetLayoutTexture = VK_NULL_HANDLE; } + if (bd->DescriptorSetLayoutSampler) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutSampler, v->Allocator); bd->DescriptorSetLayoutSampler = VK_NULL_HANDLE; } if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } @@ -1355,7 +1486,7 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) // Register a texture by creating a descriptor // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. -VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout) +VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayout image_layout) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; @@ -1368,7 +1499,7 @@ VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorPool = pool; alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = &bd->DescriptorSetLayout; + alloc_info.pSetLayouts = &bd->DescriptorSetLayoutTexture; VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); check_vk_result(err); } @@ -1377,14 +1508,13 @@ VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image if (descriptor_set != VK_NULL_HANDLE) { VkDescriptorImageInfo desc_image[1] = {}; - desc_image[0].sampler = sampler; desc_image[0].imageView = image_view; desc_image[0].imageLayout = image_layout; VkWriteDescriptorSet write_desc[1] = {}; write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_desc[0].dstSet = descriptor_set; write_desc[0].descriptorCount = 1; - write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; write_desc[0].pImageInfo = desc_image; vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, nullptr); } diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index c3fef5105..444d400d6 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -78,7 +78,8 @@ #endif // Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). -#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (8) // Minimum per atlas +#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE (8) // Minimum per atlas +#define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE (2) // Minimum for linear + nearest // Specify settings to create pipeline and swapchain struct ImGui_ImplVulkan_PipelineInfo @@ -155,7 +156,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* te // Register a texture (VkDescriptorSet == ImTextureID) // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem // Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. -IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout); +IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayout image_layout); IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set); // Optional: load Vulkan functions with a custom function loader diff --git a/backends/vulkan/glsl_shader.frag b/backends/vulkan/glsl_shader.frag index ce7e6f72b..00fa28c64 100644 --- a/backends/vulkan/glsl_shader.frag +++ b/backends/vulkan/glsl_shader.frag @@ -1,7 +1,8 @@ #version 450 core layout(location = 0) out vec4 fColor; -layout(set=0, binding=0) uniform sampler2D sTexture; +layout(set=0, binding=0) uniform texture2D _Texture; +layout(set=1, binding=0) uniform sampler _Sampler; layout(location = 0) in struct { vec4 Color; @@ -10,5 +11,5 @@ layout(location = 0) in struct { void main() { - fColor = In.Color * texture(sTexture, In.UV.st); + fColor = In.Color * texture(sampler2D(_Texture, _Sampler), In.UV.st); } diff --git a/backends/vulkan/glsl_shader.frag.u32 b/backends/vulkan/glsl_shader.frag.u32 new file mode 100644 index 000000000..725f72f3b --- /dev/null +++ b/backends/vulkan/glsl_shader.frag.u32 @@ -0,0 +1,30 @@ + // 1112.0.0 + 0x07230203,0x00010000,0x0008000b,0x00000023,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,0x00000015,0x7865545f,0x65727574, + 0x00000000,0x00050005,0x00000019,0x6d61535f,0x72656c70,0x00000000,0x00040047,0x00000009, + 0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,0x00000000,0x00040047,0x00000015, + 0x00000022,0x00000000,0x00040047,0x00000015,0x00000021,0x00000000,0x00040047,0x00000019, + 0x00000022,0x00000001,0x00040047,0x00000019,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,0x00040020, + 0x00000014,0x00000000,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000000,0x0002001a, + 0x00000017,0x00040020,0x00000018,0x00000000,0x00000017,0x0004003b,0x00000018,0x00000019, + 0x00000000,0x0003001b,0x0000001b,0x00000013,0x0004002b,0x0000000e,0x0000001d,0x00000001, + 0x00040020,0x0000001e,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,0x0000000f, + 0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000013,0x00000016,0x00000015, + 0x0004003d,0x00000017,0x0000001a,0x00000019,0x00050056,0x0000001b,0x0000001c,0x00000016, + 0x0000001a,0x00050041,0x0000001e,0x0000001f,0x0000000d,0x0000001d,0x0004003d,0x0000000a, + 0x00000020,0x0000001f,0x00050057,0x00000007,0x00000021,0x0000001c,0x00000020,0x00050085, + 0x00000007,0x00000022,0x00000012,0x00000021,0x0003003e,0x00000009,0x00000022,0x000100fd, + 0x00010038 diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index d70c7ce1b..b6bfdee91 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -193,7 +193,8 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index f39534393..956ee0025 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -184,7 +184,8 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index f461aab4c..a9414b5e5 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -186,7 +186,8 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 7f1ccd0c8..488676b24 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -182,7 +182,8 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -435,6 +436,12 @@ int main(int, char**) bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + //int my_image_width = 0; + //int my_image_height = 0; + //GLuint my_image_texture = 0; + //bool ret = LoadTextureFromFile("../../MyImage01.jpg", &my_image_texture, &my_image_width, &my_image_height); + //IM_ASSERT(ret); + // Main loop bool done = false; while (!done) @@ -457,6 +464,16 @@ int main(int, char**) ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); + //ImGui::Begin("SDL_GPU Texture Test"); + //ImGui::Text("pointer = %p", &my_texture); + //ImGui::Text("size = %d x %d", my_image_width, my_image_height); + //ImGui::Image((ImTextureID)(intptr_t)my_texture, ImVec2((float)my_image_width * 3, (float)my_image_height * 3)); + //ImGui::SameLine(); + //ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_SetSamplerNearest, NULL); + //ImGui::Image((ImTextureID)(intptr_t)my_texture, ImVec2((float)my_image_width * 3, (float)my_image_height * 3)); + //ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_SetSamplerLinear, NULL); + //ImGui::End(); + // 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); From ac261203a58e7cb3db8c7dbbb9665ed92ffac1b7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Apr 2026 14:25:08 +0200 Subject: [PATCH 06/10] (Breaking) Backends: Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (fixes, amends) (#914) --- backends/imgui_impl_vulkan.cpp | 233 ++++++++++--------------- backends/imgui_impl_vulkan.h | 17 +- docs/CHANGELOG.txt | 12 ++ examples/example_glfw_vulkan/main.cpp | 2 +- examples/example_sdl2_vulkan/main.cpp | 2 +- examples/example_sdl3_vulkan/main.cpp | 2 +- examples/example_win32_vulkan/main.cpp | 2 +- imgui.cpp | 3 + imgui.h | 2 +- 9 files changed, 121 insertions(+), 154 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 4750dedb2..ea1cade4a 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,15 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends. +// - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler. +// - Before: ImGui_ImplVulkan_AddTexture(VkSampler, VkImageView, VkImageLayout) +// - After: ImGui_ImplVulkan_AddTexture(VkImageView, VkImageLayout) +// - Kept inline redirection function that ignores the sampler. +// - When creating your own descriptor pool (instead of letting backend creates its own): +// - Before: need at least IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER. +// - After: need at least IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE. +// + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER. // 2026-03-11: Vulkan: Added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[] to allow specifying extra dynamic states to add when creating the VkPipeline. (#9211) // 2025-09-26: [Helpers] *BREAKING CHANGE*: Vulkan: Helper ImGui_ImplVulkanH_DestroyWindow() does not call vkDestroySurfaceKHR(): as surface is created by caller of ImGui_ImplVulkanH_CreateOrResizeWindow(), it is more consistent that we don't destroy it. (#9163) // 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) @@ -322,7 +331,7 @@ void main() */ static uint32_t __glsl_shader_vert_spv[] = { - 0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b, + 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, @@ -335,10 +344,10 @@ static uint32_t __glsl_shader_vert_spv[] = 0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001, 0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,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,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x0000001e,0x00000001,0x00030047,0x00000019,0x00000002,0x00050048,0x00000019,0x00000000, + 0x0000000b,0x00000000,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00030047,0x0000001e, + 0x00000002,0x00050048,0x0000001e,0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e, + 0x00000001,0x00000023,0x00000008,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, @@ -370,11 +379,12 @@ static uint32_t __glsl_shader_vert_spv[] = /* #version 450 core layout(location = 0) out vec4 fColor; -layout(set=0, binding=0) uniform sampler2D sTexture; +layout(set=0, binding=0) uniform texture2D _Texture; +layout(set=1, binding=0) uniform sampler _Sampler; layout(location = 0) in struct { vec4 Color; vec2 UV; } In; void main() { - fColor = In.Color * texture(sTexture, In.UV.st); + fColor = In.Color * texture(sampler2D(_Texture, _Sampler), In.UV.st); } */ static uint32_t __glsl_shader_frag_spv[] = @@ -388,8 +398,8 @@ static uint32_t __glsl_shader_frag_spv[] = 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000015,0x7865545f,0x65727574, 0x00000000,0x00050005,0x00000019,0x6d61535f,0x72656c70,0x00000000,0x00040047,0x00000009, 0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,0x00000000,0x00040047,0x00000015, - 0x00000022,0x00000000,0x00040047,0x00000015,0x00000021,0x00000000,0x00040047,0x00000019, - 0x00000022,0x00000001,0x00040047,0x00000019,0x00000021,0x00000000,0x00020013,0x00000002, + 0x00000021,0x00000000,0x00040047,0x00000015,0x00000022,0x00000000,0x00040047,0x00000019, + 0x00000021,0x00000000,0x00040047,0x00000019,0x00000022,0x00000001,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, @@ -484,9 +494,10 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory buffer_size = buffer_size_aligned; } -static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* rb, int fb_width, int fb_height) +static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, ImGui_ImplVulkan_RenderState* render_state, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* rb, int fb_width, int fb_height) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + render_state->SamplerCurrentDS = bd->SamplerLinearDS; // Bind pipeline: vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); @@ -518,9 +529,6 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1]; vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); - - // use linear sampler by default - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } // Render function @@ -600,10 +608,12 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm render_state.CommandBuffer = command_buffer; render_state.Pipeline = pipeline; render_state.PipelineLayout = bd->PipelineLayout; + render_state.SamplerLinearDS = render_state.SamplerCurrentDS = bd->SamplerLinearDS; + render_state.SamplerNearestDS = bd->SamplerNearestDS; platform_io.Renderer_RenderState = &render_state; // Setup desired Vulkan state - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); + ImGui_ImplVulkan_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, rb, fb_width, fb_height); // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports @@ -611,7 +621,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) - VkDescriptorSet last_desc_set = VK_NULL_HANDLE; + VkDescriptorSet last_image_view = VK_NULL_HANDLE; + VkDescriptorSet last_sampler = VK_NULL_HANDLE; int global_vtx_offset = 0; int global_idx_offset = 0; for (const ImDrawList* draw_list : draw_data->CmdLists) @@ -624,21 +635,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // 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_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); + { + ImGui_ImplVulkan_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, rb, fb_width, fb_height); + last_image_view = last_sampler = VK_NULL_HANDLE; + } else pcmd->UserCallback(draw_list, pcmd); - last_desc_set = VK_NULL_HANDLE; } - /*else if (pcmd->UserCallback == ImDrawCallback_SetSamplerLinear) - { // Bind Sampler - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); - - } - else if (pcmd->UserCallback == ImDrawCallback_SetSamplerNearest) - { - // Bind Sampler - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); - }*/ else { // Project scissor/clipping rectangles into framebuffer space @@ -661,11 +664,14 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y); vkCmdSetScissor(command_buffer, 0, 1, &scissor); - // Bind DescriptorSet with font or user texture - VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID(); - if (desc_set != last_desc_set) - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr); - last_desc_set = desc_set; + // Bind DescriptorSets for image view (font or user texture) and samplers + VkDescriptorSet image_view = (VkDescriptorSet)pcmd->GetTexID(); + if (image_view != last_image_view) + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &image_view, 0, nullptr); + if (render_state.SamplerCurrentDS != last_sampler) + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &render_state.SamplerCurrentDS, 0, nullptr); + last_image_view = image_view; + last_sampler = render_state.SamplerCurrentDS; // Draw vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); @@ -1080,6 +1086,33 @@ static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDescriptorSetLayout* p_ check_vk_result(err); } +static VkDescriptorSet ImGui_ImplVulkan_CreateSamplerDS(VkSampler sampler) +{ + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + + VkDescriptorSet descriptor_set; + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &bd->DescriptorSetLayoutSampler; + VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); + check_vk_result(err); + + VkDescriptorImageInfo desc_image = {}; + desc_image.sampler = sampler; + VkWriteDescriptorSet sampler_write_desc = {}; + sampler_write_desc.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + sampler_write_desc.dstSet = descriptor_set; + sampler_write_desc.descriptorCount = 1; + sampler_write_desc.dstBinding = 0; + sampler_write_desc.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + sampler_write_desc.pImageInfo = &desc_image; + vkUpdateDescriptorSets(v->Device, 1, &sampler_write_desc, 0, nullptr); + return descriptor_set; +} + bool ImGui_ImplVulkan_CreateDeviceObjects() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); @@ -1087,53 +1120,32 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() VkResult err; if (!bd->DescriptorSetLayoutTexture) - { - VkDescriptorSetLayoutBinding binding[1] = {}; - binding[0].binding = 0; - binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - binding[0].descriptorCount = 1; - binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.bindingCount = 1; - info.pBindings = binding; - err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayoutTexture); - check_vk_result(err); - } - + ImGui_ImplVulkan_CreateDescriptorSetLayout(&bd->DescriptorSetLayoutTexture, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); if (!bd->DescriptorSetLayoutSampler) - { - VkDescriptorSetLayoutBinding binding[1] = {}; - binding[0].binding = 0; - binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - binding[0].descriptorCount = 1; - binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.bindingCount = 1; - info.pBindings = binding; - err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayoutSampler); - check_vk_result(err); - } + ImGui_ImplVulkan_CreateDescriptorSetLayout(&bd->DescriptorSetLayoutSampler, VK_DESCRIPTOR_TYPE_SAMPLER); if (v->DescriptorPoolSize != 0) { - // TODO: need to account for the samplers too - IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE); - VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; + IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE); + VkDescriptorPoolSize pool_sizes[] = + { + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, v->DescriptorPoolSize }, + { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, + }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = v->DescriptorPoolSize; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &pool_size; + pool_info.maxSets = v->DescriptorPoolSize + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE; + pool_info.poolSizeCount = (uint32_t)IM_COUNTOF(pool_sizes); + pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool); check_vk_result(err); } - if (!bd->SamplerLinear) + // Create samplers + // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. + if (!bd->SamplerLinear || !bd->SamplerNearest) { - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = VK_FILTER_LINEAR; @@ -1147,87 +1159,14 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() info.maxAnisotropy = 1.0f; err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerLinear); check_vk_result(err); - } + bd->SamplerLinearDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerLinear); - if (!bd->SamplerNearest) - { - VkSamplerCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = VK_FILTER_NEAREST; info.minFilter = VK_FILTER_NEAREST; info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.minLod = -1000; - info.maxLod = 1000; - info.maxAnisotropy = 1.0f; err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerNearest); check_vk_result(err); - } - - if (!bd->SamplerLinearDS) - { - VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; - - // Create Descriptor Set: - VkDescriptorSet descriptor_set; - { - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = pool; - alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = &bd->DescriptorSetLayoutSampler; - VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); - check_vk_result(err); - } - - // Update the Descriptor Set: - { - VkDescriptorImageInfo desc_image[1] = {}; - desc_image[0].sampler = bd->SamplerLinear; - VkWriteDescriptorSet sampler_write_desc[1] = {}; - sampler_write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - sampler_write_desc[0].dstSet = descriptor_set; - sampler_write_desc[0].descriptorCount = 1; - sampler_write_desc[0].dstBinding = 0; - sampler_write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - sampler_write_desc[0].pImageInfo = desc_image; - vkUpdateDescriptorSets(v->Device, 1, sampler_write_desc, 0, nullptr); - } - bd->SamplerLinearDS = descriptor_set; - } - - if (!bd->SamplerNearestDS) - { - VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; - - // Create Descriptor Set: - VkDescriptorSet descriptor_set; - { - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = pool; - alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = &bd->DescriptorSetLayoutSampler; - VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); - check_vk_result(err); - } - - // Update the Descriptor Set: - { - VkDescriptorImageInfo desc_image[1] = {}; - desc_image[0].sampler = bd->SamplerNearest; - VkWriteDescriptorSet sampler_write_desc[1] = {}; - sampler_write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - sampler_write_desc[0].dstSet = descriptor_set; - sampler_write_desc[0].descriptorCount = 1; - sampler_write_desc[0].dstBinding = 0; - sampler_write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - sampler_write_desc[0].pImageInfo = desc_image; - vkUpdateDescriptorSets(v->Device, 1, sampler_write_desc, 0, nullptr); - } - bd->SamplerNearestDS = descriptor_set; + bd->SamplerNearestDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerNearest); } if (!bd->PipelineLayout) @@ -1325,7 +1264,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } if (bd->DescriptorSetLayoutTexture) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutTexture, v->Allocator); bd->DescriptorSetLayoutTexture = VK_NULL_HANDLE; } - if (bd->DescriptorSetLayoutSampler) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutSampler, v->Allocator); bd->DescriptorSetLayoutSampler = VK_NULL_HANDLE; } + if (bd->DescriptorSetLayoutSampler) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutSampler, v->Allocator); bd->DescriptorSetLayoutSampler = VK_NULL_HANDLE; } if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } @@ -1521,6 +1460,14 @@ VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayou return descriptor_set; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout) +{ + IM_UNUSED(sampler); + return ImGui_ImplVulkan_AddTexture(image_view, image_layout); +} +#endif + void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 444d400d6..7c00e6567 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -78,8 +78,8 @@ #endif // Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). -#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE (8) // Minimum per atlas -#define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE (2) // Minimum for linear + nearest +#define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE (8) // Minimum per atlas +#define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE (2) // Minimum for linear + nearest // Specify settings to create pipeline and swapchain struct ImGui_ImplVulkan_PipelineInfo @@ -110,7 +110,7 @@ struct ImGui_ImplVulkan_InitInfo uint32_t QueueFamily; VkQueue Queue; VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 - uint32_t DescriptorPoolSize; // Optional: set to create internal descriptor pool automatically instead of using DescriptorPool. + uint32_t DescriptorPoolSize; // Optional: set to create internal ImageView descriptor pool automatically instead of using DescriptorPool. uint32_t MinImageCount; // >= 2 uint32_t ImageCount; // >= MinImageCount VkPipelineCache PipelineCache; // Optional @@ -153,12 +153,14 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ // (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex); -// Register a texture (VkDescriptorSet == ImTextureID) -// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem -// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. +// Register a texture (VkDescriptorSet for a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE == ImTextureID) IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayout image_layout); IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout); // Ignore VkSampler +#endif + // Optional: load Vulkan functions with a custom function loader // This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr); @@ -171,6 +173,9 @@ struct ImGui_ImplVulkan_RenderState VkCommandBuffer CommandBuffer; VkPipeline Pipeline; VkPipelineLayout PipelineLayout; + VkDescriptorSet SamplerLinearDS; // Bilinear filtering sampler + VkDescriptorSet SamplerNearestDS; // Nearest/point filtering sampler + VkDescriptorSet SamplerCurrentDS; // Current sampler (may be changed by callback) }; //------------------------------------------------------------------------- diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 20fd49c66..b97477f28 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,18 @@ HOW TO UPDATE? Breaking Changes: +- Backends: + - Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (#914) + This change allows us to facilitate changing samplers, in line with other backends. [@yaz0r, @ocornut] + - When creating your own descriptor pool (instead of letting backend creates its own): + - Before: need at least IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER. + - After: need at least IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE. + + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER. + - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler. + - Before: ImGui_ImplVulkan_AddTexture(VkSampler, VkImageView, VkImageLayout) + - After: ImGui_ImplVulkan_AddTexture(VkImageView, VkImageLayout) + - Kept inline redirection function that ignores the sampler (will obsolete). + Other Changes: - InputText: diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index b6bfdee91..f2139cef7 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -193,7 +193,7 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE }, { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 956ee0025..131712927 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -184,7 +184,7 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE }, { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index a9414b5e5..04d17ba70 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -186,7 +186,7 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE }, { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 488676b24..7d5091045 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -182,7 +182,7 @@ static void SetupVulkan(ImVector instance_extensions) { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE }, { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; diff --git a/imgui.cpp b/imgui.cpp index 1d2364669..d3811f684 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -395,6 +395,9 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2026/04/22 (1.92.8) - Backends: Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. + - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler. + - When creating your own descriptor pool (instead of letting backend creates its own): need at least IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER. - 2026/03/19 (1.92.7) - MultiSelect: renamed ImGuiMultiSelectFlags_SelectOnClick to ImGuiMultiSelectFlags_SelectOnAuto. - 2026/02/26 (1.92.7) - Separator: fixed a legacy quirk where Separator() was submitting a zero-height item for layout purpose, even though it draws a 1-pixel separator. The fix could affect code e.g. computing height from multiple widgets in order to allocate vertical space for a footer or multi-line status bar. (#2657, #9263) diff --git a/imgui.h b/imgui.h index 5539bc7e3..fcbe5dc0e 100644 --- a/imgui.h +++ b/imgui.h @@ -30,7 +30,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.8 WIP" -#define IMGUI_VERSION_NUM 19273 +#define IMGUI_VERSION_NUM 19274 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 From fb308c14cee26af430bbcfc11178231a882cd2dd Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Apr 2026 14:48:56 +0200 Subject: [PATCH 07/10] Remove noise from 0453ae9 + amend comments. (#914) --- docs/CHANGELOG.txt | 7 +++++++ examples/example_win32_vulkan/main.cpp | 16 ---------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b97477f28..16b51c975 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,8 @@ Breaking Changes: - Before: ImGui_ImplVulkan_AddTexture(VkSampler, VkImageView, VkImageLayout) - After: ImGui_ImplVulkan_AddTexture(VkImageView, VkImageLayout) - Kept inline redirection function that ignores the sampler (will obsolete). + - Vulkan: with the change above it is now possible to change the current Sampler during + rendering, by poking into ImGui_ImplVulkan_RenderState's SamplerCurrentDS. (#914) Other Changes: @@ -124,6 +126,11 @@ Other Changes: - SDL2: made `ImGui_ImplSDL2_GetContentScaleForWindow()`/`ImGui_ImplSDL2_GetContentScaleForDisplay()` helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369) +- Examples: + - GLFW+Vulkan, SDL2+Vulkan, SDL3+Vulkan, Win32+Vulkan: reworked to create a descriptor pool with: + - IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE. + - IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER. + ----------------------------------------------------------------------- diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 7d5091045..cbdbdb830 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -436,12 +436,6 @@ int main(int, char**) bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - //int my_image_width = 0; - //int my_image_height = 0; - //GLuint my_image_texture = 0; - //bool ret = LoadTextureFromFile("../../MyImage01.jpg", &my_image_texture, &my_image_width, &my_image_height); - //IM_ASSERT(ret); - // Main loop bool done = false; while (!done) @@ -464,16 +458,6 @@ int main(int, char**) ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); - //ImGui::Begin("SDL_GPU Texture Test"); - //ImGui::Text("pointer = %p", &my_texture); - //ImGui::Text("size = %d x %d", my_image_width, my_image_height); - //ImGui::Image((ImTextureID)(intptr_t)my_texture, ImVec2((float)my_image_width * 3, (float)my_image_height * 3)); - //ImGui::SameLine(); - //ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_SetSamplerNearest, NULL); - //ImGui::Image((ImTextureID)(intptr_t)my_texture, ImVec2((float)my_image_width * 3, (float)my_image_height * 3)); - //ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_SetSamplerLinear, NULL); - //ImGui::End(); - // 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); From b065713cec5c1613a1d99bac5a79eab4cb3bb4a3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Apr 2026 17:20:27 +0200 Subject: [PATCH 08/10] Backends: OpenGL2/3, SDLRenderer2/3, DirectX9, Metal: moved Init/Shutdown code lower in the file. Allows to point to local functions without forward declaring them. --- backends/imgui_impl_dx9.cpp | 81 ++++---- backends/imgui_impl_metal.mm | 70 +++---- backends/imgui_impl_opengl2.cpp | 62 +++---- backends/imgui_impl_opengl3.cpp | 266 +++++++++++++-------------- backends/imgui_impl_sdlrenderer2.cpp | 71 +++---- backends/imgui_impl_sdlrenderer3.cpp | 71 +++---- 6 files changed, 312 insertions(+), 309 deletions(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 24911fadd..d4ebb84d2 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -325,46 +325,6 @@ static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMA return support; } -bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - - // Setup backend capabilities flags - ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_dx9"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096; - - bd->pd3dDevice = device; - bd->pd3dDevice->AddRef(); - bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); - - return true; -} - -void ImGui_ImplDX9_Shutdown() -{ - ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - - ImGui_ImplDX9_InvalidateDeviceObjects(); - if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); - platform_io.ClearRendererHandlers(); - IM_DELETE(bd); -} - // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h) { @@ -477,6 +437,47 @@ void ImGui_ImplDX9_NewFrame() IM_UNUSED(bd); } + +bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Setup backend capabilities flags + ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_dx9"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096; + + bd->pd3dDevice = device; + bd->pd3dDevice->AddRef(); + bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); + + return true; +} + +void ImGui_ImplDX9_Shutdown() +{ + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGui_ImplDX9_InvalidateDeviceObjects(); + if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); + IM_DELETE(bd); +} + //----------------------------------------------------------------------------- #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 7d604e6a5..e049c5c0b 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -130,41 +130,6 @@ bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device) #pragma mark - Dear ImGui Metal Backend API -bool ImGui_ImplMetal_Init(id device) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - - ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_metal"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - - bd->SharedMetalContext = [[MetalContext alloc] init]; - bd->SharedMetalContext.device = device; - - return true; -} - -void ImGui_ImplMetal_Shutdown() -{ - ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); - IM_UNUSED(bd); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - - ImGui_ImplMetal_DestroyDeviceObjects(); - ImGui_ImplMetal_DestroyBackendData(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); - platform_io.ClearRendererHandlers(); -} - void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); @@ -431,6 +396,41 @@ void ImGui_ImplMetal_DestroyDeviceObjects() [bd->SharedMetalContext.renderPipelineStateCache removeAllObjects]; } +bool ImGui_ImplMetal_Init(id device) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_metal"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + bd->SharedMetalContext = [[MetalContext alloc] init]; + bd->SharedMetalContext.device = device; + + return true; +} + +void ImGui_ImplMetal_Shutdown() +{ + ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); + IM_UNUSED(bd); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGui_ImplMetal_DestroyDeviceObjects(); + ImGui_ImplMetal_DestroyBackendData(); + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); +} + #pragma mark - MetalBuffer implementation @implementation MetalBuffer diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 4fffc5774..3f0116186 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -97,37 +97,6 @@ static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData() } // Functions -bool ImGui_ImplOpenGL2_Init() -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - - // Setup backend capabilities flags - ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_opengl2"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - - return true; -} - -void ImGui_ImplOpenGL2_Shutdown() -{ - ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - - ImGui_ImplOpenGL2_DestroyDeviceObjects(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures); - platform_io.ClearRendererHandlers(); - IM_DELETE(bd); -} - void ImGui_ImplOpenGL2_NewFrame() { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); @@ -344,6 +313,37 @@ void ImGui_ImplOpenGL2_DestroyDeviceObjects() } } +bool ImGui_ImplOpenGL2_Init() +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Setup backend capabilities flags + ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_opengl2"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + return true; +} + +void ImGui_ImplOpenGL2_Shutdown() +{ + ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGui_ImplOpenGL2_DestroyDeviceObjects(); + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); + IM_DELETE(bd); +} + //----------------------------------------------------------------------------- #if defined(__clang__) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index d1894a135..22baf2e33 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -312,139 +312,6 @@ static void ImGui_ImplOpenGL3_ShutdownLoader() } // Functions -bool ImGui_ImplOpenGL3_Init(const char* glsl_version) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - - // Initialize loader - if (!ImGui_ImplOpenGL3_InitLoader()) - return false; - - // Setup backend capabilities flags - ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_opengl3"; - - // Query for GL version (e.g. 320 for GL 3.2) - const char* gl_version_str = (const char*)glGetString(GL_VERSION); -#if defined(IMGUI_IMPL_OPENGL_ES2) - // GLES 2 - bd->GlVersion = 200; - bd->GlProfileIsES2 = true; - IM_UNUSED(gl_version_str); -#else - // Desktop or GLES 3 - GLint major = 0; - GLint minor = 0; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - if (major == 0 && minor == 0) - sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "." - bd->GlVersion = (GLuint)(major * 100 + minor * 10); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &bd->MaxTextureSize); - -#if defined(IMGUI_IMPL_OPENGL_ES3) - bd->GlProfileIsES3 = true; -#else - if (strncmp(gl_version_str, "OpenGL ES 3", 11) == 0) - bd->GlProfileIsES3 = true; -#endif - -#if defined(GL_CONTEXT_PROFILE_MASK) - if (!bd->GlProfileIsES3 && bd->GlVersion >= 320) - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask); - bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0; -#endif - - bd->UseBufferSubData = false; - /* - // Query vendor to enable glBufferSubData kludge -#ifdef _WIN32 - if (const char* vendor = (const char*)glGetString(GL_VENDOR)) - if (strncmp(vendor, "Intel", 5) == 0) - bd->UseBufferSubData = true; -#endif - */ -#endif - -#ifdef IMGUI_IMPL_OPENGL_DEBUG - printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2/IsEs3 = %d/%d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] -#endif - -#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET - if (bd->GlVersion >= 320) - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. -#endif - io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize; - - // Store GLSL version string so we can refer to it later in case we recreate shaders. - // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure. - if (glsl_version == nullptr) - { -#if defined(IMGUI_IMPL_OPENGL_ES2) - glsl_version = "#version 100"; -#elif defined(IMGUI_IMPL_OPENGL_ES3) - glsl_version = "#version 300 es"; -#elif defined(__APPLE__) - glsl_version = "#version 150"; -#else - glsl_version = "#version 130"; -#endif - } - IM_ASSERT((int)strlen(glsl_version) + 2 < IM_COUNTOF(bd->GlslVersionString)); - strcpy(bd->GlslVersionString, glsl_version); - strcat(bd->GlslVersionString, "\n"); - - // Make an arbitrary GL call (we don't actually need the result) - // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know! - GLint current_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); - - // Detect extensions we support -#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE - bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3); -#endif -#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER - bd->HasBindSampler = (bd->GlVersion >= 330 || bd->GlProfileIsES3); -#endif - bd->HasClipOrigin = (bd->GlVersion >= 450); -#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS - GLint num_extensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); - for (GLint i = 0; i < num_extensions; i++) - { - const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i); - if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0) - bd->HasClipOrigin = true; - } -#endif - - return true; -} - -void ImGui_ImplOpenGL3_Shutdown() -{ - ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - - ImGui_ImplOpenGL3_DestroyDeviceObjects(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); - platform_io.ClearRendererHandlers(); - IM_DELETE(bd); - - ImGui_ImplOpenGL3_ShutdownLoader(); -} - void ImGui_ImplOpenGL3_NewFrame() { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); @@ -1055,6 +922,139 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects() ImGui_ImplOpenGL3_DestroyTexture(tex); } +bool ImGui_ImplOpenGL3_Init(const char* glsl_version) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Initialize loader + if (!ImGui_ImplOpenGL3_InitLoader()) + return false; + + // Setup backend capabilities flags + ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_opengl3"; + + // Query for GL version (e.g. 320 for GL 3.2) + const char* gl_version_str = (const char*)glGetString(GL_VERSION); +#if defined(IMGUI_IMPL_OPENGL_ES2) + // GLES 2 + bd->GlVersion = 200; + bd->GlProfileIsES2 = true; + IM_UNUSED(gl_version_str); +#else + // Desktop or GLES 3 + GLint major = 0; + GLint minor = 0; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + if (major == 0 && minor == 0) + sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "." + bd->GlVersion = (GLuint)(major * 100 + minor * 10); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &bd->MaxTextureSize); + +#if defined(IMGUI_IMPL_OPENGL_ES3) + bd->GlProfileIsES3 = true; +#else + if (strncmp(gl_version_str, "OpenGL ES 3", 11) == 0) + bd->GlProfileIsES3 = true; +#endif + +#if defined(GL_CONTEXT_PROFILE_MASK) + if (!bd->GlProfileIsES3 && bd->GlVersion >= 320) + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask); + bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0; +#endif + + bd->UseBufferSubData = false; + /* + // Query vendor to enable glBufferSubData kludge +#ifdef _WIN32 + if (const char* vendor = (const char*)glGetString(GL_VENDOR)) + if (strncmp(vendor, "Intel", 5) == 0) + bd->UseBufferSubData = true; +#endif + */ +#endif + +#ifdef IMGUI_IMPL_OPENGL_DEBUG + printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2/IsEs3 = %d/%d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] +#endif + +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (bd->GlVersion >= 320) + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. +#endif + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize; + + // Store GLSL version string so we can refer to it later in case we recreate shaders. + // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure. + if (glsl_version == nullptr) + { +#if defined(IMGUI_IMPL_OPENGL_ES2) + glsl_version = "#version 100"; +#elif defined(IMGUI_IMPL_OPENGL_ES3) + glsl_version = "#version 300 es"; +#elif defined(__APPLE__) + glsl_version = "#version 150"; +#else + glsl_version = "#version 130"; +#endif + } + IM_ASSERT((int)strlen(glsl_version) + 2 < IM_COUNTOF(bd->GlslVersionString)); + strcpy(bd->GlslVersionString, glsl_version); + strcat(bd->GlslVersionString, "\n"); + + // Make an arbitrary GL call (we don't actually need the result) + // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know! + GLint current_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); + + // Detect extensions we support +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE + bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3); +#endif +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + bd->HasBindSampler = (bd->GlVersion >= 330 || bd->GlProfileIsES3); +#endif + bd->HasClipOrigin = (bd->GlVersion >= 450); +#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS + GLint num_extensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + for (GLint i = 0; i < num_extensions; i++) + { + const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i); + if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0) + bd->HasClipOrigin = true; + } +#endif + + return true; +} + +void ImGui_ImplOpenGL3_Shutdown() +{ + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGui_ImplOpenGL3_DestroyDeviceObjects(); + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); + IM_DELETE(bd); + + ImGui_ImplOpenGL3_ShutdownLoader(); +} + //----------------------------------------------------------------------------- #if defined(__GNUC__) diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index dc86f6c26..dcc03a84d 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -24,6 +24,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// (minor and older changes stripped away, please see git history for details) // 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer2_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer2_CreateFontsTexture() and ImGui_ImplSDLRenderer2_DestroyFontsTexture(). @@ -72,41 +73,6 @@ static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData() } // Functions -bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); - - // Setup backend capabilities flags - ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_sdlrenderer2"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - - bd->Renderer = renderer; - - return true; -} - -void ImGui_ImplSDLRenderer2_Shutdown() -{ - ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - - ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); - platform_io.ClearRendererHandlers(); - IM_DELETE(bd); -} - static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer) { // Clear out any viewports and cliprect set by the user @@ -293,6 +259,41 @@ void ImGui_ImplSDLRenderer2_DestroyDeviceObjects() } } +bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); + + // Setup backend capabilities flags + ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_sdlrenderer2"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + bd->Renderer = renderer; + + return true; +} + +void ImGui_ImplSDLRenderer2_Shutdown() +{ + ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); + IM_DELETE(bd); +} + //----------------------------------------------------------------------------- #if defined(__clang__) diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index be6c97d8c..d317d38b3 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -24,6 +24,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// (minor and older changes stripped away, please see git history for details) // 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer3_CreateFontsTexture() and ImGui_ImplSDLRenderer3_DestroyFontsTexture(). @@ -70,41 +71,6 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData() } // Functions -bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); - - // Setup backend capabilities flags - ImGui_ImplSDLRenderer3_Data* bd = IM_NEW(ImGui_ImplSDLRenderer3_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_sdlrenderer3"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - - bd->Renderer = renderer; - - return true; -} - -void ImGui_ImplSDLRenderer3_Shutdown() -{ - ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - - ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); - platform_io.ClearRendererHandlers(); - IM_DELETE(bd); -} - static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer) { // Clear out any viewports and cliprect set by the user @@ -309,6 +275,41 @@ void ImGui_ImplSDLRenderer3_DestroyDeviceObjects() } } +bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); + + // Setup backend capabilities flags + ImGui_ImplSDLRenderer3_Data* bd = IM_NEW(ImGui_ImplSDLRenderer3_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_sdlrenderer3"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + bd->Renderer = renderer; + + return true; +} + +void ImGui_ImplSDLRenderer3_Shutdown() +{ + ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); + + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); + IM_DELETE(bd); +} + //----------------------------------------------------------------------------- #if defined(__clang__) From 4739af2d515d8f384841c2a66c019dde9ab49097 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 15:58:04 +0200 Subject: [PATCH 09/10] Update VS toolset in all .vcxproj from VS2015 (v140) to VS2017 (v141). It supports vcpkg. --- docs/CHANGELOG.txt | 2 ++ examples/example_allegro5/example_allegro5.vcxproj | 8 ++++---- .../example_glfw_opengl2/example_glfw_opengl2.vcxproj | 8 ++++---- .../example_glfw_opengl3/example_glfw_opengl3.vcxproj | 8 ++++---- .../example_glfw_vulkan/example_glfw_vulkan.vcxproj | 8 ++++---- .../example_glut_opengl2/example_glut_opengl2.vcxproj | 8 ++++---- examples/example_null/example_null.vcxproj | 9 +++++---- .../example_sdl2_directx11.vcxproj | 8 ++++---- .../example_sdl2_opengl2/example_sdl2_opengl2.vcxproj | 8 ++++---- .../example_sdl2_opengl3/example_sdl2_opengl3.vcxproj | 8 ++++---- .../example_sdl2_sdlrenderer2.vcxproj | 10 +++++----- .../example_sdl2_vulkan/example_sdl2_vulkan.vcxproj | 10 +++++----- .../example_sdl3_directx11.vcxproj | 8 ++++---- .../example_sdl3_opengl3/example_sdl3_opengl3.vcxproj | 8 ++++---- .../example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj | 10 +++++----- .../example_sdl3_sdlrenderer3.vcxproj | 8 ++++---- .../example_sdl3_vulkan/example_sdl3_vulkan.vcxproj | 8 ++++---- .../example_win32_directx10.vcxproj | 8 ++++---- .../example_win32_directx11.vcxproj | 9 +++++---- .../example_win32_directx9.vcxproj | 8 ++++---- .../example_win32_opengl3.vcxproj | 8 ++++---- .../example_win32_vulkan/example_win32_vulkan.vcxproj | 9 +++++---- 22 files changed, 92 insertions(+), 87 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 16b51c975..a6351daf8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -127,6 +127,8 @@ Other Changes: helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369) - Examples: + - Update VS toolset in all .vcxproj from VS2015 (v140) to VS2017 (v141). The later is the + first that supports vcpkg. Onward we will likely stop testing building the library with VS2015. - GLFW+Vulkan, SDL2+Vulkan, SDL3+Vulkan, Win32+Vulkan: reworked to create a descriptor pool with: - IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE. - IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER. diff --git a/examples/example_allegro5/example_allegro5.vcxproj b/examples/example_allegro5/example_allegro5.vcxproj index 02f6a4741..aa8a752d7 100644 --- a/examples/example_allegro5/example_allegro5.vcxproj +++ b/examples/example_allegro5/example_allegro5.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj index 2aa25506e..bce5781f4 100644 --- a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj +++ b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj index 4bd503afe..cd59daed3 100644 --- a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj +++ b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj index a81d328df..6f44abfec 100644 --- a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj +++ b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj index c56452b26..2e12665d5 100644 --- a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj +++ b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_null/example_null.vcxproj b/examples/example_null/example_null.vcxproj index 8ef991f3f..75fd43b44 100644 --- a/examples/example_null/example_null.vcxproj +++ b/examples/example_null/example_null.vcxproj @@ -21,33 +21,34 @@ {1A0BF63C-18EF-4BAE-A8DA-055481B11F5D} example_win32_directx11 + 8.1 Application true Unicode - v140 + v141 Application true Unicode - v140 + v141 Application false true Unicode - v140 + v141 Application false true Unicode - v140 + v141 diff --git a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj index c23800c9e..2bcc7097c 100644 --- a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj +++ b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj @@ -29,27 +29,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj index 036463f96..aca6edc5d 100644 --- a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj +++ b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj index 6a81c6770..d0cb96ba1 100644 --- a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj +++ b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj index cf2c890bb..86b883a69 100644 --- a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj +++ b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj @@ -29,27 +29,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 @@ -184,4 +184,4 @@ - + \ No newline at end of file diff --git a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj index bcf99a46c..4bedc45d8 100644 --- a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj +++ b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 @@ -187,4 +187,4 @@ - + \ No newline at end of file diff --git a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj index 340901c3d..f38d290c6 100644 --- a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj +++ b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj @@ -29,27 +29,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj index 051f87d76..c470f88bb 100644 --- a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj +++ b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj index 3d034f52c..02b0d35f2 100644 --- a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj +++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 @@ -186,4 +186,4 @@ - + \ No newline at end of file diff --git a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj index 8b71324cc..f42014544 100644 --- a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj +++ b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj index d48e4aff3..af1144789 100644 --- a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj +++ b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj @@ -28,27 +28,27 @@ Application true MultiByte - v140 + v141 Application true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 Application false true MultiByte - v140 + v141 diff --git a/examples/example_win32_directx10/example_win32_directx10.vcxproj b/examples/example_win32_directx10/example_win32_directx10.vcxproj index d11aed883..7fb767702 100644 --- a/examples/example_win32_directx10/example_win32_directx10.vcxproj +++ b/examples/example_win32_directx10/example_win32_directx10.vcxproj @@ -28,27 +28,27 @@ Application true Unicode - v140 + v141 Application true Unicode - v140 + v141 Application false true Unicode - v140 + v141 Application false true Unicode - v140 + v141 diff --git a/examples/example_win32_directx11/example_win32_directx11.vcxproj b/examples/example_win32_directx11/example_win32_directx11.vcxproj index bace6a2c8..9e89353d4 100644 --- a/examples/example_win32_directx11/example_win32_directx11.vcxproj +++ b/examples/example_win32_directx11/example_win32_directx11.vcxproj @@ -21,33 +21,34 @@ {9F316E83-5AE5-4939-A723-305A94F48005} example_win32_directx11 + 8.1 Application true Unicode - v140 + v141 Application true Unicode - v140 + v141 Application false true Unicode - v140 + v141 Application false true Unicode - v140 + v141 diff --git a/examples/example_win32_directx9/example_win32_directx9.vcxproj b/examples/example_win32_directx9/example_win32_directx9.vcxproj index 8c3f99589..c5efda38b 100644 --- a/examples/example_win32_directx9/example_win32_directx9.vcxproj +++ b/examples/example_win32_directx9/example_win32_directx9.vcxproj @@ -28,27 +28,27 @@ Application true Unicode - v140 + v141 Application true Unicode - v140 + v141 Application false true Unicode - v140 + v141 Application false true Unicode - v140 + v141 diff --git a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj index 98fc38fd3..b9b42677c 100644 --- a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj +++ b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj @@ -28,27 +28,27 @@ Application true Unicode - v140 + v141 Application true Unicode - v140 + v141 Application false true Unicode - v140 + v141 Application false true Unicode - v140 + v141 diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj index dab8afd4e..f3ba4aa61 100644 --- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj @@ -21,33 +21,34 @@ {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88} example_win32_directx11 + 8.1 Application true Unicode - v140 + v141 Application true Unicode - v140 + v141 Application false true Unicode - v140 + v141 Application false true Unicode - v140 + v141 From ac06ad7b48f196d206c867a0638f65a723196cb2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Apr 2026 15:47:33 +0200 Subject: [PATCH 10/10] ImDrawList: made AddCallback() user data default to NULL + minor amends/comments. --- backends/imgui_impl_dx10.cpp | 2 +- backends/imgui_impl_sdlrenderer2.cpp | 2 +- backends/imgui_impl_sdlrenderer3.cpp | 2 +- backends/imgui_impl_sdlrenderer3.h | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_vulkan.h | 2 +- backends/imgui_impl_wgpu.cpp | 11 ++++++----- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 118798325..d80982a30 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. +// 2026-01-19: DirectX10: Added 'SamplerNearest' in ImGui_ImplDX10_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index dcc03a84d..df127dc60 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -15,7 +15,7 @@ // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can 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 diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index d317d38b3..dbfbea235 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -15,7 +15,7 @@ // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can 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 diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index f5f53b9d2..c01a16d48 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -15,7 +15,7 @@ // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can 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 diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index ea1cade4a..35315350a 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -2,7 +2,7 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. +// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 7c00e6567..c4b804144 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -2,7 +2,7 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. +// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 86bb36cc3..7b4082fde 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -83,7 +83,7 @@ struct ImGui_ImplWGPU_Texture struct RenderResources { - WGPUSampler Sampler = nullptr; // Sampler for textures + WGPUSampler SamplerLinear = nullptr; // Sampler for textures WGPUBuffer Uniforms = nullptr; // Shader uniforms WGPUBindGroup CommonBindGroup = nullptr; // Resources bind-group to bind the common resources to pipeline ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map) @@ -296,7 +296,7 @@ static void SafeRelease(WGPUShaderModule& res) } static void SafeRelease(RenderResources& res) { - SafeRelease(res.Sampler); + SafeRelease(res.SamplerLinear); SafeRelease(res.Uniforms); SafeRelease(res.CommonBindGroup); SafeRelease(res.ImageBindGroupLayout); @@ -538,6 +538,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder { // 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.) + IM_ASSERT(pcmd->UserCallback != ImDrawCallback_SetSamplerLinear && pcmd->UserCallback != ImDrawCallback_SetSamplerNearest); // Unsupported. if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr); else @@ -824,13 +825,13 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; sampler_desc.maxAnisotropy = 1; - bd->renderResources.Sampler = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); + bd->renderResources.SamplerLinear = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); // Create resource bind group WGPUBindGroupEntry common_bg_entries[] = { { nullptr, 0, bd->renderResources.Uniforms, 0, MEMALIGN(sizeof(Uniforms), 16), 0, 0 }, - { nullptr, 1, 0, 0, 0, bd->renderResources.Sampler, 0 }, + { nullptr, 1, 0, 0, 0, bd->renderResources.SamplerLinear, 0 }, }; WGPUBindGroupDescriptor common_bg_descriptor = {}; common_bg_descriptor.layout = bg_layouts[0]; @@ -896,7 +897,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) bd->numFramesInFlight = init_info->NumFramesInFlight; bd->frameIndex = UINT_MAX; - bd->renderResources.Sampler = nullptr; + bd->renderResources.SamplerLinear = nullptr; bd->renderResources.Uniforms = nullptr; bd->renderResources.CommonBindGroup = nullptr; bd->renderResources.ImageBindGroups.Data.reserve(100); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a6351daf8..1a0a647e9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -113,6 +113,8 @@ Other Changes: reporting the common clipper error over a table sanity check assert). (#9350) - Tweaked assert triggering when first item height measurement fails, and made it a better recoverable error. (#9350) +- DrawList: + - Made AddCallback() user data default parameter. - Misc: - Minor optimization: reduce redudant label scanning in common widgets. - Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). diff --git a/imgui.h b/imgui.h index fcbe5dc0e..707af9164 100644 --- a/imgui.h +++ b/imgui.h @@ -3385,7 +3385,7 @@ struct ImDrawList // - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in ImDrawCmd::UserCallbackData during render. // - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data. // - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to copy/store a simple void*. - IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size = 0); + IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata = NULL, size_t userdata_size = 0); // Advanced: Miscellaneous IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible