perf(ui): skip the scroll-edge mask when no edge fades

ApplyScrollEdgeMask, which fades a scroll area's content at its top
and bottom edges, walked every vertex the area emitted on every frame
and tested both edges per vertex, even when the content fit without
scrolling and no vertex could ever be written. It now returns before
the walk when neither edge fades.

The fade maths moved unchanged into scroll_edge_fade.h and is tested
against the old inline expression, so rendering is identical. All six
callers benefit without an edit: the Overview address list, Mining's
recent blocks, Console, History, Explorer and Peers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 09:50:03 -05:00
co-authored by Claude Opus 5.5
parent 88fa13dd1a
commit bb973a1007
3 changed files with 89 additions and 14 deletions
+7 -14
View File
@@ -7,6 +7,7 @@
#include "colors.h"
#include "type.h"
#include "tooltip_style.h"
#include "scroll_edge_fade.h"
#include "../layout.h"
#include "../schema/element_styles.h"
#include "../schema/color_var_resolver.h"
@@ -1149,23 +1150,15 @@ inline void ApplyScrollEdgeMask(ImDrawList* parentDL, int parentVtxStart,
float fadeZone,
float scrollY, float scrollMaxY)
{
// Neither edge fades (not scrolled down and nothing below / not scrollable): every alpha would stay 1.0
// and no vertex would be written, so skip the whole vertex walk.
const ScrollEdgeFade fade = ComputeScrollEdgeFade(scrollY, scrollMaxY);
if (!fade.any()) return;
auto mask = [&](ImDrawList* dl, int startIdx) {
for (int vi = startIdx; vi < dl->VtxBuffer.Size; vi++) {
ImDrawVert& v = dl->VtxBuffer[vi];
float alpha = 1.0f;
// Top fade — only when scrolled down
if (scrollY > 1.0f) {
float d = v.pos.y - topEdge;
if (d < fadeZone)
alpha = std::min(alpha, std::max(0.0f, d / fadeZone));
}
// Bottom fade — only when not at scroll bottom
if (scrollMaxY > 0 && scrollY < scrollMaxY - 1.0f) {
float d = bottomEdge - v.pos.y;
if (d < fadeZone)
alpha = std::min(alpha, std::max(0.0f, d / fadeZone));
}
const float alpha = ScrollEdgeAlpha(fade, v.pos.y, topEdge, bottomEdge, fadeZone);
if (alpha < 1.0f) {
int a = (v.col >> IM_COL32_A_SHIFT) & 0xFF;
+47
View File
@@ -0,0 +1,47 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
//
// Pure maths of ApplyScrollEdgeMask (draw_helpers.h), split out so it is unit-testable without ImGui.
#pragma once
#include <algorithm>
namespace dragonx {
namespace ui {
namespace material {
struct ScrollEdgeFade {
bool top = false; // content scrolled off the top edge
bool bottom = false; // more content below the bottom edge
bool any() const { return top || bottom; }
};
inline ScrollEdgeFade ComputeScrollEdgeFade(float scrollY, float scrollMaxY)
{
ScrollEdgeFade f;
f.top = scrollY > 1.0f; // only when scrolled down
f.bottom = scrollMaxY > 0 && scrollY < scrollMaxY - 1.0f; // only when not at the scroll bottom
return f;
}
// Alpha multiplier (0..1) for a vertex at screen-y `posY`. Same maths as the former inline loop.
inline float ScrollEdgeAlpha(const ScrollEdgeFade& f, float posY, float topEdge, float bottomEdge, float fadeZone)
{
float alpha = 1.0f;
if (f.top) {
float d = posY - topEdge;
if (d < fadeZone)
alpha = std::min(alpha, std::max(0.0f, d / fadeZone));
}
if (f.bottom) {
float d = bottomEdge - posY;
if (d < fadeZone)
alpha = std::min(alpha, std::max(0.0f, d / fadeZone));
}
return alpha;
}
} // namespace material
} // namespace ui
} // namespace dragonx