找回密码
 立即注册
查看: 342|回复: 2

《RTR4th》(总结 三)

[复制链接]
发表于 2021-11-26 10:28 | 显示全部楼层 |阅读模式
图形处理器

本章内容概览



图形处理器概览

数据并行架构(Data-Parallel Architectures)
不同的处理器使用不同的策略来避免性能瓶颈。
CPU优化以处理各种各样的data structures以及large code bases。CPUs可以有多核,但基本上都是串行的方式执行代码的。为了使延时的影响最小化,CPU芯片会有一些fast local caches组成,在这些caches里面可能是接下来需要用到的数据。CPU还使用了branch prediction, instruction reordering, register renaming, 以及cache prefetching诸如此类的方式避免遇到性能瓶颈。
GPU就不同了。GPU芯片的区域基本上布满了处理器,这些玩意叫shader cores,可能高达数千个。GPU是一种stream processor,它依次处理一系列有序的相似数据。GPU可以大规模并行处理vertices跟pixels。另一个重要的要点是,这些调用尽可能的独立,它们不需要知道相邻调用的信息,不共享可写内存的位置。这个规则有时候会被打破以使用一些新的、有用的功能,但是由于关联性上去了,可能就会造成“等待”。
在这种架构下,GPU通过切换到不同的fragment保持忙碌状态来隐藏延时。GPUs采用将指令执行逻辑与数据分离的设计方式,也就是SIMD(单指令多数据)。
我们把每一个pixel shader的调用称为一个thread,这种thread跟CPU的thread不一样,它包含了一些输入值的内存,还有一些shader执行的register。
shader program的结构是影响效率的重要特征。主要的一个因素是每个thread的register的使用数量。
假设有2000个threads可以同时驻留在GPU中。而每个thread关联的shader program所需的registers更多,threads也就越少,warps也因而越少。warps减少,也就意味着无法通过swapping来减少stall。warps跟占用率有关系,低占用率意味着性能很低。此外,内存频率也会影响需要隐藏的延时。
另一个影响整体效率的因素则是由"if"语句或者循环引起的动态分支(dynamic branching,见空明流转的回答)。

GPU管线概览(GPU Pipeline Overview)
GPU实现了geometry processing,rasterization,还有pixel processing管线阶段。它们被划分为几个硬件阶段,并且具有不同程度的可配置性以及可编程性。



绿油油的表示可编程,黄色表示可配置,蓝色表示固定功能

Vertex shader是完全可编程的阶段,而tessellation跟geometry shader都是可选的,并非所有的GPU都支持,尤其是移动设备。
Clipping,Triangle Setup & Traversal都是由固定功能硬件实现的。Screen mapping受window跟viewport settings的影响,形成一个简单的scale跟repositioning。Pixel shader阶段是完全可编程的。尽管merger阶段不可编程,但它高度可配,可以执行种类繁多的操作。它负责修改color、z-buffer、blend、stencil还有任何其他与输出相关的buffers。

可编程着色阶段(The Programmable Shader Stage)
在Shader中,常见的语言有:
DirectX的HLSL,HLSL可以编译成vm bytecode,或者叫中间语言(IL/DXIL),这个IL跟.NET的IL不一样,别搞错了。
OpenGL的GLSL



SM4.0

可编程着色与API的演化(The Evolution of Programmable Shading and APIs)

顶点着色器(The Vertex Shader)
顶点着色器是功能管线的第一个阶段。
Instancing技术:Instancing其实就是允许一个object在单个draw call中,为每一个instance以不同的一些数据绘制多次的玩意。
Triangle mesh就是一个一组Vertices。每一个Vertex都有一个特定的Vertex相关联在模型表面的position。除了position,每个Vertex还有其他一些可选的properties,例如color或者texture coordinates。同时,还在定义在Vertex的表面法线。
然后,接下来的章节阐述了一些vertex shader的效果,例如vertex blending,用于动画关节(animating joints),还有轮廓渲染(silhouette rendering),还有其他一些使用:

  • 对象生成(Object generation),创建一个mesh,并使用vertex shader造成形变(deformed)。
  • 通过skinning还有morphing技术做角色身体和表情动画。
  • 程序化变形(Procedural deformations),例如旗帜、布料、水等。(扩展:提到Procedural,还有一种常用的技术叫做Procedural texture,不过跟这个没有啥关系)。
  • 粒子创建。
  • Lens distortion,heat haze,water ripples,page curls,还有其他一些效果。
  • 用纹理来控制地形高度区域
曲面细分阶段(The Tessellation Stage)
曲面细分阶段使我们可以渲染曲面。DirectX11、OpenGL 4.0,以及OpenGL ES 3.2之后支持的一种feature。




后面会有章节详细讨论怎样进行曲线曲面细分。

几何着色器(The Geometry shader)
Geometry shader可以将primitives转变成其他primitives,这就是tessellation不能做的事情。



流输出(Stream Output)
GPU管线标准的使用方式就是通过Vertex shader发送数据,然后将三角形光栅化(rasterize),之后在pixel shader中处理这些三角形。
曾经,这些数据总是穿过管线并且无法访问中间结果。而在SM4.0中,引入了stream output的想法。在顶点被vertex shader(包括那些可选阶段)处理之后,可以以stream的形式进行输出。一个有序数组会被发送到光栅化阶段(rasterization stage)。实际上光栅化可以被完全关闭,而管线则完全作为一个非图形化的流式处理器。
以这种方式处理的数据可以通过管线发送回来,从而允许迭代处理。这种类型的操作可以模拟水流,或者一些粒子效果。
在OpenGL中,Stream output阶段叫做transform feedback。

像素着色器(The Pixel Shader)
在顶点处理之后,每个三角形都会被遍历来确认它覆盖的像素。Rasterizer还可以粗略的计算三角形覆盖的每个像素的cell area。这个三角形部分或者完全重叠的像素被称为fragment。
三角形顶点的值包括了z-buffer中的z-value,都会为每个像素在三角形表面进行内插值。之后这些值被传输到pixel shader。在OpenGL中,pixel shader即是大家都知道的fragment shader。
在三角形中的内插值类型是由pixel shader program指定的。一般来说使用perspective-correct interpolation。所以当一个物体在远处后退时候,像素表面位置的距离也会相应的提升。
有了输入,通常pixel shader都会输出一个fragment color。它还可能带有不透明度,并选择性的修改它对应的z-depth。在Merging期间,这些值用于修改存储在pixel中的内容。在光栅化阶段生成的depth value也可以在pixel shader中进行修改。stencil buffer value通常是不可修改的,它被传递到merging stage。而在DirectX11.3中,已经允许shader对这个值进行修改了。
Pixel shader有着discard传入片段的独特能力,也就是说,不进行输出。
最初的时候pixel只能够输出到merging stage作为最终的显示结果。但现在pixel shader可以执行的指令数量已经增大了非常多,这种增强,导致了人们产生了多重渲染目标(multiple render targets,MRT)的想法。
为每个fragment生成多个值集并存在不同的buffer之中,而不是仅将pixel shader的结果值发送到color buffer跟z-buffer。每个buffer,就叫一个渲染目标(render target)。
渲染目标通常具有相同的x和y维度,当然,一些API允许他们不同的尺寸,但是渲染区域会是最小的那个就是了。一些体系要求render targets具有相同的bit depth,甚至可能要求相同的data formats。根据GPU不同,渲染目标的数量可能是4或者8个。
Pixel shader通常只能够在传递给它的fragment位置上写入渲染目标,并且不能够从邻近像素中读取当前的结果值。也就是说,当一个pixel shader program执行时,它不能够将其输出直接发送到相邻像素也不能够访问其他邻近像素最近的修改。它的计算只能够影响它自身像素的结果。如果非要访问邻近像素的信息,可以使用图像处理的技术进行这种处理。
当然,上述规则有例外情况。
一种是pixel shader可以在梯度或者导数信息的计算过程中立即访问相邻fragments的信息(间接访问)。Pixel shader提供了沿基于屏幕的x轴和y轴每像素插值的变化量。这些值对于各种计算和纹理寻址都非常有帮助的。这些梯度对于操作纹理过滤尤为重要,比如我们想要知道一个图像覆盖像素的多少。
所有现代的GPU都通过以 2 x 2 为一组的进行的fragment处理来实现这个feature。是不是发现这个非常的熟悉?看这里。

合并阶段(The Merging Stage)
合并阶段是单个fragment的depth跟color与framebuffer结合在一起的地方。
在DirectX中,这个阶段叫做output merger,而在OpenGL指的是per-sample operations。在大多数传统的Pipeline图中,这个阶段是stencil buffer跟z-buffer操作的地方。如果fragment可见,那么在这个阶段会发生color blending的operation。对于不透明的表面,没有真正的blending,因为fragment只是简单的进行了替换之前存储的color。fragment跟存储的color实际blending通常用于透明跟合成操作。
光栅化生成的fragment是通过pixel shader执行的,在应用z-buffer时,会发现被先前渲染的fragment所隐藏,那么它接下来在pixel shader都是没有意义的。为了避免这种资源的浪费,许多GPU都会在pixel shader前进行一些merge testing。用z-depth测试可见性,如果需要隐藏,那么cull掉这个fragment,这个功能就叫early-z。Pixel shader可以改变fragment的z-depth或者完全discard掉fragment,如果发现在pixel shader program中存在这些操作,那么就会关闭early-z的功能,这一般会降低管线效率。
此外,color blending所使用的公式也是一种标志性功能。

计算着色器(The Compute Shader)
GPU不单单可以用于传统图形管线,也可以用于非图形领域。



使用了CS的一些例子


超级精简版


图形处理器的介绍说明,包括了你可以编程的、可以配置的,跟你没办法管的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-11-26 10:29 | 显示全部楼层
老哥可以的,有在线pdf链接可以分享一下么。。。
发表于 2021-11-26 10:32 | 显示全部楼层
realtime rendering 4th高清免解压
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-25 16:52 , Processed in 0.098034 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表