上帝视角看GPU(5):图形流水线里的不可编程单元


  • 【GPU】图形流水线基础
  • 【GPU】逻辑上的模块划分
  • 【GPU】部署到硬件
  • 【GPU】完整的软件栈


前几期我们过了一遍GPU的软硬栈。这次我们将深入GPU图形流水线的一些细节,看看那些不可编程的模块是怎么工作的。

对于GPU的图形流水线来说,最核心最重要的一个组件就是光栅化器。

它的存在,直接决定了GPU在实时渲染方面的优势。以至于很多时候光栅化就是GPU图形流水线的代称。

以前说过,经过vertex shader之后,每个顶点上都有了转换后的属性。

包括位置、法线方向、颜色、纹理坐标等。

经过primitive assembler之后来到光栅化阶段,转换成像素。

所以,光栅化这个操作,本质上就是把三个顶点上的信息,

插值到这个三角形覆盖的每个像素上,交给pixel shader。

Primitive assembler和光栅化总是连在一起, 因此成为了广义的光栅化器。

下面我也会把这两部分合并起来描述算法。要完成这样的插值,常见的方法称为扫描线算法。

顶点上有一系列的属性,根据三个顶点的位置和属性变化的程度,可以算出这个三角形覆盖的区域里。

从一个像素挪到右边或者下边,各个属性会改变多少。这称为ddx和ddy。

对于一个三角形来说,属性的ddx和ddy都是常量,只要算一次就行。

接着,从最靠上的顶点开始,沿着轮廓一行一行往下扫。

每一行根据三角形轮廓就能知道应该从哪里开始,到哪里结束。

往右一个像素,属性增加一次ddx,往下一行,属性增加一次ddy。

这样扫描生成三角形覆盖的所有像素。


那么,像素在什么情况下认为被三角形覆盖?这叫做光栅化规则。普通模式下,光栅化三角形看的是像素中心是否在三角形之内。

光栅化线看的是线是否经过像素里的一个菱形区域,另一种模式是只要沾到一点就算覆盖。这叫保守式光栅化,常用于体素化的需求。

比如前几年很热门的SVO cone tracing, 就用保守式光栅化来把整个场景变成体素的表达。

光栅化的算法有了,直接放到硬件上,就成了立即式光栅化。

这个做法很淳朴,用ASIC把刚才描述的算法变成硬连线。

在算法完全固定的情况下,ASIC的效率远高于FPGA和可编程单元。, 立即式光栅化生成的像素,经过流水线后面的几个阶段,写入内存里的渲染目标。

渲染目标可能是纹理也可能是帧缓存。

对于大三角形来说,这么做性能非常高。因为只要算一次ddx、ddy,后面一路累加过去就行,可以不被打断地一直执行同样的操作。

但是,如果三角形层层叠叠,就得反复写入内存,带宽占用很大,功耗高。

对PC渲染的需求来说,只要性能高,功耗高一点也可以接受的,

所以往往会选择立即式光栅化的方案。

这张图是我在AMD的GPU上得到的,其中的颜色表达了像素到达pixel shader的顺序。

从这里可以看出,这个GPU采取了32个像素的高度,一条一条的光栅化方式。

而CPU光栅化的WARP,就是一个一个像素扫过去的方式。

到了移动平台,这就够呛了。移动平台更看重的是性能功耗比。

如果性能只有一半,但功耗只有四分之一,也会考虑采纳。

于是,移动平台上,光栅化往往采用tile-based方案。它把渲染目标划分成很多固定大小的tile,常见的是32x32。

每个tile包含一个列表,存有和这个tile相交的所有三角形。所以tile-based光栅化不再是一个一个三角形处理,而是一批一批处理。

这样的GPU,需要有一个片上内存充当cache的角色,不需要大,但访问速度远远高于内存。

对于每个tile,先会把渲染目标的对应区域载入GPU的片上内存。接着用扫描线算法,把列表里的三角形都渲染上去。,最后把片上内存里的结果存到渲染目标。

然后开始处理第二个tile。

不管三角形如何层层叠叠,每个tile每次对内存的读写,总是只有32x32个像素,远低于立即式。

但因为一个三角形没法一直填充下去,会因为tile而被打断,性能其实是降低的。

只是相比之下功耗降得更多。

这是在高通的GPU上跑出来的光栅化顺序图。

可以看到每个tile大小固定,一个一个tile铺成了整个屏幕。

为了让大家加深印象,这里举两个实际的场景,比较一下立即式和tile-based在工作流程上的区别

同样是渲染两个三角形。

第一种情况,把它们渲染到同一张纹理。

第二种情况,把它们分别渲染到两张纹理。

对于立即式来说,都是把三角形光栅化出去。

两个三角形是不是到同一个纹理无所谓。操作是一样的。因此两者的性能和功耗区别可以忽略不计。

对于tile-based,这俩就很不一样了。

第一种情况,光栅化的流程是,第一个tile载入到片上内存,渲染两个三角形,存到纹理;

第二个tile载入到片上内存,渲染两个三角形,存到纹理;

依此处理完所有tile。

第二种情况的流程就变成,纹理A的第一个tile载入到片上内存,渲染三角形A,存到纹理A;

纹理A的第二个tile载入到片上内存,渲染三角形A,存到纹理A;

依此处理完纹理A的所有tile;

纹理B的第一个tile载入到片上内存,渲染三角形B,存到纹理B;

纹理B的第二个tile载入到片上内存,渲染三角形B,存到纹理B;依此处理完纹理B的所有tile。

注意,在片上内存里的操作非常快,访问内存里的纹理,慢得多而且耗电得多。

因此第一种情况比第二种好情况得多。这也是为什么在tile-based GPU上,切换渲染目标成为大忌。

这几年API的改进集中于提供subpass和invalidate等操作,可以让开发者决定是否把纹理的tile载入片上内存,以及渲染后是否存到纹理,以减少这部分的开销和功耗。

继续往后看。光栅化产生的像素,会进入pixel shader,然后是output merger。

场景是存在遮挡的,近的会挡住远的。

之前说过,这是在output merger里通过深度测试来完成。

假设光栅化产生了像素A,跑完后面的流程,写入渲染目标,又在同一位置产生像素B。

这里会产生两个问题。

第一,如果像素B比像素A还近,,那它跑完后面的流程之后,会覆盖掉像素A。

这使得像素A经过的pixel shader和output merger完全浪费了。

第二,如果像素B比像素A还远,也得等到运行了pixel shader,进入output merger,才能发现有遮挡,才抛弃掉像素B。

那么像素B的pixel shader也白运行了。能不能把深度测试从output merger挪到pixel shader之前呢?

不总是可以的,因为pixel shader不但能输出颜色,也能输出深度。

如果光栅化产生的深度和pixel shader输出的深度顺序不一致,在pixel shader之前执行深度测试就会出错。

为解决第二个问题,GPU引入的功能称为early-z。

在渲染状态符合条件的情况下,驱动会检查一下pixel shader,如果不输出深度、不用discard丢弃像素,就启用early-z。

像素在进入pixel shader之前提前进行一次深度测试。

如果已经被挡住,就不往下走,直接丢弃掉。


在tile-based的光栅化上,有的GPU会有个称为TBDR的模式,tile-based deferred rendering。

TBDR在开启深度测试的情况下,把光栅化插值得到的像素属性都写入片上内存。

这时候不可见的像素就被抛弃了,只有可见的继续往下走,同时解决那两个问题。

但是它无法独立存在的,也是要一系列条件都符合的情况下才能启用,否则退回到tile-based模式。

既然立即式性能高,tile-based性能功耗比高,能不能取长补短一下?


有的,Maxwell之后的NVIDIA GPU,就采用了两者的结合,称为tiled caching。

它的tile巨大,256x256这个级别,cache也很大,不光像素,还可以把tile需要的几何也载入cache。

这么做降低了内存访问,性能和性能功耗比都更高了。这里仍然可以用一张光栅化的顺序图来看到这个情况。

前面说的,都是用硬件直接构造光栅化。它的性能优势来自于ASIC上执行固定的算法,但因此牺牲了灵活性。

有没有可能用软件来构造光栅化呢?这里说的软件,不是指在CPU运行,而是在GPU的可编程单元里运行。

有些需求使得软件光栅化变得很重要。

第一个需求,小三角形的光栅化性能。

在实际中,硬件光栅化的输出并不是一个一个像素,而是一个一个2x2的像素块。

这称为一个quad,quad之内每个像素都有邻居,于是可以在pixel shader里获得任何变量的ddx和ddy,只要和邻居一减就出来了。


这四个像素如果有在三角形之外的,之后才会被丢弃。

对于大三角形来说,最多也就是边缘的像素存在浪费。

但对于小于一个像素的三角形,这就浪费了3/4。

因此,对于大量三角形都小于一个像素的时候,构造一个以像素为单位的软件光栅化器,可以避免浪费,性能反而更高。

在UE5的Nanite里就是这么做的优化。另一个需求,在无法使用硬件光栅化的时候执行光栅化。

典型的是Intel在08年的Larrabee。上面没有常规的流式处理器,而是堆了48个奔腾的x86 CPU,加上很宽的SIMD指令集。

在那些CPU上执行的是个特制的软件光栅化算法,自适应细分的tile-based光栅化。

首先,像普通的tile-based一样,, 把整个渲染目标分成一系列tile,但是每个tile较大,至少64x64。

每次都是进行宽度为16的SIMD计算。这部分细节,






有兴趣的朋友可以看Salvia渲染器,里面有这个算法的开源实现。

Salvia渲染器: https://github.com/wuye9036/SalviaRenderer/

同样也是每个tile包含与它相交的三角形列表。接着把这个tile等分成16个小tile,测试每个小tile和三角形的相交情况。

完全覆盖了,就全部填充。完全不相交,就跳过。

如果部分覆盖,就把小tile再继续分成16个更小的tile,再次测试,以此类推直到像素级别为止。


后来,Larrabee项目停止,砍掉显示输出能力后改造成Xeon Phi运算卡,那个SIMD指令集成了AVX-512。

普遍猜测是功耗控制不住。NVIDIA也有个类似的工作,用CUDA构造软件光栅化。既然光栅化器也可以用软件构造了,那么其他固定流水线模块呢?

挨个过一遍吧。Input assembler负责读取和组装顶点。

在shader能直接访问buffer之后,, 这很容易就能改成让shader读取。

有时候性能还能更高。比如位置和法线用不同的index的情况,

如果必须用硬件input assembler,就得重新组织buffer,有些数据得复制组合多份。

在shader里写代码读取的话,可以支持多个index buffer,总的数据量更小。这在虚幻引擎里面叫做manual vertex fetch模式,用得越来越多。

Stream output原理也一样,无非就是改成写入UAV。Tessellator是在三角形内生成新的顶点, 连起来变成一组三角形。

我发明过一个方法,通过查找表迅速定位顶点之间的连接关系,在compute shader里实现tessellator。只要修改查找表就能更换连接的pattern,不一定要按照硬件写死的。

这个算法被《文明》系列游戏借鉴了,用于地形的细分,通过可定制pattern的思路,做到比硬件tessellator更高的速度。

最后的output merger,执行的是这个流程图,变成代码是非常直接了当的事情。

唯一需要注意的是alpha blending如果没有硬件帮助,性能会受一些影响。

如此看来,图形流水线里的几乎每一部份,都可以用可编程单元来构造。唯一必须用硬件才有绝对性能优势的是纹理采样。

它需要对纹理进行读取、解压、插值,计算量不小,算法很固定,适合硬件连线去做。

按照Larrabee的研究,用软件实现性能会降低12到40倍。

而对于那些所谓“通用GPU,只有计算流水线没有图形流水线的诈骗货,其实也可以用这样的软件方式构造图形流水线,在驱动里无缝衔接,成为真正的GPU。

我们把光栅化的各种方法过了一遍,并提出了如何用可编程的单元构造整条图形流水线。下一期,我们将关注于另一条越来越重要的流水线,光线跟踪。

欢迎继续收看,再见。

来自:龚大的杂货铺的教学视频

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/268966.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode第 387 场周赛总结

很久没打周赛了,这周开始恢复 这次周赛,题目比较简单,第三道题有点浪费了时间,思路是对的,但是被我把问题复杂化了。 给你一个下标从 1 开始、包含 不同 整数的数组 nums ,数组长度为 n 。 你需要通过 n 次…

【QT 5 +Linux下软件qt软件打包+qt生成软件创建可以安装压缩包+学习他人文章+第三篇:学习打包】

【QT 5 Linux下软件qt软件打包qt生成软件创建可以安装压缩包学习他人文章第三篇:学习打包】 1、前言2、实验环境3、自我学习总结-本篇总结(1)了解安装包的目录结构(2)了解要编写文件与编写脚本1. control文件2. postin…

美女街拍3000张高清图

美女街拍3000张高清图,需要的可以直接下载 2.资源下载 ​途径一:点击以下链接直接下载 美女街拍3000张高清图 途径二:直接长按住以下图片识别进去下载即可

北京大学发布,将试错引入大模型代理学习!

引言:探索语言智能的新边界 在人工智能的发展历程中,语言智能始终是一个核心的研究领域。随着大语言模型(LLM)的兴起,我们对语言智能的理解和应用已经迈入了一个新的阶段。这些模型不仅能够理解和生成自然语言&#x…

UCSF DOCK 分子对接详细案例(01)- rigid, fixed anchor, flexible dock

欢迎浏览我的CSND博客! Blockbuater_drug …点击进入 文章目录 前言一、操作环境二、研究背景三、受体-配体结构文件准备3.1准备文件夹DOCK_workdir, 下载晶体结构3.1.1 来自湿实验的受体配体共晶结构:3.1.2 来自深度学习和语言模型推理预测的蛋白结构&a…

了解游戏中的数据同步

目录 数据同步 通过比较来看状态同步和帧同步 状态同步 帧同步 帧同步实现需要的条件 两者相比较 数据同步 在联机游戏中,我的操作和数据要同步给同一局游戏中其他所有玩家,其他玩家的操作和数据也会同步给我。这叫做数据同步,目前数据…

幻兽帕鲁(1.5.0)可视化管理工具(0.5.7 docker版)安装教程

文章目录 局域网帕鲁服务器部署教程帕鲁服务可视化工具安装配置服务器地址(可跳过)使用工具管理面板 1.5.0服务端RCON错误1.5.0服务端无法启动RCON端口 解决方法第一步:PalWorldSettings.ini配置第二步:修改PalServer.sh配置 局域…

Unity(第二十一部)动画的基础了解(感觉不了解其实也行)

1、动画组件老的是Animations 动画视频Play Automatically 是否自动播放Animate Physics 驱动方式,勾选后是物理驱动Culling Type 剔除方式 默认总是动画化就会一直执行下去,第二个是基于渲染播放(离开镜头后不执行), …

数仓模型设计方法论

在当今大数据时代,数据已经成为企业最重要的资产之一。而数据仓库作为企业数据管理和分析的核心基础设施,其设计方法论对于企业的数据治理和决策分析至关重要。本文将探索数仓模型设计的方法论,帮助读者更好地理解和应用数仓模型设计。 一、…

day06_菜单管理(查询菜单,添加菜单,添加子菜单,修改菜单,删除菜单,角色分配菜单,查询菜单,保存菜单,动态菜单)

文章目录 1 菜单管理1.1 表结构介绍1.2 查询菜单1.2.1 需求说明1.2.2 页面制作1.2.3 后端接口SysMenuSysMenuControllerSysMenuServiceMenuHelperSysMenuMapperSysMenuMapper.xml 1.2.4 前端对接sysMenu.jssysMenu.vue 1.3 添加菜单1.3.1 需求说明1.3.3 页面制作1.3.3 后端接口…

AI新工具(20240228) EMO - 阿里巴巴的表情驱动的音频到视频转换框架;DepthFlow;Globe Explorer等

EMO - 阿里巴巴的表情驱动的音频到视频转换框架 EMO(Emote Portrait Alive)是一个先进的表情驱动的音频到视频转换框架,可以通过音频(比如说话或唱歌的声音)和一张单独的参考图片,生成带有丰富面部表情和头…

【前端面试题5】利用 border 属性画一个三角形

举例1:利用 border 属性画一个三角形(小技巧) 完整代码如下: div{width: 0;height: 0;border: 50px solid transparent;border-top-color: red;border-bottom: none; }步骤如下: (1)当我们设…

es集群的详细搭建过程

目录 一、VM配置二、集群搭建三、集群配置 一、VM配置 VM的安装 VMware Workstation 15 Pro的安装与破解 VM新建虚拟机 VM新建虚拟机 二、集群搭建 打开新建好的服务器,node1,使用xshell远程连接 下载es:https://www.elastic.co/cn/down…

java中的set

Set Set集合概述和特点 不可以存储重复元素 没有索引,不能使用普通for循环遍历 哈希值 哈希值简介 是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值 如何获取哈希值 Object类中的public int hashCode():返回对象的哈希码值。 哈希值的特点 同一个…

xss.haozi.me:0x0B

<svg><script>(1)</script>

【王道操作系统】ch1计算机系统概述-06虚拟机

文章目录 【王道操作系统】ch1计算机系统概述-06虚拟机01传统计算机02虚拟机的基本概念&#xff08;1&#xff09;第一类虚拟机管理程序&#xff08;2&#xff09; 第二类虚拟机管理程序&#xff08;3&#xff09; 两类虚拟机管理程序的对比 【王道操作系统】ch1计算机系统概述…

面试经典150题 -- 回溯 (总结)

总的链接 : 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 17 . 电话号码的字母组合 1 . 先创建一个下标 与 对应字符串映射的数组&#xff0c;这里使用hash表进行映射也是可以的 &#xff1b; 2 . 对于回溯 &#xff0c;…

live555学习 - 环境准备

环境&#xff1a;Ubuntu 16.04.7 ffmpeg-6.1 1 代码下载 最新版本&#xff1a; http://www.live555.com/liveMedia/public/ 历史版本下载 https://download.videolan.org/pub/contrib/live555/ 选择版本live.2023.01.19.tar.gz ps&#xff1a;没有选择新版本是新版本在…

用堆排序解决topk问题

topk问题 从一群数中取出前k高或者低的数。&#xff08;就好比要做一个像csdn热度榜一样的东西&#xff09; 堆的基础知识&#xff1a;【python】堆排序-CSDN博客 堆排序解决思路 1.先用列表的k个元素构建一个小根堆&#xff0c;小根堆最上面的元素就是最小的元素 2.依次拿…

(学习日记)2024.03.01:UCOSIII第三节 + 函数指针 (持续更新文件结构)

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…