From 3bef743df464c5dbbf527981c7f50be7a0f7f719 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 19:06:55 +0200 Subject: [PATCH] ImDrawList: Clarifying and guarateeing that CmdBuffer.back()->UserCallback should be always be NULL. --- imgui_draw.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d0ea99fb0..0af2c3c52 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -451,7 +451,8 @@ void ImDrawList::_PopUnusedDrawCmd() void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) { ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) + IM_ASSERT(curr_cmd->UserCallback == NULL); + if (curr_cmd->ElemCount != 0) { AddDrawCmd(); curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -473,11 +474,12 @@ void ImDrawList::_OnChangedClipRect() { // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if ((curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) + if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) { AddDrawCmd(); return; } + IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; @@ -494,11 +496,12 @@ void ImDrawList::_OnChangedTextureID() { // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if ((curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) || curr_cmd->UserCallback != NULL) + if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) { AddDrawCmd(); return; } + IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; @@ -1427,6 +1430,11 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } } draw_list->_IdxWritePtr = idx_write; + + // Ensure there's always a non-callback draw command trailing the command-buffer + if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) + draw_list->AddDrawCmd(); + draw_list->_OnChangedClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. draw_list->_OnChangedTextureID(); _Count = 1; @@ -1437,6 +1445,7 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) IM_ASSERT(idx >= 0 && idx < _Count); if (_Current == idx) return; + // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));