完善异步架构:后台线程池 + 预览曲线上层绘制 + 快速帧只用于改主体的拖拽
1) 后台派生曲线计算改为多线程池(线程数 = clamp(硬件并发-1,1,4)),多条预览曲线并行计算、更快出现(原单线程顺序处理 5 条整段弱波增强约 1.8s,用户长时间看不到曲线)。 2) PaintLane 分两遍:先画全部原信号,再画全部派生预览曲线,保证预览曲线在本网格全部原信号之上、不被覆盖(用户要求)。 3) 「快速帧(关抗锯齿)」只用于会改变画面主体的拖拽(PAN/SCROLL/LANE_REORDER/MOVE_SIGNAL/BOOST_*);拖时间光标、选区框选、拖面板这类只改叠加层的交互改为复用静态场景缓存(贴图约 1ms),实测拖光标从整幅重画降到约 1-4ms。 小跨度渲染与旧实现逐像素 0 差异。
This commit is contained in:
1 parent
99247622c1
commit
226943921b
3 files changed
+58
-17
No files matched your search
@@ -1746,7 +1746,7 @@ namespace jdi
|
||||
// 缩放等交互的反馈始终跟手,不会被计算拖住,同时把重计算放到后台充分利用多核。
|
||||
mutable std::mutex m_curveMutex; /**< 保护任务队列与已算好条目。 */
|
||||
mutable std::condition_variable m_curveCv; /**< 唤醒后台线程。 */
|
||||
mutable std::thread m_curveWorker; /**< 后台计算线程(惰性启动)。 */
|
||||
mutable std::vector<std::thread> m_curveWorkers; /**< 后台计算线程池(惰性启动,多核并行)。 */
|
||||
mutable bool m_curveWorkerStop = false; /**< 请求后台线程退出。 */
|
||||
mutable std::uint64_t m_curveGeneration = 0; /**< 数据代次(结构变化时自增)。 */
|
||||
mutable std::uint64_t m_curveSerial = 0; /**< 已发布条目序号。 */
|
||||
|
||||
@@ -2353,17 +2353,27 @@ namespace jdi
|
||||
|
||||
void PlotView::EnsureCurveWorker() const
|
||||
{
|
||||
if (m_curveWorker.joinable())
|
||||
if (!m_curveWorkers.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// **多核并行**:后台线程池并发计算多条派生曲线(5 个网格各一条时,
|
||||
// 串行要 5×368ms,并行只要约 1×368ms),预览曲线因此能很快出现。
|
||||
// 线程数 = 硬件并发 - 1(给 UI/绘制线程留一个核),夹在 1~4。
|
||||
unsigned int hardware = std::thread::hardware_concurrency();
|
||||
int workers = static_cast<int>(hardware == 0 ? 2u : hardware) - 1;
|
||||
workers = std::max(1, std::min(workers, 4));
|
||||
m_curveWorkerStop = false;
|
||||
m_curveWorker = std::thread([this]() { CurveWorkerLoop(); });
|
||||
m_curveWorkers.reserve(static_cast<std::size_t>(workers));
|
||||
for (int index = 0; index < workers; ++index)
|
||||
{
|
||||
m_curveWorkers.emplace_back([this]() { CurveWorkerLoop(); });
|
||||
}
|
||||
}
|
||||
|
||||
void PlotView::StopCurveWorker() const
|
||||
{
|
||||
if (!m_curveWorker.joinable())
|
||||
if (m_curveWorkers.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2373,7 +2383,14 @@ namespace jdi
|
||||
m_curveJobs.clear();
|
||||
}
|
||||
m_curveCv.notify_all();
|
||||
m_curveWorker.join();
|
||||
for (std::thread& worker : m_curveWorkers)
|
||||
{
|
||||
if (worker.joinable())
|
||||
{
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
m_curveWorkers.clear();
|
||||
}
|
||||
|
||||
void PlotView::CurveWorkerLoop() const
|
||||
@@ -5461,11 +5478,18 @@ namespace jdi
|
||||
return;
|
||||
}
|
||||
|
||||
// 交互期间(拖拽 / 拖动滑块)改用「快速绘制」:关闭波形与派生曲线的抗锯齿。
|
||||
// 用户明确要求"先用低分辨率,绘制完成后再用高分辨率替换"——
|
||||
// 抗锯齿是单帧最贵的一项(同一条包络带实测 27.6ms → 3.2ms),几何完全不变;
|
||||
// 松手时宿主会整帧失效,因此全质量版本随即补上。
|
||||
m_fastFrame = (m_dragMode != PlotDragMode::NONE);
|
||||
// 「快速绘制(关闭抗锯齿)」只在**会改变画面主体(波形/网格几何)**的拖拽期间启用:
|
||||
// 这些拖拽每帧都要重画波形,关掉抗锯齿能显著加速(同一条包络带 27.6ms → 3.2ms)。
|
||||
// ⚠️ 像「拖时间光标」「选区框选」「拖浮动面板」这类**只改叠加层、画面主体不变**的交互,
|
||||
// 一旦启用快速帧就会给静态场景缓存打上「已降级」标记 → 缓存失效 → 每帧整幅重画
|
||||
//(实测拖光标从约 1ms 骤升到十几毫秒)。因此这里**不**把它们算作快速帧,
|
||||
// 让它们直接复用静态场景缓存(贴图 ~1ms)+ 叠加层,做到真正跟手。
|
||||
const bool sceneChangingDrag =
|
||||
(m_dragMode == PlotDragMode::PAN) || (m_dragMode == PlotDragMode::SCROLL_LANES) ||
|
||||
(m_dragMode == PlotDragMode::LANE_REORDER) || (m_dragMode == PlotDragMode::MOVE_SIGNAL) ||
|
||||
(m_dragMode == PlotDragMode::BOOST_LEVEL) ||
|
||||
(m_dragMode == PlotDragMode::BOOST_ITERATIONS);
|
||||
m_fastFrame = sceneChangingDrag;
|
||||
|
||||
// 贴图之后、静态场景之外的全部内容(随鼠标变化或位于最上层)。
|
||||
// 三个分支(完全命中 / 局部重画 / 整幅重绘)共用同一段,保证观感完全一致。
|
||||
@@ -6857,10 +6881,20 @@ namespace jdi
|
||||
g.FillPath(&brush, &scatterPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 中心轴均值滤波曲线(「实验性功能 → 边沿计数(中心轴)」)叠加绘制在原信号之上。
|
||||
// 它只是叠加显示的派生曲线,**不会**加入左侧信号列表;
|
||||
// **只有该信号被勾选时**才绘制(参数与「均值滤波」同源,曲线逐位一致)。
|
||||
// 第二遍:把所有**派生预览曲线**统一绘制在**本网格全部原信号之上**。
|
||||
// 若在同一个信号循环里就地叠加,后绘制的原信号会把先前信号的预览曲线盖住
|
||||
//(用户明确要求"预览信号处于原信号上层不要被覆盖")。
|
||||
for (const SignalRef& ref : laneSignals)
|
||||
{
|
||||
const ResolvedSignal resolved = ResolveSignal(ref);
|
||||
if (resolved.data == nullptr || resolved.style == nullptr || !resolved.visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 中心轴均值滤波曲线(「实验性功能 → 边沿计数(中心轴)」):与「均值滤波」同源,
|
||||
// 只有被勾选的信号才绘制。
|
||||
if (centerOn)
|
||||
{
|
||||
const Lane::EdgeCenterItem* centerItem =
|
||||
@@ -6870,8 +6904,7 @@ namespace jdi
|
||||
PaintMeanFilterCurve(g, resolved, lane, centerItem->points, centerItem->iterations);
|
||||
}
|
||||
}
|
||||
// 均值滤波曲线(「实验性功能 → 均值滤波」):同样是仅用于预览的叠加曲线,
|
||||
// 但**只有该信号被勾选时**才绘制(参数取自它自己的条目)。
|
||||
// 均值滤波预览曲线:只有被勾选的信号才绘制(参数取自它自己的条目)。
|
||||
if (meanFilterOn)
|
||||
{
|
||||
const Lane::MeanFilterItem* item =
|
||||
@@ -6881,8 +6914,7 @@ namespace jdi
|
||||
PaintMeanFilterCurve(g, resolved, lane, item->points, item->iterations);
|
||||
}
|
||||
}
|
||||
// 弱波增强曲线:同样是仅用于预览的叠加曲线,只在被勾选时绘制
|
||||
//(增强等级取自整个网格)。
|
||||
// 弱波增强预览曲线:只有被勾选的信号才绘制(增强等级取自整个网格)。
|
||||
if (weakBoostOn)
|
||||
{
|
||||
const Lane::WeakBoostItem* item =
|
||||
|
||||
Reference in new issue
Block a user