From 84b4b35902b40cff54649d6d2148947a26380014 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Sun, 12 Apr 2026 15:50:54 +0200 Subject: [PATCH 01/44] Fonts: rework UpdateCurrentFontSize() check. (#9364) Consistent with line above. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 0dbd6321..79e9a780 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9107,7 +9107,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) } g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL; - g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; + g.FontBakedScale = (g.FontBaked != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; g.DrawListSharedData.FontScale = g.FontBakedScale; } From f83a378d623a9fa8f55b749883f811fe4cec3742 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Apr 2026 14:11:19 +0200 Subject: [PATCH 02/44] TabBar: changed edge's TabItem ClipRect to not pass an inverted PushClipRect(). While not currently a problem, it would be if ImRect::Overlaps() is changed to use <= instead of < (cc: #3976 which deal with Contains but sort of similar topic). Changing ImDrawList::PushClipRect()'s intersect_with_current_clip_rect path to use ClipRectFull() would also fix this, but it may ambiguous there which behavior would be correct. Amend 1ec464eb9. --- imgui_draw.cpp | 2 +- imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 97c6f355..657e1c51 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -662,7 +662,7 @@ void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool i if (intersect_with_current_clip_rect) { ImVec4 current = _CmdHeader.ClipRect; - if (cr.x < current.x) cr.x = current.x; + if (cr.x < current.x) cr.x = current.x; // = ClipWith(). Note that passing inverted range wouldn't be fixed here. if (cr.y < current.y) cr.y = current.y; if (cr.z > current.z) cr.z = current.z; if (cr.w > current.w) cr.w = current.w; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7d0ac8c3..e94dd3e8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -10598,7 +10598,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX); if (want_clip_rect) - PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); + PushClipRect(ImVec2(ImClamp(bb.Min.x, tab_bar->ScrollingRectMinX, tab_bar->ScrollingRectMaxX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; ItemSize(bb.GetSize(), style.FramePadding.y); From bbd0af72565c12322ce4b3864d030991dc0e698f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Apr 2026 19:38:15 +0200 Subject: [PATCH 03/44] Multi-Select: Box-Select+Tables: fixed using BeginMultiSelect() before table layout is locked. (#8250) --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 2 +- imgui_widgets.cpp | 6 +++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e18f5a99..ab05e516 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other Changes: and ImGuiSelectionUserData is technically opaque storage. (#7994, #1861) (we will probably bring this back as a minor optimization if we have a way to for user to tell us ImGuiSelectionUserData are indices) + - Box-Select, Tables: fixed an issue when calling `BeginMultiSelect()` in a table + before layout has been locked (first row or headers row submitted). (#8250) - Fonts: - imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details. - Clipper: diff --git a/imgui_tables.cpp b/imgui_tables.cpp index d06fe1e7..c311c904 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1647,7 +1647,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo ImGuiTable* table = g.CurrentTable; IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); - IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); + IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select. IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e94dd3e8..0d1a178c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7958,8 +7958,12 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel // FIXME: Workaround to the fact we override CursorMaxPos, meaning size measurement are lost. (#8250) // They should perhaps be stacked properly? if (ImGuiTable* table = g.CurrentTable) - if (table->CurrentColumn != -1) + { + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + else if (table->CurrentColumn != -1) TableEndCell(table); // This is currently safe to call multiple time. If that properly is lost we can extract the "save measurement" part of it. + } // FIXME: BeginFocusScope() const ImGuiID id = window->IDStack.back(); From 3cd86830613e5a48f0334bc58f26757590d1d501 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Apr 2026 16:45:18 +0200 Subject: [PATCH 04/44] Fonts: assert when using MergeMode with an explicit size over a target font with an implicit size, as scale factor are likely erroneous. (#9361) --- docs/CHANGELOG.txt | 2 ++ imgui.h | 1 + imgui_draw.cpp | 13 ++++++++++++- misc/freetype/imgui_freetype.cpp | 3 ++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ab05e516..739a1925 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other Changes: before layout has been locked (first row or headers row submitted). (#8250) - Fonts: - imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details. + - Assert when using MergeMode with an explicit size over a target font with an implicit + size, as scale factor are likely erroneous. (#9361) - Clipper: - Improved error reporting when misusing the clipper inside a table (prioritize reporting the common clipper error over a table sanity check assert). (#9350) diff --git a/imgui.h b/imgui.h index e73b5b0d..fb30f362 100644 --- a/imgui.h +++ b/imgui.h @@ -3861,6 +3861,7 @@ enum ImFontFlags_ ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display. + ImFontFlags_ImplicitRefSize = 1 << 4, // [Internal] Reference size was not set explicitly. }; // Font runtime data and rendering diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 657e1c51..21e368a4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3039,7 +3039,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) } else { - IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. + IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font!"); // When using MergeMode make sure that a font has already been added before. font = font_cfg_in->DstFont ? font_cfg_in->DstFont : Fonts.back(); ImFontAtlasFontDiscardBakes(this, font, 0); // Need to discard bakes if the font was already used, because baked->FontLoaderDatas[] will change size. (#9162) } @@ -3067,6 +3067,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL); IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet. } + // | Target w/ Implicit RefSize | Target w/ Explicit RefSize | + // Adding w/ Implicit RefSize: | OK (same scale) | OK (same scale) | + // Adding w/ Explicit RefSize: | KO | OK (custom scale) | + if (font_cfg_in->MergeMode && font_cfg_in->SizePixels > 0) + IM_ASSERT((font->Flags & ImFontFlags_ImplicitRefSize) == 0 && "Cannot use MergeMode with an explicit reference size when the destination font used an implicit reference size!"); IM_ASSERT(font_cfg->FontLoaderData == NULL); if (!ImFontAtlasFontSourceInit(this, font_cfg)) @@ -3134,7 +3139,10 @@ ImFont* ImFontAtlas::AddFontDefaultBitmap(const ImFontConfig* font_cfg_template) if (!font_cfg_template) font_cfg.PixelSnapH = true; // Prevents sub-integer scaling factors at lower-level layers. if (font_cfg.SizePixels <= 0.0f) + { font_cfg.SizePixels = 13.0f; // This only serves (1) as a reference for GlyphOffset.y setting and (2) as a default for pre-1.92 backend. + font_cfg.Flags |= ImFontFlags_ImplicitRefSize; + } if (font_cfg.Name[0] == '\0') ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "ProggyClean.ttf"); font_cfg.EllipsisChar = (ImWchar)0x0085; @@ -3159,7 +3167,10 @@ ImFont* ImFontAtlas::AddFontDefaultVector(const ImFontConfig* font_cfg_template) if (!font_cfg_template) font_cfg.PixelSnapH = true; // Precisely match ProggyClean, but prevents sub-integer scaling factors at lower-level layers. if (font_cfg.SizePixels <= 0.0f) + { font_cfg.SizePixels = 13.0f; + font_cfg.Flags |= ImFontFlags_ImplicitRefSize; + } if (font_cfg.Name[0] == '\0') ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "ProggyForever.ttf"); font_cfg.ExtraSizeScale *= 1.015f; // Match ProggyClean diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 76c0ac9b..3c817d20 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -428,8 +428,9 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s { IM_UNUSED(atlas); float size = baked->Size; + const float ref_size = baked->OwnerFont->Sources[0]->SizePixels; if (src->MergeMode && src->SizePixels != 0.0f) - size *= (src->SizePixels / baked->OwnerFont->Sources[0]->SizePixels); + size *= (src->SizePixels / ref_size); size *= src->ExtraSizeScale; ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; From ed4dd679f1a103f01094a7f864ae74b7758de88a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 14 Apr 2026 16:39:08 +0200 Subject: [PATCH 05/44] Fixed vertical scrollbar top coordinates when using thick borders on windows with no title bar and no menu bar. (#9366) --- docs/CHANGELOG.txt | 3 +++ imgui_widgets.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 739a1925..5a305155 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,9 @@ Other Changes: user to tell us ImGuiSelectionUserData are indices) - Box-Select, Tables: fixed an issue when calling `BeginMultiSelect()` in a table before layout has been locked (first row or headers row submitted). (#8250) +- Style: + - Fixed vertical scrollbar top coordinates when using thick borders on windows + with no title bar and no menu bar. (#9366) - Fonts: - imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details. - Assert when using MergeMode with an explicit size over a target font with an implicit diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0d1a178c..9356e268 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -977,7 +977,7 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) IM_ASSERT(scrollbar_size >= 0.0f); const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f); - const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f; + const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : (window->Flags & ImGuiWindowFlags_NoTitleBar) ? border_size : 0; if (axis == ImGuiAxis_X) return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); else From 4b80d409e721b096b2b26e5edbf575178bdb48f0 Mon Sep 17 00:00:00 2001 From: Andy Grundman Date: Mon, 13 Apr 2026 19:16:15 -0400 Subject: [PATCH 06/44] Backends: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for synchronize(). (#9367) This also removes the dispatch onto main when adding the finished buffers back into the cache. This operation should be fine to run on any thread as long as it's inside the sync block. --- backends/imgui_impl_metal.mm | 19 ++++++++++--------- docs/CHANGELOG.txt | 4 +++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 037782bf..7d604e6a 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367) // 2026-04-03: Metal: avoid redundant vertex buffer bind in SetupRenderState. (#9343) // 2026-03-19: Fixed issue in ImGui_ImplMetal_RenderDrawData() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -78,6 +79,7 @@ @property (nonatomic, strong) FramebufferDescriptor* framebufferDescriptor; // framebuffer descriptor for current frame; transient @property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors @property (nonatomic, strong) NSMutableArray* bufferCache; +@property (nonatomic, strong) NSObject* bufferCacheLock; @property (nonatomic, assign) double lastBufferCachePurge; - (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device; - (id)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id)device; @@ -328,13 +330,11 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id MetalContext* sharedMetalContext = bd->SharedMetalContext; [commandBuffer addCompletedHandler:^(id) { - dispatch_async(dispatch_get_main_queue(), ^{ - @synchronized(sharedMetalContext.bufferCache) - { - [sharedMetalContext.bufferCache addObject:vertexBuffer]; - [sharedMetalContext.bufferCache addObject:indexBuffer]; - } - }); + @synchronized(sharedMetalContext.bufferCacheLock) + { + [sharedMetalContext.bufferCache addObject:vertexBuffer]; + [sharedMetalContext.bufferCache addObject:indexBuffer]; + } }]; } @@ -514,6 +514,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() { self.renderPipelineStateCache = [NSMutableDictionary dictionary]; self.bufferCache = [NSMutableArray array]; + self.bufferCacheLock = [[NSObject alloc] init]; _lastBufferCachePurge = GetMachAbsoluteTimeInSeconds(); } return self; @@ -521,9 +522,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects() - (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device { - uint64_t now = GetMachAbsoluteTimeInSeconds(); + double now = GetMachAbsoluteTimeInSeconds(); - @synchronized(self.bufferCache) + @synchronized(self.bufferCacheLock) { // Purge old buffers that haven't been useful for a while if (now - self.lastBufferCachePurge > 1.0) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5a305155..05dd294e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -89,8 +89,10 @@ Other Changes: - Misc: - Minor optimization: reduce redudant label scanning in common widgets. - Backends: - - Metal: avoid redundant vertex buffer bind in SetupRenderState, which leads + - 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 + replaced by a new object while being used for `@synchronize()`. (#9367) [@andygrundman] ----------------------------------------------------------------------- From 6fb74f38afd76bc5ab46e3f208d963e29676e7da Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Apr 2026 14:22:42 +0200 Subject: [PATCH 07/44] Demo: Assets Browser: make default icon size font dependant. --- imgui_demo.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 461b2cd8..338a55cb 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10724,7 +10724,7 @@ struct ExampleAssetsBrowser bool AllowBoxSelect = true; // Will set ImGuiMultiSelectFlags_BoxSelect2d bool AllowBoxSelectInsideSelection = false; // Will set ImGuiMultiSelectFlags_SelectOnClickAlways bool AllowDragUnselected = false; // Will set ImGuiMultiSelectFlags_SelectOnClickRelease - float IconSize = 32.0f; + float IconSize = 0; int IconSpacing = 10; int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer. bool StretchSpacing = true; @@ -10791,6 +10791,9 @@ struct ExampleAssetsBrowser void Draw(const char* title, bool* p_open) { + if (IconSize <= 0.0f) + IconSize = ImGui::CalcTextSize("99999").x; + ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar)) { From 19753a30d81e8daca0b2392ae45e68907590de7d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Apr 2026 15:08:41 +0200 Subject: [PATCH 08/44] Multi-Select: Box-Select+Tables: fixed Column return value when UnClipRect is active. (#7994, #8250) Amend 6ce4b44 + bbd0af7. This probably should be redesigned to be more generic, e.g. move UnclipRect concept outside of Boxselect. --- imgui_internal.h | 1 + imgui_tables.cpp | 22 +++++++++++++++++----- imgui_widgets.cpp | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 85c9daab..9bc0f9a5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3544,6 +3544,7 @@ namespace ImGui IMGUI_API void TableUpdateLayout(ImGuiTable* table); IMGUI_API void TableUpdateBorders(ImGuiTable* table); IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); + IMGUI_API void TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect); IMGUI_API void TableDrawBorders(ImGuiTable* table); IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display); IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c311c904..c58694bc 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1152,7 +1152,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->ClipRect.Min.y = work_rect.Min.y; column->ClipRect.Max.x = column->MaxX; //column->WorkMaxX; column->ClipRect.Max.y = FLT_MAX; - ImRect clip_rect_unclipped = column->ClipRect; column->ClipRect.ClipWithFull(host_clip_rect); // Mark column as Clipped (not in sight) @@ -1170,9 +1169,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; - ImGuiBoxSelectState* bs = &g.BoxSelectState; - if (!column->IsRequestOutput && bs->UnclipMode && bs->UnclipRect.Overlaps(clip_rect_unclipped)) - column->IsRequestOutput = true; // Mark column as SkipItems (ignoring all items/layout) // (table->HostSkipItems is a copy of inner_window->SkipItems before we cleared it above in Part 2) @@ -1319,14 +1315,30 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight; table_instance->LastFrozenHeight = 0.0f; - // Initial state ImGuiWindow* inner_window = table->InnerWindow; + ImGuiBoxSelectState* bs = &g.BoxSelectState; + if (bs->Window == inner_window && bs->UnclipMode) + TableApplyExternalUnclipRect(table, bs->UnclipRect); + + // Initial state if (table->Flags & ImGuiTableFlags_NoClip) table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); else inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); // FIXME: use table->InnerClipRect? } +// When starting a BeginMultiSelect() after table has been layout we update IsRequestOutput fields. +void ImGui::TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect) +{ + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsRequestOutput) + if (rect.Overlaps(ImRect(column->MinX, table->WorkRect.Min.y, column->MaxX, FLT_MAX))) + column->IsRequestOutput = true; + } +} + // Process hit-testing on resizing borders. Actual size change will be applied in EndTable() // - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise. void ImGui::TableUpdateBorders(ImGuiTable* table) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9356e268..f5b7e49f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7848,6 +7848,8 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI bs->UnclipRect = bs->BoxSelectRectPrev; // FIXME-OPT: UnclipRect X coordinates could be intersection of Prev and Curr rect on X axis. bs->UnclipRect.Add(bs->BoxSelectRectCurr); } + if (bs->UnclipMode && g.CurrentTable != NULL) + TableApplyExternalUnclipRect(g.CurrentTable, bs->UnclipRect); #ifdef IMGUI_DEBUG_BOXSELECT if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d) From 0e318a518299ba606dcb5e39cfb3da0a0aa8124c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 11:32:07 +0200 Subject: [PATCH 09/44] Backends: SDL2: Made ImGui_ImplSDL2_GetContentScaleXXX helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369) --- backends/imgui_impl_sdl2.cpp | 6 ++++++ docs/CHANGELOG.txt | 3 +++ imgui.cpp | 1 + 3 files changed, 10 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index f578977c..ebad7601 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-04-16: 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) // 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL2_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235) // 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) // 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_MOUSEMOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) @@ -748,6 +749,7 @@ float ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) return ImGui_ImplSDL2_GetContentScaleForDisplay(SDL_GetWindowDisplayIndex(window)); } +// SDL_GetDisplayDPI() seems rather unreliable on Linux. float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) { const char* sdl_driver = SDL_GetCurrentVideoDriver(); @@ -757,7 +759,11 @@ float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) #if !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) float dpi = 0.0f; if (SDL_GetDisplayDPI(display_index, &dpi, nullptr, nullptr) == 0) + { + if (dpi < 96.0f) + dpi = 96.0f; return dpi / 96.0f; + } #endif #endif IM_UNUSED(display_index); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 05dd294e..baabbcbc 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,9 @@ Other Changes: to validation issue. (#9343) [@Hunam6] - Metal: use a dedicated `bufferCacheLock` to avoid crashing when `bufferCache` is replaced by a new object while being used for `@synchronize()`. (#9367) [@andygrundman] + - 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) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 79e9a780..66a4a18d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1542,6 +1542,7 @@ ImGuiStyle::ImGuiStyle() // Scale all spacing/padding/thickness values. Do not scale fonts. +// Consider not calling this if your initial scale factor if <1.0. // Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. void ImGuiStyle::ScaleAllSizes(float scale_factor) { From 39e7bf5a08d48f5431778862d3fc70654099e214 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 11:32:40 +0200 Subject: [PATCH 10/44] Separator(): enforce a minimum border size if style.SeparatorSize is 0.0f. (#9369) --- imgui.h | 4 ++-- imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index fb30f362..d9f6a8cd 100644 --- a/imgui.h +++ b/imgui.h @@ -2335,7 +2335,7 @@ struct ImGuiStyle ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - float SeparatorSize; // Thickness of border in Separator() + float SeparatorSize; // Thickness of border in Separator(). Must be >= 1.0f. float SeparatorTextBorderSize; // Thickness of border in SeparatorText() ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. @@ -2365,7 +2365,7 @@ struct ImGuiStyle // Functions IMGUI_API ImGuiStyle(); - IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts. + IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts. See comments in definition. Consider not calling this if your initial scale factor if <1.0. // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f5b7e49f..50fec659 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1728,7 +1728,7 @@ void ImGui::Separator() if (window->DC.CurrentColumns) flags |= ImGuiSeparatorFlags_SpanAllColumns; - SeparatorEx(flags, g.Style.SeparatorSize); + SeparatorEx(flags, ImMax(g.Style.SeparatorSize, 1.0f)); } void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) From ce855cada2f1b27e4f6dd15b54b7f6e6fc22784b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 15:07:56 +0200 Subject: [PATCH 11/44] Tables, Multi-Select: Fixed an issue using Multi-Select within a Table causing column width measurement to be invalid when trailing column contents is not submitted in the last row. (#9341, #8250) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index baabbcbc..208c5865 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,8 @@ Other Changes: - Child windows with only ImGuiChildFlags_AutoResizeY flag keep using the proportional default ItemWidth. (#9355) - Multi-Select: + - Fixed an issue using Multi-Select within a Table causing column width measurement to + be invalid when trailing column contents is not submitted in the last row. (#9341, #8250) - Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect2d mode, where items out of view wouldn't be properly selected while scrolling while mouse cursor is hovering outside of selection scope. (#7994, #1861, #6518) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 50fec659..bdec3440 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7917,6 +7917,7 @@ static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) { // Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only + // This probably doesn't work inside a table as there are ample ambiguities related to exact time of calling BeginMultiSelect()/EndMultiSelect(). return ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin)); } else @@ -7974,7 +7975,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel ms->Flags = flags; ms->IsFocused = (ms->FocusScopeId == g.NavFocusScopeId); ms->BackupCursorMaxPos = window->DC.CursorMaxPos; - ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos; + ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos; // CalcScopeRect() for ImGuiMultiSelectFlags_ScopeRect will measure in EndMultiSelect(). PushFocusScope(ms->FocusScopeId); if (flags & ImGuiMultiSelectFlags_ScopeWindow) // Mark parent child window as navigable into, with highlight. Assume user will always submit interactive items. window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; @@ -8129,10 +8130,13 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if (ms->Flags & ImGuiMultiSelectFlags_NavWrapX) { IM_ASSERT(ms->Flags & ImGuiMultiSelectFlags_ScopeWindow); // Only supported at window scope - ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX); + NavMoveRequestTryWrapping(GetCurrentWindow(), ImGuiNavMoveFlags_WrapX); } // Unwind + if (ImGuiTable* table = g.CurrentTable) + if (table->IsInsideRow) + TableEndRow(table); window->DC.CursorMaxPos = ImMax(ms->BackupCursorMaxPos, window->DC.CursorMaxPos); PopFocusScope(); From d4783bd5534d984f728edff9ed31888ecb0002f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 16:39:07 +0200 Subject: [PATCH 12/44] Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). --- docs/CHANGELOG.txt | 1 + imgui_tables.cpp | 2 ++ imgui_widgets.cpp | 2 ++ 3 files changed, 5 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 208c5865..5c79b346 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -90,6 +90,7 @@ Other Changes: a better recoverable error. (#9350) - Misc: - Minor optimization: reduce redudant label scanning in common widgets. + - Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). - Backends: - Metal: avoid redundant vertex buffer bind in `SetupRenderState()`, which leads to validation issue. (#9343) [@Hunam6] diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c58694bc..84d29e65 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3311,6 +3311,8 @@ void ImGui::TableHeader(const char* label) // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden if (IsPopupOpenRequestForItem(ImGuiPopupFlags_None, id)) TableOpenContextMenu(column_n); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); } // Unlike TableHeadersRow() it is not expected that you can reimplement or customize this with custom widgets. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bdec3440..e26b3388 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3542,6 +3542,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return value_changed; } @@ -8933,6 +8934,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get // Return hovered index or -1 if none are hovered. // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx(). + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return idx_hovered; } From 2cbdb7a337af7da5cfe6adf320f0e84ef56bee01 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 16:47:13 +0200 Subject: [PATCH 13/44] TextLink(), BeginCombo(): fixed two remainig instances of needlessly scanning for ##. --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e26b3388..1e5058af 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1558,7 +1558,7 @@ bool ImGui::TextLink(const char* label) window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf), 1.0f * (float)(int)g.Style._MainScale); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); - RenderText(bb.Min, label, label_end); + RenderText(bb.Min, label, label_end, false); PopStyleColor(); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); @@ -1950,7 +1950,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); const char* label_end = FindRenderedTextEnd(label); const ImVec2 label_size = CalcTextSize(label, label_end, false); - const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, NULL, true).x : 0.0f; + const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, NULL, false).x : 0.0f; const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : ((flags & ImGuiComboFlags_WidthFitPreview) ? (arrow_size + preview_width + style.FramePadding.x * 2.0f) : CalcItemWidth()); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); From a2916923a12fd4c6caaa3fc7508e0bf817913263 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 23:32:34 +0200 Subject: [PATCH 14/44] MultiSelect: Box-Select + Clipper: extend UnclipRect by ItemSpacing. (#7994, #8250, #7821, #7850, #7970) Amend 1ac469b50f --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 8 +++++--- imgui.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5c79b346..fe77e73e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,7 +74,9 @@ Other Changes: and ImGuiSelectionUserData is technically opaque storage. (#7994, #1861) (we will probably bring this back as a minor optimization if we have a way to for user to tell us ImGuiSelectionUserData are indices) - - Box-Select, Tables: fixed an issue when calling `BeginMultiSelect()` in a table + - Box-Select + Clipper: fixed an issue selecting items while scrolling while a clipper + active. (#7994, #8250, #7821, #7850, #7970) + - Box-Select + Tables: fixed an issue when calling `BeginMultiSelect()` in a table before layout has been locked (first row or headers row submitted). (#8250) - Style: - Fixed vertical scrollbar top coordinates when using thick borders on windows diff --git a/imgui.cpp b/imgui.cpp index 66a4a18d..4735960e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3454,12 +3454,14 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) // FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos. // RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that. // As a workaround we currently half ItemSpacing worth on each side. - min_y -= g.Style.ItemSpacing.y; - max_y += g.Style.ItemSpacing.y; + float pad_y = g.Style.ItemSpacing.y; + min_y -= pad_y; + max_y += pad_y; // Box-select on 2D area requires different clipping. + // (best adding pad_y here than in BeginBoxSelect() as we are closer to current state) if (bs->UnclipMode) - data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y, bs->UnclipRect.Max.y, 0, 0)); + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y - pad_y, bs->UnclipRect.Max.y + pad_y, 0, 0)); } // Add main visible range diff --git a/imgui.h b/imgui.h index d9f6a8cd..5539bc7e 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 19272 +#define IMGUI_VERSION_NUM 19273 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 From a2eb6d99ed6ccbf453a3bdefe6b576af442e8e1a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Apr 2026 16:42:56 +0200 Subject: [PATCH 15/44] MultiSelect: Box-Select +Tables: revert 4d00bf8ad which seems unneeded since enforce table layout in BeginMultiSelect(). (#7970, #7821). --- imgui_widgets.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1e5058af..0ea586a4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7914,7 +7914,6 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) { - ImGuiContext& g = *GImGui; if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) { // Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only @@ -7923,10 +7922,10 @@ static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) } else { - // When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970) + //// When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970) ImRect scope_rect = window->InnerClipRect; - if (g.CurrentTable != NULL) - scope_rect = g.CurrentTable->HostClipRect; + //if (g.CurrentTable != NULL) + // scope_rect = g.CurrentTable->HostClipRect; // Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect? scope_rect.Min = ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max); From c91b03060de6a758b51623ff7ddf99978b6edbb7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Apr 2026 23:59:19 +0200 Subject: [PATCH 16/44] Multi-Select: Box-Select: improve dirty unclip rectangle calculation + use in ImGuiMultiSelectFlags_BoxSelect1d mode when needed (e.g. wheel scrolling up). (#7994, #8250, #7821, #7850, #7970) --- docs/CHANGELOG.txt | 4 +++ imgui_internal.h | 3 ++ imgui_tables.cpp | 2 ++ imgui_widgets.cpp | 69 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fe77e73e..32f6a976 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,10 @@ Other Changes: - Multi-Select: - Fixed an issue using Multi-Select within a Table causing column width measurement to be invalid when trailing column contents is not submitted in the last row. (#9341, #8250) + - Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect1d mode while scrolling. + Notably, using mouse wheel while holding a box-selection could lead items close to windows + edges from not being correctly unselected. (#7994, #8250, #7821, #7850, #7970) + - Box-Select: improved dirty/unclip rectangle logic for ImGuiMultiSelectFlags_BoxSelect2d. - Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect2d mode, where items out of view wouldn't be properly selected while scrolling while mouse cursor is hovering outside of selection scope. (#7994, #1861, #6518) diff --git a/imgui_internal.h b/imgui_internal.h index 9bc0f9a5..f1f4d357 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -606,6 +606,8 @@ struct IMGUI_API ImRect bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } + void AddX(float x) { if (Min.x > x) Min.x = x; if (Max.x < x) Max.x = x; } + void AddY(float y) { if (Min.y > y) Min.y = y; if (Max.y < y) Max.y = y; } void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } @@ -1893,6 +1895,7 @@ struct ImGuiBoxSelectState // Temporary/Transient data bool UnclipMode; // (Temp/Transient, here in hot area). Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select. ImRect UnclipRect; // Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets. + ImRect UnclipRects[2]; // Per-axis versions. ImRect BoxSelectRectPrev; // Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos) ImRect BoxSelectRectCurr; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 84d29e65..c590dac8 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1330,6 +1330,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // When starting a BeginMultiSelect() after table has been layout we update IsRequestOutput fields. void ImGui::TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect) { + if (rect.IsInverted()) + return; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0ea586a4..4998c6a8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7508,8 +7508,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, label_end, &label_size, style.SelectableTextAlign, &bb); #ifdef IMGUI_DEBUG_BOXSELECT - if (g.BoxSelectState.UnclipMode) - GetForegroundDrawList()->AddText(pos, IM_COL32(255,255,0,200), label); + if (g.BoxSelectState.UnclipMode) { GetForegroundDrawList()->AddText(pos, IM_COL32(255,255,0,200), label, label_end); } #endif // Automatically close popups @@ -7827,7 +7826,7 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI return false; // Current frame absolute prev/current rectangles are used to toggle selection. - // They are derived from positions relative to scrolling space. + // They are derived from positions relative to scrolling space, so "previous" rectangle is reprojected for current frame coordinates. ImVec2 start_pos_abs = WindowPosRelToAbs(window, bs->StartPosRel); ImVec2 prev_end_pos_abs = WindowPosRelToAbs(window, bs->EndPosRel); // Clamped already ImVec2 curr_end_pos_abs = g.IO.MousePos; @@ -7837,26 +7836,68 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI bs->BoxSelectRectPrev.Max = ImMax(start_pos_abs, prev_end_pos_abs); bs->BoxSelectRectCurr.Min = ImMin(start_pos_abs, curr_end_pos_abs); bs->BoxSelectRectCurr.Max = ImMax(start_pos_abs, curr_end_pos_abs); + //IMGUI_DEBUG_LOG("StartPosRel (%.2f,%.2f) EndPosRel (%.2f,%.2f) -> (%.2f,%.2f)\n", bs->StartPosRel.x, bs->StartPosRel.y, bs->EndPosRel.x, bs->EndPosRel.y, WindowPosAbsToRel(window, g.IO.MousePos).x, WindowPosAbsToRel(window, g.IO.MousePos).y); // Box-select 2D mode detects change of the rectangle. - // Storing unclip rect used by widgets supporting box-select. - if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d) + // Storing unclip rects which will be tested by widgets supporting box-select. Always update rectangles when active (even if we don't use them). + // To facilitate understanding this: enable IMGUI_DEBUG_BOXSELECT and visualize all geometry. + if (ms_flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) { - if (bs->BoxSelectRectPrev.Min != bs->BoxSelectRectCurr.Min || bs->BoxSelectRectPrev.Max != bs->BoxSelectRectCurr.Max) - bs->UnclipMode = true; + // For both sides, compute the area differing between Prev and Curr rectangles. + bs->UnclipRects[0] = bs->UnclipRects[1] = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int side = 0; side < 2; side++) + { + ImVec2 d_min = (side == 0) ? ImMin(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectPrev.Min) : ImMin(bs->BoxSelectRectCurr.Max, bs->BoxSelectRectPrev.Max); + ImVec2 d_max = (side == 0) ? ImMax(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectPrev.Min) : ImMax(bs->BoxSelectRectCurr.Max, bs->BoxSelectRectPrev.Max); + if (d_min.x != d_max.x) + { + bs->UnclipRects[0].AddX(d_min.x); + bs->UnclipRects[0].AddX(d_max.x); + } + if (d_min.y != d_max.y) + { + bs->UnclipRects[1].AddY(d_min.y); + bs->UnclipRects[1].AddY(d_max.y); + } + } - // Always update rect even if we don't use it. - bs->UnclipRect = bs->BoxSelectRectPrev; // FIXME-OPT: UnclipRect X coordinates could be intersection of Prev and Curr rect on X axis. - bs->UnclipRect.Add(bs->BoxSelectRectCurr); + ImRect box_select_intersection = bs->BoxSelectRectPrev; + box_select_intersection.Add(bs->BoxSelectRectCurr); + if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d) + if (bs->BoxSelectRectPrev.Min.x != bs->BoxSelectRectCurr.Min.x || bs->BoxSelectRectPrev.Max.x != bs->BoxSelectRectCurr.Max.x) + { + bs->UnclipRects[0].AddY(box_select_intersection.Min.y); + bs->UnclipRects[0].AddY(box_select_intersection.Max.y); + } + if (ms_flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) + if (bs->BoxSelectRectPrev.Min.y != bs->BoxSelectRectCurr.Min.y || bs->BoxSelectRectPrev.Max.y != bs->BoxSelectRectCurr.Max.y) + { + bs->UnclipRects[1].AddX(box_select_intersection.Min.x); + bs->UnclipRects[1].AddX(box_select_intersection.Max.x); + } + + // Merge both rectangles into one. + // FIXME-OPT: When UnclipRect.Area() is much larger than the sum of UnclipRects[0]/[1] Areas, widgets should + // ideally first use UnclipRect as a first coarse cull layer + the individual ones as a second validation. + bs->UnclipRect = bs->UnclipRects[0]; + bs->UnclipRect.Add(bs->UnclipRects[1]); + if (!bs->UnclipRect.IsInverted() && (!window->ClipRect.Contains(bs->UnclipRect.Min) || !window->ClipRect.Contains(bs->UnclipRect.Max))) // !! Don't use Contains(ImRect) + bs->UnclipMode = true; + if (bs->UnclipMode && g.CurrentTable != NULL) + TableApplyExternalUnclipRect(g.CurrentTable, bs->UnclipRect); // No need submitting both } - if (bs->UnclipMode && g.CurrentTable != NULL) - TableApplyExternalUnclipRect(g.CurrentTable, bs->UnclipRect); #ifdef IMGUI_DEBUG_BOXSELECT - if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d) - GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, bs->UnclipMode ? IM_COL32(255,255,0,200) : IM_COL32(255,0,0,200), 0.0f, 0, 4.0f); + //GetForegroundDrawList()->AddRect(scope_rect.Min, scope_rect.Max, IM_COL32(0, 255, 0, 200), 0.0f, 0, 4.0f); //GetForegroundDrawList()->AddRect(bs->BoxSelectRectPrev.Min, bs->BoxSelectRectPrev.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f); //GetForegroundDrawList()->AddRect(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectCurr.Max, IM_COL32(0,255,0,200), 0.0f, 0, 1.0f); + if (ms_flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) + { + for (ImRect& unclip_r : bs->UnclipRects) + if (!unclip_r.IsInverted()) + GetForegroundDrawList()->AddRect(unclip_r.Min, unclip_r.Max, bs->UnclipMode ? IM_COL32(255, 255, 0, 200) : IM_COL32(255, 0, 0, 200), 0.0f, 0, 4.0f); + GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, bs->UnclipMode ? IM_COL32(255, 255, 0, 200) : IM_COL32(255, 0, 0, 200), 0.0f, 0, 2.0f); + } #endif return true; } From 97939e6837afbd4c440db323fcfbeb9915b1da84 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 17 Apr 2026 16:30:53 +0200 Subject: [PATCH 17/44] Multi-Select: Box-Select: fixes for using accross nested child windows. (#8364) - IsFocused scan nav focus route. - When covering multiple windows, draw in front most ones (grabbed FindFrontMostVisibleChildWindow() from docking branch). --- docs/CHANGELOG.txt | 1 + imgui.cpp | 19 +++++++++++++++++++ imgui_internal.h | 2 ++ imgui_widgets.cpp | 9 +++++---- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 32f6a976..42e4f790 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -78,6 +78,7 @@ Other Changes: and ImGuiSelectionUserData is technically opaque storage. (#7994, #1861) (we will probably bring this back as a minor optimization if we have a way to for user to tell us ImGuiSelectionUserData are indices) + - Box-Select: fixes for using accross nested child windows. (#8364) - Box-Select + Clipper: fixed an issue selecting items while scrolling while a clipper active. (#7994, #8250, #7821, #7850, #7970) - Box-Select + Tables: fixed an issue when calling `BeginMultiSelect()` in a table diff --git a/imgui.cpp b/imgui.cpp index 4735960e..836ba0cc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6588,6 +6588,14 @@ void ImGui::EndChild() g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } +ImGuiWindow* ImGui::FindFrontMostVisibleChildWindow(ImGuiWindow* window) +{ + for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--) + if (IsWindowActiveAndVisible(window->DC.ChildWindows[n])) + return FindFrontMostVisibleChildWindow(window->DC.ChildWindows[n]); + return window; +} + static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) { window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); @@ -8754,6 +8762,17 @@ void ImGui::PopFocusScope() g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back().ID : 0; } +bool ImGui::IsInNavFocusRoute(ImGuiID focus_scope_id) +{ + ImGuiContext& g = *GImGui; + if (g.NavFocusScopeId == focus_scope_id) + return true; + for (const ImGuiFocusScopeData& focus_scope : g.NavFocusRoute) + if (focus_scope.ID == focus_scope_id) + return true; + return false; +} + void ImGui::SetNavFocusScope(ImGuiID focus_scope_id) { ImGuiContext& g = *GImGui; diff --git a/imgui_internal.h b/imgui_internal.h index f1f4d357..cd8e2200 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3328,6 +3328,7 @@ namespace ImGui // Childs IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags); + IMGUI_API ImGuiWindow* FindFrontMostVisibleChildWindow(ImGuiWindow* window); // Popups, Modals IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags); @@ -3481,6 +3482,7 @@ namespace ImGui // We don't use the ID Stack for this as it is common to want them separate. IMGUI_API void PushFocusScope(ImGuiID id); IMGUI_API void PopFocusScope(); + IMGUI_API bool IsInNavFocusRoute(ImGuiID focus_scope_id); inline ImGuiID GetCurrentFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentFocusScopeId; } // Focus scope we are outputting into, set by PushFocusScope() // Drag and Drop diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4998c6a8..d4f7c0ee 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7914,8 +7914,9 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag bs->EndPosRel = WindowPosAbsToRel(window, ImClamp(g.IO.MousePos, scope_rect.Min, scope_rect.Max)); // Clamp stored position according to current scrolling view ImRect box_select_r = bs->BoxSelectRectCurr; box_select_r.ClipWith(scope_rect); - window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling - window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling + ImGuiWindow* draw_window = FindFrontMostVisibleChildWindow(window); + draw_window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling + draw_window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling // Scroll const bool enable_scroll = (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0; @@ -8014,10 +8015,10 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel ms->Clear(); ms->FocusScopeId = id; ms->Flags = flags; - ms->IsFocused = (ms->FocusScopeId == g.NavFocusScopeId); ms->BackupCursorMaxPos = window->DC.CursorMaxPos; ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos; // CalcScopeRect() for ImGuiMultiSelectFlags_ScopeRect will measure in EndMultiSelect(). PushFocusScope(ms->FocusScopeId); + ms->IsFocused = IsInNavFocusRoute(g.CurrentFocusScopeId); if (flags & ImGuiMultiSelectFlags_ScopeWindow) // Mark parent child window as navigable into, with highlight. Assume user will always submit interactive items. window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; @@ -8145,7 +8146,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() // Clear selection when clicking void? // We specifically test for IsMouseDragPastThreshold(0) == false to allow box-selection! // The InnerRect test is necessary for non-child/decorated windows. - bool scope_hovered = IsWindowHovered() && window->InnerRect.Contains(g.IO.MousePos); + bool scope_hovered = window->InnerRect.Contains(g.IO.MousePos) && IsWindowHovered(ImGuiHoveredFlags_ChildWindows); if (scope_hovered && (ms->Flags & ImGuiMultiSelectFlags_ScopeRect)) scope_hovered &= scope_rect.Contains(g.IO.MousePos); if (scope_hovered && g.HoveredId == 0 && g.ActiveId == 0) From cdb046ac3f8df9a6adf3844f5e420709da46527e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 17 Apr 2026 19:19:21 +0200 Subject: [PATCH 18/44] Demo: Assets Browser: fixed not submitting anything after a SetCursorScreenPos() call when no items. Would not manifest because BeginMultiSelect() altered CursorMaxPos. (#5548) cc: 2819ab32f8, edcd5b113e1 --- imgui.cpp | 3 ++- imgui_demo.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 836ba0cc..188b53d4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10839,7 +10839,8 @@ bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si // to extend contents size of our parent container (e.g. window contents size, which is used for auto-resizing // windows, table column contents size used for auto-resizing columns, group size). // This was causing issues and ambiguities and we needed to retire that. -// From 1.89, extending contents size boundaries REQUIRES AN ITEM TO BE SUBMITTED. +// 2022/08/05 (1.89): extending contents size boundaries REQUIRES AN ITEM TO BE SUBMITTED. However we gated the new logic behind a '#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS' block. +// 2025/06/25 (1.92): removed the legacy path and turned into an assert. It was a mistake that there was a #ifndef before: our obsolescence schedule gets pushed back a bit more :( // // Previously this would make the window content size ~200x200: // Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK ANYMORE diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 338a55cb..08924ea9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -11016,6 +11016,8 @@ struct ExampleAssetsBrowser } } clipper.End(); + if (Items.Size == 0) + ImGui::Dummy(ImVec2(0, 0)); ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing // Context menu From ea1c04f7abc31f3089e5b163eef69d933e0a6209 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 17 Apr 2026 19:21:51 +0200 Subject: [PATCH 19/44] Multi-Select + Tables: fixed an issue which could lead to an extra vertical offset in the Header row. (#8250, #7994) Because BeginMultiSelect() does `ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos` at a time where CursorPos is already past MaxPos.y because of ItemSpacing.y. Accumulate spacing. --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 42e4f790..9a3e84f9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,8 @@ Other Changes: - Multi-Select: - Fixed an issue using Multi-Select within a Table causing column width measurement to be invalid when trailing column contents is not submitted in the last row. (#9341, #8250) + - Fixed an issue using Multi-Select within a Table with the right-most column visible, + which could lead to an extra vertical offset in the Header row. (#8250) - Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect1d mode while scrolling. Notably, using mouse wheel while holding a box-selection could lead items close to windows edges from not being correctly unselected. (#7994, #8250, #7821, #7850, #7970) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d4f7c0ee..3d9f2bec 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8016,7 +8016,9 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel ms->FocusScopeId = id; ms->Flags = flags; ms->BackupCursorMaxPos = window->DC.CursorMaxPos; - ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos; // CalcScopeRect() for ImGuiMultiSelectFlags_ScopeRect will measure in EndMultiSelect(). + ms->ScopeRectMin = window->DC.CursorPos; + if (flags & ImGuiMultiSelectFlags_ScopeRect) + window->DC.CursorMaxPos = ms->ScopeRectMin; // CalcScopeRect() for ImGuiMultiSelectFlags_ScopeRect will measure in EndMultiSelect(). PushFocusScope(ms->FocusScopeId); ms->IsFocused = IsInNavFocusRoute(g.CurrentFocusScopeId); if (flags & ImGuiMultiSelectFlags_ScopeWindow) // Mark parent child window as navigable into, with highlight. Assume user will always submit interactive items. From ac88294b4a28b3b56ed2aaec013acfc5e2a9eda8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Apr 2026 11:07:45 +0200 Subject: [PATCH 20/44] MultiSelect: Box-Select +Tables: fix usage of box-selection columns with items straying out of columns. (#7994, #2221) Use 00d3f9295e. + Assets Browser toggle to enable ScrollX. --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 11 ++++++++--- imgui_widgets.cpp | 11 +++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9a3e84f9..a907de65 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,8 @@ Other Changes: - Box-Select: fixes for using accross nested child windows. (#8364) - Box-Select + Clipper: fixed an issue selecting items while scrolling while a clipper active. (#7994, #8250, #7821, #7850, #7970) + - Box-Select + Tables: fixed an issue using box-selection in a tables with + items straying out of columns boundaries. (#7994, #2221) - Box-Select + Tables: fixed an issue when calling `BeginMultiSelect()` in a table before layout has been locked (first row or headers row submitted). (#8250) - Style: diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 08924ea9..bbdfa1c3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10726,8 +10726,9 @@ struct ExampleAssetsBrowser bool AllowDragUnselected = false; // Will set ImGuiMultiSelectFlags_SelectOnClickRelease float IconSize = 0; int IconSpacing = 10; - int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer. + int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer. bool StretchSpacing = true; + bool UseScrollX = false; // Debug: submit twice the number of items per line (overflow horizontally to exercise ScrollX + box-select) // State ImVector Items; // Our items @@ -10778,12 +10779,15 @@ struct ExampleAssetsBrowser // Layout: calculate number of icon per line and number of lines LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize)); LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1); - LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount; // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer. if (StretchSpacing && LayoutColumnCount > 1) LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount; + if (UseScrollX) + LayoutColumnCount *= 2; + LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount; + LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing); LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f); LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f); @@ -10843,6 +10847,7 @@ struct ExampleAssetsBrowser ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32); ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32); ImGui::Checkbox("Stretch Spacing", &StretchSpacing); + ImGui::Checkbox("Use ScrollX", &UseScrollX); ImGui::PopItemWidth(); ImGui::EndMenu(); } @@ -10872,7 +10877,7 @@ struct ExampleAssetsBrowser ImGuiIO& io = ImGui::GetIO(); ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing))); - if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove)) + if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_HorizontalScrollbar)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3d9f2bec..9eb00762 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8358,8 +8358,15 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) if (ms->BoxSelectId != 0) if (ImGuiBoxSelectState* bs = GetBoxSelectState(ms->BoxSelectId)) { - const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(g.LastItemData.Rect); - const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(g.LastItemData.Rect); + ImRect item_rect = g.LastItemData.Rect; + if (!window->DC.NavIsScrollPushableX) + { + const ImRect& clip_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasClipRect) ? g.LastItemData.ClipRect : window->ClipRect; + item_rect.Min.x = ImMax(item_rect.Min.x, clip_rect.Min.x); + item_rect.Max.x = ImMin(item_rect.Max.x, clip_rect.Max.x); + } + const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(item_rect); + const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(item_rect); if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr)) { if (storage->LastSelectionSize <= 0 && bs->IsStartedSetNavIdOnce) From d7b40ab9a9799ba0ce94e6e8ee96d5b3ac55483a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Apr 2026 11:40:01 +0200 Subject: [PATCH 21/44] MultiSelect: Box-Select + Tables: Amend ac88294. fix usage of box-selection columns with items straying out of columns. (#7994, #2221) --- imgui.cpp | 2 +- imgui_widgets.cpp | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 188b53d4..1d236466 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13349,7 +13349,7 @@ static void ImGui::NavProcessItem() const ImGuiID id = g.LastItemData.ID; const ImGuiItemFlags item_flags = g.LastItemData.ItemFlags; - // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221, #8816) + // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221, #8816, #7994) ImRect nav_bb = g.LastItemData.NavRect; if (window->DC.NavIsScrollPushableX == false) { diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9eb00762..d26e407d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8359,12 +8359,16 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) if (ImGuiBoxSelectState* bs = GetBoxSelectState(ms->BoxSelectId)) { ImRect item_rect = g.LastItemData.Rect; - if (!window->DC.NavIsScrollPushableX) - { - const ImRect& clip_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasClipRect) ? g.LastItemData.ClipRect : window->ClipRect; - item_rect.Min.x = ImMax(item_rect.Min.x, clip_rect.Min.x); - item_rect.Max.x = ImMin(item_rect.Max.x, clip_rect.Max.x); - } + if (!window->DC.NavIsScrollPushableX) // FIXME: Rename to be more generic. + if (ImGuiTable* table = g.CurrentTable) + if (table->CurrentColumn != -1) + { + // FIXME: We cannot use current ClipRect as it includes HostClipRect. + // A more generic version would be nice, but window->WorkRect.Min/Max exclude CellPadding. (#7994) + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + item_rect.Min.x = ImMax(item_rect.Min.x, column->MinX); + item_rect.Max.x = ImMin(item_rect.Max.x, column->MaxX); + } const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(item_rect); const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(item_rect); if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr)) From a1e05521e942c1611bef1aafe1631506c85f1148 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Apr 2026 17:24:41 +0200 Subject: [PATCH 22/44] 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 27f5fe90..37e933cf 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 a907de65..20fd49c6 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 23/44] 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 dc49ac1f..c74f4bcb 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 24/44] 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 d26e407d..cb6e09dc 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 25/44] 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 c74f4bcb..f6ea891c 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 26/44] (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 f6ea891c..4750dedb 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 c3fef510..444d400d 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 ce7e6f72..00fa28c6 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 00000000..725f72f3 --- /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 d70c7ce1..b6bfdee9 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 f3953439..956ee002 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 f461aab4..a9414b5e 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 7f1ccd0c..488676b2 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 27/44] (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 4750dedb..ea1cade4 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 444d400d..7c00e656 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 20fd49c6..b97477f2 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 b6bfdee9..f2139cef 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 956ee002..13171292 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 a9414b5e..04d17ba7 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 488676b2..7d509104 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 1d236466..d3811f68 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 5539bc7e..fcbe5dc0 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 28/44] 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 b97477f2..16b51c97 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 7d509104..cbdbdb83 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 29/44] 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 24911fad..d4ebb84d 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 7d604e6a..e049c5c0 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 4fffc577..3f011618 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 d1894a13..22baf2e3 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 dc86f6c2..dcc03a84 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 be6c97d8..d317d38b 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 30/44] 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 16b51c97..a6351daf 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 02f6a474..aa8a752d 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 2aa25506..bce5781f 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 4bd503af..cd59daed 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 a81d328d..6f44abfe 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 c56452b2..2e12665d 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 8ef991f3..75fd43b4 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 c23800c9..2bcc7097 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 036463f9..aca6edc5 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 6a81c677..d0cb96ba 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 cf2c890b..86b883a6 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 bcf99a46..4bedc45d 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 340901c3..f38d290c 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 051f87d7..c470f88b 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 3d034f52..02b0d35f 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 8b71324c..f4201454 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 d48e4aff..af114478 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 d11aed88..7fb76770 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 bace6a2c..9e89353d 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 8c3f9958..c5efda38 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 98fc38fd..b9b42677 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 dab8afd4..f3ba4aa6 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 31/44] 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 11879832..d80982a3 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 dcc03a84..df127dc6 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 d317d38b..dbfbea23 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 f5f53b9d..c01a16d4 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 ea1cade4..35315350 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 7c00e656..c4b80414 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 86bb36cc..7b4082fd 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 a6351daf..1a0a647e 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 fcbe5dc0..707af916 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 From adc0027912d46e42bc5cd8af235e7b325867d410 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 16:08:11 +0200 Subject: [PATCH 32/44] Backends: Vulkan: remove unused artefacts (mistakenly commited in 0453ae9). --- backends/vulkan/glsl_shader.frag.u32 | 30 ---------------------------- 1 file changed, 30 deletions(-) delete mode 100644 backends/vulkan/glsl_shader.frag.u32 diff --git a/backends/vulkan/glsl_shader.frag.u32 b/backends/vulkan/glsl_shader.frag.u32 deleted file mode 100644 index 725f72f3..00000000 --- a/backends/vulkan/glsl_shader.frag.u32 +++ /dev/null @@ -1,30 +0,0 @@ - // 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 From f2f843c11338fba0f324b77bab28a1457e9298dd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 17:01:02 +0200 Subject: [PATCH 33/44] Fixed some extremely zealous warnings (GCC -Wconversion, -Wdouble-promotion) (amend a1e0552) --- backends/imgui_impl_dx10.cpp | 4 ++-- backends/imgui_impl_dx11.cpp | 4 ++-- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx9.cpp | 4 ++-- backends/imgui_impl_glfw.cpp | 8 ++++---- backends/imgui_impl_metal.mm | 4 ++-- backends/imgui_impl_sdl2.cpp | 4 ++-- backends/imgui_impl_sdl3.cpp | 6 +++--- backends/imgui_impl_sdlgpu3.cpp | 8 ++++---- backends/imgui_impl_vulkan.cpp | 4 ++-- backends/imgui_impl_vulkan.h | 2 +- backends/imgui_impl_wgpu.cpp | 4 ++-- backends/imgui_impl_win32.cpp | 6 +++--- imgui_internal.h | 3 ++- imgui_tables.cpp | 1 + imgui_widgets.cpp | 1 + 16 files changed, 34 insertions(+), 31 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index d80982a3..45f1d824 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -177,7 +177,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; D3D10_BUFFER_DESC desc = {}; desc.Usage = D3D10_USAGE_DYNAMIC; - desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); + desc.ByteWidth = (UINT)bd->VertexBufferSize * sizeof(ImDrawVert); desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; desc.MiscFlags = 0; @@ -191,7 +191,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; D3D10_BUFFER_DESC desc = {}; desc.Usage = D3D10_USAGE_DYNAMIC; - desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); + desc.ByteWidth = (UINT)bd->IndexBufferSize * sizeof(ImDrawIdx); desc.BindFlags = D3D10_BIND_INDEX_BUFFER; desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; if (device->CreateBuffer(&desc, nullptr, &bd->pIB) < 0) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 193127b4..439e4413 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -183,7 +183,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; D3D11_BUFFER_DESC desc = {}; desc.Usage = D3D11_USAGE_DYNAMIC; - desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); + desc.ByteWidth = (UINT)bd->VertexBufferSize * sizeof(ImDrawVert); desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; desc.MiscFlags = 0; @@ -196,7 +196,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; D3D11_BUFFER_DESC desc = {}; desc.Usage = D3D11_USAGE_DYNAMIC; - desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); + desc.ByteWidth = (UINT)bd->IndexBufferSize * sizeof(ImDrawIdx); desc.BindFlags = D3D11_BIND_INDEX_BUFFER; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index a5420782..3c57bb66 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -200,7 +200,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic command_list->IASetVertexBuffers(0, 1, &vbv); D3D12_INDEX_BUFFER_VIEW ibv = {}; ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress(); - ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx); + ibv.SizeInBytes = (UINT)fr->IndexBufferSize * sizeof(ImDrawIdx); ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; command_list->IASetIndexBuffer(&ibv); command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index d4ebb84d..d8c7add6 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -184,14 +184,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) { if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; - if (device->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0) + if (device->CreateVertexBuffer((UINT)bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0) return; } if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) { if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; - if (device->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0) + if (device->CreateIndexBuffer((UINT)bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0) return; } diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 37e933cf..6af9f5d1 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -952,9 +952,9 @@ static void ImGui_ImplGlfw_UpdateGamepads() // 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(); } +static float ImGui_ImplWin32_GetLegacyDpiScale() { const HDC dc = ::GetDC(nullptr); UINT xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); ::ReleaseDC(nullptr, dc); return (float)xdpi / 96.0f; } +static void glfwGetWindowContentScale(GLFWwindow*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); } +static 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 @@ -1027,7 +1027,7 @@ void ImGui_ImplGlfw_NewFrame() // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644) double current_time = glfwGetTime(); if (current_time <= bd->Time) - current_time = bd->Time + 0.00001f; + current_time = bd->Time + 0.00001; io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); bd->Time = current_time; diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index e049c5c0..02c6b88c 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -257,8 +257,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id // Clamp to viewport as setScissorRect() won't accept values that are off bounds if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } + if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; } if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index ebad7601..3f4a6ace 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -890,7 +890,7 @@ static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window, if (out_size != nullptr) *out_size = ImVec2((float)w, (float)h); if (out_framebuffer_scale != nullptr) - *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / w, (float)display_h / h) : ImVec2(1.0f, 1.0f); + *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / (float)w, (float)display_h / (float)h) : ImVec2(1.0f, 1.0f); } void ImGui_ImplSDL2_NewFrame() @@ -908,7 +908,7 @@ void ImGui_ImplSDL2_NewFrame() Uint64 current_time = SDL_GetPerformanceCounter(); if (current_time <= bd->Time) current_time = bd->Time + 1; - io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); + io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / (double)frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; if (bd->MouseLastLeaveFrame && bd->MouseLastLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a2bd606a..bab2d231 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -686,8 +686,8 @@ static void ImGui_ImplSDL3_UpdateMouseData() int window_x, window_y; SDL_GetGlobalMouseState(&mouse_x, &mouse_y); SDL_GetWindowPosition(focused_window, &window_x, &window_y); - mouse_x -= window_x; - mouse_y -= window_y; + mouse_x -= (float)window_x; + mouse_y -= (float)window_y; io.AddMousePosEvent(mouse_x, mouse_y); } } @@ -860,7 +860,7 @@ void ImGui_ImplSDL3_NewFrame() Uint64 current_time = SDL_GetPerformanceCounter(); if (current_time <= bd->Time) current_time = bd->Time + 1; - io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); + io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / (double)frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; if (bd->MousePendingLeaveFrame && bd->MousePendingLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 54a527a3..50ff9f1f 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -174,8 +174,8 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData; - uint32_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); - uint32_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); + uint32_t vertex_size = (uint32_t)draw_data->TotalVtxCount * sizeof(ImDrawVert); + uint32_t index_size = (uint32_t)draw_data->TotalIdxCount * sizeof(ImDrawIdx); if (fd->VertexBuffer == nullptr || fd->VertexBufferSize < vertex_size) CreateOrResizeBuffers(&fd->VertexBuffer, &fd->VertexTransferBuffer, &fd->VertexBufferSize, vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX); if (fd->IndexBuffer == nullptr || fd->IndexBufferSize < index_size) @@ -271,8 +271,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe // Clamp to viewport as SDL_SetGPUScissor() won't accept values that are off bounds if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } + if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; } if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 35315350..190b4337 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -651,8 +651,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } + if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; } if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index c4b80414..869d61c4 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -260,7 +260,7 @@ struct ImGui_ImplVulkanH_Window memset((void*)this, 0, sizeof(*this)); // Parameters to create SwapChain - PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this. + PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; // Ensure we get an error if user doesn't set this. // Parameters to create RenderPass AttachmentDesc.format = VK_FORMAT_UNDEFINED; // Will automatically use wd->SurfaceFormat.format. diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 7b4082fd..5ce92d26 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -564,8 +564,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Clamp to viewport as wgpuRenderPassEncoderSetScissorRect() won't accept values that are off bounds if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } + if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; } if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index de92040a..d789f25f 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -412,7 +412,7 @@ void ImGui_ImplWin32_NewFrame() // Setup time step INT64 current_time = 0; ::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time); - io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond; + io.DeltaTime = (float)((double)(current_time - bd->Time) / (double)bd->TicksPerSecond); bd->Time = current_time; // Update OS mouse position @@ -930,7 +930,7 @@ float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) { GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! - return xdpi / 96.0f; + return (float)xdpi / 96.0f; } } #ifndef NOGDI @@ -940,7 +940,7 @@ float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! ::ReleaseDC(nullptr, dc); #endif - return xdpi / 96.0f; + return (float)xdpi / 96.0f; } float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) diff --git a/imgui_internal.h b/imgui_internal.h index cd8e2200..70589997 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -509,7 +509,8 @@ inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } template T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } template T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } template T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } -template T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template T ImLerp(double a, double b, float t) { return (T)(a + (b - a) * (double)t); } +template T ImLerp(T a, T b, float t) { return (T)((float)a + (float)(b - a) * t); } template void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } template T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } template T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c590dac8..cc910b98 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -240,6 +240,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wstrict-overflow" #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may change value #pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index cb6e09dc..9f3f871f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -92,6 +92,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may change value #pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif From ce3fe4078accdf5d3d44461fd55dc98ab420cf18 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 17:31:14 +0200 Subject: [PATCH 34/44] Backends: WGPU: fixed build. Incorrect line from a WIP branch slipped in ac06ad7 --- backends/imgui_impl_wgpu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 5ce92d26..e66005ae 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -538,7 +538,6 @@ 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 From f934719fbf002e712cbcaf34c8275a13d738fa58 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 18:31:53 +0200 Subject: [PATCH 35/44] TabBar: comments about ImGuiTabBarFlags_FittingPolicyMixed and TabMinWidthShrink. (#9376, #3421, #8800) --- imgui.cpp | 2 +- imgui.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d3811f68..e83d4f5b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1498,7 +1498,7 @@ ImGuiStyle::ImGuiStyle() TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. TabMinWidthBase = 1.0f; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected. - TabMinWidthShrink = 80.0f; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy. + TabMinWidthShrink = 80.0f; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy. FLT_MAX: never shrink, will behave like ImGuiTabBarFlags_FittingPolicyScroll. TabCloseButtonMinWidthSelected = -1.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. TabCloseButtonMinWidthUnselected = 0.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected. TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. diff --git a/imgui.h b/imgui.h index 707af916..e671c5f4 100644 --- a/imgui.h +++ b/imgui.h @@ -1401,7 +1401,7 @@ enum ImGuiTabBarFlags_ ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab // Fitting/Resize policy - ImGuiTabBarFlags_FittingPolicyMixed = 1 << 7, // Shrink down tabs when they don't fit, until width is style.TabMinWidthShrink, then enable scrolling buttons. + ImGuiTabBarFlags_FittingPolicyMixed = 1 << 7, // Shrink down tabs when they don't fit, until width is style.TabMinWidthShrink, then enable scrolling. Setting TabMinWidthShrink to FLT_MAX makes this behave like ImGuiTabBarFlags_FittingPolicyScroll. ImGuiTabBarFlags_FittingPolicyShrink = 1 << 8, // Shrink down tabs when they don't fit ImGuiTabBarFlags_FittingPolicyScroll = 1 << 9, // Enable scrolling buttons when tabs don't fit ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyMixed | ImGuiTabBarFlags_FittingPolicyShrink | ImGuiTabBarFlags_FittingPolicyScroll, @@ -2319,7 +2319,7 @@ struct ImGuiStyle float TabBorderSize; // Thickness of border around tabs. float TabMinWidthBase; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected. float TabMinWidthShrink; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy. - float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. + float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never shrink, will behave like ImGuiTabBarFlags_FittingPolicyScroll. float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected. float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. From e887098740e1653806bf792c9ab608b32c544b6f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 19:42:08 +0200 Subject: [PATCH 36/44] Backends: WebGPU: always use SPIR-V shader on WGVK, as it cannot be detected at runtime. (#9316, #9246, #9257) --- backends/imgui_impl_wgpu.cpp | 4 +++- docs/CHANGELOG.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index e66005ae..9a2aebbc 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -313,6 +313,7 @@ static void SafeRelease(FrameResources& res) static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(const char* wgsl_source) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); + IM_UNUSED(bd); WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; @@ -322,9 +323,10 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(con desc.nextInChain = (WGPUChainedStruct*)&wgsl_desc; WGPUProgrammableStageDescriptor stage_desc = {}; +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc); - stage_desc.entryPoint = { "main", WGPU_STRLEN }; +#endif return stage_desc; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1a0a647e..a546eb30 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -128,6 +128,7 @@ 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) + - WebGPU: always use SPIR-V shader on WGVK, as it cannot be detected at runtime. (#9316, #9246, #9257) - 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. From a6a16cf8a2bf859f9b9f593cbc62e78c22a90203 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 20:13:25 +0200 Subject: [PATCH 37/44] Backends: WebGPU: protect better against zero tex id. --- backends/imgui_impl_wgpu.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 9a2aebbc..1dc93095 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -551,12 +551,11 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder ImTextureID tex_id = pcmd->GetTexID(); ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id), 0); WGPUBindGroup bind_group = (WGPUBindGroup)bd->renderResources.ImageBindGroups.GetVoidPtr(tex_id_hash); - if (!bind_group) - { - bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bd->renderResources.ImageBindGroupLayout, (WGPUTextureView)tex_id); - bd->renderResources.ImageBindGroups.SetVoidPtr(tex_id_hash, bind_group); - } - wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, nullptr); + if (!bind_group && tex_id != 0) + if ((bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bd->renderResources.ImageBindGroupLayout, (WGPUTextureView)tex_id)) != 0) + bd->renderResources.ImageBindGroups.SetVoidPtr(tex_id_hash, bind_group); + if (bind_group) + wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, nullptr); // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); From 82f46a73f84c103ae9ec3fc3d62a35e0b92a7214 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 16:14:53 +0200 Subject: [PATCH 38/44] (Breaking) Moved ImDrawCallback_ResetRenderState -> ImGui::GetPlatformIO().DrawCallback_ResetRenderState + added room in ImGuiPlatformIO for more standard backend-agnostic draw callbacks. (#9378) --- docs/BACKENDS.md | 4 ++-- docs/CHANGELOG.txt | 19 +++++++++++++++++-- imgui.cpp | 2 ++ imgui.h | 17 ++++++++++------- imgui_draw.cpp | 7 ++++++- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 7839764c..17e34dd3 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -255,8 +255,8 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - MyEngineSetupenderState(); + if (pcmd->UserCallback == platform_io.DrawCallback_ResetRenderState) + MyEngineSetupSenderState(); else pcmd->UserCallback(cmd_list, pcmd); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a546eb30..75ce0995 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,10 @@ HOW TO UPDATE? Breaking Changes: +- DrawList: + - Obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`, + which is part of our new standard draw callbacks. (#9378) + Redirecting the earlier value into the later one when set, so both old and new code should work. - 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] @@ -57,6 +61,19 @@ Breaking Changes: Other Changes: +- DrawList: + - Added room in ImGuiPlatformIO for standard backend-agnostic draw callbacks. Those callbacks + are setup/provided by the backend and available in most of our standard backends. + They allow backend-agnostic code from e.g. switching to a Nearest/Point sampler without + messing with custom Renderer-specific callbacks. + platform_io.DrawCallback_ResetRenderState; // Request to reset the graphics/render state. + platform_io.DrawCallback_SetSamplerLinear; // Request to set current texture sampling to Linear + platform_io.DrawCallback_SetSamplerNearest; // Request to set current texture sampling to Nearest/Point + platform_io.DrawCallback_SetSamplerCustom; // Request to set current texture sampling using Backend Specific data. + Note that some backends might not support all callbacks. + (#9378, #9371, #3590, #8926, #2973, #7485, #7468, #6969, #5118, #7616, #9173, #8322, #7230, + #5999, #6452, #5156, #7342, #7592, #7511) + - Made AddCallback() user data default to Null for convenience. - InputText: - InputTextMultiline: fixed an issue processing deactivation logic when an active multi-line edit is clipped due to being out of view. @@ -113,8 +130,6 @@ 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.cpp b/imgui.cpp index e83d4f5b..5cf11f5b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -395,6 +395,7 @@ 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/23 (1.92.8) - Obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`, which is part of our new standard draw callbacks. (#9378) - 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. @@ -15816,6 +15817,7 @@ void ImGuiPlatformIO::ClearRendererHandlers() { Renderer_TextureMaxWidth = Renderer_TextureMaxHeight = 0; Renderer_RenderState = NULL; + DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = DrawCallback_SetSamplerCustom = NULL; } ImGuiViewport* ImGui::GetMainViewport() diff --git a/imgui.h b/imgui.h index e671c5f4..1e6d79ee 100644 --- a/imgui.h +++ b/imgui.h @@ -3166,12 +3166,6 @@ typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibilit typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); #endif -// Special Draw callback value to request renderer backend to reset the graphics/render state. -// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address. -// This is useful, for example, if you submitted callbacks which you know have altered the render state and you want it to be restored. -// Render state is not reset by default because they are many perfectly useful way of altering render state (e.g. changing shader/blending settings before an Image call). -#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) - // Typically, 1 command = 1 GPU draw call (unless command is a callback) // - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, // this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. @@ -3378,7 +3372,8 @@ struct ImDrawList // Advanced: Draw Callbacks // - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom rendering commands (difficult to do correctly, but possible). - // - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default. + // - Use special GetPlatformIO().DrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default. + // - See other standard callbacks in GetPlatformIO(), which may or not be supported by your backend. // - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. All standard backends are honoring this. // - For some backends, the callback may access selected render-states exposed by the backend in a ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState. // - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and using size>0 (copying pointed data into a buffer). @@ -4022,6 +4017,12 @@ struct ImGuiPlatformIO // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. void* Renderer_RenderState; + // Standard draw callbacks + ImDrawCallback DrawCallback_ResetRenderState; // Request to reset the graphics/render state. + ImDrawCallback DrawCallback_SetSamplerLinear; // Request to set current texture sampling to Linear + ImDrawCallback DrawCallback_SetSamplerNearest; // Request to set current texture sampling to Nearest/Point + ImDrawCallback DrawCallback_SetSamplerCustom; // Request to set current texture sampling using Backend Specific data. + //------------------------------------------------------------------ // Output //------------------------------------------------------------------ @@ -4150,6 +4151,8 @@ namespace ImGui //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 } +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) // OBSOLETED in 1.92.8: Use ImGui::GetPlatformIO().DrawCallback_ResetRenderState + //-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect // - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y // - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 21e368a4..dc814a4a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -528,9 +528,14 @@ void ImDrawList::_PopUnusedDrawCmd() void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size) { + IM_ASSERT(callback != NULL); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (callback == ImDrawCallback_ResetRenderState && _Data->Context != NULL && _Data->Context->PlatformIO.DrawCallback_ResetRenderState != NULL) + callback = _Data->Context->PlatformIO.DrawCallback_ResetRenderState; // == ImGui::GetPlatformIO().DrawCallback_ResetRenderState +#endif + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - IM_ASSERT(callback != NULL); IM_ASSERT(curr_cmd->UserCallback == NULL); if (curr_cmd->ElemCount != 0) { From 0a811e8ea13a7dcf0a51a39c961d7f47f42c8786 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:55:00 +0200 Subject: [PATCH 39/44] Backends: DX9, DX10, DX11, DX12, Allegro5, OpenGL2, OpenGL3, SDLRenderer2, SDLRenderer3, SDLGPU3, Vulkan: added standard draw callbacks when possible. (#9378) --- backends/imgui_impl_allegro5.cpp | 14 ++++++--- backends/imgui_impl_allegro5.h | 1 + backends/imgui_impl_dx10.cpp | 14 +++++++-- backends/imgui_impl_dx11.cpp | 19 +++++++++--- backends/imgui_impl_dx12.cpp | 31 ++++++++++++------- backends/imgui_impl_dx9.cpp | 12 ++++++-- backends/imgui_impl_metal.h | 2 ++ backends/imgui_impl_metal.mm | 12 ++++++-- backends/imgui_impl_opengl2.cpp | 33 ++++++++++++++++++-- backends/imgui_impl_opengl2.h | 1 + backends/imgui_impl_opengl3.cpp | 46 ++++++++++++++++++++++++++-- backends/imgui_impl_sdlgpu3.cpp | 21 +++++++++++-- backends/imgui_impl_sdlrenderer2.cpp | 12 ++++++-- backends/imgui_impl_sdlrenderer2.h | 2 ++ backends/imgui_impl_sdlrenderer3.cpp | 18 +++++++++-- backends/imgui_impl_vulkan.cpp | 21 ++++++++++--- backends/imgui_impl_wgpu.cpp | 13 ++++++-- backends/imgui_impl_wgpu.h | 2 ++ docs/CHANGELOG.txt | 15 +++++++++ 19 files changed, 244 insertions(+), 45 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 6ee88a18..c5d28318 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -9,6 +9,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. // [ ] Platform: Missing gamepad support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -21,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported by Allegro5). // 2025-09-18: Call platform_io.ClearRendererHandlers() and platform_io.ClearPlatformHandlers() on shutdown. // 2025-08-12: Inputs: fixed missing support for ImGuiKey_PrintScreen under Windows, as raw Allegro 5 does not receive it. // 2025-08-12: Added ImGui_ImplAllegro5_SetDisplay() function to change current ALLEGRO_DISPLAY, as Allegro applications often need to do that. @@ -136,7 +138,10 @@ static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data) } } -// Render function. +// Draw callbacks +static void ImGui_ImplAllegro5_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. + +// Render function void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized @@ -152,6 +157,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // Backup Allegro state that will be modified ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ALLEGRO_TRANSFORM last_transform = *al_get_current_transform(); ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform(); int last_clip_x, last_clip_y, last_clip_w, last_clip_h; @@ -208,8 +214,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback) { // 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) + if (pcmd->UserCallback == ImGui_ImplAllegro5_DrawCallback_ResetRenderState) ImGui_ImplAllegro5_SetupRenderState(draw_data); else pcmd->UserCallback(draw_list, pcmd); @@ -486,11 +491,12 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) ImGui_ImplAllegro5_SetDisplay(display); -#if ALLEGRO_HAS_CLIPBOARD ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); +#if ALLEGRO_HAS_CLIPBOARD platform_io.Platform_SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; platform_io.Platform_GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; #endif + platform_io.DrawCallback_ResetRenderState = ImGui_ImplAllegro5_DrawCallback_ResetRenderState; return true; } diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 135c4ff8..3fe531af 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -9,6 +9,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. // [ ] Platform: Missing gamepad support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 45f1d824..d412a9e5 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: DirectX10: Added support for ImDrawCallback_SetSamplerLinear, ImDrawCallback_SetSamplerPoint. // 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. @@ -153,6 +154,12 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device->RSSetState(bd->pRasterizerState); } +// Draw callbacks +static void ImGui_ImplDX10_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplDX10_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); bd->pd3dDevice->PSSetSamplers(0, 1, &bd->pTexSamplerLinear); } +static void ImGui_ImplDX10_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); bd->pd3dDevice->PSSetSamplers(0, 1, &bd->pTexSamplerNearest); } +static void ImGui_ImplDX10_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); ID3D10SamplerState* sampler = (ID3D10SamplerState*)cmd->UserCallbackData; bd->pd3dDevice->PSSetSamplers(0, 1, &sampler); } + // Render function void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) { @@ -279,8 +286,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplDX10_DrawCallback_ResetRenderState) ImGui_ImplDX10_SetupRenderState(draw_data, device); else pcmd->UserCallback(draw_list, pcmd); @@ -613,6 +619,10 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX10_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX10_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX10_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplDX10_DrawCallback_SetSamplerCustom; // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 439e4413..29f4914f 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. // 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. @@ -85,6 +86,7 @@ struct ImGui_ImplDX11_Data ID3D11DepthStencilState* pDepthStencilState; int VertexBufferSize; int IndexBufferSize; + ImGui_ImplDX11_RenderState* RenderState; // == (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState during rendering. ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; @@ -159,6 +161,12 @@ static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11D device_ctx->RSSetState(bd->pRasterizerState); } +// Draw callbacks +static void ImGui_ImplDX11_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplDX11_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &bd->pTexSamplerLinear); } +static void ImGui_ImplDX11_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &bd->pTexSamplerNearest); } +static void ImGui_ImplDX11_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); ID3D11SamplerState* sampler = (ID3D11SamplerState*)cmd->UserCallbackData; bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &sampler); } + // Render function void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) { @@ -277,7 +285,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) render_state.SamplerLinear = bd->pTexSamplerLinear; render_state.SamplerNearest = bd->pTexSamplerNearest; render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; - platform_io.Renderer_RenderState = &render_state; + platform_io.Renderer_RenderState = bd->RenderState = &render_state; // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -293,8 +301,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplDX11_DrawCallback_ResetRenderState) ImGui_ImplDX11_SetupRenderState(draw_data, device); else pcmd->UserCallback(draw_list, pcmd); @@ -320,7 +327,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; + platform_io.Renderer_RenderState = bd->RenderState = nullptr; // Restore modified DX state device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); @@ -629,6 +636,10 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX11_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX11_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX11_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplDX11_DrawCallback_SetSamplerCustom; // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 3c57bb66..b4344f2a 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002) // 2025-09-29: DirectX12: Rework synchronization logic. (#8961) // 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965) @@ -91,6 +92,8 @@ struct ImGui_ImplDX12_Texture struct ImGui_ImplDX12_Data { ImGui_ImplDX12_InitInfo InitInfo; + ImGui_ImplDX12_RenderState* RenderState; + IDXGIFactory5* pdxgiFactory; ID3D12Device* pd3dDevice; ID3D12RootSignature* pRootSignatureLinear; @@ -142,19 +145,15 @@ struct VERTEX_CONSTANT_BUFFER_DX12 float mvp[4][4]; }; -// FIXME-WIP: Allow user to forward declare those two, for until we come up with a backend agnostic API to do this. (#9173) -void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list); -void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list); - // Functions -void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list) +static void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); command_list->SetPipelineState(bd->pPipelineStateLinear); command_list->SetGraphicsRootSignature(bd->pRootSignatureLinear); } -void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list) +static void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); command_list->SetPipelineState(bd->pPipelineStateNearest); @@ -220,6 +219,11 @@ static inline void SafeRelease(T*& res) res = nullptr; } +// Draw callbacks +static void ImGui_ImplDX12_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplDX12_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); ImGui_ImplDX12_SetupSamplerLinear(bd->RenderState->CommandList); } +static void ImGui_ImplDX12_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); ImGui_ImplDX12_SetupSamplerNearest(bd->RenderState->CommandList); } + // Render function void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list) { @@ -317,7 +321,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL ImGui_ImplDX12_RenderState render_state; render_state.Device = bd->pd3dDevice; render_state.CommandList = command_list; - platform_io.Renderer_RenderState = &render_state; + platform_io.Renderer_RenderState = bd->RenderState = &render_state; // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -334,7 +338,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL { // 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) + if (pcmd->UserCallback == ImGui_ImplDX12_DrawCallback_ResetRenderState) ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr); else pcmd->UserCallback(draw_list, pcmd); @@ -361,7 +365,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; + platform_io.Renderer_RenderState = bd->RenderState = nullptr; } static void ImGui_ImplDX12_DestroyTexture(ImTextureData* tex) @@ -664,7 +668,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignatureLinear)); blob->Release(); - // Root Signature for ImDrawCallback_SetSamplerNearest + // Nearest sampler staticSampler[0].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK) return false; @@ -813,7 +817,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects() return false; } - // Pipeline State for ImDrawCallback_SetSamplerNearest psoDesc.pRootSignature = bd->pRootSignatureNearest; result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineStateNearest)); @@ -927,6 +930,11 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) 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.DrawCallback_ResetRenderState = ImGui_ImplDX12_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX12_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX12_DrawCallback_SetSamplerNearest; + #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (init_info->SrvDescriptorAllocFn == nullptr) ImGui_ImplDX12_InitLegacySingleDescriptorMode(init_info); @@ -971,6 +979,7 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO bool ret = ImGui_ImplDX12_Init(&init_info); ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); bd->commandQueueOwned = true; + ImGuiIO& io = ImGui::GetIO(); io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; // Using legacy ImGui_ImplDX12_Init() call with 1 SRV descriptor we cannot support multiple textures. diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index d8c7add6..d6464a4a 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. @@ -162,6 +163,11 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) } } +// Draw callbacks +static void ImGui_ImplDX9_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplDX9_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); } +static void ImGui_ImplDX9_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); } + // Render function. void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) { @@ -269,8 +275,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplDX9_DrawCallback_ResetRenderState) ImGui_ImplDX9_SetupRenderState(draw_data); else pcmd->UserCallback(draw_list, pcmd); @@ -453,6 +458,9 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096; + platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX9_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX9_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX9_DrawCallback_SetSamplerNearest; bd->pd3dDevice = device; bd->pd3dDevice->AddRef(); diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 8af2c8b6..2baa4de9 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -5,6 +5,8 @@ // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [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). +// Missing features or Issues: +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. // 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. diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 02c6b88c..ddde093f 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -5,6 +5,8 @@ // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [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). +// Missing features or Issues: +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. // 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. @@ -16,6 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). // 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367) // 2026-04-03: Metal: avoid redundant vertex buffer bind in SetupRenderState. (#9343) // 2026-03-19: Fixed issue in ImGui_ImplMetal_RenderDrawData() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) @@ -186,6 +189,9 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id commandBuffer, id commandEncoder) { @@ -242,8 +248,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id if (pcmd->UserCallback) { // 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) + if (pcmd->UserCallback == ImGui_ImplMetal_DrawCallback_ResetRenderState) ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset); else pcmd->UserCallback(draw_list, pcmd); @@ -408,6 +413,9 @@ bool ImGui_ImplMetal_Init(id device) 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.DrawCallback_ResetRenderState = ImGui_ImplMetal_DrawCallback_ResetRenderState; + bd->SharedMetalContext = [[MetalContext alloc] init]; bd->SharedMetalContext.device = device; diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 3f011618..ac17f81f 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -6,6 +6,7 @@ // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler(). // 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. @@ -25,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_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-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) @@ -86,6 +88,9 @@ // OpenGL data struct ImGui_ImplOpenGL2_Data { + bool UseTexParameterToSetSampler; + GLuint NextSampler; + ImGui_ImplOpenGL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -107,6 +112,7 @@ void ImGui_ImplOpenGL2_NewFrame() static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) { // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. + ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha @@ -124,6 +130,7 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glShadeModel(GL_SMOOTH); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + bd->NextSampler = GL_LINEAR; // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), // you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below. @@ -148,12 +155,18 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid glLoadIdentity(); } +// Draw callbacks +static void ImGui_ImplOpenGL2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } +static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } + // OpenGL2 Render function. // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. // This is in order to be able to run within an OpenGL engine that doesn't do so. void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); if (fb_width == 0 || fb_height == 0) @@ -197,8 +210,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback) { // 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) + if (pcmd->UserCallback == ImGui_ImplOpenGL2_DrawCallback_ResetRenderState) ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); else pcmd->UserCallback(draw_list, pcmd); @@ -215,7 +227,17 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)); // Bind texture, Draw - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()); + GLuint pcmd_texture = (GLuint)(intptr_t)pcmd->GetTexID(); + glBindTexture(GL_TEXTURE_2D, pcmd_texture); + + // Emulate sampler change (even though it is technically part of texture data) + // As a sort of hack/workaround, we only start writing using glTextParameter() if sampler is ever changed explicitly. + if (bd->UseTexParameterToSetSampler) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bd->NextSampler); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bd->NextSampler); + } + glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset); } } @@ -325,6 +347,11 @@ bool ImGui_ImplOpenGL2_Init() io.BackendRendererName = "imgui_impl_opengl2"; io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL2_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest; + return true; } diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index 65b0fe0b..b9f7453f 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -6,6 +6,7 @@ // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler(). // 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. diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 22baf2e3..228294c5 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) // 2025-12-11: OpenGL: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -252,6 +253,12 @@ struct ImGui_ImplOpenGL3_Data bool HasBindSampler; bool HasClipOrigin; bool UseBufferSubData; + bool UseTexParameterToSetSampler; + GLuint NextSampler; +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + GLuint TexSamplers[2]; // Linear, Nearest +#endif + ImVector TempBuffer; ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); } @@ -378,7 +385,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER if (bd->HasBindSampler) - glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. + glBindSampler(0, bd->TexSamplers[0]); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. #endif (void)vertex_array_object; @@ -397,6 +404,12 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col))); } +// Draw callbacks +static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[0]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } } +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[1]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } } +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd){ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, (GLuint)(intptr_t)cmd->UserCallbackData); } } + // OpenGL3 Render function. // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. // This is in order to be able to run within an OpenGL engine that doesn't do so. @@ -511,8 +524,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplOpenGL3_DrawCallback_ResetRenderState) ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); else pcmd->UserCallback(draw_list, pcmd); @@ -530,6 +542,15 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) // Bind texture, Draw GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID())); + + // Emulate sampler change (even though it is technically part of texture data) + // As a sort of hack/workaround, we only start writing using glTextParameter() if sampler is ever changed explicitly. + if (!bd->HasBindSampler && bd->UseTexParameterToSetSampler) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bd->NextSampler); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bd->NextSampler); + } + #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET if (bd->GlVersion >= 320) GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset)); @@ -895,6 +916,20 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() glGenBuffers(1, &bd->VboHandle); glGenBuffers(1, &bd->ElementsHandle); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + if (bd->HasBindSampler) + { + glGenSamplers(2, &bd->TexSamplers[0]); + for (int sampler_n = 0; sampler_n < 2; sampler_n++) + { + GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_MIN_FILTER, (sampler_n == 0) ? GL_LINEAR : GL_NEAREST)); + GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_MAG_FILTER, (sampler_n == 0) ? GL_LINEAR : GL_NEAREST)); + GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + } + } +#endif + // Restore modified GL state glBindTexture(GL_TEXTURE_2D, last_texture); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); @@ -912,6 +947,7 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects() { ImGui_ImplOpenGL3_InitLoader(); ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + if (bd->TexSamplers[0]) { glDeleteSamplers(2, &bd->TexSamplers[0]); bd->TexSamplers[0] = bd->TexSamplers[1] = 0; } if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; } if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; } if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; } @@ -991,6 +1027,10 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize; + platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL3_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplOpenGL3_DrawCallback_SetSamplerCustom; // 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. diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 50ff9f1f..a8b6dcd2 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -22,6 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) // 2025-11-26: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. @@ -58,6 +59,7 @@ struct ImGui_ImplSDLGPU3_FrameData struct ImGui_ImplSDLGPU3_Data { ImGui_ImplSDLGPU3_InitInfo InitInfo; + ImGui_ImplSDLGPU3_RenderState* RenderState = nullptr; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering. // Graphics pipeline & shaders SDL_GPUShader* VertexShader = nullptr; @@ -216,6 +218,12 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff SDL_EndGPUCopyPass(copy_pass); } +// Draw callbacks +static void ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->RenderState->SamplerCurrent = bd->TexSamplerLinear; } +static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->RenderState->SamplerCurrent = bd->TexSamplerNearest; } +static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd){ ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->RenderState->SamplerCurrent = (SDL_GPUSampler*)cmd->UserCallbackData; } + void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) @@ -240,7 +248,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe render_state.Device = bd->InitInfo.Device; render_state.SamplerLinear = render_state.SamplerCurrent = bd->TexSamplerLinear; render_state.SamplerNearest = bd->TexSamplerNearest; - platform_io.Renderer_RenderState = &render_state; + platform_io.Renderer_RenderState = bd->RenderState = &render_state; ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); @@ -256,8 +264,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState) ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); else pcmd->UserCallback(draw_list, pcmd); @@ -306,6 +313,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe // We perform a call to SDL_SetGPUScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644) SDL_Rect scissor_rect { 0, 0, fb_width, fb_height }; SDL_SetGPUScissor(render_pass, &scissor_rect); + + platform_io.Renderer_RenderState = bd->RenderState = nullptr; } static void ImGui_ImplSDLGPU3_DestroyTexture(ImTextureData* tex) @@ -656,6 +665,12 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) 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.DrawCallback_ResetRenderState = ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerCustom; + IM_ASSERT(info->Device != nullptr); IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID); diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index df127dc6..2f6fcc6e 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -14,6 +14,8 @@ // [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'. +// Missing features or Issues: +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. // 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. @@ -25,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported). // 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(). @@ -88,6 +91,9 @@ void ImGui_ImplSDLRenderer2_NewFrame() IM_UNUSED(bd); } +// Draw callbacks +static void ImGui_ImplSDLRenderer2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. + void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) { // If there's a scale factor set by the user, use that instead @@ -150,8 +156,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (pcmd->UserCallback) { // 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) + if (pcmd->UserCallback == ImGui_ImplSDLRenderer2_DrawCallback_ResetRenderState) ImGui_ImplSDLRenderer2_SetupRenderState(renderer); else pcmd->UserCallback(draw_list, pcmd); @@ -273,6 +278,9 @@ bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer) 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.DrawCallback_ResetRenderState = ImGui_ImplSDLRenderer2_DrawCallback_ResetRenderState; + bd->Renderer = renderer; return true; diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index 860e9550..7b2edd4d 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -14,6 +14,8 @@ // [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'. +// Missing features or Issues: +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. // 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. diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index dbfbea23..eb05073d 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -25,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 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(). @@ -60,6 +61,9 @@ struct ImGui_ImplSDLRenderer3_Data SDL_Renderer* Renderer; // Main viewport's renderer ImVector ColorBuffer; + // Render State + SDL_ScaleMode CurrentScaleMode; + ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -104,6 +108,11 @@ static int SDL_RenderGeometryRaw8BitColor(SDL_Renderer* renderer, ImVectorCurrentScaleMode = SDL_SCALEMODE_LINEAR; } +static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); bd->CurrentScaleMode = SDL_SCALEMODE_NEAREST; } + void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); @@ -170,8 +179,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (pcmd->UserCallback) { // 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) + if (pcmd->UserCallback == ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState) ImGui_ImplSDLRenderer3_SetupRenderState(renderer); else pcmd->UserCallback(draw_list, pcmd); @@ -197,6 +205,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* // Bind texture, Draw SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); + SDL_SetTextureScaleMode(tex, bd->CurrentScaleMode); SDL_RenderGeometryRaw8BitColor(renderer, bd->ColorBuffer, tex, xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), @@ -289,6 +298,11 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) 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.DrawCallback_ResetRenderState = ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest; + bd->Renderer = renderer; return true; diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 190b4337..e62d0df7 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. // 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) @@ -275,6 +276,7 @@ struct ImGui_ImplVulkan_Texture struct ImGui_ImplVulkan_Data { ImGui_ImplVulkan_InitInfo VulkanInitInfo; + ImGui_ImplVulkan_RenderState* RenderState; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering. VkDeviceSize BufferMemoryAlignment; VkDeviceSize NonCoherentAtomSize; VkPipelineCreateFlags PipelineCreateFlags; @@ -531,6 +533,12 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, ImGui_ImplV vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); } +// Draw callbacks +static void ImGui_ImplVulkan_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } +static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); } +static void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(cmd->UserCallbackDataSize == sizeof(VkDescriptorSet)); VkDescriptorSet* ds = (VkDescriptorSet*)cmd->UserCallbackData; vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, ds, 0, nullptr); } + // Render function void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) { @@ -610,7 +618,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm render_state.PipelineLayout = bd->PipelineLayout; render_state.SamplerLinearDS = render_state.SamplerCurrentDS = bd->SamplerLinearDS; render_state.SamplerNearestDS = bd->SamplerNearestDS; - platform_io.Renderer_RenderState = &render_state; + platform_io.Renderer_RenderState = bd->RenderState = &render_state; // Setup desired Vulkan state ImGui_ImplVulkan_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, rb, fb_width, fb_height); @@ -633,8 +641,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplVulkan_DrawCallback_ResetRenderState) { ImGui_ImplVulkan_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, rb, fb_width, fb_height); last_image_view = last_sampler = VK_NULL_HANDLE; @@ -680,7 +687,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; + platform_io.Renderer_RenderState = bd->RenderState = nullptr; // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called. // Our last values will leak into user/application rendering IF: @@ -1360,6 +1367,12 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) 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.DrawCallback_ResetRenderState = ImGui_ImplVulkan_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplVulkan_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplVulkan_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplVulkan_DrawCallback_SetSamplerCustom; + // Sanity checks IM_ASSERT(info->Instance != VK_NULL_HANDLE); IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE); diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 1dc93095..0b89abe8 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -7,6 +7,8 @@ // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// Missing features or Issues: +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. // Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags. @@ -20,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). // 2026-03-25: Added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK define, with SPIRV shaders if WGSL is not available. (#9316, #9246, #9257) // 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281) // 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898) @@ -427,8 +430,10 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas wgpuRenderPassEncoderSetBlendConstant(ctx, &blend_color); } +// Draw callbacks +static void ImGui_ImplWGPU_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. + // Render function -// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder) { // Avoid rendering when minimized @@ -539,8 +544,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + if (pcmd->UserCallback == ImGui_ImplWGPU_DrawCallback_ResetRenderState) ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr); else pcmd->UserCallback(draw_list, pcmd); @@ -889,6 +893,9 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) 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.DrawCallback_ResetRenderState = ImGui_ImplWGPU_DrawCallback_ResetRenderState; + bd->initInfo = *init_info; bd->wgpuDevice = init_info->Device; bd->defaultQueue = wgpuDeviceGetQueue(bd->wgpuDevice); diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index c06c25f8..2e4ea92e 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -19,6 +19,8 @@ // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// Missing features or Issues: +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. // 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. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 75ce0995..ba0f28cf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -134,6 +134,21 @@ Other Changes: - Minor optimization: reduce redudant label scanning in common widgets. - Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). - Backends: + - Added support for new standardized draw callbacks in most backends: (#9378) + - Allegro5: Reset n/a n/a n/a + - DX9: Reset SetSamplerLinear SetSamplerNearest n/a + - DX10: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom + - DX11: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom + - DX12: Reset SetSamplerLinear SetSamplerNearest n/a + - Metal: Reset *missing* *missing* *missing* + - OpenGL2: Reset SetSamplerLinear SetSamplerNearest *missing* + - OpenGL3+: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom + - SDLGPU3: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom + - SDLRenderer2: Reset n/a n/a n/a + - SDLRenderer3: Reset SetSamplerLinear SetSamplerNearest n/a + - Vulkan: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom + - WebGPU: Reset *missing* *missing* *missing* + (Vulkan backend by @yaz0r, others by @ocornut) - 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 From 37952fb3b8f0986403900701c89dd747140175bf Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Apr 2026 18:06:17 +0200 Subject: [PATCH 40/44] Backends: Vulkan, SDLGPU3: remove samplers from RenderState. (#9378) Revert part of ac261203a58e7cb3db8c7dbbb9665ed92ffac1b7, 9ee3d731b5934b92da9ebe8ae2442015eac600ac (#8866, #8163, #7998, #7988) since we have a better solution. --- backends/imgui_impl_sdlgpu3.cpp | 23 ++++++++++++----------- backends/imgui_impl_sdlgpu3.h | 3 --- backends/imgui_impl_vulkan.cpp | 18 +++++++----------- backends/imgui_impl_vulkan.h | 3 --- docs/CHANGELOG.txt | 2 -- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index a8b6dcd2..41933a1e 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -59,7 +59,10 @@ struct ImGui_ImplSDLGPU3_FrameData struct ImGui_ImplSDLGPU3_Data { ImGui_ImplSDLGPU3_InitInfo InitInfo; - ImGui_ImplSDLGPU3_RenderState* RenderState = nullptr; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering. + + // Render state + ImGui_ImplSDLGPU3_RenderState* RenderState = nullptr; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering. + SDL_GPUSampler* CurrentSampler = nullptr; // Graphics pipeline & shaders SDL_GPUShader* VertexShader = nullptr; @@ -89,10 +92,10 @@ static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } -static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplSDLGPU3_RenderState* render_state, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) +static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - render_state->SamplerCurrent = bd->TexSamplerLinear; + bd->CurrentSampler = bd->TexSamplerLinear; // Bind graphics pipeline SDL_BindGPUGraphicsPipeline(render_pass, pipeline); @@ -220,9 +223,9 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff // Draw callbacks static void ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. -static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->RenderState->SamplerCurrent = bd->TexSamplerLinear; } -static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->RenderState->SamplerCurrent = bd->TexSamplerNearest; } -static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd){ ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->RenderState->SamplerCurrent = (SDL_GPUSampler*)cmd->UserCallbackData; } +static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = bd->TexSamplerLinear; } +static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = bd->TexSamplerNearest; } +static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd){ ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = (SDL_GPUSampler*)cmd->UserCallbackData; } void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { @@ -246,11 +249,9 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplSDLGPU3_RenderState render_state; render_state.Device = bd->InitInfo.Device; - render_state.SamplerLinear = render_state.SamplerCurrent = bd->TexSamplerLinear; - render_state.SamplerNearest = bd->TexSamplerNearest; platform_io.Renderer_RenderState = bd->RenderState = &render_state; - ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -265,7 +266,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe { // User callback, registered via ImDrawList::AddCallback() if (pcmd->UserCallback == ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState) - ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); else pcmd->UserCallback(draw_list, pcmd); } @@ -294,7 +295,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe // Bind DescriptorSet with font or user texture SDL_GPUTextureSamplerBinding texture_sampler_binding; texture_sampler_binding.texture = (SDL_GPUTexture*)(intptr_t)pcmd->GetTexID(); - texture_sampler_binding.sampler = render_state.SamplerCurrent; + texture_sampler_binding.sampler = bd->CurrentSampler; SDL_BindGPUFragmentSamplers(render_pass, 0, &texture_sampler_binding, 1); // Draw diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 1c73dfd7..bc21d1c7 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -57,9 +57,6 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex); struct ImGui_ImplSDLGPU3_RenderState { SDL_GPUDevice* Device; - SDL_GPUSampler* SamplerLinear; // Bilinear filtering sampler - SDL_GPUSampler* SamplerNearest; // Nearest/point filtering sampler - SDL_GPUSampler* SamplerCurrent; // Current sampler (may be changed by callback) }; #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index e62d0df7..fb3049e7 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -496,10 +496,9 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory buffer_size = buffer_size_aligned; } -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) +static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, 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); @@ -531,6 +530,9 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, ImGui_ImplV 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); + + // Setup sampler + vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } // Draw callbacks @@ -616,12 +618,10 @@ 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 = bd->RenderState = &render_state; // Setup desired Vulkan state - ImGui_ImplVulkan_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, rb, fb_width, fb_height); + 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 @@ -630,7 +630,6 @@ 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_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) @@ -643,8 +642,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // User callback, registered via ImDrawList::AddCallback() if (pcmd->UserCallback == ImGui_ImplVulkan_DrawCallback_ResetRenderState) { - ImGui_ImplVulkan_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, rb, fb_width, fb_height); - last_image_view = last_sampler = VK_NULL_HANDLE; + ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); + last_image_view = VK_NULL_HANDLE; } else pcmd->UserCallback(draw_list, pcmd); @@ -675,10 +674,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm 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); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 869d61c4..603f3947 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -173,9 +173,6 @@ 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 ba0f28cf..3df41200 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,8 +56,6 @@ 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: From dfe6f9ebca22dadea98319e0c4602df2084bde4b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 19:22:04 +0200 Subject: [PATCH 41/44] Backends: WebGPU: added SetSamplerLinear/Nearest draw callbacks. (#9378) --- backends/imgui_impl_wgpu.cpp | 55 +++++++++++++++++++++--------------- backends/imgui_impl_wgpu.h | 2 +- docs/CHANGELOG.txt | 2 +- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 0b89abe8..fe01dcf4 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -8,7 +8,7 @@ // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerCustom. // Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags. @@ -22,7 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2026-03-25: Added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK define, with SPIRV shaders if WGSL is not available. (#9316, #9246, #9257) // 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281) // 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898) @@ -86,11 +86,13 @@ struct ImGui_ImplWGPU_Texture struct RenderResources { - 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) - WGPUBindGroupLayout ImageBindGroupLayout = nullptr; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM + WGPUSampler SamplerLinear = nullptr; // Bilinear sampler + WGPUSampler SamplerNearest = nullptr; // Nearest/point sampler + WGPUBuffer Uniforms = nullptr; // Shader uniforms + WGPUBindGroup CommonBindGroupLinear = nullptr; // Common bind-group bound to group 0 (uniforms + SamplerLinear) + WGPUBindGroup CommonBindGroupNearest = nullptr; // Common bind-group bound to group 0 (uniforms + SamplerNearest) + ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map) + WGPUBindGroupLayout ImageBindGroupLayout = nullptr; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM }; struct FrameResources @@ -117,6 +119,7 @@ struct ImGui_ImplWGPU_Data WGPUTextureFormat renderTargetFormat = WGPUTextureFormat_Undefined; WGPUTextureFormat depthStencilFormat = WGPUTextureFormat_Undefined; WGPURenderPipeline pipelineState = nullptr; + ImGui_ImplWGPU_RenderState* RenderState = nullptr; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering. RenderResources renderResources; FrameResources* pFrameResources = nullptr; @@ -300,8 +303,10 @@ static void SafeRelease(WGPUShaderModule& res) static void SafeRelease(RenderResources& res) { SafeRelease(res.SamplerLinear); + SafeRelease(res.SamplerNearest); SafeRelease(res.Uniforms); - SafeRelease(res.CommonBindGroup); + SafeRelease(res.CommonBindGroupLinear); + SafeRelease(res.CommonBindGroupNearest); SafeRelease(res.ImageBindGroupLayout); }; @@ -423,7 +428,7 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize * sizeof(ImDrawVert)); wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize * sizeof(ImDrawIdx)); wgpuRenderPassEncoderSetPipeline(ctx, bd->pipelineState); - wgpuRenderPassEncoderSetBindGroup(ctx, 0, bd->renderResources.CommonBindGroup, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(ctx, 0, bd->renderResources.CommonBindGroupLinear, 0, nullptr); // Setup blend factor WGPUColor blend_color = { 0.f, 0.f, 0.f, 0.f }; @@ -431,7 +436,9 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas } // Draw callbacks -static void ImGui_ImplWGPU_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplWGPU_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplWGPU_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); wgpuRenderPassEncoderSetBindGroup(bd->RenderState->RenderPassEncoder, 0, bd->renderResources.CommonBindGroupLinear, 0, nullptr); } +static void ImGui_ImplWGPU_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); wgpuRenderPassEncoderSetBindGroup(bd->RenderState->RenderPassEncoder, 0, bd->renderResources.CommonBindGroupNearest, 0, nullptr); } // Render function void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder) @@ -528,7 +535,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder ImGui_ImplWGPU_RenderState render_state; render_state.Device = bd->wgpuDevice; render_state.RenderPassEncoder = pass_encoder; - platform_io.Renderer_RenderState = &render_state; + platform_io.Renderer_RenderState = bd->RenderState = &render_state; // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -591,7 +598,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder } image_bind_groups.Data.resize(0); - platform_io.Renderer_RenderState = nullptr; + platform_io.Renderer_RenderState = bd->RenderState = nullptr; } static void ImGui_ImplWGPU_DestroyTexture(ImTextureData* tex) @@ -819,19 +826,23 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() ImGui_ImplWGPU_CreateUniformBuffer(); - // Create sampler + // Create samplers (Linear/Nearest) // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; sampler_desc.maxAnisotropy = 1; + sampler_desc.minFilter = WGPUFilterMode_Linear; + sampler_desc.magFilter = WGPUFilterMode_Linear; + sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; bd->renderResources.SamplerLinear = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); + sampler_desc.minFilter = WGPUFilterMode_Nearest; + sampler_desc.magFilter = WGPUFilterMode_Nearest; + sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Nearest; + bd->renderResources.SamplerNearest = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); - // Create resource bind group + // Create resource bind groups (one per sampler, otherwise identical) WGPUBindGroupEntry common_bg_entries[] = { { nullptr, 0, bd->renderResources.Uniforms, 0, MEMALIGN(sizeof(Uniforms), 16), 0, 0 }, @@ -841,7 +852,9 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() common_bg_descriptor.layout = bg_layouts[0]; common_bg_descriptor.entryCount = sizeof(common_bg_entries) / sizeof(WGPUBindGroupEntry); common_bg_descriptor.entries = common_bg_entries; - bd->renderResources.CommonBindGroup = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor); + bd->renderResources.CommonBindGroupLinear = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor); + common_bg_entries[1].sampler = bd->renderResources.SamplerNearest; + bd->renderResources.CommonBindGroupNearest = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor); bd->renderResources.ImageBindGroupLayout = bg_layouts[1]; SafeRelease(vertex_shader_desc.module); @@ -895,6 +908,8 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.DrawCallback_ResetRenderState = ImGui_ImplWGPU_DrawCallback_ResetRenderState; + platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplWGPU_DrawCallback_SetSamplerLinear; + platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplWGPU_DrawCallback_SetSamplerNearest; bd->initInfo = *init_info; bd->wgpuDevice = init_info->Device; @@ -904,11 +919,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) bd->numFramesInFlight = init_info->NumFramesInFlight; bd->frameIndex = UINT_MAX; - bd->renderResources.SamplerLinear = nullptr; - bd->renderResources.Uniforms = nullptr; - bd->renderResources.CommonBindGroup = nullptr; bd->renderResources.ImageBindGroups.Data.reserve(100); - bd->renderResources.ImageBindGroupLayout = nullptr; // Create buffers with a default size (they will later be grown as needed) bd->pFrameResources = new FrameResources[bd->numFramesInFlight]; diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 2e4ea92e..e1bbf9d8 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -20,7 +20,7 @@ // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerCustom. // 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. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3df41200..658d895a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -145,7 +145,7 @@ Other Changes: - SDLRenderer2: Reset n/a n/a n/a - SDLRenderer3: Reset SetSamplerLinear SetSamplerNearest n/a - Vulkan: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom - - WebGPU: Reset *missing* *missing* *missing* + - WebGPU: Reset SetSamplerLinear SetSamplerNearest *missing* (Vulkan backend by @yaz0r, others by @ocornut) - GLFW: added a Win32-specific implementation of `ImGui_ImplGlfw_GetContentScaleXXXX` functions for legacy GLFW 3.2. (#9003) From 7e7f3adb808a4ad868d355aab33b133268f4dbe5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 21:00:13 +0200 Subject: [PATCH 42/44] Removed DrawCallback_SetSamplerCustom feature for now. Too unreliable to get working everywhere. (#9378) --- backends/imgui_impl_allegro5.cpp | 2 +- backends/imgui_impl_allegro5.h | 2 +- backends/imgui_impl_dx10.cpp | 2 -- backends/imgui_impl_dx11.cpp | 4 +--- backends/imgui_impl_metal.h | 2 +- backends/imgui_impl_metal.mm | 2 +- backends/imgui_impl_opengl3.cpp | 4 +--- backends/imgui_impl_sdlgpu3.cpp | 4 +--- backends/imgui_impl_sdlrenderer2.cpp | 2 +- backends/imgui_impl_sdlrenderer2.h | 2 +- backends/imgui_impl_vulkan.cpp | 4 +--- backends/imgui_impl_wgpu.cpp | 2 -- backends/imgui_impl_wgpu.h | 2 -- docs/CHANGELOG.txt | 27 +++++++++++++-------------- imgui.cpp | 2 +- imgui.h | 2 +- 16 files changed, 25 insertions(+), 40 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index c5d28318..57865f91 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -9,7 +9,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. // [ ] Platform: Missing gamepad support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 3fe531af..84ebf433 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -9,7 +9,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. // [ ] Platform: Missing gamepad support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index d412a9e5..e6cc5955 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -158,7 +158,6 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* static void ImGui_ImplDX10_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. static void ImGui_ImplDX10_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); bd->pd3dDevice->PSSetSamplers(0, 1, &bd->pTexSamplerLinear); } static void ImGui_ImplDX10_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); bd->pd3dDevice->PSSetSamplers(0, 1, &bd->pTexSamplerNearest); } -static void ImGui_ImplDX10_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); ID3D10SamplerState* sampler = (ID3D10SamplerState*)cmd->UserCallbackData; bd->pd3dDevice->PSSetSamplers(0, 1, &sampler); } // Render function void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) @@ -622,7 +621,6 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device) platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX10_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX10_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX10_DrawCallback_SetSamplerNearest; - platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplDX10_DrawCallback_SetSamplerCustom; // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 29f4914f..b365f395 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -17,7 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. +// 2026-XX-XX: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. @@ -165,7 +165,6 @@ static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11D static void ImGui_ImplDX11_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. static void ImGui_ImplDX11_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &bd->pTexSamplerLinear); } static void ImGui_ImplDX11_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &bd->pTexSamplerNearest); } -static void ImGui_ImplDX11_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); ID3D11SamplerState* sampler = (ID3D11SamplerState*)cmd->UserCallbackData; bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &sampler); } // Render function void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) @@ -639,7 +638,6 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX11_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX11_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX11_DrawCallback_SetSamplerNearest; - platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplDX11_DrawCallback_SetSamplerCustom; // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 2baa4de9..879fadcf 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -6,7 +6,7 @@ // [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). // Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks. // 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. diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index ddde093f..1e529756 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -6,7 +6,7 @@ // [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). // Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks. // 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. diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 228294c5..77de814b 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,7 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. +// 2026-XX-XX: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) // 2025-12-11: OpenGL: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -408,7 +408,6 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[0]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } } static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[1]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } } -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd){ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, (GLuint)(intptr_t)cmd->UserCallbackData); } } // OpenGL3 Render function. // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. @@ -1030,7 +1029,6 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL3_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest; - platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplOpenGL3_DrawCallback_SetSamplerCustom; // 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. diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 41933a1e..f8a109a5 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -22,7 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) // 2025-11-26: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. @@ -225,7 +225,6 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff static void ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = bd->TexSamplerLinear; } static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = bd->TexSamplerNearest; } -static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd){ ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = (SDL_GPUSampler*)cmd->UserCallbackData; } void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { @@ -670,7 +669,6 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest; - platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerCustom; IM_ASSERT(info->Device != nullptr); IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID); diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 2f6fcc6e..5372d1cf 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'. // Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. // 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. diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index 7b2edd4d..f33bc160 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.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'. // Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. +// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. // 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. diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index fb3049e7..bb4f2cbd 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,7 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest, DrawCallback_SetSamplerCustom. +// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. // 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) @@ -539,7 +539,6 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline static void ImGui_ImplVulkan_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); } -static void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(cmd->UserCallbackDataSize == sizeof(VkDescriptorSet)); VkDescriptorSet* ds = (VkDescriptorSet*)cmd->UserCallbackData; vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, ds, 0, nullptr); } // Render function void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) @@ -1367,7 +1366,6 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) platform_io.DrawCallback_ResetRenderState = ImGui_ImplVulkan_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplVulkan_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplVulkan_DrawCallback_SetSamplerNearest; - platform_io.DrawCallback_SetSamplerCustom = ImGui_ImplVulkan_DrawCallback_SetSamplerCustom; // Sanity checks IM_ASSERT(info->Instance != VK_NULL_HANDLE); diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index fe01dcf4..fb9b05f4 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -7,8 +7,6 @@ // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). -// Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerCustom. // Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags. diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index e1bbf9d8..c06c25f8 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -19,8 +19,6 @@ // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). -// Missing features or Issues: -// [ ] Renderer: Missing support for DrawCallback_SetSamplerCustom. // 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. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 658d895a..7b1e89cd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,7 +67,6 @@ Other Changes: platform_io.DrawCallback_ResetRenderState; // Request to reset the graphics/render state. platform_io.DrawCallback_SetSamplerLinear; // Request to set current texture sampling to Linear platform_io.DrawCallback_SetSamplerNearest; // Request to set current texture sampling to Nearest/Point - platform_io.DrawCallback_SetSamplerCustom; // Request to set current texture sampling using Backend Specific data. Note that some backends might not support all callbacks. (#9378, #9371, #3590, #8926, #2973, #7485, #7468, #6969, #5118, #7616, #9173, #8322, #7230, #5999, #6452, #5156, #7342, #7592, #7511) @@ -133,19 +132,19 @@ Other Changes: - Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). - Backends: - Added support for new standardized draw callbacks in most backends: (#9378) - - Allegro5: Reset n/a n/a n/a - - DX9: Reset SetSamplerLinear SetSamplerNearest n/a - - DX10: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom - - DX11: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom - - DX12: Reset SetSamplerLinear SetSamplerNearest n/a - - Metal: Reset *missing* *missing* *missing* - - OpenGL2: Reset SetSamplerLinear SetSamplerNearest *missing* - - OpenGL3+: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom - - SDLGPU3: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom - - SDLRenderer2: Reset n/a n/a n/a - - SDLRenderer3: Reset SetSamplerLinear SetSamplerNearest n/a - - Vulkan: Reset SetSamplerLinear SetSamplerNearest SetSamplerCustom - - WebGPU: Reset SetSamplerLinear SetSamplerNearest *missing* + - Allegro5: Reset n/a n/a + - DX9: Reset SetSamplerLinear SetSamplerNearest + - DX10: Reset SetSamplerLinear SetSamplerNearest + - DX11: Reset SetSamplerLinear SetSamplerNearest + - DX12: Reset SetSamplerLinear SetSamplerNearest + - Metal: Reset *missing* *missing* + - OpenGL2: Reset SetSamplerLinear SetSamplerNearest + - OpenGL3+: Reset SetSamplerLinear SetSamplerNearest + - SDLGPU3: Reset SetSamplerLinear SetSamplerNearest + - SDLRenderer2: Reset n/a n/a + - SDLRenderer3: Reset SetSamplerLinear SetSamplerNearest + - Vulkan: Reset SetSamplerLinear SetSamplerNearest + - WebGPU: Reset SetSamplerLinear SetSamplerNearest (Vulkan backend by @yaz0r, others by @ocornut) - GLFW: added a Win32-specific implementation of `ImGui_ImplGlfw_GetContentScaleXXXX` functions for legacy GLFW 3.2. (#9003) diff --git a/imgui.cpp b/imgui.cpp index 5cf11f5b..1635e18a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15817,7 +15817,7 @@ void ImGuiPlatformIO::ClearRendererHandlers() { Renderer_TextureMaxWidth = Renderer_TextureMaxHeight = 0; Renderer_RenderState = NULL; - DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = DrawCallback_SetSamplerCustom = NULL; + DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = NULL; } ImGuiViewport* ImGui::GetMainViewport() diff --git a/imgui.h b/imgui.h index 1e6d79ee..f867f34b 100644 --- a/imgui.h +++ b/imgui.h @@ -4021,7 +4021,7 @@ struct ImGuiPlatformIO ImDrawCallback DrawCallback_ResetRenderState; // Request to reset the graphics/render state. ImDrawCallback DrawCallback_SetSamplerLinear; // Request to set current texture sampling to Linear ImDrawCallback DrawCallback_SetSamplerNearest; // Request to set current texture sampling to Nearest/Point - ImDrawCallback DrawCallback_SetSamplerCustom; // Request to set current texture sampling using Backend Specific data. + //ImDrawCallback DrawCallback_SetSamplerCustom; // Request to set current texture sampling using Backend Specific data. //------------------------------------------------------------------ // Output From 86ebb3bc1134aa5d79ab7380c2c690eeb669a05d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 22:03:11 +0200 Subject: [PATCH 43/44] Backends: removed samplers from ImGui_ImplDX10_RenderState, ImGui_ImplDX11_RenderState + fixed all Changelogs. (#9378) --- backends/imgui_impl_allegro5.cpp | 2 +- backends/imgui_impl_dx10.cpp | 4 +--- backends/imgui_impl_dx10.h | 4 ++-- backends/imgui_impl_dx11.cpp | 4 +--- backends/imgui_impl_dx11.h | 4 ++-- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx9.cpp | 2 +- backends/imgui_impl_metal.mm | 2 +- backends/imgui_impl_opengl2.cpp | 2 +- backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_sdlgpu3.cpp | 2 +- backends/imgui_impl_sdlrenderer2.cpp | 2 +- backends/imgui_impl_sdlrenderer3.cpp | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_wgpu.cpp | 2 +- docs/CHANGELOG.txt | 3 +++ 16 files changed, 20 insertions(+), 21 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 57865f91..79b169da 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -22,7 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported by Allegro5). +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported by Allegro5). (#9378) // 2025-09-18: Call platform_io.ClearRendererHandlers() and platform_io.ClearPlatformHandlers() on shutdown. // 2025-08-12: Inputs: fixed missing support for ImGuiKey_PrintScreen under Windows, as raw Allegro 5 does not receive it. // 2025-08-12: Added ImGui_ImplAllegro5_SetDisplay() function to change current ALLEGRO_DISPLAY, as Allegro applications often need to do that. diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index e6cc5955..9858cbe9 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-XX-XX: DirectX10: Added support for ImDrawCallback_SetSamplerLinear, ImDrawCallback_SetSamplerPoint. +// 2026-04-23: DirectX10: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX10_RenderState. (#9378) // 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. @@ -266,8 +266,6 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplDX10_RenderState render_state; render_state.Device = bd->pd3dDevice; - render_state.SamplerLinear = bd->pTexSamplerLinear; - render_state.SamplerNearest = bd->pTexSamplerNearest; render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; platform_io.Renderer_RenderState = &render_state; diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 87945d64..179756fb 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -41,9 +41,9 @@ IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex); struct ImGui_ImplDX10_RenderState { ID3D10Device* Device; - ID3D10SamplerState* SamplerLinear; - ID3D10SamplerState* SamplerNearest; ID3D10Buffer* VertexConstantBuffer; + //ID3D10SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear) + //ID3D10SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index b365f395..6573d274 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -17,7 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX11_RenderState. (#9378) // 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. @@ -281,8 +281,6 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) ImGui_ImplDX11_RenderState render_state; render_state.Device = bd->pd3dDevice; render_state.DeviceContext = bd->pd3dDeviceContext; - render_state.SamplerLinear = bd->pTexSamplerLinear; - render_state.SamplerNearest = bd->pTexSamplerNearest; render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; platform_io.Renderer_RenderState = bd->RenderState = &render_state; diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 338e0093..56166b92 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -44,9 +44,9 @@ struct ImGui_ImplDX11_RenderState { ID3D11Device* Device; ID3D11DeviceContext* DeviceContext; - ID3D11SamplerState* SamplerLinear; - ID3D11SamplerState* SamplerNearest; ID3D11Buffer* VertexConstantBuffer; + //ID3D11SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear) + //ID3D11SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index b4344f2a..157384ab 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -20,7 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002) // 2025-09-29: DirectX12: Rework synchronization logic. (#8961) // 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index d6464a4a..360398f0 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -17,7 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 1e529756..db2fcd3c 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -18,7 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378) // 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367) // 2026-04-03: Metal: avoid redundant vertex buffer bind in SetupRenderState. (#9343) // 2026-03-19: Fixed issue in ImGui_ImplMetal_RenderDrawData() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index ac17f81f..6cbaaac7 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -26,7 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_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-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 77de814b..cf190f63 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,7 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) // 2025-12-11: OpenGL: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index f8a109a5..8f0408c8 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -22,7 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplSDLGPU3_RenderState. (#9378) // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) // 2025-11-26: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 5372d1cf..d9f329bd 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -27,7 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported). +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported). (#9378) // 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(). diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index eb05073d..bf025040 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -25,7 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 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(). diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index bb4f2cbd..3baf3b75 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,7 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 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) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index fb9b05f4..5636178b 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -20,7 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-XX-XX: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. +// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-25: Added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK define, with SPIRV shaders if WGSL is not available. (#9316, #9246, #9257) // 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281) // 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7b1e89cd..c1d9f2b7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,9 @@ 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). + - DirectX10, DirectX11, SDLGPU3, Vulkan: removed samplers from ImGui_ImplXXXX_RenderState. + Prefer to use backend-agnostic DrawCallback_SetSamplerLinear which works everywhere! (#9378) + If there is a legit need/request for them or any render state we can always add them back. Other Changes: From 6b05f711fdd1fb27248ad30c94f0c2d860e1e360 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Apr 2026 22:06:42 +0200 Subject: [PATCH 44/44] Backends: WebGPU: build fix for WebGL/ES2. --- backends/imgui_impl_opengl3.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index cf190f63..c950c7a0 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -254,10 +254,8 @@ struct ImGui_ImplOpenGL3_Data bool HasClipOrigin; bool UseBufferSubData; bool UseTexParameterToSetSampler; - GLuint NextSampler; -#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER - GLuint TexSamplers[2]; // Linear, Nearest -#endif + GLuint NextSampler; // Used if !HasBindSampler && UseTexParameterToSetSampler. + GLuint TexSamplers[2]; // Used if IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER && HasBindSimpler (0=linear, 1=nearest). ImVector TempBuffer;