深度修复实验性功能预览曲线导致的交互卡顿(平移/拖滑块/缩放/改样式不跟手)
根因:派生预览曲线按可见采样窗口计算,代价正比于窗口采样数(弱波增强整段 2576 万采样单条约 368ms);旧策略对超过 4M 采样的窗口不缓存,导致大跨度下每帧(含悬停重绘)重算整段曲线;拖滑块每帧改参数即每帧重算。实测弱波增强整段拖滑块单帧约 2303ms,2.5s 跨度约 89ms。 修复:1) 大窗口也进缓存并按总字节预算淘汰(静止重绘 2247ms-0.25ms);2) 交互期间对超出预算的大窗口延迟重算、复用旧曲线(拖滑块 2303ms-18ms),小窗口仍实时重算;3) 计算缓冲改 thread_local 复用容量。仅改何时计算与是否缓存,几何与取值算法不变,逐像素比对 0 差异。 缩放等级差异:整段放大时窗口为整条信号(千万级)每帧重算故最卡;极小跨度窗口仅几千采样故不卡;中间跨度几十毫秒亦卡。
This commit is contained in:
1 parent
2f7a6bc2d2
commit
aca84df0ac
4 files changed
+138
-19
No files matched your search
@@ -1032,7 +1032,10 @@ namespace jdi
|
||||
}
|
||||
|
||||
// 后续各阶以上一阶的结果为输入(double 中转,避免 float→double 的精度损失累积)。
|
||||
std::vector<double> buffer(values.size(), std::numeric_limits<double>::quiet_NaN());
|
||||
// 中转缓冲复用容量(线程本地),避免每阶重新分配上千万元素的向量。
|
||||
thread_local std::vector<double> bufferBuffer;
|
||||
std::vector<double>& buffer = bufferBuffer;
|
||||
buffer.assign(values.size(), std::numeric_limits<double>::quiet_NaN());
|
||||
std::vector<float> stage;
|
||||
for (int iteration = 1; iteration < stages; ++iteration)
|
||||
{
|
||||
@@ -1070,7 +1073,7 @@ namespace jdi
|
||||
* @return 确实有采样点被改动返回 true;完全无弱波时返回 false。
|
||||
*/
|
||||
bool ApplyWeakBoostStage(const std::vector<float>& input, double strength,
|
||||
std::vector<float>& output)
|
||||
std::vector<float>& output, std::vector<BoostExtremum>& extremes)
|
||||
{
|
||||
const std::size_t count = input.size();
|
||||
output.assign(count, std::numeric_limits<float>::quiet_NaN());
|
||||
@@ -1092,7 +1095,7 @@ namespace jdi
|
||||
// 1) 识别波峰 / 波谷:扫描单调段,方向翻转处的上一个采样点即为极值点。
|
||||
// 波峰(先升后降)与波谷(先降后升)必然交替出现,
|
||||
// 因此同类极值就是极值序列里下标 ±2 的两个。
|
||||
std::vector<BoostExtremum> extremes;
|
||||
extremes.clear();
|
||||
{
|
||||
int direction = 0; // 当前单调段方向(+1 上升、-1 下降)。
|
||||
bool hasPrevious = false;
|
||||
@@ -1145,7 +1148,9 @@ namespace jdi
|
||||
|
||||
// 2) 逐个极值点判定“是否偏弱”,并算出它自己的目标偏移量。
|
||||
const std::size_t extremeCount = extremes.size();
|
||||
std::vector<double> shift(extremeCount, 0.0);
|
||||
thread_local std::vector<double> shiftBuffer;
|
||||
std::vector<double>& shift = shiftBuffer;
|
||||
shift.assign(extremeCount, 0.0);
|
||||
for (std::size_t k = 2; k + 2 < extremeCount; ++k)
|
||||
{
|
||||
const BoostExtremum& current = extremes[k];
|
||||
@@ -1241,7 +1246,13 @@ namespace jdi
|
||||
}
|
||||
|
||||
// 第 1 阶:从原始采样值出发(非有限值保持 NaN)。
|
||||
std::vector<float> current(count, std::numeric_limits<float>::quiet_NaN());
|
||||
// 工作缓冲用线程本地变量复用容量:单条曲线动辄上千万采样,若每次调用都重新分配
|
||||
// 并零初始化,单条「弱波增强」的耗时会被明显放大(内存分配 + page fault)。
|
||||
thread_local std::vector<float> currentBuffer;
|
||||
thread_local std::vector<float> nextBuffer;
|
||||
thread_local std::vector<BoostExtremum> extremesBuffer;
|
||||
std::vector<float>& current = currentBuffer;
|
||||
current.assign(count, std::numeric_limits<float>::quiet_NaN());
|
||||
for (std::size_t index = 0; index < count; ++index)
|
||||
{
|
||||
const double value = values[index];
|
||||
@@ -1256,10 +1267,10 @@ namespace jdi
|
||||
// 多次迭代时相邻的弱波会互相抬高彼此的基准,从而把较宽的弱波区逐步恢复。
|
||||
const int stages = std::max(1, std::min(iterations, 1000));
|
||||
const double strength = std::max(0.0, std::min(1.0, level));
|
||||
std::vector<float> next;
|
||||
std::vector<float>& next = nextBuffer;
|
||||
for (int stage = 0; stage < stages; ++stage)
|
||||
{
|
||||
if (!ApplyWeakBoostStage(current, strength, next))
|
||||
if (!ApplyWeakBoostStage(current, strength, next, extremesBuffer))
|
||||
{
|
||||
// 这一阶没有任何采样点需要调整:后续迭代次数也不会再有变化,提前结束。
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user