4. Framebuffer 基础:内存布局、像素格式与颜色深度

Framebuffer(帧缓冲)是图形渲染管线的最终输出目标,也是 CPU/GPU 与显示控制器之间的数据桥梁。理解其内存布局、像素格式与颜色深度,是进行 Vblank 中断与缓存管理联合调优的前提。本章将系统梳理 Framebuffer 的核心概念,并建立后续章节所需的知识基础。

核心要点:Framebuffer 本质上是一块连续的物理内存区域,每个像素的二进制编码方式(像素格式)决定了颜色深度与显示效果,而内存布局则直接影响访问效率与缓存切换策略。

4.1 Framebuffer 内存布局

Framebuffer 在物理内存中通常以线性布局或平铺布局两种方式组织。嵌入式系统中,线性布局因其地址连续、DMA 友好而最为常见。

4.1.1 线性布局(Linear Layout)

像素数据按行顺序连续存储,第 0 行第 0 列像素位于基地址,第 0 行第 1 列像素紧随其后。这种布局适合逐行扫描的显示控制器,且便于通过偏移量快速计算任意像素地址。

// 线性布局地址计算示例
// 假设:分辨率 W x H,每像素占用 bytes_per_pixel 字节
// 第 y 行第 x 列像素的地址:
uint32_t pixel_offset = (y * W + x) * bytes_per_pixel;
uint8_t* pixel_addr = framebuffer_base + pixel_offset;

4.1.2 平铺布局(Tiled Layout)

将图像划分为固定大小的块(如 32x32 像素),每个块内连续存储,块之间按顺序排列。平铺布局能提高 CPU/GPU 的缓存局部性,适合 2D 加速引擎,但地址计算稍复杂。

调优提示:在双缓冲或多缓冲场景中,线性布局更适合使用 DMA 进行整帧传输;平铺布局则更适合 GPU 渲染后直接输出。选择哪种布局需结合硬件特性与驱动设计。
Framebuffer 内存布局对比:线性 vs 平铺 Framebuffer 内存布局对比 线性布局 (Linear) 行 0: 像素 0,0 | 像素 0,1 | 像素 0,2 | ... | 像素 0,W-1 行 1: 像素 1,0 | 像素 1,1 | 像素 1,2 | ... | 像素 1,W-1 行 2: 像素 2,0 | 像素 2,1 | 像素 2,2 | ... | 像素 2,W-1 行 3: 像素 3,0 | 像素 3,1 | 像素 3,2 | ... | 像素 3,W-1 ... 行 H-1: 像素 H-1,0 | 像素 H-1,1 | ... | 像素 H-1,W-1 地址递增方向 → 平铺布局 (Tiled) Tile 0 32x32 像素 连续存储 Tile 1 32x32 像素 连续存储 Tile 2 32x32 像素 连续存储 Tile 3 32x32 像素 连续存储 地址递增方向 → 线性布局:地址计算简单,适合逐行扫描与 DMA 传输 | 平铺布局:缓存局部性好,适合 GPU 渲染

4.2 像素格式与颜色深度

像素格式定义了每个像素在内存中的二进制编码方式,直接决定了颜色深度(每个通道的位数)和色彩表达能力。常见的像素格式包括 RGB、BGR、ARGB、RGBA 等变体。

4.2.1 颜色深度分类

颜色深度 每像素位数 (bpp) 通道分配 色彩数量 典型应用
1-bit 1 单色(黑/白) 2 低端 LCD、电子墨水屏
8-bit 索引色 8 调色板索引 256 早期 GUI、GIF 图像
16-bit 高彩色 16 RGB565 (R:5, G:6, B:5) 65,536 嵌入式 LCD、低成本显示
24-bit 真彩色 24 RGB888 (R:8, G:8, B:8) 16,777,216 桌面显示器、摄像头预览
32-bit 真彩色+Alpha 32 ARGB8888 (A:8, R:8, G:8, B:8) 16,777,216 + 256 级透明度 现代 GUI、游戏、合成渲染

4.2.2 常见像素格式详解

嵌入式系统中,RGB565 和 ARGB8888 是最主流的两种格式。前者节省内存带宽,后者提供高质量色彩与透明度支持。

  • RGB565:16 位,内存布局为 R[4:0] | G[5:3] G[2:0] | B[4:0],共 5+6+5=16 位。每个像素占用 2 字节,内存效率高,适合带宽受限的嵌入式设备。
  • ARGB8888:32 位,内存布局为 A[7:0] | R[7:0] | G[7:0] | B[7:0],共 8+8+8+8=32 位。每个像素占用 4 字节,支持 Alpha 混合,是现代 GUI 框架(如 LVGL、Qt)的首选。
  • XRGB8888:32 位,与 ARGB8888 类似但 Alpha 通道未使用(保留位),常用于无需透明度的场景以保持对齐。
// RGB565 像素打包/解包示例
// 将 R(0-31), G(0-63), B(0-31) 打包为 16 位 RGB565
uint16_t rgb565_pack(uint8_t r, uint8_t g, uint8_t b) {
    return ((r & 0x1F) << 11) | ((g & 0x3F) << 5) | (b & 0x1F);
}

// 从 16 位 RGB565 解包
void rgb565_unpack(uint16_t pixel, uint8_t* r, uint8_t* g, uint8_t* b) {
    *r = (pixel >> 11) & 0x1F;
    *g = (pixel >> 5) & 0x3F;
    *b = pixel & 0x1F;
}

// ARGB8888 像素结构体
typedef struct {
    uint8_t blue;    // B 通道
    uint8_t green;   // G 通道
    uint8_t red;     // R 通道
    uint8_t alpha;   // A 通道
} __attribute__((packed)) argb8888_pixel_t;
常见像素格式内存布局 常见像素格式内存布局 RGB565 (16-bit) R[4:0] G[5:0] B[4:0] 共 16 位,2 字节/像素 ARGB8888 (32-bit) A[7:0] R[7:0] G[7:0] B[7:0] 共 32 位,4 字节/像素 注意:RGB565 按 2 字节对齐,ARGB8888 按 4 字节对齐。Framebuffer 基地址通常要求 4 字节或 8 字节对齐。 内存地址递增方向 →

4.3 Framebuffer 大小计算与对齐约束

Framebuffer 所需内存大小由分辨率、像素格式和行对齐要求共同决定。许多显示控制器要求每行像素的字节数为 4、8 或 16 的倍数,这可能导致行尾填充(pitch/stride 大于实际宽度)。

// Framebuffer 大小计算示例
// 参数:分辨率 1024x600,像素格式 ARGB8888 (4 字节/像素)
// 硬件要求:每行 16 字节对齐

uint32_t width_pixels = 1024;
uint32_t height_pixels = 600;
uint32_t bytes_per_pixel = 4;  // ARGB8888

// 实际每行字节数(未对齐)
uint32_t raw_stride = width_pixels * bytes_per_pixel;  // 4096 字节

// 对齐到 16 字节
uint32_t aligned_stride = (raw_stride + 15) & ~15;  // 4096 字节(恰好对齐)

// 总 Framebuffer 大小
uint32_t framebuffer_size = aligned_stride * height_pixels;  // 4096 * 600 = 2,457,600 字节

// 若使用双缓冲,总内存需求翻倍
uint32_t double_buffer_size = framebuffer_size * 2;  // 4,915,200 字节
常见陷阱:驱动开发中容易忽略行对齐(stride vs width)。如果直接使用 width * bytes_per_pixel 计算偏移,而硬件实际使用更大的 stride,会导致图像错位或撕裂。务必从硬件寄存器或驱动 API 中获取实际 stride 值。

4.4 像素格式选择对性能的影响

像素格式直接影响内存带宽、缓存命中率和渲染效率。下表总结了不同格式在典型嵌入式场景中的性能特征:

像素格式 内存带宽需求(相对值) 缓存友好性 渲染复杂度 推荐场景
RGB565 低(1x 基准) 高(每像素 2 字节) 低(无需 Alpha 混合) 低功耗设备、简单 UI、视频播放
ARGB8888 高(2x 基准) 中(每像素 4 字节) 中(支持 Alpha 混合) 现代 GUI、透明效果、图像合成
XRGB8888 高(2x 基准) 中(每像素 4 字节) 低(无 Alpha 计算) 无需透明度的高质量显示
调优建议:在 Vblank 中断驱动的双缓冲方案中,若带宽成为瓶颈(如高分辨率 60fps 场景),考虑使用 RGB565 替代 ARGB8888,可减少 50% 的帧传输数据量。若必须使用 ARGB8888,可启用显示控制器的压缩模式(如 DSI 压缩)或降低帧率。

4.5 本章小结

  • Framebuffer 内存布局分为线性和平铺两种,线性布局适合 DMA 传输,平铺布局适合 GPU 渲染。
  • 像素格式(RGB565、ARGB8888 等)决定了颜色深度、内存占用和渲染能力。
  • Framebuffer 大小计算必须考虑行对齐(stride),忽略对齐会导致显示异常。
  • 像素格式选择直接影响内存带宽和系统性能,需根据硬件能力和应用需求权衡。