Pipeline调度基础:帧同步与帧间隔、VBlank与HBlank、逐行与逐帧、调度器职责

各位同学,今天我们进入Pipeline调度的核心地带。说实话,这部分内容我当年刚接触时也绕了不少弯路。你想想看,一个ISP Pipeline里同时跑着几十个模块,每个模块处理速度还不一样,怎么让它们步调一致?这就是调度要解决的问题。

我个人习惯把调度比作交响乐指挥。每个乐器(模块)都有自己的节奏,指挥(调度器)得让它们在同一首曲子里合拍。ISP里这个“拍子”就是帧同步信号。

帧同步与帧间隔

帧同步,说白了就是告诉所有模块:“新的一帧来了,准备干活!”

在传感器端,帧同步通常由VSYNC(垂直同步)信号触发。VSYNC拉高时,表示新一帧图像数据开始传输。我见过不少新手工程师,以为帧同步就是简单的“开始”信号,其实它背后还带着帧间隔的概念。

帧间隔(Frame Interval):相邻两帧VSYNC脉冲之间的时间差。典型值:

  • 30fps → 帧间隔 ≈ 33.3ms
  • 60fps → 帧间隔 ≈ 16.67ms
  • 120fps → 帧间隔 ≈ 8.33ms

帧间隔决定了Pipeline的“时间预算”。你所有模块的处理时间加起来,必须小于这个预算。否则就会丢帧——我在一个1080p@60fps的项目里就踩过这个坑,当时RAW域处理模块慢了2ms,结果每3秒就跳一帧,画面肉眼可见地卡顿。

VBlank与HBlank:被忽视的“喘息时间”

这两个概念,很多做上层应用的人不太在意,但做底层Pipeline调度的人必须吃透。

VBlank(垂直消隐期):一帧结束到下一帧开始之间的时间窗口。传感器在这段时间里不输出有效像素数据,只输出消隐信号。

HBlank(水平消隐期):一行结束到下一行开始之间的时间窗口。同样,这段时间不输出有效像素。

为什么要关注这两个“空白期”?因为它们是调度器的黄金时间!

消隐期类型 典型时长 调度用途
VBlank 几百μs ~ 几ms 帧级配置切换、统计更新、DMA搬运
HBlank 几μs ~ 几十μs 行级参数更新、小批量数据搬运

我的经验:我曾经在一个4K@60fps的项目里,利用VBlank窗口做3A统计数据的DMA搬运。如果不卡这个窗口,数据搬运会抢占行处理时间,导致HBlank不够用,最终出现行撕裂。记住:VBlank是“大块时间”,HBlank是“碎片时间”,调度策略完全不同。

逐行处理 vs 逐帧处理

这是Pipeline调度里最容易混淆的概念。我直接画个图帮你理清。

逐行处理 vs 逐帧处理 对比 逐行处理(Line-by-Line) 行0 读入 行0 处理 行0 输出 行1 读入 行1 处理 行1 输出 流水线深度 = 3 行 逐帧处理(Frame-by-Frame) 帧N 全部读入 帧N 全部处理 帧N+1 全部读入 帧N+1 全部处理 流水线深度 = 2 帧 关键区别 • 逐行处理:延迟低(几行时间),但行间依赖强,适合LSC、CFA插值等模块 • 逐帧处理:延迟高(至少一帧),但帧内数据完整,适合3A统计、全局色调映射 • 实际ISP:混合使用!前端模块逐行,后端模块逐帧,调度器负责桥接 • 我曾经在HDR融合模块里用逐帧处理,结果延迟多了2帧,被算法团队追着改了一周...

逐行处理的好处是延迟低。你想想看,传感器扫完第一行,你就能开始处理了,不用等整帧读完。但坏处是行与行之间有依赖关系——比如去噪模块需要参考相邻行,这时候逐行处理就有点麻烦。

逐帧处理正好相反。延迟高,但数据完整。3A统计(自动曝光、自动白平衡、自动对焦)必须基于整帧数据,所以只能用逐帧方式。

避坑指南:我曾经在一个项目里,把去马赛克(Demosaic)模块设计成逐帧处理,结果延迟从2行飙升到1080行(一帧)。后来改成逐行+行缓存的方式,延迟降到3行。记住:能用逐行就别用逐帧,除非你确实需要整帧信息。

调度器的基本职责

调度器不是简单的“谁先来谁先走”。它的职责可以归纳为四点:

  1. 时序对齐:确保所有模块在正确的帧/行边界开始工作。比如,BLC模块必须在RAW域第一行数据到达前完成配置。
  2. 资源仲裁:多个模块争用DMA带宽、行缓存、Line Buffer时,调度器决定谁先用。我见过一个案例,两个模块同时写同一块DDR区域,数据全乱了。
  3. 延迟预算管理:每个模块分配多少处理时间,调度器要心里有数。超时的模块要么降质,要么跳过。
  4. 异常处理:某个模块卡住了怎么办?调度器要能超时复位,或者走旁路。
职责 典型实现 常见问题
时序对齐 VSYNC/HSYNC计数器 计数器溢出导致错位
资源仲裁 轮询/优先级仲裁器 低优先级模块饿死
延迟预算管理 看门狗定时器 预算设置过紧导致频繁超时
异常处理 超时复位 + 旁路模式 复位后状态未完全恢复

我的建议:设计调度器时,先画一张“时间轴图”。把VSYNC、HSYNC、每个模块的启动/结束时间都标出来。这张图画清楚了,调度逻辑基本就定了。我每个项目都这么干,从没出过大问题。

嗯,这一节的内容就到这里。帧同步和帧间隔是Pipeline的“心跳”,VBlank和HBlank是“喘息窗口”,逐行和逐帧是两种基本处理模式,调度器就是那个让一切有序运转的“大脑”。把这些基础打牢,后面讲具体调度策略时你会轻松很多。