From fac7c8606547ce15b3a2703ffacec88dcd585102 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Thu, 23 Jul 2026 12:46:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/整体架构思路.md | 167 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 158 insertions(+), 9 deletions(-) diff --git a/doc/整体架构思路.md b/doc/整体架构思路.md index 1730009..2554439 100644 --- a/doc/整体架构思路.md +++ b/doc/整体架构思路.md @@ -348,15 +348,78 @@ ready_color.version 新于 front_color.version: paintEvent 流程: ```text -try swap front_color, ready_color +按 Plot_Buffer_Acquire_Mode 消费 ready_color mark front_color drawImage(front_color) unmark front_color ``` -paintEvent 只能使用 Try,不允许等待后台。 +Plot_Buffer_Acquire_Mode 有两种策略: -## 8. 调度版本 +```text +Try: + paintEvent 尝试交换 ready_color -> front_color。 + 如果物理 buffer 正忙,立即放弃本次新帧消费。 + 这是默认模式,GUI 线程不进入 atomic_wait。 + +Wait: + paintEvent 等待参与交换或 front_color lease 可用。 + 只适合调用方明确接受 GUI 线程短暂等待的场景。 +``` + +Color 发布侧仍然可以等待 Color_Render / Color_Ready,因为它运行在调度和后台渲染流程,不阻塞 Qt paintEvent。 + +## 8. 三缓冲获取策略 + +三缓冲获取策略不是单一全局开关,而是分层控制。 + +Plot 层: + +```text +Plot_Buffer_Acquire_Mode +``` + +只控制 Qt paintEvent 消费 Color_Ready / Color_Front 的行为。 + +默认: + +```text +Try +``` + +RenderAble 层: + +```text +Triple_Buffer_Mode +``` + +控制单个 RenderAble 在后台 draw 阶段获取 State_Render lease 的行为。 + +默认: + +```text +Wait +``` + +RenderAble 设置为 Try 后: + +```text +draw 阶段取不到 State_Render lease + ↓ +跳过该 RenderAble 本帧绘制 +``` + +State/Input 的编辑发布路径默认仍使用 Wait。 + +原因: + +```text +setter / giveData 当前多数是 void 语义。 +Try 失败后没有统一返回值表达本次修改是否被接受。 +在没有重新设计 API 返回语义前,不允许静默丢弃编辑和输入。 +``` + +## 9. 调度版本 渲染调度使用 RenderPipeline 的帧版本。 @@ -380,7 +443,45 @@ Input dirty 不递增 edit_state.version。 它保证流式输入不会导致 RenderState 全量复制。 -## 9. prepareData 边界 +## 10. asio timer 和帧率 + +Plot 仍保留 asio steady_timer: + +```text +PlotPrivate::mRenderTimer +PlotPrivate::mRefreshTimesPreSecond +Plot::startRender(int refreshTimesPreSecond) +Plot::scheduleRenderTimer() +``` + +当前 timer 的语义: + +```text +按 mRefreshTimesPreSecond 周期触发 submitRender() +作为渲染 heartbeat / 兜底轮询 +保持旧 startRender(int) 调用语义 +``` + +当前 timer 不是严格 FPS 上限。 + +原因: + +```text +State dirty 会立即 requestRender() +Input dirty 会立即 requestRender() +finishRender 发现还有新版本也会继续 submitRender() +``` + +因此实际渲染触发是: + +```text +事件驱动为主 +timer 周期触发为辅 +``` + +如果后续需要严格限帧,应该增加独立的 render trigger 策略,而不是把 startRender(int) 继续解释成硬性 FPS cap。 + +## 11. prepareData 边界 prepareData 的标准流程: @@ -413,7 +514,7 @@ prepareData 不应该触发 QWidget 绘制。 prepareData 不应该把 RenderCache 复制回 State。 -## 10. draw 边界 +## 12. draw 边界 draw 的标准流程: @@ -431,7 +532,7 @@ draw 不修改 ready_state。 draw 不做输入队列交换。 -## 11. 数据分类规则 +## 13. 数据分类规则 判断一个字段应该放哪里: @@ -459,7 +560,7 @@ draw 不做输入队列交换。 把配置项放 InputData。 ``` -## 12. 锁使用边界 +## 14. 锁使用边界 radio 渲染链路不允许使用 RenderData 对象级大锁。 @@ -475,12 +576,15 @@ RenderPipeline: 只保护帧发布和 Qt update 请求合并。 Plot / TimerThread: - mRenderEnabled / mDestroying / mActiveRenderTasks / pending render size 使用 atomic。 + mRenderEnabled / mDestroying / mActiveRenderTasks / pending render size / paint buffer acquire mode 使用 atomic。 mRenderTaskMutex + mRenderTaskDone 只用于 Plot 析构等待已投递任务结束。 TimerThread::postAndWait 的局部 mutex + condition_variable 只用于跨线程同步 shutdown/removePlot。 PerformanceShower: mMutex 只保护统计 map 和显示列表。 + 计数使用 CPP_Core/Core/Statistics::Speed_Statistics。 + 耗时使用 CPP_Core/Core/Statistics::Value_Statistics。 + Value_Statistics 提供 instant / smooth / variation。 ``` 不允许重新引入: @@ -524,7 +628,52 @@ spdlog / asio / googlepinyin: 这些同步不能向 RenderData、prepareData、draw 路径扩散。 -## 13. 最终规则 +## 15. 性能统计 + +性能测试框不再维护自己的耗时平滑算法。 + +计数类数据: + +```text +PerformanceShower::counterIncrease() + ↓ +Psc::Speed_Statistics::update(1) +``` + +耗时类数据: + +```text +Cacl 析构 + ↓ +Psc::Value_Statistics::update(useTime) +``` + +Value_Statistics 的含义: + +```text +instant: + 本次采样值。 + +average: + 保留旧字段语义的 EWMA 平均值。 + +smooth: + 类似 SRTT 的平滑值。 + +variation: + 类似 RTTVAR 的波动估计。 + 它不是严格方差或标准差,而是 instant 与 smooth 偏差的 EWMA。 +``` + +性能框显示耗时时使用: + +```text +instant +SRTT +RTTVAR +``` + +## 16. 最终规则 ```text State 负责配置快照。