-
-
Notifications
You must be signed in to change notification settings - Fork 11.3k
Description
Version/Branch of Dear ImGui:
Version 1.XX, Branch: XXX (master/docking/etc.)
Back-ends:
imgui_impl_android.cpp + imgui_impl_opengl3.cpp
Compiler, OS:
Clang (NDK), Android
Full config/build information:
It doesn't depend on the version
Details:
When rendering a large number of primitives (AddRectFilled and AddCircleFilled) on the Android device "Redmi Note 13 Pro+", serious rendering artifacts appear - the text becomes blurred, distorted (zalgo effect), while other UI elements remain clear and my function that displays the "Toggle Button" in other places is displayed without problems on this the device.
The problem is a rare exception, because my other 100+ Android users did not have this problem (including on my three phones of different models), as well as on Windows, where there are about 50 users and no one complained about something like this.
v1.92.4 is currently in use (Release version), before that v1.92.2b was used. And I can't know if it could have been before, because I made the application initially on v1.92.2b.
I don't have this device in my hands. Therefore, the user helped me in finding and solving the problem, I dropped the APK to him, and he sent me screenshots of the result. That's how the problem was solved in a couple of hours.
My version of the problem: vertex buffer overflow.
And as I understand it, BeginChild does "clipping", but then why did using a separate "clipping" help solve the problem? Or is it a GPU issue?
And the main question is: Is this an ImGui bug, or is this the expected behavior?
Screenshots/Video:
I thought it was bad to implement toggle_button_with_text, so I found a repository imgui_toggle, but that didn't help either:

Also, at the moment, I came up with the idea to change my "Toggle Button" to something similar, then I substituted ImGui::CheckBox and it solved the problem, but I needed the "Toggle Button".

Next, I just remove the pieces of code (toggle_button_with_text) and drop the APK to the user to find out about the result:
Here I come across "what happens if you remove draw_list->AddRectFilled or draw_list->AddCircleFilled ?" And I'm trying this:
I'm giving you clipping strings for testing:

As a result, the problem is solved (don't pay attention to the slightly small Toggle Button, I'll fix it):

I attach information about the user's phone:
Minimal, Complete and Verifiable Example code:
The full code of the function that causes the problem only on one device, but does not cause problems on others (I think there are more devices, but so far there have been no more):
static void toggle_button_with_text(const char* str_id, bool* v, const char* text)
{
ImVec2 p = ImGui::GetCursorScreenPos();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
float height = ImGui::GetFrameHeight() / 1.5f;
float width = height * 1.6f;
float radius = height * 0.50f;
// Draw toggle button
ImGui::InvisibleButton(str_id, ImVec2(width, height));
bool button_clicked = ImGui::IsItemClicked();
// Handle button click immediately (like original function)
if (button_clicked) {
*v = !*v;
}
float t = *v ? 1.0f : 0.0f;
ImGuiContext& g = *GImGui;
float ANIM_SPEED = 0.08f;
if (g.LastActiveId == g.CurrentWindow->GetID(str_id))
{
float t_anim = ImClamp(g.LastActiveIdTimer / ANIM_SPEED, 0.0f, 1.0f);
t = *v ? (t_anim) : (1.0f - t_anim);
}
ImU32 col_bg;
if (ImGui::IsItemHovered())
col_bg = ImGui::GetColorU32(ImVec4(
0.78f + (0.64f - 0.78f) * t,
0.78f + (0.83f - 0.78f) * t,
0.78f + (0.34f - 0.78f) * t,
1.0f
));
else
col_bg = ImGui::GetColorU32(ImVec4(
0.85f + (0.56f - 0.85f) * t,
0.85f + (0.83f - 0.85f) * t,
0.85f + (0.26f - 0.85f) * t,
1.0f
));
//I found the problem here. If you comment out one of the lines, then everything becomes fine, but we need both primitives (I added screenshots).
draw_list->AddRectFilled(p, ImVec2(p.x + width, p.y + height), col_bg, height * 0.5f);
draw_list->AddCircleFilled(ImVec2(p.x + radius + t * (width - radius * 2.0f), p.y + radius), radius - 1.5f, IM_COL32(255, 255, 255, 255));
ImGui::SameLine();
// Calculate text size for clickable area
ImVec2 text_size = ImGui::CalcTextSize(text);
// Create invisible button for text click area (same height as toggle button for alignment)
std::string text_id = std::string(str_id) + "_text";
float frame_height = ImGui::GetFrameHeight();
ImGui::InvisibleButton(text_id.c_str(), ImVec2(text_size.x, frame_height));
if (ImGui::IsItemClicked()) {
*v = !*v;
// Trigger animation by simulating button click
ImGuiContext& g = *GImGui;
ImGuiID button_id = g.CurrentWindow->GetID(str_id);
g.LastActiveId = button_id;
g.LastActiveIdTimer = 0.0f;
}
ImVec2 text_draw_pos = ImGui::GetItemRectMin();
text_draw_pos.y += (frame_height - text_size.y) * 0.5f; // Center text vertically
draw_list->AddText(text_draw_pos, ImGui::GetColorU32(ImGuiCol_Text), text);
}Here's how the function was used in the problematic code:
int app_count = imgui_android_get_app_count();
// Render in two passes: selected apps first, then the rest
for (int pass = 0; pass < 2; ++pass) {
const bool render_selected = (pass == 0);
for (int i = 0; i < app_count; i++) {
const char* app_name = android_get_app_name(i);
const char* app_package = android_get_app_package(i);
//... my code
// App row with toggle
ImGui::PushID(i);
std::string toggle_id = "##" + std::string(app_package);
// This is where I found the problem. Rendering of all elements - causes artifacts on "Redmi Note 13 Pro+"
toggle_button_with_text(toggle_id.c_str(), &is_selected, app_name);
// ... my code ...
ImGui::SameLine();
ImGui::Text(" (%s)", app_package);
ImGui::PopID();
}
}At the moment, the idea comes to me to make a test list with "clipping" and it saves the situation:
// STRESS TEST: Render 1000 toggle buttons to test rendering performance
// Using ImGuiListClipper to only render visible items and avoid vertex limit (65535)
static bool test_toggle_states[1000] = {false}; // Static array to preserve state between frames
const int test_count = 1000;
ImGuiListClipper clipper;
clipper.Begin(test_count);
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
ImGui::PushID(i);
// Generate test text for each toggle
char test_text[64];
snprintf(test_text, sizeof(test_text), "Test Item %d", i);
std::string toggle_id = "##test_toggle_" + std::to_string(i);
// Render toggle button (only visible ones)
toggle_button_with_text(toggle_id.c_str(), &test_toggle_states[i], test_text);
ImGui::PopID();
}
}
clipper.End();The problem is solved by using ImGuiListClipper to render only visible elements.:
// I had to change the logic of the code a bit
// Use ImGuiListClipper to render only visible items
// This prevents rendering artifacts by avoiding vertex buffer overflow
ImGuiListClipper clipper;
clipper.Begin((int)filtered_apps.size());
while (clipper.Step()) {
for (int idx = clipper.DisplayStart; idx < clipper.DisplayEnd; idx++) {
const AppItem& item = filtered_apps[idx];
int i = item.index;
bool is_selected = item.is_selected;
const char* app_name = android_get_app_name(i);
const char* app_package = android_get_app_package(i);
if (!app_name || !app_package) continue;
ImGui::PushID(i);
std::string toggle_id = "##" + std::string(app_package);
// We only render visible elements - artifacts disappear
toggle_button_with_text(toggle_id.c_str(), &is_selected, app_name);
// ... my code ...
ImGui::SameLine();
ImGui::Text(" (%s)", app_package);
ImGui::PopID();
}
}
clipper.End();







