# startRender(int fps) 作用流程 FAQ ## startRender(int fps) 做了什么 `startRender(int refreshTimesPreSecond)` 只做两件事: ```text 保存 mRefreshTimesPreSecond 调用 startRender() ``` 对应代码流程: ```text Plot::startRender(int fps) ↓ d->mRefreshTimesPreSecond = fps ↓ Plot::startRender() ``` ## startRender() 做了什么 `startRender()` 的作用是启动 Plot 的渲染调度。 流程: ```text 检查 Plot 是否正在析构 ↓ mRenderEnabled = true ↓ 投递任务到 asio scheduler ↓ 取消旧 mRenderTimer ↓ scheduleRenderTimer() ↓ submitRender() ``` 它会立即触发一次 `submitRender()`,不是等下一个 timer 周期。 ## fps 参数现在是不是严格帧率上限 不是。 当前 `fps` 只决定 asio timer 的周期: ```text interval = round(1000.0 / fps) ``` timer 到期后: ```text submitRender() scheduleRenderTimer() ``` 所以它的真实语义是周期性 heartbeat / 兜底触发,不是硬性 FPS cap。 ## 为什么不是严格限帧 因为当前渲染是事件驱动为主。 除了 timer 会触发 `submitRender()`,下面这些路径也会立即触发: ```text RenderAble::markStateDirty() ↓ Plot::markRenderStateDirty() ↓ requestRender() ↓ submitRender() ``` ```text RenderData::markInputDirty() ↓ RenderAble::markRenderDirty() ↓ requestRender() ↓ submitRender() ``` ```text finishRender() ↓ pipeline.hasNewState() ↓ submitRender() ``` 只要 State/Input 有新版本,系统可以绕过 timer 周期继续推进下一帧。 ## asio 里面还有没有定时器 有。 相关成员和函数: ```text PlotPrivate::mRenderTimer PlotPrivate::mRefreshTimesPreSecond Plot::scheduleRenderTimer() RenderScheduler::initializePlotOnScheduler() ``` `RenderScheduler::initializePlotOnScheduler()` 为每个 Plot 创建 `asio::steady_timer`。 `scheduleRenderTimer()` 使用 `mRefreshTimesPreSecond` 计算间隔并注册 `async_wait`。 ## timer 在当前架构里还有没有必要 当前仍然有必要保留。 原因: ```text 保持 startRender(int) 旧调用语义 保证没有显式 dirty 事件时仍有周期性检查 作为异常丢事件后的兜底触发 给性能测试框提供一个稳定的周期参考 ``` 但它不是渲染正确性的唯一入口。 当前正确性主要依赖: ```text State dirty Input dirty finishRender 后续版本检查 ``` ## 如果以后要严格限帧应该怎么做 应该新增独立调度策略,而不是继续复用 `startRender(int)` 的现有语义。 建议拆成: ```text Immediate: dirty 后立即 requestRender() FixedRate: dirty 后只标记 pending,由 timer 周期统一 submitRender() Throttle: dirty 后允许立即渲染,但两帧之间必须满足最小间隔 ``` 这样 `startRender(int)` 才能变成明确的帧率策略参数。