ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible.

This commit is contained in:
omar 2019-01-08 17:37:22 +01:00
parent f53cd3ee0f
commit 9ad341902d
3 changed files with 70 additions and 56 deletions

View File

@ -72,6 +72,8 @@ Other Changes:
Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen.
Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected
into e.g. an error log and stopping the script execution. into e.g. an error log and stopping the script execution.
- ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible.
(Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.)
- IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends.
- IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
- IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful - IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful

View File

@ -1847,11 +1847,11 @@ struct ImDrawList
IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0);
// Stateful path API, add points then finish with PathFillConvex() or PathStroke() // Stateful path API, add points then finish with PathFillConvex() or PathStroke()
inline void PathClear() { _Path.resize(0); } inline void PathClear() { _Path.Size = 0; }
inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); }
inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); }
inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); } // Note: Anti-aliased filling requires points to be in clockwise order. inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order.
inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); PathClear(); } inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; }
IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10);
IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle
IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0);

View File

@ -656,7 +656,13 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
_IdxWritePtr += 6; _IdxWritePtr += 6;
} }
// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds.
// Those macros expects l-values.
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } }
#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } }
// TODO: Thickness anti-aliased lines cap are missing their AA fringe. // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
{ {
if (points_count < 2) if (points_count < 2)
@ -686,10 +692,11 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
for (int i1 = 0; i1 < count; i1++) for (int i1 = 0; i1 < count; i1++)
{ {
const int i2 = (i1+1) == points_count ? 0 : i1+1; const int i2 = (i1+1) == points_count ? 0 : i1+1;
ImVec2 diff = points[i2] - points[i1]; float dx = points[i2].x - points[i1].x;
diff *= ImInvLength(diff, 1.0f); float dy = points[i2].y - points[i1].y;
temp_normals[i1].x = diff.y; IM_NORMALIZE2F_OVER_ZERO(dx, dy);
temp_normals[i1].y = -diff.x; temp_normals[i1].x = dy;
temp_normals[i1].y = -dx;
} }
if (!closed) if (!closed)
temp_normals[points_count-1] = temp_normals[points_count-2]; temp_normals[points_count-1] = temp_normals[points_count-2];
@ -712,17 +719,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3; unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
// Average normals // Average normals
ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
float dmr2 = dm.x*dm.x + dm.y*dm.y; float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
if (dmr2 > 0.000001f) IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f)
{ dm_x *= AA_SIZE;
float scale = 1.0f / dmr2; dm_y *= AA_SIZE;
if (scale > 100.0f) scale = 100.0f;
dm *= scale; // Add temporary vertexes
} ImVec2* out_vtx = &temp_points[i2*2];
dm *= AA_SIZE; out_vtx[0].x = points[i2].x + dm_x;
temp_points[i2*2+0] = points[i2] + dm; out_vtx[0].y = points[i2].y + dm_y;
temp_points[i2*2+1] = points[i2] - dm; out_vtx[1].x = points[i2].x - dm_x;
out_vtx[1].y = points[i2].y - dm_y;
// Add indexes // Add indexes
_IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
@ -766,20 +774,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4; unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
// Average normals // Average normals
ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
float dmr2 = dm.x*dm.x + dm.y*dm.y; float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
if (dmr2 > 0.000001f) IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
{ float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
float scale = 1.0f / dmr2; float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
if (scale > 100.0f) scale = 100.0f; float dm_in_x = dm_x * half_inner_thickness;
dm *= scale; float dm_in_y = dm_y * half_inner_thickness;
}
ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE); // Add temporary vertexes
ImVec2 dm_in = dm * half_inner_thickness; ImVec2* out_vtx = &temp_points[i2*4];
temp_points[i2*4+0] = points[i2] + dm_out; out_vtx[0].x = points[i2].x + dm_out_x;
temp_points[i2*4+1] = points[i2] + dm_in; out_vtx[0].y = points[i2].y + dm_out_y;
temp_points[i2*4+2] = points[i2] - dm_in; out_vtx[1].x = points[i2].x + dm_in_x;
temp_points[i2*4+3] = points[i2] - dm_out; out_vtx[1].y = points[i2].y + dm_in_y;
out_vtx[2].x = points[i2].x - dm_in_x;
out_vtx[2].y = points[i2].y - dm_in_y;
out_vtx[3].x = points[i2].x - dm_out_x;
out_vtx[3].y = points[i2].y - dm_out_y;
// Add indexes // Add indexes
_IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
@ -817,11 +829,13 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
const int i2 = (i1+1) == points_count ? 0 : i1+1; const int i2 = (i1+1) == points_count ? 0 : i1+1;
const ImVec2& p1 = points[i1]; const ImVec2& p1 = points[i1];
const ImVec2& p2 = points[i2]; const ImVec2& p2 = points[i2];
ImVec2 diff = p2 - p1;
diff *= ImInvLength(diff, 1.0f);
const float dx = diff.x * (thickness * 0.5f); float dx = p2.x - p1.x;
const float dy = diff.y * (thickness * 0.5f); float dy = p2.y - p1.y;
IM_NORMALIZE2F_OVER_ZERO(dx, dy);
dx *= (thickness * 0.5f);
dy *= (thickness * 0.5f);
_VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
_VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
_VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
@ -836,6 +850,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
} }
} }
// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
{ {
if (points_count < 3) if (points_count < 3)
@ -867,10 +882,11 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
{ {
const ImVec2& p0 = points[i0]; const ImVec2& p0 = points[i0];
const ImVec2& p1 = points[i1]; const ImVec2& p1 = points[i1];
ImVec2 diff = p1 - p0; float dx = p1.x - p0.x;
diff *= ImInvLength(diff, 1.0f); float dy = p1.y - p0.y;
temp_normals[i0].x = diff.y; IM_NORMALIZE2F_OVER_ZERO(dx, dy);
temp_normals[i0].y = -diff.x; temp_normals[i0].x = dy;
temp_normals[i0].y = -dx;
} }
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
@ -878,19 +894,15 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
// Average normals // Average normals
const ImVec2& n0 = temp_normals[i0]; const ImVec2& n0 = temp_normals[i0];
const ImVec2& n1 = temp_normals[i1]; const ImVec2& n1 = temp_normals[i1];
ImVec2 dm = (n0 + n1) * 0.5f; float dm_x = (n0.x + n1.x) * 0.5f;
float dmr2 = dm.x*dm.x + dm.y*dm.y; float dm_y = (n0.y + n1.y) * 0.5f;
if (dmr2 > 0.000001f) IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
{ dm_x *= AA_SIZE * 0.5f;
float scale = 1.0f / dmr2; dm_y *= AA_SIZE * 0.5f;
if (scale > 100.0f) scale = 100.0f;
dm *= scale;
}
dm *= AA_SIZE * 0.5f;
// Add vertices // Add vertices
_VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
_VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
_VtxWritePtr += 2; _VtxWritePtr += 2;
// Add indexes for fringes // Add indexes for fringes
@ -2422,7 +2434,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
{ {
if (c >= IndexLookup.Size) if (c >= IndexLookup.Size)
return FallbackGlyph; return FallbackGlyph;
const ImWchar i = IndexLookup[c]; const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1) if (i == (ImWchar)-1)
return FallbackGlyph; return FallbackGlyph;
return &Glyphs.Data[i]; return &Glyphs.Data[i];
@ -2432,7 +2444,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
{ {
if (c >= IndexLookup.Size) if (c >= IndexLookup.Size)
return NULL; return NULL;
const ImWchar i = IndexLookup[c]; const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1) if (i == (ImWchar)-1)
return NULL; return NULL;
return &Glyphs.Data[i]; return &Glyphs.Data[i];
@ -2492,7 +2504,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
} }
} }
const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX); const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
if (ImCharIsBlankW(c)) if (ImCharIsBlankW(c))
{ {
if (inside_word) if (inside_word)
@ -2609,7 +2621,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
continue; continue;
} }
const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale; const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
if (line_width + char_width >= max_width) if (line_width + char_width >= max_width)
{ {
s = prev_s; s = prev_s;