Skip to content

Instantly share code, notes, and snippets.

@thedmd
Created April 25, 2020 12:15
Show Gist options
  • Save thedmd/e384a83c0fe9e82ec0f69c869510ad44 to your computer and use it in GitHub Desktop.
Save thedmd/e384a83c0fe9e82ec0f69c869510ad44 to your computer and use it in GitHub Desktop.
ImDrawListSplitter::Merge - corrupted data in buffer (64k+ vertices) with 16-bits indices #3129
static bool randomize = false;
static int vtx_count = 64790;
static int map[100000 / 4];
static int rev_map[100000 / 4];
# include <random>
ImDrawList* ShowBackendCheckerWindow(bool* p_open, int* p_vertex_delta)
{
ImDrawList* draw_list = nullptr;
int dummy_vertex_delta = 0;
int& vertex_delta = p_vertex_delta ? *p_vertex_delta : dummy_vertex_delta;
vertex_delta = 0;
if (!ImGui::Begin("Dear ImGui Backend Checker##1", p_open))
{
ImGui::End();
return draw_list;
}
ImGuiIO& io = ImGui::GetIO();
ImGui::Text("Dear ImGui %s Backend Checker", ImGui::GetVersion());
ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
ImGui::Separator();
if (ImGui::TreeNodeEx("0001: Renderer: Large Mesh Support", ImGuiTreeNodeFlags_DefaultOpen))
{
draw_list = ImGui::GetWindowDrawList();
{
auto* draw_list = ImGui::GetWindowDrawList();
int start_vertex_count = draw_list->VtxBuffer.Size;
ImDrawListSplitter splitter;
splitter.Split(draw_list, 100000 / 4);
ImVec2 p = ImGui::GetCursorScreenPos();
for (int n = 0; n < vtx_count / 4; n++)
{
splitter.SetCurrentChannel(draw_list, map[n]);
float off_x = (float)(n % 100) * 3.0f;
float off_y = (float)(n % 100) * 1.0f;
ImU32 col = IM_COL32(((n * 17) & 255), ((n * 59) & 255), ((n * 83) & 255), 255);
draw_list->AddRectFilled(ImVec2(p.x + off_x, p.y + off_y), ImVec2(p.x + off_x + 50, p.y + off_y + 50), col);
}
splitter.Merge(draw_list);
int end_vertex_count = draw_list->VtxBuffer.Size;
vertex_delta = end_vertex_count - start_vertex_count;
ImGui::Dummy(ImVec2(300 + 50, 100 + 50));
ImGui::Text("VtxBuffer.Size = %d", draw_list->VtxBuffer.Size);
}
ImGui::TreePop();
}
ImGui::End();
return draw_list;
}
ImDrawList* ShowBackendCheckerWindow_NoSplitter(bool* p_open, int* p_vertex_delta)
{
ImDrawList* draw_list = nullptr;
int dummy_vertex_delta = 0;
int& vertex_delta = p_vertex_delta ? *p_vertex_delta : dummy_vertex_delta;
vertex_delta = 0;
if (!ImGui::Begin("Dear ImGui Backend Checker##2", p_open))
{
ImGui::End();
return draw_list;
}
ImGuiIO& io = ImGui::GetIO();
ImGui::Text("Dear ImGui %s Backend Checker", ImGui::GetVersion());
ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
ImGui::Separator();
if (ImGui::TreeNodeEx("0001: Renderer: Large Mesh Support", ImGuiTreeNodeFlags_DefaultOpen))
{
draw_list = ImGui::GetWindowDrawList();
{
auto* draw_list = ImGui::GetWindowDrawList();
int start_vertex_count = draw_list->VtxBuffer.Size;
ImVec2 p = ImGui::GetCursorScreenPos();
for (int i = 0; i < vtx_count / 4; i++)
{
int n = randomize ? rev_map[i] : i;
float off_x = (float)(n % 100) * 3.0f;
float off_y = (float)(n % 100) * 1.0f;
ImU32 col = IM_COL32(((n * 17) & 255), ((n * 59) & 255), ((n * 83) & 255), 255);
draw_list->AddRectFilled(ImVec2(p.x + off_x, p.y + off_y), ImVec2(p.x + off_x + 50, p.y + off_y + 50), col);
}
int end_vertex_count = draw_list->VtxBuffer.Size;
vertex_delta = end_vertex_count - start_vertex_count;
ImGui::Dummy(ImVec2(300 + 50, 100 + 50));
ImGui::Text("VtxBuffer.Size = %d", draw_list->VtxBuffer.Size);
}
ImGui::TreePop();
}
ImGui::End();
return draw_list;
}
void TestSplitterBug()
{
auto& io = ImGui::GetIO();
ImGui::SliderInt("VtxCount##1", &vtx_count, 0, 100000);
if (ImGui::Button("-10", ImVec2(50.0f, 0.0f)))
vtx_count -= 10;
ImGui::SameLine();
if (ImGui::Button("-1", ImVec2(50.0f, 0.0f)))
vtx_count -= 1;
ImGui::SameLine();
if (ImGui::Button("+1", ImVec2(50.0f, 0.0f)))
vtx_count += 1;
ImGui::SameLine();
if (ImGui::Button("+10", ImVec2(50.0f, 0.0f)))
vtx_count += 10;
vtx_count = ImMax(ImMin(vtx_count, 100000), 0);
ImGui::SameLine();
if (ImGui::Button("Copy", ImVec2(50.0f, 0.0f)))
{
char buffer[64];
_itoa_s(vtx_count, buffer, 10);
ImGui::SetClipboardText(buffer);
}
ImGui::SameLine();
ImGui::Checkbox("Randomize", &randomize);
for (int n = 0; n < vtx_count / 4; n++)
map[n] = n;
if (randomize)
{
std::srand(13);
std::random_shuffle(&map[0], &map[vtx_count / 4], [](auto n) { return std::rand() % n; });
for (int i = 0; i < vtx_count / 4; ++i)
rev_map[map[i]] = i;
}
ImGui::Spacing();
ImGui::Spacing();
ImGui::Spacing();
int vertex_delta_a = 0;
int vertex_delta_b = 0;
ImGui::SetNextWindowPos(ImVec2(700, 100));
auto draw_list_a = ShowBackendCheckerWindow(nullptr, &vertex_delta_a);
ImGui::SetNextWindowPos(ImVec2(1200, 100));
auto draw_list_b = ShowBackendCheckerWindow_NoSplitter(nullptr, &vertex_delta_b);
if (!draw_list_a || !draw_list_b)
return;
ImGui::Spacing();
ImGui::Spacing();
ImGui::Spacing();
const int table_width = 600.0f;
ImGui::PushItemWidth(table_width);
auto work_rect_max_x = ImGui::GetCurrentWindow()->WorkRect.Max.x;
ImGui::GetCurrentWindow()->WorkRect.Max.x = table_width;
ImGui::GetCurrentWindow()->Size.x -= work_rect_max_x - table_width;
ImGui::Columns(3);
ImGui::NextColumn();
ImGui::Text("Splitter");
ImGui::NextColumn();
ImGui::Text("No Splitter");
ImGui::Separator(); ImGui::NextColumn();
ImGui::Text("VtxCount");
ImGui::NextColumn();
ImGui::Text("%d", draw_list_a->VtxBuffer.Size);
ImGui::Text("%d (delta)", vertex_delta_a);
ImGui::NextColumn();
ImGui::Text("%d", draw_list_b->VtxBuffer.Size);
ImGui::Text("%d (delta)", vertex_delta_b);
ImGui::Separator(); ImGui::NextColumn();
ImGui::Text("Commands");
ImGui::NextColumn();
ImGui::Text("%d", draw_list_a->CmdBuffer.Size);
ImGui::NextColumn();
ImGui::Text("%d", draw_list_b->CmdBuffer.Size);
ImGui::Separator(); ImGui::NextColumn();
auto max_cmd_buffers = ImMax(draw_list_a->CmdBuffer.Size, draw_list_b->CmdBuffer.Size);
for (int i = 0; i < max_cmd_buffers; ++i)
{
ImGui::Text("Command Buffer %d", i);
ImGui::NextColumn();
if (i < draw_list_a->CmdBuffer.Size)
{
auto& cmd_buffer = draw_list_a->CmdBuffer[i];
ImGui::Text("ElemCount %d", cmd_buffer.ElemCount);
ImGui::Text("VtxOffset %d", cmd_buffer.VtxOffset);
}
ImGui::NextColumn();
if (i < draw_list_b->CmdBuffer.Size)
{
auto& cmd_buffer = draw_list_b->CmdBuffer[i];
ImGui::Text("ElemCount %d", cmd_buffer.ElemCount);
ImGui::Text("VtxOffset %d", cmd_buffer.VtxOffset);
}
ImGui::Separator(); ImGui::NextColumn();
}
ImGui::GetCurrentWindow()->WorkRect.Max.x = work_rect_max_x;
ImGui::GetCurrentWindow()->Size.x += work_rect_max_x - table_width;
ImGui::Columns();
ImGui::PopItemWidth();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment