1.CPU给GPU传输数据 1.CPU给GPU传输数据 1 ) . 直接传输的原始数据( "CPU传实际字节到GPU显存" ) 这类是GPU渲染必须的"原材料" , CPU会把数据打包成连续缓冲区上传到GPU显存 a. 顶点属性 比如: 顶点坐标, 法线, 切线, UV坐标, 顶点颜色, 骨骼权重( 蒙皮动画用) , GPU会将这些数据整理成连续的数组上传到GPU 的顶点缓冲区, 是渲染网格形状的基础b. 索引数据 几乎所有的网格都会用索引缓冲区, CPU把顶点索引数组上传到GPUc. 常量缓冲区 这是GPU渲染的"全局参数" , CPU每次渲染都会更新并传输- 矩阵类: MVP矩阵( 模型 → 视图 → 投影矩阵, 决定对象在屏幕上的位置/ 大小/ 角度) , 对象的世界矩阵- 材质动态参数: 比如材质的颜色、透明度、高光强度、金属度/ 粗糙度( 从材质中提取的可变参数) - 全局渲染参数: 比如光源位置、环境光颜色、时间(做动画用) d. 实例化数据( 实例化渲染时传) 如果用GPU实例化渲染多个相同对象( 比如批量渲染树木/ 石头) , CPU会传"实例缓冲区" , 包含每个实例的位置, 旋转, 缩放等 独立参数, 让GPU一次渲染多个对象e. 骨骼动画数据( 蒙皮动画时传) 若对象有骨骼动画( 比如人物) , CPU会计算骨骼的最终变换矩阵, 再上传到GPU的"骨骼缓冲区" , 供Shader做蒙皮计算( 网格跟 随骨骼动) 2 ) . 传输的引用 材质是"Shader + 参数 + 纹理" 的集合, CPU不会传材质本身, 而是传递Shader+ 参数+ 纹理 a. Shader Shader的二进制代码会提前编译并加载到GPU显存, CPU只传Shader程序的ID/ 引用, 告诉GPU本次渲染用哪个Shader程序执行 计算 b. 纹理 纹理图片会提前上传到GPU显存( 变成"纹理对象" ) , CPU只传- 纹理ID ( 指向GPU显存中的纹理) - 采样器状态( 比如纹理的过滤方式、寻址模式, 比如是否重复平铺) c. 参数 材质参数( 比如颜色、高光) → 打包到上面说的"常量缓冲区" 3 ) . 传输的"渲染指令 / 状态配置" ( CPU告诉GPU"怎么渲染" ) 这类不是"数据" , 但却是渲染的核心指令, CPU必须传给GPU a. DrawCall 指令 最关键的指令( 比如 glDrawElements/ DrawIndexed) , 告诉GPU用当前绑定的顶点缓冲区、索引缓冲区、Shader、纹理, 渲染 多少个三角形/ 顶点 b. 渲染状态配置, CPU会设置GPU的渲染规则, 比如: - 深度测试开关(是否遮挡)、混合模式(透明对象怎么叠加);- 裁剪模式(只渲染正面/ 背面)、多边形填充模式(线框/ 实心);- 模板测试(比如做镜面、阴影时用)。渲染状态是给GPU硬件各个模块下的工作指令, 硬件必须切换到对应模式下才能正确渲染, 就像给打印机设置黑白/ 彩色/ 单面/ 双面, 是硬件级别的配置CPU和GPU是异步工作的, 核心逻辑是 a. CPU的操作: 异步提交指令 CPU只是把设置渲染状态, 上传数据, DrawCall这些指令按顺序写入命令缓冲区, 然后一次性提交给GPU, 提交后CPU就去处理 下一个任务( 比如逻辑代码、准备下一批指令) , 完全不等GPU执行 b. GPU的操作: 串行执行指令 GPU会按命令缓冲区的顺序执行指令, 但渲染状态切换时, GPU的流水线会出现"停顿" : - GPU内部是流水线式工作( 顶点着色 → 光栅化 → 片元着色 → 混合) , 切换渲染状态时, 必须等当前流水线里的所有像素处 理完, 才能重置硬件单元的配置- 这个停顿会让GPU短时间空等, 而GPU的停顿会间接导致命令缓冲区被快速占满 —— CPU后续提交指令时, 发现缓冲区满了就 不得不等待缓冲区腾出空间, 这就是DrawCall开销的核心来源 c. 举个通俗例子 CPU= 餐厅点餐员, GPU= 后厨厨师, 渲染状态= 厨师的烹饪工具( 炒锅) CPU ( 点餐员) 写完菜单( 命令缓冲区) 就交给后厨, 不会等厨师换工具; 但厨师( GPU) 换工具( 切换渲染状态) 时, 必须等当前菜 炒完, 期间没法做新菜 —— 后厨效率下降, 菜单会堆在窗口( 命令缓冲区满) , 点餐员最终还是得等窗口空了才能递新菜单