搜档网
当前位置:搜档网 › Direct3D 10系统

Direct3D 10系统

Direct3D 10系统
Direct3D 10系统

摘要

本文描述了第四代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必须分别为每个渲染目标输出单独的值(不支持多点传送)。此外,所有的渲染目标都共享一种混合功能,但是,可以对每个渲染目标独立的激活或者屏蔽混合。

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)是很有吸引力的,但当前,我们我们只允在对一定阶段进行这些操作。

5 Core API and Runtime

我们把API和运行时分为了两个独立,但是完整的部分:核心API/运行时以及着色语言/状态管理系统。我们将讲述新运行时中几个比较重要的部分,以及与当前系统相比的变化。

核心API以及运行时作为硬件系统上的一个薄抽象层(thin abstraction layer),扮演了low-overhead的角色。可编程管线的转变和固定功能冗余功能的移除,戏剧性的简化了API和运行时。API为以下操作提供服务:分配以及修改资源;创建视图状态并把他们绑定到管线的不同部分;创建shader并且把他们绑定到管线;控制管线不可编程部分的状态;初始化渲染操作;通过检索统计(retrieving statistics)或资源内容,从管线中查询信息。

5.1 StateManagement

我们要解决的主要问题之一,就是减少应用程序到硬件之间传输指令的端到端的消耗。我们把指令分为两类:分配或释放资源的类型,以及改变管线状态的类型。其中,我们特别关心后者,因为他们在应用程序中将频繁出现。我们使用了一个简单的模型,来把这些指令传递给管线。运行时将为应用程序的指令分配一块内存缓冲。每条通过运行时到驱动的API指令,都将转变为特定的硬件指令,并储存到这个缓冲里。当缓冲被填满或另一个操作需要同步渲染状态的时候(e.g 读取一个渲染目标的内容),整个缓冲就被提交给硬件。

在过去10年的PC系统上,运行时模型几乎没变化。我们的目标是在不需要额外处理的情况下,把指令附加到缓冲中。在过去,这显然是不切实际的,因此,我们尽量了解其中的原因,并且寻找和修改设计方案,让我们的模型接近这个目标。

我们发现在运行时和驱动两方面,都有一些原因,会带来额外的处理。

l API和硬件之间的不匹配

l 延迟处理的风格(deferred processing style)

l 错误传输应用程序请求

上面三个原因中,第三个是最容易解决的,只要在应用程序开发者,运行时,驱动,以及硬件提供者之间达成一致,就能极大的改善情况(e.g 不是10%而是数十倍的提高)。

第二个问题涉及到传统的实现策略:当图元提交到管线时,分辨哪些状态改变是累积的。这样做的优点是可以成批的处理一组状态的改变,同时,相互独立的(非正交的non-orthogonal)状态实现可以一起处理,而不是每次处理相关改变中一个独立的状态。他还允许丢弃冗余状态。但是,这些功能都需要占用额外的CPU周期来记录改变,并且进行全局控制。非正交的灾难性例子之一,就是纹理绑定的改变,需要重新编译shader,以适应新的纹理格式。我们提倡尽可能减少对硬件状态实现的依赖性,把对冗余状态改变的处理,划分到运行时中一个可选的层来处理。

第一个问题涉及到多种类型的不匹配。重编译shader时的正交不匹配??就是例子之一(orthogonality mismatches as exemplified by the shader recompile example),当然还有很多种其他情况。原因之一与状态改变的粒度(granularity)有关。无论OpenGL还是以前的Direct3D本版,都把状态改变的粒度定义的非常精细(fine granularity),e.g,改变一个混合因子,或者改变一种采样模式。我们已经进行了许多尝试,努力把状态改变集中到一起,以提高效率,比如,使用OpenGL中的显示列表或者Direct3D 9中的状态块(state blocks)。虽然这些解决方案可以工作的很好,但是,我们选择了一种更简单的方法。丢弃固定管线的冗余功能已经大大减少了总的状态种类数量。通过分析,我们发现当前过细的粒度划分,并没有什么优点,因此,我们把分散的状态组织为了较大的,相关的,不可变的聚合体(immutable aggregates)成为状态对象(state objects)。这样可以建立一个清晰的模型,指明哪些状态应该是独立的,哪些不是,从而减少完全重新装配管线所需的API调用数量。我们发现使用了这些新API 的程序,能提高匹配的准确性。

Direct3D 10定义了5个状态对象:InputLayout(vertex buffer layout),Sampler,Rasterizer,DepthStencil,以及Blend。这样的划分,反映了状态逻辑上的关系,如果应用程序需要单独频繁的改变某个独立状态,那么可以进一步对此进行细分。当创建状态对象时,驱动将为此状态创建相应的硬件表示(e.g,一组寄存器值),当对象需要绑定到管线时,相应的命令就被复制到命令缓冲中。某些硬件实现可能会在硬件中保留(缓存)状态表示,从而减少把API命令转换为硬件命令的代价。

在第四节中,我们描述了更新管线常量时可能出现的问题。他实际上只是管道故障(hazards)中,比较普通的一种。当某个值即将被使用,但之前的值仍在使用时,同样可能导致一些故障。解决这个问题通常使用的方法就是,使用额外的储存空间来保存新值,同时,重定向引用,指向新的缓冲。

另一种故障发生在从刚写入数据的资源中读取数据时。比如,把之前的渲染目标作为纹理来使用。当进行这样的交换时,要求渲染指令已经执行完毕,同时,所有数据已被写入渲染目标,这样才能从中拾取数据。与前面的描述的更新故障不同,read-after-write故障更难,或者根本不可能在API和运行时中解决。为了避免在这种情况下对管线造成延迟(stalling),应用程序在构建时,就应该尽量避免渲染操作需要立即读取之前渲染目标中的数据。

5.2 Validation and Error Handing

部分API设计的原则是避免发生错误,或者避免对某些使用频率较低,但代价很大的操作进行错误检查,比如对创建对象进行检查,而不是对使用对象检查。虽然我们对性能的需求,不允许通过API对已部署的程序进行过多错误检查。这里,我们的错误检测和报告策略是把错误分为两类,致命和非致命的。在任何版本的运行时中,都会对致命错误进行检测和报告。非致命错误的检测则是通过一个单独的监听层来完成,它对运行时来说是透明的。这个验证层最初是在程序的开发时使用,当部署程序的时候,开发者通常会屏蔽它。为了检测错误,它通常还会寻找和报告API的不理想(non-ideal)使用类型。可以对这个验证层进行控制,指定他对哪些错误进行探测和报告。

错误分化的方法确实有一点点模糊(ambiguity):哪些错误总是会被检测,哪些没有被检测出的错误将有怎样的行为?未定义的错误行为稍后可能会转变为一种unintended but relied upon (defacto) behavior。再者,如果运行时没有检测出某个特定的错误,那么驱动将忽略性能代价,尽力避免出现灾难性的硬件错误。我们将努力鉴别出这种错误,并且在运行时中对他们进行检测。另外,在渲染时,我们不会进行任何错误检查,e.g,错误检测将被延迟,直到一个Draw命令完成。致命错误保护扩了深度缓冲和渲染目标尺寸不匹配,同时把一个资源绑定到读取和写入操作上,等等,不致命的错误则包括:不匹配的shader类型联接(签名),以及数据格式声明不匹配。

在当前着色编成模型发展的阶段,捕获着色程序运行期间的错误代价是很大的。因此,我们定义了完善的行为,比如,当数组越界时返回0,来获得一致的行为。从长远来看,硬件将会支持异常机制。

5.3 Resource Mapping and Access

API和管线设计比较复杂的问题之一,关系到如何在CPU和GPU之间共享资源。举个例子,无论Direct3D还是OpenGL都允许

顶点缓冲映射到程序的地址空间中,而不管缓冲具体是分配在系统内存还是显存中。但是,分配的位置将会导致性能的巨大差异。现代图形加速器上,显存和加速器之间的带宽可能超过50GB/s,而PCI-E则只能为系统和GPU之间提供2.8GB/s的带宽。此外还有一些其它的问题。比如,CPU对所访问的数据缓存与否,同样会带来很大的性能差异。同时,是否write-combine,也会造成同样的差异。另外,当GPU访问资源时,为了提高空间的一致性,资源加载的方法可能是form row-order to another(e.g, Morton, boustrophedon, or pi orders), or tiled [Blinn 1990; Hakura and Gupta 1997; Igehy et al. 1999]。我们认为这些方法本质上都是为了保证分割模式(tiling pattern)对应用程序透明,因此,当资源映射到CPU时,应该是以线形方式组织的。由于分割模式同时也依赖于访问模式,2D和3D纹理之间是有差异的,而且这种差异不仅仅是CPU和GPU之间的不同造成的。出于对性能的重要用影响,我们尝试暴露所有这些功能,但由于其本身的复杂性,却很难让应用程序真正获得性能上的提升。我使用了一个简单的模型,尽力提供了尽可能多的功能。

我们对特定资源的写入者和读取者进行了分类,e.g,GPU vs.CPU以及read vs. write。如果最初只有一位客户访问资源,那么问题就变得简单了,因为可以采取对主要客户比较有利的方式,来分配资源。同样,如果可以预知资源将被用来读取或写入,也会有很大帮助。幸运的是,这样的描述完全可以覆盖大部分典型的应用范围。比如,渲染目标和纹理主要由GPU进行访问,并且分别被限制为写入目标和读取资源。另一方面,顶点缓冲的使用就比较复杂了。虽然静态的集合体主要由GPU来读取,但是动态的几何体则常常作为动画的一部分,先由CPU来生成,在由GPU进行处理。这些操作将导致频繁的CPU写入和GPU读取处理。

Direct3D 10根据使用类型,把资源分为3类:default, immutable, dynamic,以及staging。Default对应比较简单的纹理,渲染目标,或者只由GPU访问的静态顶点缓冲。Default类型资源的初始化,通常需要复制另一资源的数据来进行。Immutable类型的资源不允许复制操作,但是在创建时,提供了另一种方法来进行初始化。Default和immutable类型的资源都不能映射到应用程序地址空间中,让CPU对它们进行访问。动态资源不但可以在管线中使用,也允许映射到CPU,进行只写的操作。适合于生成顶点数据,或者进行视频解码,等等。最后,staging类型的资源只允许CPU对其进行访问,但是,可以对它的数据进行复制。Staging类型的资源对于初始化或者获取只有GPU能访问的资源时比较有用。

为了检查资源可以绑到管线的哪个位置,将在创建资源时,对资源的布局(placement)和编码方式进行验证。这些分类包括:顶点缓冲,索引缓冲,常量缓冲,shader资源(纹理),输出流缓冲,渲染目标,或者depth/stencil缓冲。这样的分类有两个目的:为驱动提供资源布局的信息,简化使用资源时的错误检查。

5.4 HLSL 10

高级着色语言广泛,迅速的被人们所接受,无疑显示了这种语言的重要性。为了支持新管线的特性,我们对高级着色语言――HLSL 也提出了一些新的目标。简单的说,我们希望应用程序开发者使用HLSL高效的开发程序,而不需要了解虚拟机的复杂细节,比如,寄存器名称或常量缓冲索引。我们把目标精炼为以下几个小点:

1.应用程序不需要了解资源是如何配置和分配的。

2.把bind-by-position作为主要的绑定机制,而不是现在的bind-by-name。

3.程序员不再需要编写中间(汇编)语言代码

第一个目标主要用于解决下面这个问题:当前系统中,应用程序开发者需要学会控制常量储存空间中的参数布局。开发者需要对多个shader进行全局分配和布局(global allocation and placement),以便在多个shader之间共享某些变量。通过在每个管线阶段添加的多个常量缓冲,我们相信,编译器有足够的信息能自动对缓冲进行布局,当然,程序员还是要控制把参数分配到常量缓冲中的操作。我们对语言进行了扩展,允许把缓冲名作为参数的一部分,进行声明。

第二个目标则是设计思想的改变,主要与性能和未来的进一步发展有关系。Bind-by-name主要用于几个地方:对多个shader之间输入和输出数据进行匹配,让vertex shader的布局与vertex shader进行匹配,等等。虽然运行时可以让源数据和目标数据之间的名字匹配操作进行的比较高效,并且实现源—目标对缓存,但我们觉得这些只会带来不必要的复杂性,并且为运行时添加额外的负载。新系统中,将在多个方面发生变化。Shader的输出和输入将与签名(signature)相关,这和C总的函数原形有些类似。只有当前一阶段的输出和后一阶段的输入兼容时,管线才是有效的。兼容意味着输入和输出间element-by-element的对应。这里,我们允许下一阶段的管线,不使用上一阶段拖尾的(trailing)的输出数据。

Bind-by-postion通用影响到IA和SO阶段的顶点缓冲绑定。但是,对这几个阶段,我们将创建独立的对象来封装(encapsulate)绑定,让代价较大的匹配操作只在创建时运行一次。

第三个目标是比较具有争议性的,它表示我们的实现将不支持使用使用中间语言编写的shader作为输入。我们认为着色程序的发展已经达到了一定复杂程度,因此,手写的IL很难比编译器产生的代码高效。此外,当我们改进优化技巧,联接,以及与驱动的交互时,无法保证对手写IL代码的支持和兼容。作为诊断技术,系统将支持编译器生成中间代码作为输出,但是,我们不允许应用程序开发者修改编译器的输出,并把它注入到运行时中。

如何最优化编译器生成的代码性能,有很多问题。首先,是优化的范围,驱动可能允许把中间语言转换为特定机器语言时进行优化。随着shader复杂性的增加,确保开发者在优化之上,有充分的控制权,改变操作的执行顺序是相当重要的。特别是需要保证关键代码的恒定性(invariance),多pass算法应该能生成同样的中间值,以便把这些值复制到分散的shader中。我们考虑了几种在源码上指定中间值的方案,比如,要求以一种特定的方式来编译子程序,而不管这个子程序是否是内连的。但是,研究最终让我们选择了更加常见的方法:使用与驱动编译器相关的,可选择的,定义良好的优化级别。

请注意,我们首选的使用模型是在编写shader时,编译HLSL代码,在程序运行时通过驱动编译IL代码。这样的目的是希望减少程序运行时,编译shader所花费的时间。但是,在运行时再把HLSL编译为IL也是可以的。

5.5 HLSL-FX 10

我们注意到,编程管道的成功,改变了人们的观点,shader程序不但是引擎的一部分,同时,也是艺术家创作工具之一。为了适应这方面的应用,Effect(FX)系统对HLSL进行了扩展,允许使用它来初始化管线的固定功能部分。这和CgFX以及Cg所描述的方法很类似。虽然这些方法有共同的基础,但HLSL-FX是进行了革新的。我们的目标是,FX首先需要满足实时运行的需求,其次,才是作为内容创建者的工具。基于一些历史原因,这两者在很多方面都是由差别的。创作工具常常通过牺牲性能来换取灵活性,而我们的运行时则把性能放在第一位。

通过我们积累的经验和努力,FX系统在易用性和性能方便都有了充分的提高。最终FX,HLSL,API,运行时,以及管线都紧密的结合到一起,作为互补的解决方案。我们同样对频繁的状态操作进行了改变,分离了名字查找以及匹配操作。

再次来讨论处理状态改变的方式。构建应用程序的方法之一是渲染一系列几何体,每个几何体都有其各自的管线配置(一个Effect)。通过设置常量缓冲中的shader参数,纹理绑定,以及其他固定功能的状态,来传递参数给Effect。为了最大化性能,应用程序应该使用一个Effect来绘制所有物体。这是场景管理系统中,传统的状态排序解决方案。但是,对一个Effect来说,可能

有几个层次的参数,比如,当前时间和观察点是属于per-frame的状态;纹理或顶点数据则是角色的静态状态;位置和姿势则是对象的动态状态,等等。我们使用了一个单独的常量缓冲来储存shader每个层次的参数,当绘制物体时,将直接绑定保存静态参数的常量缓冲,保存动态参数的缓冲则要经过更新后再绑定。

在实际应用中,应用程序并不能总是通过Effect来排序对象。通常还可能有其他的机制,控制着绘图,比如物体的远近程度,透明度,等等。我们已经把Direct3D 10系统状态改变的代价进行了充分缩减,因此,重新配置整个管道也是很高效的。

6 System Experience(略)

7 Future Work(略)

8 Conclusions(略)

~~~~~~~~~~~~~~~~~~~~~~~~全文完~~~~~~~~~~~~~~~~~~~~~

呼呼,终于把主要部分都弄完了,希望理解错误的地方不是太多。后3个部分基本都是总结性的东西,就不再翻了。

Direct3D应用中的2D应用

Direct3D应用中的2D应用 2D Application 收藏(转载)2D Application 这一章将讨论IDirect3DDevices9接口怎样应用到简单的两维应用程序里去。然而,接下来讨论的方法和接口的方法不仅仅只应用在两维应用程序里面。 开始我们将看看IDirect3DSurface9接口,它用于存放像素数据。我们将看看怎样创建surfaces,怎样填充数据,并且执行像素拷贝操作。 接下来,我们讨论IDirect3DSwapChain9接口管理back buffer 集合。设备创建的时候都会携带一个默认的swap chain,但是也可以为window模式下多个视图创建新的swap chain。 再接下来,我们将讨论Presentation,Present 也是 IDirect3DDevice9提供的方法。 即使Direct3D可以不使用GDI,但是他们也要处理发送到应用程序top-level窗口的消息。我们推荐使用Direct3D应用程序来处理窗口消息。DirectX 并没有提供直接方法来将

GDI和Direct3D结合起来。但是,通常是在内存DC和流水线产生的结果像素数据上执行GDI操作。

最后,我们将讨论流水线的Video scan out部分以及swap chain从back buffer到front back 的过程。video scan out 电流读取数据,使用cursor overlay,gamma校正以及像素数据转化成monitor的模拟信号。Pixel Surface Pixel 面是像素数据的矩形集合。像素数据的内存layout 是通过D3DFORMAT定义的。在设备上使用surface有几处地方:back buffer surfaces, depth/stencil buffer surfaces,纹理层surface,render target surface 以及图片surface。Direct3D 使用IDirect3DSurface9接口表示一个surface,CreateOffscreenPlainsurface方法可以创建一个图片surface,它能存在于scrath内存池,系统内存池和设备内存池。CreateDepthStencilSurface和CreateRenderTarget分别返回depth/stencil的surface和render target的surface。一个plain surface可能不是3D 渲染的目标,但是你能在plain surface和其他surface之间进行数据拷贝。HRESULT CreateOffscreenPlainSurface(UINT width,

Direct3D 10系统

摘要 本文描述了第四代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),如表一所示:

UML状态图编写规范

UML状态图规范说明 一、状态图简介 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为,显示了该实体如何根据当前所处的状态对不同的时间做出反应的。通常我们创建一个UML状态图是为了以下的研究目的:研究类、角色、子系统、或组件的复杂行为。 状态图用于显示状态机(它指定对象所在的状态序列)、使对象达到这些状态的事件和条件、以及达到这些状态时所发生的操作。 状态机用于对模型元素的动态行为进行建模,更具体地说,就是对系统行为中受事件驱动的方面进行建模(请参见概念:事件与信号)。状态机专门用于定义依赖于状态的行为(即根据模型元素所处的状态而有所变化的行为)。其行为不会随着其元素状态发生变化的模型元素不需要用状态机来描述其行为(这些元素通常是主要负载管理数据的被动类)。 状态是对象执行某项活动或等待某个事件时的条件。对象可能会在有限 长度内保持某一状态。状态具有以下几项特征: 二、状态图内容 2.1 转移 转移是两个状态之间的关系,它表示当发生指定事件并且满足指定条件时,第一个状态中的对象将执行某些操作并进入第二个状态。当发生这种状态变更

时,即“触发”了转移。在触发转移之前,可认为对象处于“源”状态;在触发转移之后,可认为对象处于“目标”状态。转移具有以下几项特征: 一个转移可能有多个源状态,在这种情况下,它将呈现为一个从多个并行状态出发的结合点;一个转移也可能有多个目标状态,在这种情况下,它将呈现为一个到多个并发状态的叉形图。 2.2 事件触发器 在状态机环境中,事件是指可触发状态转移的激励的发生。事件可能包括信号、调用、时间推移或状态变更。信号或调用可能具有其值可用于转移的参数,其中包括警戒条件和操作的表达式。也可能会有无触发器的转移,这样的转移没有事件触发器。这种转移也被称为完成转移,它们在源状态完成其活动后将被隐含触发。 2.3 警戒条件 当转移的触发事件发生时,将对警戒条件进行求值。只要警戒条件不重叠,就可能会有来自同一源状态并具有同一事件触发器的多个转移。在事件发生时,只为转移进行一次警戒条件求值。该布尔表达式可能会引用对象的状态。 2.4 操作

Win7系统Direct3d功能不可用的解决方法

Win7系统Direct3d功能不可用的解决方法 DirectX加速不可用或者被禁用,直接导致我们大型游戏玩不,这对于爱玩游戏的人来说是个麻烦。最近,使用Win7系统的用户,发现Direct3d功能不可用,是由于DirectX组件出现问题,才导致Direct3d功能不可用。那要如何解决这个问题呢?今天,小编就和大家介绍一下Win7系统Direct3d功能不可用的解决方法。 推荐更快速解决方法:系统重装 步骤如下: 1、首先,点开开始按钮,在搜索框里输入“dxdiag”。 2、会搜索出一大堆东西,没关系的,只要打开最上边的“dxdiag.exe”这个程序就行了。 3、Dxdiag的中文名叫做DirectX诊断工具,打开后界面如下图: 4、这时我们在主界面上点击“显示”选项卡(如上图红圈所示),就能看到关于系统中所有与图形有关的内容了(如下图):

5、正常的话,下面“DirectX功能”框里的DirectDraw加速、Direct3D 加速、AGP纹理加速应该都是“已启用”状态,这时你的电脑的显示系统没有问题,玩大型游戏、用CAD软件等,应该都可以正常使用。 6、但是有一部分人的DirectX加速功能是不可用状态,怎么修复呢?确定你的显卡驱动是否正常。

7、注意到画红框的部分了吗?这里就会显示你的显卡驱动是否正常。第一张图为一个显卡驱动正常的系统截图,第二张图为一个显卡驱动有问题的系统截图。通过两张图的对比,各位其实很好看出什么样的叫正常,什么样的叫异常。为了严谨,我还是把驱动中每项参数都简单介绍一下。 8、参数中主程序驱动里面会写着驱动的文件名,如果写的是一大堆文件名(如nvd3dumx.dll,nvwgf2umx.dll等等,不同的显卡品牌这里显示的文件名会不一样,这个无所谓的),就是正常状态,如果只写了vga,则100%是显卡驱动有问题。 9、下面是版本信息,如果是以6.1.7600开头的,那么就是显卡驱动有问题,如果是其他的,就是显卡驱动正常。其实这个6.1.7600指的是Windows 7的版本号,系统只能用自己的版本号填在这,说明显卡驱动就是缺失的。 接下来是日期,如果是2009/7/14 7:25:51,那么就是显卡驱动有问题,如果是其他的,就是显卡驱动正常。其实这个2009/7/14 7:25:51,指的是Windo ws 7系统编译完成的时间。 然后是WHQL签名,这个签名无所谓,不管有还是没有都不影响使用。

Direct 2D与Direct 3D 11协同工作时遇到的一些问题

Direct 2D与Direct 3D 11协同工作时遇到的一些问题 Direct 2D与Direct 3D 11协同工作时遇到的一些问题 1、前言 最近在把游戏引擎的API从DirectX 9升级到DirectX 11,因为两套API之间存在巨大的差异,因此在升级迁移的过程中撞了不少坑,现在主要把Direct 2D和Direct3D 11协同工作时遇到的问题总结一下。 原来的游戏引擎对纹理做处理的时候(如写字、绘制简单图形等)用的都是GDI+这套API,使用的方法也比较傻,就是在内存中存两套完全相同的图片,一套交给Direct 3D作为纹理,一套作为Bitmap保留在GDI+中,当需要对纹理做一些处理的时候,首先在Bitmap中用GDI+来处理,然后把Direct 3D中的纹理Lock住,然后往里面逐个拷贝像素。 在打算升级到DirectX 11的时候,就已经打算不再使用GDI+了,改为使用Direct 2D,毕竟Direct 2D有硬件加速并且更加底层,而且能够直接和Direct 3D交互。 2、思路 对于Direct 2D和Direct 3D的交互,我的主要思路是在Direct 2D中绘制图片,然后作为纹理让Direct 3D使用,中途参考了MSDN上的文档: Direct2D and Direct3D Interoperability Overview 我一开始是按照这篇文章中Using Direct2D Content as a Texture这一小节的说明为指导来进行编写的,但是在前面的工作都顺利完成的时候,最后卡在了这里: hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget( pDxgiSurface, &props, &m_pRenderTarget );

UML状态图文档

UML状态图文档 题目要求: 题目一: (1)Windows的图形用户界面(GUI)有多种状态,请画一张GUI的状态图。(不需要很详尽,只需画出状态和之间的转换关系) (2)在GUI工作时,它不仅仅是等待、识别、显示用户输入,还可能要监视系统的时钟或者定期更新应用程序的界面显示。请据此画出GUI工作状态的详细状态图。 题目二: 电梯系统有如下几个状态:空闲状态(Idle),运行状态(Run),上升状态(Moving Up),下降状态(Moving Down),停止状态(Stop),开门状态(Door Open),关门状态(Door Close)。请根据这几个状态,画一张状态图。 题目一(1) 状态分析: 1、状态类型:开机状态(Start)、睡眠状态(Sleep)、工作状态(Run)、关机状态(Colse) 2、初始状态:开机状态 3、状态装换 从开机状态开始,在电脑启动后,WINDOWS GUI进入工作状态。 在工作状态下如果用户选择SLEEP选项或者电脑长期没有得到请求,WINDOWS进入睡眠状态。 睡眠之后如果得到启动电脑进入工作状态。 在睡眠状态下如果电脑电力不足将直接进入关机状态。 在工作状态下选择关机选项或者电脑电力不足电脑进入关机状态。 状态图: 题目一(2) 状态分析: 1、状态类型:等待状态(Waiting)、识别状态(Chceking)、显示状态(Printing)、监视状

态(Overlooking)、更新状态(Updating) 2、初始状态:等待状态 3、状态转换 在等待状态下,接受用户输入即进入识别状态。 在识别成功后进入显示状态。 显示结束后系统进入等待状态。 在等待识别显示状态过程中,经过一段时间GUI都将进入监视状态或者更新状态检查系统时钟。 在显示状态中,经过一段时间系统可以进入更新状态,定期更新应用程序的显示界面。 无论是监视状态还是更新状态,在工作结束后都将回到原来进入的状态,即等待识别显示状态或者显示状态。 状态图: 题目二 状态分析: 1、状态类型:空闲状态(Idle),运行状态(Run),上升状态(Moving Up),下降状态(Moving Down),停止状态(Stop),开门状态(Door Open),关门状态(Door Close) 2、初始状态:空闲状态(Idle) 3、状态装换 从空闲状态开始,如果电梯被请求了,电梯进入运行状态。 运行过程中,如果期望楼层大于当前楼层,电梯上升,反之电梯下降。 在上升或者下降过程中,当期望楼层等于当前楼层时,电梯停止。 在经历一段时间等待后,电梯门开。 电梯门打开一段时间后,电梯门关闭。 若电梯没有任何请求,电梯进入空闲状态,有请求继续进入运行状态。 状态图:

怎么画uml状态图

怎么画uml状态图 导语: UML状态图是描述一个实体基于事件反应的动态行为,在软件开发行业运用的较为广泛。作为行业的基础图示,我们很有必要学习这类图形该如何绘制。 免费获取免费UML建模软件:https://www.sodocs.net/doc/0f16430875.html,/software-diagram-tool/umldiagramsoftware/ 可以轻松绘制UML状态图的软件 亿图图示软件可以轻松绘制理想的uml状态图。UML状态图本质是一种连接线、图框与少量文字构成的图表,但绘制过程需要使用特殊的符号。亿图作为一款专业的图形图表设计软件,配有齐全的绘图符号,能够满足广大绘图用户的需求。即使是零基础的绘图者,也能够快速入门,并绘出具有专业水准的状态图。

系统要求 Windows 2000, Windows XP, Windows 2003, Windows Vista, Windows 7,Windows 8, Windows 10 Mac OS X 10.10 + Linux Debian, Ubuntu, Fedora, CentOS, OpenSUSE, Mint, Knoppix, RedHat, Gentoo及更多 亿图图示绘制“UML状态图”的特点 ●例子供参考:软件提供相关的例子,供用户参考学习,也可以直接使用模板 进行修改。 ●更多绘图功能:软件不仅仅可以回绘制UML所有类型的图示,还可以绘制 流程图、思维导图等。 ●独特的中文软件:这是一款仅有的国产图形图表设计软件,比国外软件更懂 国人的操作习惯。 ●便捷的操作:简单的拖拽式操作,让零基础的绘图者也能够享受软件带来的 便利。

UML实例图讲解

UML实践----用例图、顺序图、状态图、类图、包图、协作图 2009-01-20 作者:Randy Miller 来源:网络 面向对象的问题的处理的关键是建模问题。建模可以把在复杂世界的许多重要的细节给抽象出。许多建模工具封装了UML(也就是Unified Modeling Language?),这篇课程的目的是展示出UML的精彩之处。 UML中有九种建模的图标,即: ?用例图 ?类图 ?对象图 ?顺序图 ?协作图 ?状态图 ?活动图 ?组件图 ?配置图 本课程中的某些部分包含了这些图的细节信息的页面链接。而且每个部分都有一个小问题,测试一下你对这个部分的理解。 为什么UML很重要? 为了回答这个问题,我们看看建筑行业。设计师设计出房子。施工人员使用这个设计来建造房子。建筑越复杂,设计师和施工人员之间的交流就越重要。蓝图就成为了这个行业中的设计师和施工人员的必修课。 写软件就好像建造建筑物一样。系统越复杂,参与编写与配置软件的人员之间的交流也就越重要。在过去十年里UML就成为分析师,设计师和程序员之间的“建筑蓝图”。现在它已经成为了软件行业的一部分了。UML提供了分析师,设计师和程序员之间在软件设计时的通用语言。 UML被应用到面向对象的问题的解决上。想要学习UML必须熟悉面向对象解决问题的根本原则――都是从模型的建造开始的。一个模型model就是根本问题的抽象。域domain就是问题所处的真实世界。 模型是由对象objects组成的,它们之间通过相互发送消息messages来相互作用的。记住把一个对象想象成“活着的”。对象有他们知道的事(属性attributes)和他们可以做的事(行为或操作behaviors or operations)。对象的属性的值决定了它的状态state。 类Classes是对象的“蓝图”。一个类在一个单独的实体中封装了属性(数据)和行为(方法或函数)。对象是类的实例instances。 用例图 用例图Use case diagrams描述了作为一个外部的观察者的视角对系统的印象。强调这个系统是什么而不是这个系统怎么工作。 用例图与情节紧紧相关的。情节scenario是指当某个人与系统进行互动时发生的情况。下面是一个医院门诊部的情节。 “一个病人打电话给门诊部预约一年一次的身体检查。接待员找出在预约记录本上找出最近的没有预约过的时间,并记上那个时间的预约记录。”

关于Direct3D驱动流程的大致描述

关于Direct3D驱动流程的大致描述 作者: 谢克香 1.首先总体上的认识如下图所示:

由上图的流程可以知道, 任何一个有界面的程序, 如果要显示在具备独立显卡的显示 器上, 首先第一步要做的就是在显存中分配空间, 此内核函数DxgkDdiCreateDevice(DirectX graphic kernel driver device interface create deivce的缩写)是 由显卡厂商提供的, 在display miniport driver中, 主要起到在显存中分配空间的作用, 注 意这个分配的空间放的是GPU可执行代码, 分配空间的名字叫DMA buffer, DMA 是Direct Memory Access的缩写, 是计算机中的硬件, DMA buffer是DMA可以访问的buffer, 通过DMA硬件, 可以大大提到向DMA buffer写入数据的能力. 上面进行的操作都是在内 核态下, 所以上面的DMA buffer, 和函数,在用户态下都访问不了, 要访问的话, 必须通 过系统提供给用户层的api. 当用户调用DirectX3D Run Time提供的CreateDevice时, CreateDeivce其实是一个虚 函数, 当编译器工作时, CreateDevice形成的代码其实是一个在虚拟表中的偏移量, 虚拟 表是一个放函数地址地方. 然后直接Call这个地址, 经过Direc3D Runtime的一序列函 数的处理, 最终调用use‐mode display drive(用户态显示驱动)中的CreateDeivce函数, 而 这个函数调用Direct3D runtime中提供的pfnCreateContextCb(point function create context call back) 这个函数主要的作用是在系统内存或者AGP内存中分配command buffer, command buffer就是放GPU执行指令的地方, 通常这个command buffer的大小是固定的,,返回一个主要是command buffer的结构(此结构描述context, 也就是主要描述command buffer, 比如它的地址, 当然此结构还描述了其它东西), 到画图的最后阶段, command buffer最终会被GPU处理 当用户调用Direct3D Run time中分配资源的函数时, 比如类似于CreateResource的函 数, 然后Direct3D run time调用use‐mode driver中的CreateResource, 而use‐mode driver 中的函数最终调回Direct3D run time中的分配资源的函数, 通过回调函数pfnAllocationCb, 此函数最终通过DirectX Graphics kernel subystem调用display miniport driver中的DxgkDdiCreateAllocation函数, 此函数主要是在显存或者AGP内存或 者 系统内存中分配资源空间 由此可见 use‐mode display driver主要起到钩子的作用, 也就是截获Direct3D的执行 流程, 然后执行自己的处理, 然后又回调回去, Direct3D Run time应该是指d3d9.dll, 等其 它文件 Direct3D run time中画图操作函数最终调用use‐mode display driver中的draw图函数, 联想一下刚才的command buffer, 由此可见此函数就是把draw图函数转化为GPU能够 识别的command, 并把这些command 放到command buffer 当用户调用present时, Direct3D run time调用use‐mode display driver中的present的 函数, 而这个函数的执行又通过回调函数pfnPresentCB, 返回Direct3D run time执行, 有另一种情况, 也就是command buffer满了的时候, Direct3D run time会自动调用 use‐mode display driver中的flush函数, 此函数也一样通过pfRenderCb回调给Direct3D run time执行. 现在已经分为两种不同的执行流程, 一个present, 一个是flush, 两者执行的操作是不一 样的, present描述如下: Direct3D run time通过系统api, 进入到内核态中的directx graphic kernel subsytem中执行, 然后 graphic kernel紧接着调用显卡驱动中的

UML状态机图介绍

UML状态机图 1.状态机图的作用 状态机图是用来为对象的状态及造成状态改变的事件建模。UML的状态机图主要用于建立对象类或对象的动态行为模型,表现一个对象所经历的状态序列,引起状态或活动转移的事件,以及因状态或活动转移而伴随的动作。状态机图也可用于描述Use Case,以及全系统的动态行为。 状态机图表示一个模型元素在其生命期间的情况:从该模型元素的开始状态起,响应事件,执行某些动作,引起转移到新状态,又在新状态下响应事件,执行动作,引起转移到另一个状态,如此继续,直到终结状态。 2.状态机图的基本元素 状态机图的基本元素包括:状态、转移、事件、伪状态和复合状态。 状态图由状态(state,圆角矩形)与转换(transition,连接状态的箭头)组成。引起状态改变的触发器(trigger)或者事件(event)沿着转换箭头标示。如图所示灯光有2个状态:off与on。当lift switch或者lower switch事件被触发时,灯光状态会改变。 图表1 状态图的基本元素 状态图通常有初始伪状态(initial pseudostate)和最终状态(final state),分别表示状态机的开始和结束。初始状态用实心圆表示,终止状态用牛眼表示。

图表2状态图中的初始伪状态与最终状态 2.1状态(state) 状态是指在对象生命周期中满足某些条件、执行某些活动或等待某些事件的一个条件和状况。一个状态通常包括名称、进入/退出活动、内部转换、子状态和延迟事件等五个部分组成。 图表3 带分栏的状态 在状态图的下面部分可以标识内部活动,包括事件和动作(event/action)。Entry和exit事件是标准的,任何一个进入状态的转换都将会调用entry动作,任何一个退出状态的转换都将会调用exit动作,而且也可以添加自己的事件。与do行为不同,进入和退出行为是无法被中断的。 图表4状态的内部行为 例如,咖啡机正在煮咖啡的状态(Brewing),并且可以把行为写在状态内。

directx从入门到精通(direct简介)

返回总目录 第一篇 DirectX

目录 第一章 DirectX简介 1.1 DOS已经过时 1.2 加速DirectX 1.3 加速计算机工业 1.4 Directness原理 1.5 Direct结构 1.6 DirectX组件 1.7 小结 第二章基础 2.1 期望什么 2.2 COM(对象组件模型)入门 2.3 编程经验 24 2.4 调试DirectX 2.5 总结 第三章开始使用DirectX 3.1 安装 3.2 文档

3.3 例子程序源代码3.4 其他有用的信息3.5 使DirectX开始工作3.6 总结

第一章 DirectX简介 到目前为止,Microsoft Windows下的计算机游戏还没有一个辉煌的历史──它的成功还受到多媒体技术方面的限制。Windows所提供的应用程序和PC平台之间的设备独立性使得游戏和多媒体开发者备受压力,这是因为设备独立性技术使得软件和硬件之间增添了许多中间层次,因此要想在Windows平台上生成平滑、快速的动画和紧凑、实时的输入和声音是非常困难的。Windows的中心思想就是要把开发者和应用程序从硬件中分离出来,但这一点对于那些想直接操作硬件而获得最大速度的游戏开发者来说是致命的。市场需要的是高性能的游戏,因此,对于那些想把Windows作为计算机游戏平台的推广者来说,“DOS!DOS!DOS!”是他们经常遇到的对DOS游戏的赞歌! 1.1 DOS已经过时 然而,MS-DOS也有它自已的问题,其中最棘手的是硬件设备的支持。PC机的游戏开发者是不能享受到游戏机开发者的那种平台一致性的。对于游戏机软件开发者,他们晚上可以睡得很香,因为白天所写的代码将在上百万台同样的机器上运行。而PC机的开发者却不能这样,他们老是梦见新

Direct3D场景中3D模型的处理方法

万方数据

万方数据

万方数据

万方数据

辽宁石油化工大学学报第28卷 NORMALIZENORMALS渲染状态。 pD3DDevice一>SetRenderState(D3DRS—NoRMALIZENORMALS,TRUE); 下面是通过程序实现的真实场景。网1是未经添加实体的空旷房间, 图l 未经添加实体的空旷房间 图2是通过加载.x文件(会议桌,椅子,植物, 沙发),确定不同实体的位置或相同实体的不同位置,把它们放在了合理的伉置。 图2加载.x文件后的房间 通过3DSMAX建造的3D模型得到的.x文 件,经过一系列的转换正确加载后可以得到十分逼 真的动画效果,可以很好的应用于虚拟场景,例如三维建筑系统,仓库管理系统等。 参考文献 于忠德.DirectX实时渲染技术详解VM].重庆:重庆出版社,2006. 童晓然,昊晟.用DirectX实现地图3D展示及模拟行走[J].科技广场,2007(1):117--119. 任咏林,任伟林,秦魁.基于MicrosoftDirectX浅析COM组件与多媒体游戏的开发[J].北京工商大学学报,2005,23 (6):38—4Z. JimAdams.AdvancedanimationwithdirectX[M].Thomson:Publishedbythomsnlearning,2002. 叶至军,于忠德.DireetX宾时渲染技术详解EM].重庆:重庆大学出版社,2006.王德才.精通DireetX3D图形与动画程序设计EM].北京:人民邮电出版社,2007.金纯..x文件的解读和处理[J].福建电脑,2005(9):68—69. 金采工作室.3D游戏程序设计基础EM3.北京;北京希望电子出版社,2006. 王德才,张安慧.Direct3D中的三维坐标变换[J].电脑编程技巧与维护,2007(5):4—6. (Ed.:ZW,Z) 叫跚嘲 刚嘲网吲嘲嘲 万方数据 万方数据

Direct3D11教程1Direct3D11基础

Direct3D 11 教程1:Direct3D 11基础 原文地址:。 概览 在第一个教程中,我们学习了创建一个最小Direct3D 11应用程序所需的元素,每个Direct3D 11应用程序必须包含这些元素才能正常工作,这些元素包括创建一个窗口和设备对象,然后才能在窗口中显示颜色。 源代码 (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial01。 创建Direct3D 11设备 第一个步骤中的创建窗口和消息循环在Direct3D 9、Direct3D 10、Direct3D 11都是相同的,可参见Direct3D 10教程0:Win32编程基础理解这个过程。当显示了一个窗口后,下面继续创建一个Direct3D 11设备,这个设备用于绘制3D场景。首先必须创建三个对象:一个设备(device)、一个立即执行上下文(immediate context)和一个交换链(Swap Chain),立即执行上下文对象是Direct3D 11中新添加的。 在Direct3D 10中,设备同时用来绘制和资源的创建。在Direct3D 11中,立即执行上下文用于将内容绘制到缓存,而设备用于创建资源。 交换链即表示对缓冲的操作,这些缓冲就是设备绘制的和显示在屏幕上的内容。交换链包含两个或两个以上的缓冲,主要是前缓冲和后备缓冲,它们就是设备绘制形成的纹理,用于显示在屏幕上。前缓冲(front buffer)就是当前显示在屏幕上的内容,这个缓冲是只读的,无法修改。后备缓冲(back buffer)是设备将要绘制的渲染目标,一旦它完成了绘制操作,交换链就会通过交换前缓冲和后备缓冲,将后备缓冲的内容显示在屏幕上,此时后备缓冲就变成了前缓冲。 要创建交换链,我们需要设置一个DXGI_SWAPCHAIN_DESC结构体说明将要创建的交换链。此结构体的几个字段需要说明一下:BackBufferUsage标志告诉程序我们使用后备缓冲的方式。本例中我们想绘制到后备缓冲,所以将BackBufferUsage设置为

解析UML活动图和状态图的作用和区别

本文和大家重点讨论一下UML活动图和状态图的概念,这两种图都有各自的特点和作用,那么他们之间有什么区别和联系呢,请看本文详细介绍。 UML活动图和状态图 一、UML活动图: ◆流程图常被用来建立算法模型 ◆UML活动图与流程图类似,不同在于它支持并行活动. ◆缺点:不能清楚的表示 二、作用: 1、描述一个操作的执行过程中所完成的工作或者动作 2、描述对象内部的工作 3、描述用例的执行 4、处理多线程 5、显示如何执行一组相关的动作,以及这些动作如何影响周围对象 三、以下情况不用UML活动图 1、显示对象之间的合作 2、显示对象在其生命周期内的运转情况。 这两点是通过序列图和协作图完成的。 四、UML活动图的基本要素: ◆活动状态 ◆活动状态之间的转移(箭头) ◆判断(决策点) ◆保证条件 ◆同步条:活动之间的同步 ◆起点和终点 --起点有且只有一个,终点可以有n个。 五、泳道: 用于对UML活动图中的活动进行分组,用于描述对象之间的合作关系。 ----所谓泳道技术,就是将活动用线分成一些纵向区域,这些纵向区域称为泳道。 UML状态图 一、状态图: ◆描述一个特定对象的所有可能状态以及由于各种事件的发生而引起的状态之间的转换。例如呼叫中心系统。

◆状态图符 --状态:矩形(四角圆弧) --转移 --起点 --终点 1、状态机: ◆一种行为:描述了一个对象或一个交互在生命周期内响应事件所经历的状态序列。 ◆单个类或者一组类之间协作的行为可以用状态机来描述 ◆一个状态机涉及到一些其他元素,包括状态、转换、事件 2、状态: 在对象的生命周期中满足某些条件、执行某些活动或等待某些事件的一个条件活状况。1)名称 2)进入协作和退出动作 3)内部转换 4)子状态 5)延迟事件 3、转换:两个状态之间的一种关系,表示对象将在第一个状态中执行一定的动作并在某个特定事件发生而某个特定条件满足时进入第二个状态。 1)源状态 2)事件触发 3)监护条件 4)动作 5)目标状态 例子:电话机状态图 二、UML活动图与状态图的区别: 状态:行为的结果 活动:行为的动作 在uml中图符不一样。 注意:实际项目中,UML活动图不是必须的。 用到UML活动图的情况: --描述并行的过程或这行为 --描述一个算法 --描述一个跨越多个用例的活动 状态图描述了一个具体对象的可能状态以及他们之间的转换。 单独的说UML活动图很抽象,但是当把UML活动图与流程图进行简单的比较之后就

UML 状态图 StateChart Diagram

A、State Diagram(状态图)、State Machine Diagrams(状态机图) 状态机图是说明一个元素(通常是类)能在不同状态之间变动。状态机图的其它方面进一步描述和解释其运动和行为。 状态图主要用来描述对象、子系统、系统的生命周期。通过状态图可以了解到一个对象所能到达的所有状态以及对象收到的事件(收到消息,超时,错误,条件满足)对对象状态的影响等。 状态 所有对象都有状态,状态是对象操作的前一次活动的结果。类的状态由类中的指定属性来说明。 事件 当某些事情发生时对象的状态发生改变,我们称改变对象状态的事情为事件。 B、状态图的模型元素 B.1、Initial(起点)初始态 Initial元素是伪状态用于表明一个复合状态的默认状态。可以在每一个复合状态的区域有一个初始顶点。 B.2、Final(终点)终态 B.3、State(状态) State描述一些不变条件成立的情形。这个条件可以是静态的(等待某个事件)也可以是动态的(正在执行一组活动)。状态建模通常用于阐述类。 你可以适用State的operation(操作)来定义enter(进入)、internal(内部)、exit(退出)动作。State 也可以有Attributes(属性)。 B.3、State Machine(状态机) 状态机是一组相关状态元素的容器。你可以创建状态机图的各个部分。 B.4、Synch(同步) Synch状态用于描述状态机的并发部分同时发生。在同步发生后Synch状态的新兴过滤路径将合并。 B.5、Choice(选择) Choice伪状态用于组成复制过滤路径,例如:在状态机图中一个过滤的路径取决于一个动态的运行时的条件。这个运行时的条件是由状态机路径选择决定的。 B.5、Junction(汇合) Junction伪状态用于设计复杂过滤路径。一个Junction可以用来汇合或组合多个过滤路径为一个过滤路径。另外一个Junction可以把一个进来的路径分割成多个路径。和叉不同的是Junction可以看守每一个流入或流出过滤,这样看守表达式是false,过滤就被阻止。 B.6、Entry(进入) 入口点伪状态是用来定义一个状态机开始。每个区域都存在一个切入点,指导并发初始状态配置。 B.6、Exit(离开) Exit伪状态用于子状态机表述状态机过滤退出点。 B.7、Terminate(终止) Terminate伪状态表示状态机终止执行。 B、状态图的关系 Transition(过渡):表示状态之间的状态转换。状态转换线旁边的标签表示事件。

directx direct3d 的第八章的内容详细注释说明

Checker brick0 Ice d3dUtility.cpp ////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.cpp // // Author: Frank Luna (C) All Rights Reserved //

// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUtility.h" bool d3d::InitD3D( HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device) { // // Create the main application window. // WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)d3d::WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "Direct3D9App"; if( !RegisterClass(&wc) ) { ::MessageBox(0, "RegisterClass() - FAILED", 0, 0); return false; } HWND hwnd = 0; hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App", WS_EX_TOPMOST, 0, 0, width, height, 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);

direct3d到2D编程方法

1用DirectDraw 这是早期的做法,由于现在的DirectDraw已经并入到DirectGraphic当中,而且微软也已经在Direct SDk8中把DirectDraw部分的文档取消了,现在多用D3D 来做2D的游戏 2用ID3DXSprite 这个接口可以很好的制作2D动画,ID3DXSprite是DriectX 9.0里面的一个简单模块,在DriectX 9.0帮助文档里面对其功能的描术为:“向用户提供一套简单的在屏幕上实现精灵渲染的接口。”何为精灵渲染,说白了就是渲染2D画面,ID3DXSprite帮助用户通过简单的操作就能运用DriectX 9.0制作2D游戏(渲染2D图形)。对于绘制2D图片,其主要步骤就是 (1) 读取图片,载入纹理 (2) 如果需要对图片做旋转或者缩放的话,设置相应的矩阵 (3) ID3DXSprite::Draw(….) 具体参考代码如下: //初始化精灵对像 D3DXCreateSprite(g_pDevice, &g_pSprite); g_pDevice->BeginScene(); g_pDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR _STENCIL, D3DCOLOR_XRGB(0,0,0),1.0f,0L); g_pSprite->Begin(D3DXSPRITE_ALPHABLEND); //得到2D坐标转换矩阵 D3DXMatrixTransformation2D(&mat, NULL, 0.0f, &D3DXVECTOR2(0.1f, 0.1f), &D3DXVECTOR2(50.0f, 50.0f), 0.5f, &D3DXVECTOR2(100.0f, 100.0f));

相关主题