» 您尚未登录:请 登录 | 注册 | 标签 | 帮助 | 小黑屋 |


 25 12
发新话题
打印

SIGGRAPH2006上MS对DX10的规范性定义

这篇文章是MS在SIGGraph 2006上发表的论文,可以在MS主业的MSDN页面下直接下载,作者是David Blythe,翻译翻译:clayman ,Blog:http://blog.csdn.net/soilwork 邮箱:clayman_joe@yahoo.com.cn 。本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
本来偶打算自己翻译后贴在EG,但后来入住XHW月许已然存在现成翻译文章,要不是看到天湿等一干人等有关神机“软件模拟DX10,且效率不俗”、“容积云”、“OPENGL2.1秒杀DX10”等高论屡屡现世于各大BBS,偶都差点忘了这事。现转贴供有兴趣的人分享请勿随意转载。

摘要

       本文描述了第四代PC平台上图形图像单元(GPU)的系统构架。与上一代图形管道相比,新的管道有了重大改变,引入了一个新的可编程阶段(stage)用于生产额外的图元,并把图元流保存到内存中;扩展了所有可编程阶段的功能,涉及到顶点、图片内存资源,以及新的储存格式。此外,我们还描述了API、运行时以及实现新管道的着色语言的结构性改变。解决当前系统中的缺陷,是我们设计的基本思想。文章不但描述了重要设计抉择背后的原理,同时也描述了那些最终被否决的方案。



1.前言

         过去10年,OpenGL和Direct3D所依赖的渲染管道构架已经取得了重大发展。最近5年中,随着从固定管道到可编程管道的过渡,发生了许多戏剧性的变化。虽然变化的进程很快,但每一步都反映出了设计者在通用性、性能以及成本上所做出的妥协。

         我们一直在努力了解以及构建一个系统,来解决许多程序中对图形加速器的需求(呈现图形、CAD、多媒体处理,等等)。但是,我们更想把注意力集中在交互式娱乐应用中。这些程序需要管理数十亿字节的艺术品,包括几何体、纹理、动画数据以及着色程序,占用大量系统资源(CPU、内存、带宽),以可交互的速率渲染丰富的、充满细节的图片。在处理海量数据的同时,保证渲染的灵活性,是对设计者的重大挑战之一。在系统设计的方方面面,都可以反映出我们对这个问题的解决方案。

         与上个版本的Direct3D一样,Direct3D 10同样是在应用程序开发者、硬件设计师以及API/运行时构架师三方的合作下设计的。在三年多的设计过程中,合作者之间详细的交流是无价的,让我们更深入了软硬件部署的代价,以及在大量不同硬件进行权衡。在开发Direct3D 10的过程中,调查显示应用程序开发者通常受以下限制的困扰,以及用来缓解这些问题的策略:

1. 状态(state)改变的代价过高。 改变任何类型的状态(顶点格式、纹理、shader、shader参数、混合模式,等等)都会付出很大代价。优化方法通常是通过查询对象状态来排序,减少API状态改变次数;减少外观的改变;或者使用基于shader的技术,使用shader来决定状态。对于后者,例子之一就是把多张纹理打包为一张纹理地图(texture map)(也称为纹理地图集),通过纹理坐标变换,来索引相应的子纹理。

2. 硬件加速器性能变化太多。   应用程序不得不编写一系列分支语句,以保证在不同硬件上都能正常运行。这些问题会影响到程序的特性设置,资源管理,算法精度,以及储存格式。

3. CPU和GPU之间频繁的同步。传统的图形管道允许有限制的重新使用管道当前产生的数据,作为下一个处理步骤的输入数据。Render-to-texture就是这种机制的最好例子之一,所渲染的图片接下来能被当作纹理使用,最小化CPU的干涉。但是,产生新顶点数据,或者创建立方贴图就需要CPU与GPU进行更多的协调和通信,降低了效率。

4. 指令以及数据类型的限制。通常都以精度和所支持的流程控制指令来衡量vertex shader,同样的方法也用来衡量pixel shader,但是,无论是pixel还是vertex shader都不支持整数指令。此外,出于对pixel shader精确性的要求,还指定了浮点算法。应用程序要么不使用这些额外的功能,要么模仿他们的使用。基于表格功能的计算就是例子之一。

5. 资源限制。 纹理读取的次数、纹理范围、程序指令,等等,都受到限制。应用程序不得不压缩算法,或者把它们分为多个shader pass。因此,还出现了对自动划分shader程序的研究。



2.背景

         我们的系统建立于PC,工作站以及游戏机平台上的应用程序可编程渲染管道。当前的图形管道分为两个编程阶段,一个用于处理顶点数据(vertex shader),一个用来处理像素或片断(fragment or pixel shader)。在Lindholm2001里描述了设计早期vertex shader的思想和折中。除了细小的差别以外,pixel shader也是按这样的轨迹来设计的。可以把顶点以及像素着色器的发展分为4代(包括Direct3D 10),如表一所示:



通过挖掘顶点和像素片断之间的独立性,硬件管道实现了很高的处理吞吐量。大多数顶点和像素着色器都是以并行的状态来处理相互独立的顶点和像素片断。典型的硬件实现中pixel shader的数量要比vertex shader多很多,反映出典型的渲染过程中,像素处理的工作量要比顶点多很多。与vertex shader相比,这种特性将影响pixel shader的性能,因为pixel shader被过多的复制了。

         可编程管道直接使用了较低的抽象层,比如OpenGL或Direct3D。这些抽象层隐藏了不同硬件管道实现之间的差别,提供了一个方便的接口。对特定的平台来说,比如游戏机,它的硬件管道与PC平台相比是不同的,底层细节也是由这些抽象层来暴露。

         我们把这些抽象层称为运行时(runtime),并且通过它所提供的API对他进行控制。运行时为设备提供了独立的资源管理(分配内存,控制生存期,初始化,虚拟技术,等等),所有纹理贴图,顶点缓冲,状态改变以及和硬件加速器的通信都通过特定设备的驱动程序来完成。对可变成管道来说,运行时还加入了对照色程序的抽象和管理任务。

         由于早期可编程处理器对指令储存空间的限制,为了在有限资源内,最大化对硬件的控制,不得不使用类似于汇编的语言来编写照色程序。但是,随着硬件功能的增加,需要一种高级的编程抽象来提高程序员的生产力。一种与C类似,并且添加了对潜在渲染管道进行定制的编程语言满足了这种需求。此外,还发展出了一些其他的语言,利用浮点处理器和GPU内存带宽来完成渲染以外的一些计算,但是,我们不打算在这篇文章里对这些应用进行讨论。

         虽然新的编程语言有必要与CPU编程语言(特别是C)类似,但我们还是进行了一些重要的修饰。举例来说,硬件结构和编译模型更像是一台虚拟机,汇编着色语言扮演了独立于硬件的中间语言(IL),而不是特定的机器语言。在离线环境下,Microsoft HLSL之类的高级语言被编译为IL,在程序运行时,通过驱动程序内建的翻译器,实时转换为目标硬件的指令。需要注意的是,OpenGL shading language使用了一种不同的方法来完成运行时的编译过程。

         另一个重要的区别是,着色程序并不是孤立的程序,通过一个运行在CPU上的程序来协调渲染管道,它们通常是共同(in concert)执行的。 此外CPU程序还以纹理或填充寄存器常量的方式,为着色程序提供参数。

         虽然本文没有具体描述特定硬件新图形管道的构架,但图形管道的设计很大程度上都是根据硬件实用性以及多硬件并行处理来设计的。此外,当前硬件实现的结构体系也将延续或者影响我们的设计。



3.图形管道

         Direct3D保留了通用硬件加速器的3D管道结构。我们添加了两个新的阶段,并对其他的阶段进行了简化或者进一步归纳(generalized)。基本的图形管道如图1所示。为了保证文章的连续性,我们将讨论图形管道的每一个阶段,而不是只讨论新增的两个阶段。为了和以前的术语一致,使用了通用的术语,比如 顶点(vertex),纹理(texture)以及像素(pixel),但需要注意,这些术语只表示普通用法中的某些特定含义。

         Input Assembler(IA)从附加到顶点缓冲上的8个输入流中接收1D的顶点数据,并且把数据项转换为规范的格式(比如,float32)。可以为每个流指定独立的顶点结构,每种结构最多包含16个域(也称为元素,element)。每种元素可以由1到4个基本数据项组成(比如,float32s)。通过读取当前的有效流来装配(assembled)顶点。一般来说,将会连续的从顶点缓冲中读取顶点数据,但是,如果指定了索引缓冲,那么每个流将使用共享的索引来计算每个顶点缓冲中顶点数据的偏移值。指定索引可以带来额外的性能优化,顶点处理器将根据索引值计算结果,通过用索引值作索引的结果缓存,可以避免使用相同索引重新计结果(译注:这里的结果因该是指顶点数据序列)。

         此外,IA还提供了一种机制,允许IA高效的复制对象n次。这种机制是实现instancing的解决方案,把包含k个顶点的数据块(block)复制n次。同时,将使用当前的实体(instance),图元(primitive),以及顶点id对图元数据进行“标记(tagged)”,在可编程阶段,可以访问这些id,以便计算变换,材质等参数。



Vertex Shader(VS) 通常用来把顶点从模型空间变换到裁剪空间。VS读取一个顶点,输出一个顶点。VS与其它可编程阶段一样,有一些共同的特性,包括支持扩展的浮点、整数、控制类型,可以访问128块内存缓冲(纹理)以及16个参数(常量)冲。我们会在第四节详细讨论这些通用核心(common core)。

         Geometry Shader(GS) 把同一图元的所有顶点作为输入,产生新的顶点或者图元。输入和输出图元的类型不一定要匹配,但对着色程序程序来说是固定的。以发射额外图元对象的方式,GS程序可以增加输入图元的数量,每一次调用(per-invocation)最多产生1024个32-bit的顶点数据。三角形和线段被输出为连续的顶点带。在一次调用中,GS程序可以输出1个以上的图形带,或者删除输入的图元,不进行任何输出。GS程序同样可以在不产生新几何体的情况下,把额外的属性附加到图元上,比如为每个图元计算额外的属性。由于可以访问当前图元的所有顶点,因此,计算三角形平面方程(triangle’s plane equation)之类的几何属性将会容易。

         除了输入图元之外,还可以处理三角形和线段的邻接顶点。每个三角形包含三个顶点,以及三个邻接顶点,而每条线段则包含2个顶点以及2个邻接顶点。对于三角形和线段来说,邻接顶点将作为顶点缓冲格式的一部份,当指定(渲染)了带邻接的图元拓扑之后,IA会对提取邻接顶点。


         Stream Output(SO)将把GS输出的顶点信息复制为4个连续的输出缓冲子集。理想情况下,SO的输出能力(不带索引)应该和IA(8 streams * 16 elements)的输入能力相匹配,但硬件代价是不合理的。SO只能输出一个1~16元素的流,或者4个单一元素的流。此外, IA可以读取8或者16bit的数据类型,并把他们转换为float32,而SO只能写入原始的32-bit的数据类型。但是,数据类型转换和打包可以在GS程序中轻易实现,减少了固定功能的支持。

         Set-up and Rasterization Stage(RS) 是一个功能固定的阶段,用来处理剪切(clipping),剔除(culling),透视划分,观察点变化,图元设置,裁剪(scissoring),深度偏移,以及片断(fragment)生成。现代GPU设计总是包含某种形势的早期深度处理(z-cull,hierarchical-z)。我们将明确讨论这种优化,因为对应用程序开发者来说,它变的不太透明了。RS的输入是单一图元的顶点以及属性,输出一系列像素片断。

         Pixel shader程序指定了通过顶点属性插值产生片断属性的方式(no interpolation, non-perspective-corrected interpolation, or perspective-corrected interpolation)。现代GPU通常支持多采样抗锯齿。当一个片断不包含像素的中心时,需要很小心的指定属性赋值行为,因为中心点的值有可能超出范围。通过片断边界,可以使用赋值限定器(质心centroid)来指定所需的值。

         Pixel Shader(PS)读取单一像素片断的属性,输出包含1~8个属性(颜色)以及任意深度值的单一片断。每个属性值(元素)要么被分别写入单独的颜色缓冲中(称为渲染目标),要么完全丢弃(不输出片断)。一般情况下,深度和stencil值来自于RS。PS可以可以替些深度值,但无法改变stencil值。无论是丢弃像素还是重写深度值,都有可能影响RS中的深度处理优化(depth-processing optimizations),因为这样做会改变片断的可见性。

         Output Merger(OM)接收来自于PS的片断,执行普通的 stencil和深度测试操作,以及渲染目标混合。OM为一个统一的depth / stencil缓冲以及8个其他的渲染目标(属性缓冲)指定了约束点(bind point)。Pixel shader必须分别为每个渲染目标输出单独的值(不支持多点传送)。此外,所有的渲染目标都共享一种混合功能,但是,可以对每个渲染目标独立的激活或者屏蔽混合。


TOP

3.1 内存结构以及数据流

         现代GPU很大程度上都在处理持续性(retained)的数据结构,包括顶点和索引缓冲,纹理贴图,渲染目标,以及depth/stencil缓冲。GPU通常把这些数据储存在直接连接到它自身的高性能内存系统中。数据结构的类型包括1D到3D的图片、 2D的立方贴图(所有贴图都可以选择是否包含mipmap层次),以及1D同族(homogenous)或不同族(heterogeneous)的索引以及顶点缓冲。为了提高效率,Direct3D 10对这些数据结构进行了统一,统称为资源。性能在两个方面得到了提升:首先,在一个单独的渲染pass中,可以增加处理数据的范围;第二,增加了易用性,可以在第一个pass中产生资源数据,然后在接下来的渲染pass中使用这些数据。

         单pass渲染效率的提高得益于几个方面。首先是数组化资源(arrayed resources)。纹理以及渲染目标将被创建为一个同类型资源的线形数组(最多包含512个元素),并且作为纹理或者渲染目标,约束到图形管道上。用于处理纹理的着色指令将包含由着色器计算(shader-computed)的数组索引。这减轻了应用程序开发者把多张图片打包为一张纹理,以及控制纹理坐标选取子纹理的工作量。但是,纹理数组队对打(解)包尺寸不一致的的图片不一定有用,应为数组中的元素都应该具有相同尺寸。

         当把一个渲染目标的数组约束到OM时,将为GS中的每个图元计算目标数组索引。这允许GS把图元分类(或者复制)到不同的数组元素中。使用一个pass,把环境渲染到包含6个2D渲染目标的立方贴图就是例子之一。当处理环境中的几何体时,由GS决定把图元渲染到立方贴图的哪个面,并且为每个面输出(issue)一次图元。需要注意,GS的渲染目标数据选择机制与PS的多渲染目标输出是独立的。

         为了激活render-to-cube-map以及简化数组的使用,我们为资源引入了view的概念(resource are extended with the notion of a view),要么选择资源中的一个子集(e.g 选取数组中的一个元素),要么把额外的类型数据绑定到部分类型化(partially-typed)的资源上。对后一种情况来说Direct3D 10允许创建不受特定元素类型约束的资源(e.g float16,snorm 16,etc)。这在一定程度上允许了储存类型的“转换”,数据类型可以改变,但数据类型的大小不能变(e.g 不能把两个float16当作一个float32 来对待)。不能直接把资源约束到管道上;而需要通过view来绑定。同一资源的两个不同view可以同死约束到管道上。

         在接下来的pass中使用渲染好的立方贴图是multipass渲染或重复渲染的一个例子,它们都是由Direct3D 10更加灵活的资源模型来实现。另外一个类似的有用特性就是render-to-vertex-buffer。实现方法之一就是把顶点缓冲作为渲染目标(使用一个view)连接到管道上,使用着色器中的一个阶段来计算新顶点数据,并且把它当作颜色熟悉数据传递到余下的管道,输入渲染目标。这种方法的复杂性在于:数据尺寸以及顶点元素类型一致性(4 x float32)的限制, 相对简单操作却需要使用管道的多个阶段(e.g VS and PS),以及如何把1D顶点数据映射为2D渲染目标的问题。Driect3D 10应用程序使用view来选择顶点缓冲中邻近的子区域,并把它作为宽度为n,高度为1的2D渲染目标,子区域的最大宽度为8K个元素。

         流输出的特性提供了交替(alternative)处理连续1D输出的能力。流输出的特性之一就是支持丰富的输出格式,举个例子来说,可以输出相当于每个顶点16 x 4x float32个元素的数据,也意味着更大的缓冲(128MB vs. 128KB)。流输出不支持随机访问(分散scatter)输出流中的数据,相反渲染目标的方法却可以,通过绘制点和使用VS修改渲染目标点坐标的方法来控制寻址。出于这些原因,两种方法都是很有用的。

         为了支持重复计算,根据资源将会连接到图形管道的哪一个约束点(bind points),我们放宽了资源系统规定参数(constraints)的范围(i.e IA buffer, VS/GS/PS texture, SO buffer,以及OM render targets),并把view作为适配器(e.g 渲染到一个单独的mipmap层次,或者3D纹理中的2D片)。然而,这些适配器并不是完全通用的:2D资源不能当作1D资源来处理,由单一元素组成的同族资源不能转变为非同族的资源,比如多元素顶点缓冲。这些限制主要是为了防止对整个资源结构的多重定义(reinterpretation),以便硬件实现优化储存层次。同样,同一资源不能同时作为输入和输出数据的限制仍然存在。




3.2 储存格式

         虽然在着色器上操作的都是32-bit的数据(浮点或者整数),但是我们提供了丰富的数据储存类型来减少内存占用以及带宽。如果数据类型不是8-bit的整数倍,那么将被和其他类型的数据打包到一起,组成8-bit的整数倍数据。几乎可以使用所有格式来处理顶点缓冲,纹理,流输出(使用手动转换和打包),以及渲染目标。下表列举了这些数据类型。




  Unorm,snorm,以及float16(half)是已经被广泛使用的格式。虽然float16对高动态范围(hight-dynamic range)图片的应用很有吸引力,但他需要消耗过多的储存空间,以及内存带宽。Direct3D 10提供了两种可选的32-bit打包方式:两个float11(R,G)和一个float10(B)的组合,以及一种共享指数?(shared-exponent)的格式—R、G、B每个元素9-bit,指数5-bit。这些类型被限制为正数,可以提供与float16一样地动态范围(10个数量级 order of magnitude)。对于低精度的情况来说,11-11-10的格式是渲染HDR颜色数据的目标(destination)格式,而共享指数的格式则被限制为用来进行纹理操作的源格式。共享指数的格式使用了一种比较复杂的编码方式来避免人工效果(artifacts),因此被限定为只读的。

         除了这些简单的压缩格式之外,Direct3D 10还增加了一种4x4 texel block compression (S3TC) 格式。这种格式一到四元素的版本,分别可以提供8:1,6:1,以及4:1的压缩率。包含三到四个颜色元素的格式适合于低动态范围(low-dynamic-range)颜色,而二个元素的格式则适合于切线空间的法线图数据。




3.3设计考虑

         另外还有几个构架设计决定也是值得讨论的。

         与前一代的技术相比,Direct3D 10要求所有特性都必须由硬件来实现。但其中有两个例外的地方:代价昂贵的32-bit浮点纹理过滤,以及包含多采用(multisampler)抗锯齿的渲染纹理格式。这增加了实现提供者的负担,但也反映出应用程序开发者更注重性能,而不是如何解决特性难题。强调硬件对重要格式的支持,增加了他们支持各种不同应用程序的可能性。

         从管道与核心API中移除了所有可以通过可编程体系实现的传统固定管道功能。包括顶点变换,光照,点精灵,雾,以及alpha混合。虽然使用软件可以轻易模拟固定功能的特性,但我们相信为了减少复杂性,应该通过其他的库来实现这些功能,而不是核心API。

         尽管我们对管道进行了比较大的改动,但固定管道中一些重要的部分仍然存在。在早期的考虑中,我们曾希望把IA也作为完全可编程的部分,允许实现复杂的索引风格或者顶点布局(layouts),但最终我们认为这些额外的复杂性不一定是有用的。相反,VS的内存读取功能允许在VS中实现复杂的索引方案(indexing schemes);事实上,可以只计算顶点的id,而不从IA中读取任何数据。不管怎样,出于性能的考虑,我们仍然保留了一个强大的IA,它在管道中的位置和功能可以为硬件在管理与顶点相关的内存通信时提供便利。

         对于GS来说,涉及到许多复杂的设计问题。其中,比较重要的管道性能权衡之一,就是在保持顺序操作的情况下实现并行。GS保留了输入数据的顺序,因此,多个并行执行的GS单元不能发射出超出顺序(out of order)的图元。这需要对并行的实现做一些变化:缓冲他们的输出,按照输入顺序依次处理整个缓冲。高效的缓存管理,可以根据输出数据的上限,以及GS程序的能力,来指定一个较小的(译注:缓冲)界限(bound)。1024个32-bit值的最大限度(ceiling)是硬件代价和有效放大率(amplification)的折衷,比如,挤出(extruding)三角形的边。毫无疑问,使用GS来进行更大的尺度缩放——比如镶嵌(tessellation)——是很有诱惑力的,但是,我们预料这将会导致性能的迅速降低。

         在应用中,GS包含了和RS同样多的功能。虽然我们希望GS执行族划分(homogeneous devide),观察变换,等等。但在这些操作之前进行剪切是不切实际的,因此,在剪切时,GS-RS进行了划分。GS执行一些剪切设置,e.g 计算顶点到模型剪切平面(model clip-plane)的距离,之后,连同顶点在裁剪空间的坐标,一起传递给RS。由于没有精确定义过固定功能的RS顶点处理精度和准度设置,因此对GS来说,虽然误差不大,但无法精确模拟变换,来产生图片空间(image-space)的坐标。这限制了GS的通用性,无法实现一些基于图元的图片空间坐标的算法。

         最后,固定功能对OM的限制也是经常讨论到的。OM单元是唯一的同时支持内存读写(read-modify-write)的阶段,这也是可编程单元经常需要使用的特性之一。有人曾提出把OM的功能合并到PS中。但是,管理复杂管道要承担的风险,以及最大化内存系统的效率的需求,都没有理由证明这种合并是有必要的。由于PS的计算都是在像素片断上执行,而混合(blend)操作是基于采样来计算,因此,多采样(multisampling)进一步复杂化了结构。促使PS依据采样粒度来执行,对性能有重要意义。此外,使用提前的depth和stencil遮挡优化,也能极大的提高性能。

4.Shader Model 4.0

         在以前的Direct3D版本中,可编程管道阶段都是通过每个阶段独立的虚拟机来实现,i.e.,顶点和片断处理器。每个虚拟机都被描述为一个基于寄存器的冯.诺依曼式处理器(register-based Von Neumann-style),包含一组和汇编语言类似的指令,作为交互阶段之间的通信的输入和输出寄存器,通用寄存器(也称为临时寄存器),以及一组连接到纹理之类资源的资源绑定点。

         Direct3D 10定义了一个称为“公共核心(common core)”的虚拟机,作为每个编程阶段的基础,如图3所示。这个虚拟机保留了以前模型中的许多特性,比如基本的4 –tuple寄存器,以及浮点运算操作,此外,还增加了以下特性:



l          32-bit的整数指令(数学运算,位运算以及转换);

l          通用和索引寄存器将使用统一的内存池(4096 x 4);

l          独立的不过滤或者过滤内存读取指令(加载和采样指令);

l          不相关(decoupled)的纹理绑定点(128)和采样状态(16);

l          支持阴影贴图采样;

l          多层(16)常量(参数)缓冲(4096 x 4);

以上几点,就是显卡功能的主要增加部分。这个统一的模型,能让GPU上各种算法,逻辑和流程控制指令更接近于CPU。寄存器,纹理绑定点以及指令储存空间都得到了显著的提升,将不会是未来几年,困扰开发者的问题。随着资源量的增长,为了不影响性能,硬件实现将发生一定的线性退化。

很显然,随着纹理绑定点的增加, 并不需要增加相同数量的独特纹理过滤组合(unique texture filtering combinations)。相反,我们将减少采样阶段的耦合,用单独的对象和采样指令来指定纹理和对其进行采样的采样器。通过load指令,以非标准化寻址(non-normalized addresses)的方式,可以读取未经过滤的纹理。

满足常量储存空间的增长和高效更新常量的需求,是一个挑战。当前系统的问题在于高效的更新单独的常量单元,以及管道化(pipelining)更新的操作两方面。当需要在多个shader程序之间转换时,这个问题会更加严重,每一次都需要重新加载与新shader相关的所有常量。其中,很明显的解决方案之一,就是以不同的频率来每次更新一个常量组(e.g 每帧一次,每个对象一次,每个对象实体一次)。这样,我们就能把常量储存空间分为独立的缓冲,同时,把更新常量与把常量绑定到管道的操作分离开。分离这些操作,允许(注:硬件)实现更好的完成两种操作的管道化。因为这些操作将等同于处理纹理资源,我们考虑过随纹理移除(remove)或统一(unifying)常量。

但是,在许多重要方面,常量和纹理的引用方式是不同的。通常,常量的访问频率比纹理高的多,同时,对一组顶点或者像素来说,将使用相同索引。相反,纹理的访问频率则比较低,此外,索引值(纹理坐标值)也是不同的。这表示在实际的硬件实现中,处理常量和纹理的方式是截然不同的。

         还有一个不太明显,但对处理核心来说同样重要的地方,就是数据的呈现方式,算法精度,以及(注:数据)行为和以前的版本相比,都有更加严格的规范。因为大部分人都只把着色程序,常量以及其他管道阶段认为是应用程序艺术创作内容的一部分,而没有认识到他们是执行引擎(execution engine)的一部分。因此,为了保证这些内容在不同实现间的可移植性(portable)以及不同代系统间的兼容性,有很大压力。当然,这也反映出了可编程着色所取得的成功。

         我们尽可能的在所有地方都避免了使用自定义的行为,而遵守CPU标准。为了获得精确的行为,我们花了几年时间,转向IEEE-754[IEEE 1985]定义的单精度浮点数据呈现方式。对这一代的显卡来说,基本的运算操作(加,减,乘)都精确到1 ulp(而不是IEEE-754中定义的0.5ulp)。除法和平方根精确到2ulp。非规格化数将被近似为0 (Denormalized numbers are flushed to zero)(但是将被定义为float16类型的数据),并且完全实现了IEEE-754文档(NaNs,无限大)。部分差异是由于实现代价和实用性的考虑而产生的,在设计中,我们放在第一位考虑的是在不同硬件实现间创建良好定义的(well-defined)、一致的行为,其次才是在合理的硬件代价之下,提高精度。

         其中比较大的设计决定争议之一就在直接采用IEEE-754特定行为(special behavior)。在前一代(shader model 3.0)的系统中,我们就引入了这一行为,但对于那些依赖于把NaNs近似(flushed)为0的系统来说,带来了一些与可移植性相关的问题。虽然我们考虑了添加一个独特的模式来允许特定的抑制(suppression of specials),但最终我们决定:让未来所有的硬件都支持这个功能,虽然在很长一个时期内都将付出昂贵的维护代价,但能在短期减少shader开发的复杂性。

         这个严格的规范不仅限制了可编程单元,还将影响到过滤、光栅化,subpixel precision,数据转换,混合操作等各方面规则的定义。我们的目标有两个:对应用程序的开发者来说,保证行为的一致性和可预言性(predictability)。

         为了实现这些目标,需要仔细讨论关于NaN-propagation,算法优化或者内存操作,包括0和1的系数???等等(Pursuit of these objectives necessitated detailed discussions about NaN-propagation, optimizations of arithmetic or memory operations involving coefficients of 0 and 1, etc)。总的来说,我们尽量在对性能有重大优化的地方达成妥协。



4.1 Stage-Specific Functionality

         每个独特的着色阶段可能会有一些独特功能,来扩展普通行为。这些特点包括输入和输出属性寄存器的结构差异,以及额外的指令。对VS来说,16x4浮点数据元素的输入和输出结构,定义了公共核心。

         GS可以读取上面这个值6倍数量的顶点,因为它不但必须读取一个三角形的所有顶点,还必须访问3个邻接顶点。由于GS可以输出一个以上的顶点或图元,它可以使用其它阶段的流模型:把值累积(accumulated)在输出寄存器,在程序结束时产生输出信号。我们添加了一条emit指令,作为把累积的结果输出给下一阶段的信号。同样,我们还增加了一条cut指令,作为一条图元带结束的标志。GS使用一条编译时配置指令(compile-time configuration directive)来指定最大输出量。每个输出的顶点都可以包含多达32个4 x float32的元素,作为RS的输入,并且接下来再作为PS的输入。这个值是vertex shader的两倍。这些额外的资源将把裁剪和剔除信息传递给RS,同时也可作为传递给PS的基于每个图元数据的额外信息。

         PS有32x4个输入寄存器,但只能在GS处于激活(active)状态时才能完全使用它们。如果GS没有处于激活状态,那么PS只能使用来自于VS的16x4个值作为输入。这些输入值将包含编译时的指令,用来指定对每种属性的赋值(插值)方式。PS的输出直接连接到8个渲染目标上,因此,它有8x4个输出寄存器,外加一个深度寄存器。PS添加用于丢弃像素的指令,避免把这些像素渲染到渲染目标上,此外还将添加计算图像空间(image-space)微分(derivatives)的指令。只有PS阶段包含内建(built-in)的屏幕空间概念,因此,即使VS和PS都包含纹理采样的指令,但它们并不包含用来计算mipmap过滤的LOD指令,也不包含微分指令。当条件表达式在像素间发生变化时,在流程控制语句中的微分行为将会出问题(ill-defined)。因此,通过编译时的强制,不允许在非标准(non-uniform)流程控制中使用微分指令。

         最后一组支持数据交换的特性是为IA和RS之类的固定功能的阶段而设计的。举个例子,IA产生一组系统生成的值(system-generated values):顶点,实体,图元id,同时RS产生一个值用来指定某个多边形是正面还是背面。类似的,RS接受来自于shader的系统插值数据(system interpreted values),比如图元中每个位置的纹理坐标,剪切和剔出距离,以及渲染目标数组索引。系统生成的值,声明为相应的系统生成名称(system-generated name)之后,作为可编程阶段的输入数据。相反,系统插值数据是通过在可编程阶段把输出数据定义为相应的系统插值值的名称(name of the system-interpreted value)来生成。这些值可能会在shader所用的众多输入输出寄存器中产生不利影响,因此某些情况下必须对它们进行定义,否侧将返回错误结果(e.g., RS需要从各种属性中分辨出位置信息)。共享其他类型的寄存器用来输入和输出保证了整体构架更加规则,同时避免浪费资源,

         虽然在可编程阶段中创建一种机制来管理固定功能阶段(e.g. 混合模式,depth or stencil configurations)是很有吸引力的,但当前,我们我们只允在对一定阶段进行这些操作。

[ 本帖最后由 爱你一棒陲 于 2007-7-17 15:02 编辑 ]



TOP

Z天湿咋不进来指点江山激扬文字粪土.XXX.呢?


TOP

哇~原来~

字真多`
没看~

TOP

要画面,目前还真没看到什么特别震撼的

TOP

真正意义上的DX10游戏还没诞生呢,但是DX10带来的理念比DX8到DX9的过渡大得多,具有开创性的重大意义。

[ 本帖最后由 爱你一棒陲 于 2007-7-17 15:28 编辑 ]

TOP

占个位置等天师进来指点江山……

TOP

引用:
原帖由 爱你一棒陲 于 2007-7-17 15:26 发表
真正意义上的DX10游戏还没诞生呢,但是DX10带来的理念比DX8到DX9的过渡大得多,具有开创性的重大意义。
什么时候出现

crysis除了海水还真没什么特别有印象

TOP

天师的中文能力应该没问题吧:D

TOP

引用:
原帖由 chovosky 于 2007-7-17 15:31 发表


什么时候出现

crysis除了海水还真没什么特别有印象
什么时候GS和SO应用像PS\VS一样平常效果自然就来了,最大的好处就是逼真的粒子、茂密的植被、烟雾、云气,再不是平板一块的水面和溪流。封闭环境处理倒不见得来得那么有冲击力,毕竟DOOM3做得已经很不俗了。

TOP

很容易理解,DX8游戏繁荣是在DX9显卡开始上市之后,DX9游戏繁荣是DX9C版本出现之后。

同理可证,DX10游戏繁荣,是在DX11发布前后。

TOP

唉,天师要战只要脸皮厚就行,哪里需要真正对技术的了解

TOP

引用:
原帖由 liuyicheng 于 2007-7-17 15:40 发表
很容易理解,DX8游戏繁荣是在DX9显卡开始上市之后,DX9游戏繁荣是DX9C版本出现之后。

同理可证,DX10游戏繁荣,是在DX11发布前后。
很对,而且恰好说明理论和现实存在不可弥合的差距。要说起来XO也支持GS和SO的,可又有哪个游戏有DX10游戏该有的效果呢?没有,起码现在没有。神机也可以玩GS,一样是理论上,可有些人看见这些噱头听风就是雨,立马成了炮轰对手的本钱,HIGH得都不行了。

TOP

哦,知道了.

TOP

天湿要是技术流,乌龟都能上树

TOP

 25 12
发新话题
     
官方公众号及微博