修复深放大下样式/参数滑块卡顿(探针定位:样式补丁用抗锯齿 + 后台发布整幅作废)

复现:VERY_BIG_DATA 全信号在视界 [40.1756,40.1885]s(Δt≈12.9ms)下拖透明度/粗细/自定义颜色/拾色/弱波增强滑块极卡,但拖光标流畅(光标命中场景缓存)。用 JDI_PERF_PROBE 门控的临时探针精确拆解:整幅/补丁耗时几乎全在包络带 FillPath(抗锯齿 ≈29ms/网格,关掉 ≈5.4ms)。

两个根因:① 样式补丁(拖透明度/粗细/颜色)不在拖拽态 → m_fastFrame=false → 用抗锯齿重画该网格包络带 ≈72ms;② 拖弱波增强/均值滤波滑块时后台每算完一条就 InvalidateSceneCache → 每帧退化成整幅重绘(150ms+)。

修复:① 样式补丁强制快速帧并置 m_sceneDegraded(补丁 72→14ms,静止后自动补全质量);② 拖拽中后台发布只标记降级、不整幅作废(弱波增强滑块 96–176→26ms);③ 交互期间省略浮动面板投影。

同一负载机器实测:透明度/粗细/颜色 77→16ms,弱波增强滑块 96–176→26ms,平移拖动 34ms(快速帧,空闲机约 8ms)。全质量/结算帧与修复前逐像素 0 差异(LockBits 验证)。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-11 19:07:37 +08:00
1 parent c794967b02
commit aefaaef6fa
2 files changed
+53 -7

No files matched your search

+30 -7
View File
@@ -5487,10 +5487,22 @@ namespace jdi
std::lock_guard<std::mutex> lock(m_curveMutex);
PruneCurveEntriesLocked();
}
// 后台算好了新曲线:静态场景缓存里仍是旧曲线(或还没有曲线),作废一次以纳入最新结果。
// 后台算好了新曲线:
// * **静止**时:整幅作废一次,让新曲线(与新的静态场景缓存)立刻出现。
// * **拖拽中**(拖弱波增强/均值滤波参数滑块):**不作废整幅** —— 拖拽时参数每帧都在变,
// 本来就每帧走"样式补丁"路径,补丁会直接取到最新曲线;若此时还整幅作废,
// 每帧会退化成整幅重绘(实测单帧 150ms+,与"拖动要跟手"直接冲突)。
// 改为标记"已降级",等拖拽结束后再补一帧全质量。
if (m_curveSceneDirty.exchange(false, std::memory_order_relaxed))
{
InvalidateSceneCache();
if (m_dragMode == PlotDragMode::NONE)
{
InvalidateSceneCache();
}
else
{
m_sceneDegraded = true;
}
}
if (m_lanes.empty())
@@ -5567,7 +5579,6 @@ namespace jdi
paintOverlays();
return;
}
// 只有"外观样式"变化(典型场景:拖动自定义颜色滑块实时调色):网格结构、视图几何、
// 波形采样都没变,只是颜色/不透明度/线宽/模式不同 —— 此时只重画受影响的网格,
// 再写回缓存。(VERY_BIG_DATA 实测:整幅重绘 30ms+,单网格重画约 4ms。)
@@ -5575,7 +5586,14 @@ namespace jdi
std::vector<int> patchLanes;
if (FindStyleOnlyLanes(patchLanes) && BlitSceneCache(g))
{
// ⚠️ 样式/参数**正在连续变化**(拖透明度/粗细/拾色/实验性功能滑块):这本身就是
// 一种"交互中"。若不切换快速帧,本帧会用**抗锯齿**重画波形包络带 —— 实测
// 单条网格的包络带 AA 填充 ≈29ms(本机负载下 72ms),而关掉 AA 只要 ≈5.6ms。
// 因此补丁阶段强制快速帧,并在补丁后把场景缓存标记为"已降级",
// 下一帧(参数稳定后)自动补一帧全质量 —— 既保证拖动手感,又不牺牲最终画质。
m_fastFrame = true;
RepaintSceneCachePatch(g, patchLanes);
m_sceneDegraded = true;
paintOverlays();
return;
}
@@ -6942,7 +6960,7 @@ namespace jdi
const DrawMode mode = resolved.style->mode;
// 顶点由“几何键”缓存提供:同一视图下重复绘制不再重算全量采样。
const PolylineCacheEntry* cached = AcquirePolyline(ref, resolved, lane);
const PolylineCacheEntry* cached = AcquirePolyline(ref, resolved, lane);
if (cached == nullptr)
{
continue;
@@ -9162,9 +9180,14 @@ namespace jdi
const float pad = kEdgePanelPad * m_scale;
// 面板主体 + 标题栏。
UiFillRoundRect(g, gd::RectF(panel.X + 1.0f * m_scale, panel.Y + 2.0f * m_scale,
panel.Width, panel.Height),
5.0f * m_scale, 0x14000000u);
// 投影响用两张大面积的半透明圆角矩形模拟,代价不低;交互期间(快速帧)省略它,
// 让拖动参数滑块时面板重绘不再被投影拖累(松手后的全质量帧会补回投影)。
if (!m_fastFrame)
{
UiFillRoundRect(g, gd::RectF(panel.X + 1.0f * m_scale, panel.Y + 2.0f * m_scale,
panel.Width, panel.Height),
5.0f * m_scale, 0x14000000u);
}
UiFillRoundRect(g, panel, 5.0f * m_scale, WithAlpha(m_theme->cardBg, 0xF4));
UiDrawRoundRect(g, panel, 5.0f * m_scale, m_theme->borderStrong, 1.0f);
UiFillRoundRect(g, gd::RectF(panel.X, panel.Y, panel.Width, titleHeight), 5.0f * m_scale,