2、GPU基础概念:图形管线、并行计算、着色器、纹理、帧缓冲等核心术语解析
在深入ARM Mali GPU的编程之前,我们必须先建立一套共同的语言体系。GPU(图形处理器)并非只是“画图的芯片”,它本质上是一台高度特化的并行计算机。无论是渲染3D场景,还是运行通用计算(GPGPU)任务,其底层都围绕着几个核心概念展开:图形管线(Graphics Pipeline)、并行计算模型(Parallel Computing Model)、着色器(Shader)、纹理(Texture)与帧缓冲(Framebuffer)。本章将逐一拆解这些术语,并特别结合ARM Mali GPU的架构特性(如Tile-Based Rendering,分块渲染)进行说明,帮助你从“会用API”进阶到“理解硬件行为”。
上图展示了本章的核心知识框架。从CPU提交命令开始,数据流经Mali GPU的图形管线(顶点→光栅化→片段),同时与并行计算单元、着色器、纹理单元和帧缓冲紧密交互。特别需要注意的是Mali的分块渲染架构,它将屏幕划分为多个小方块(Tile)进行逐块渲染,这直接影响帧缓冲的读写方式和性能调优策略。下面我们逐一深入解析。
2.1 图形管线:从顶点到像素的流水线
核心原理
图形管线是GPU执行渲染任务的标准流程,它定义了从输入几何数据(顶点坐标)到最终屏幕像素颜色的完整路径。在ARM Mali GPU中,这条管线被划分为两个主要阶段:几何处理阶段和分块渲染阶段。几何阶段负责处理顶点变换、光照计算等;分块渲染阶段则负责将几何数据转换为屏幕上的像素颜色。这种设计使得Mali GPU能够以极低的功耗实现高填充率,因为每个Tile的渲染都在芯片内部的快速内存(On-Chip Memory)中完成,无需频繁访问外部DRAM。
操作流程
- 顶点输入:CPU将顶点数据(位置、法线、UV坐标等)通过顶点缓冲对象(VBO)提交给GPU。
- 顶点着色器:对每个顶点执行用户自定义的变换逻辑(如模型-视图-投影矩阵变换)。
- 图元装配:将顶点组装成三角形、线段或点。
- 光栅化:将图元转换为屏幕上的像素片段(Fragment),并计算每个片段的深度值。
- 片段着色器:对每个片段执行颜色计算(如纹理采样、光照计算)。
- 逐片段操作:包括深度测试、模板测试、混合(Blending)等,最终写入帧缓冲。
案例拆解:绘制一个旋转立方体
假设我们要绘制一个旋转的彩色立方体。在每一帧中,CPU更新旋转矩阵,然后提交绘制命令。Mali GPU的几何引擎处理8个顶点(每个面4个,但共享顶点),顶点着色器将每个顶点乘以旋转矩阵。光栅化阶段将12个三角形转换为屏幕上的像素片段。对于每个片段,片段着色器根据顶点颜色进行插值,输出最终颜色。整个过程在Mali GPU上以并行方式处理:多个顶点同时被处理,多个片段同时被着色。
常见误区
2.2 并行计算:GPU的“人多力量大”哲学
核心原理
GPU之所以能快速渲染复杂场景,核心在于其大规模并行架构。与CPU拥有少量高性能核心(如8核)不同,GPU拥有成百上千个小型计算核心(Mali-G78 MP24拥有24个核心)。这些核心被组织成多个执行引擎(Execution Engine),每个引擎可以同时处理多个线程。这种架构被称为SIMD(单指令多数据)或SIMT(单指令多线程)。在Mali GPU中,一组线程(通常称为Wavefront或Warp,大小通常为16或32)会同时执行同一条指令,但作用于不同的数据。
判断方法:如何评估并行效率
| 指标 | 含义 | Mali中的表现 |
|---|---|---|
| 占用率 (Occupancy) | 活跃线程束与最大线程束的比值 | 高占用率有助于隐藏内存延迟 |
| 内存带宽 | 单位时间内读写数据量 | Mali的L2缓存和Tile内存设计旨在减少带宽压力 |
| 分支发散 (Divergence) | 同一线程束内线程执行不同路径 | 会导致串行执行,应尽量避免 |
实战场景:GPGPU计算
除了图形渲染,Mali GPU也支持通用计算(通过OpenCL或Vulkan Compute)。例如,在图像处理应用中,我们可以将一张1920x1080的图片划分为多个像素块,每个线程处理一个像素。假设Mali GPU有16个核心,每个核心同时处理4个线程,那么一个Wavefront包含64个线程。GPU会调度多个Wavefront来覆盖所有像素。关键优化点在于确保内存访问是合并的(Coalesced),即相邻线程访问相邻内存地址,这样硬件可以将多次访问合并为一次事务。
常见误区
2.3 着色器:可编程的GPU灵魂
核心原理
着色器(Shader)是运行在GPU上的小型程序,用于控制顶点和片段的处理。在Mali GPU中,着色器使用高级语言编写(如GLSL、SPIR-V),然后编译为GPU微码。着色器分为多种类型:顶点着色器(处理顶点)、片段着色器(处理像素)、几何着色器(处理图元)以及计算着色器(用于通用计算)。Mali GPU的着色器核心是统一的(Unified Shader Core),意味着同一个核心既可以执行顶点着色器,也可以执行片段着色器,这提高了硬件利用率。
操作流程:编写一个简单的片段着色器
// GLSL 片段着色器示例
#version 300 es
precision mediump float;
in vec2 v_uv;
out vec4 fragColor;
uniform sampler2D u_texture;
void main() {
vec4 texColor = texture(u_texture, v_uv);
fragColor = texColor * vec4(1.0, 0.8, 0.8, 1.0); // 轻微红色调
}
这段代码从纹理中采样颜色,并乘以一个色调向量。在Mali GPU上,这个着色器会被编译为一系列指令,每个片段执行一次。由于片段数量巨大(例如1080p屏幕有200万个像素),GPU会并行执行数百万次该着色器。
案例拆解:优化着色器性能
假设我们有一个复杂的片段着色器,包含多个纹理采样和动态分支。在Mali GPU上,动态分支可能导致Wavefront内线程发散,降低效率。优化策略包括:1) 将纹理采样移到顶点着色器(如果插值足够);2) 使用Mipmap减少采样开销;3) 避免在循环中使用非恒定次数。通过Mali Offline Compiler工具,我们可以查看着色器的指令数和寄存器使用情况,从而定位瓶颈。
常见误区
2.4 纹理与帧缓冲:内存与带宽的艺术
核心原理
纹理是存储在GPU内存中的图像数据,通过UV坐标进行采样。纹理不仅用于贴图,还可用于存储法线、高度、光照信息等。Mali GPU支持多种纹理压缩格式(如ASTC、ETC2),这些格式能显著减少内存占用和带宽消耗。帧缓冲则是GPU渲染的目标区域,通常包含颜色缓冲、深度缓冲和模板缓冲。在Mali的分块渲染架构中,帧缓冲被划分为多个Tile,每个Tile在芯片内部完成渲染后,再一次性写回主存。
操作流程:纹理加载与帧缓冲配置
- 纹理创建:使用
glTexImage2D上传像素数据,并设置过滤方式(线性/最近邻)和Mipmap。 - 帧缓冲对象(FBO):创建FBO并附加颜色纹理附件和深度渲染缓冲。
- 渲染循环:绑定FBO,执行绘制命令,然后解绑FBO,将结果作为纹理用于后续Pass。
案例拆解:延迟渲染中的G-Buffer
在延迟渲染中,我们需要将场景的几何信息(位置、法线、颜色)渲染到多个纹理中,这些纹理统称为G-Buffer。在Mali GPU上,由于分块渲染的特性,G-Buffer的写入和读取都在Tile内存中完成,效率极高。但需要注意,如果G-Buffer使用过多纹理,会增加Tile内存的压力,导致溢出到主存,性能骤降。因此,在移动端延迟渲染中,通常使用紧凑的G-Buffer格式(如RGB10_A2)来减少内存占用。