关于D3D11,你必须了解的几件事情
Posted wolf96
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于D3D11,你必须了解的几件事情相关的知识,希望对你有一定的参考价值。
仅以此文献给那些自以为了解D3D11的专家
D3D11正式发布已经有两年多了。在这短短的时间里,各GPU厂商 都相继推出了支持D3D11的显卡,许多游戏引擎也迅速推出了对D3D11的支持。但在国内,D3D11的接受度几乎为零。国内很多“大”游戏公司的“技 术人员”对于D3D11完全出于一知半解的状态,却又在不懂装懂地指手画脚。
关于D3D11,有些事情你确实必须了解。
Feature Level
从KlayGE 3.11.0发布以来,几乎每个月都会听见有人问我,“为什么要去掉D3D9和D3D10插件,仅保留D3D11和OpenGL?”。(最近这个频率显著 提高,基本到了每周1-2次的程度)。在他们的观点里,D3D11就得在D3D11的硬件上跑,而现在D3D11硬件尚未普及,这么做会影响到 KlayGE在D3D10硬件上的运行。我对这类问题的回答一般是非常冰冷的“为什么不了解D3D11就枉加评论”。
D3D11的一个最基 本知识就是feature level。其实这不是新发明,在D3D 10.1的时候就提出来了,只是因为D3D 10.1的使用量实在太小,直接被忽略了。feature level对D3D11的功能进行了划分,不同功能所需要的最低硬件要求是不同的。feature level的存在使得D3D11 runtime可以在D3D10甚至D3D9的硬件上执行。下面我们从低到高看一些各个feature level所能做的事情。
Feature level | 典型显卡 | 能力 |
---|---|---|
D3D_FEATURE_9_1 | Intel G965,NV GeforceFX 5200,ATI Radeon 9600 | D3D9硬件:必须支持SM2,2k大小的纹理,3D纹理,query,BC1-3 |
D3D_FEATURE_9_2 | NV GeforceFX 5600,ATI Radeon 9500 | D3D9硬件:必须支持SM2,occlusion query,浮点纹理,所有9_1的功能 |
D3D_FEATURE_9_3 | NV GeforceFX 6600, ATI Radeon X1300 | D3D9硬件:必须支持SM2b,instancing,4k大小的纹理,MRT,浮点纹理混合,所有9_2的功能 |
D3D_FEATURE_10_0 | NV Geforce 8800/GTX 280 | D3D10 硬件:必须支持SM4,geometry shader,stream output,alpha to coverage,MSAA纹理,双面stencil,texuture array,BC4/5,所有9_3的功能;可选支持compute shader 4.0 |
D3D_FEATURE_10_1 | ATI Radeon HD 2/3/4,NV Geforce GT220 | D3D10.1硬件:必须支持SM4.1,cubemap array,扩展的MSAA,所有10_0的功能;可选支持compute shader 4.1 |
D3D_FEATURE_11_0 | ATI Radeon HD 5/6, NV Geforce GTX 4/5 | D3D11硬件:必须支持SM5,tessellation,hull shader,domain shader,compute shader 5,BC6H/BC7,所有10_1的功能 |
所以很明显,D3D11并不一定要D3D11的GPU。在D3D10的GPU上,D3D11的功能相当于原有D3D10的,加上compute shader 4.0,以及可能有multi-threading。性能取决于厂商驱动,目前来说性能可以做到和D3D10完全一致。在D3D9的GPU上的也可以类比 出来。唯一不同的是vertex texture fetch,即使level 9_3也只有instancing而没有VTF。其实在SM3的GPU上,NV的6系列和7系列的VTF性能和支持的纹理格式特别差,使得VTF的实用性 很有限。ATI更是一直放弃了VTF,自己搞出来R2VB的方法,性能上远超VTF。后期的驱动里,NV的SM3 GPU也都支持R2VB了,所以R2VB反而后来居上成为通用的功能。除此之外,D3D11在早期硬件上执行,只会带来好处,没有损失。
有了feature level这个重要的能力,D3D10已经完全没有存在的必要。所以,KlayGE、CE3、UE3这些渲染技术一流的游戏引擎全都不约而同地跳过或者删除了D3D10的支持,直奔D3D11。
顺 便说说D3D9。目前D3D9存在的唯一理由是广大的XP用户。但实际上很多人都是有D3D10的GPU,而因为XP被限制在了D3D9上。其实XP下的 OpenGL驱动也是与时俱进的,可以给XP带来原本属于D3D10/11的新GPU能力,又没有性能损失。因此KlayGE坚决地去掉了D3D9,让 OpenGL接手D3D9在XP上的任务。
Optional Features
当年D3D10在宣传的时候,有个好处就是没有caps。在D3D9时代,caps几乎折磨了每一个程序员。实现某个功能之前经常需要根据caps作判断,来选择不同的方法。D3D10去掉了所有的caps,要求硬件都必须达到某个规范,解放了caps测试。
话 虽如此,实际上D3D10还是留了一手。ID3D10Device和ID3D11Device里面都有个叫作CheckFormatSupport的函 数,可以检查某个格式是否支持,只是可选的范围非常窄罢了。(理论上驱动还可以通过这种方式暴露出D3D1x本身不支持的古怪格式,就好象它们在D3D9 时代做的事情一样)
用过D3D10的人一般会发现,D3D10不支持ARGB这种D3D9上最常用的颜色格式,然后开始抓狂。其实按照定 义,那个格式在D3D11里面应该是这样的:对feature level 9_x和11_0是必须支持,对feature level 10_x是可选支持。所以解决方法很简单,升级到D3D11就是了。
另外,feature level 11_0还必须支持R10G10B10_XR_BIAS_X2_A2_UNORM(我也不知道这个格式是做什么的),而feature level 10_x是可选支持,9_x是不支持。在D3D11里,格式的支持情况一般取决于feature level,所以直接通过feature level检查就可以了,大可不必每个格式每次逐一检查。
除了CheckFormatSupport之外,D3D11还增加了 CheckFeatureSupport这个函数,用来检查multithread、double、atomic、compute shader 4.x是否支持。所以说,caps不是完全消失,而是尽可能变少。但保证剩下的都是有意义的,不能随便忽视。
Compute Shader
compute shader(也叫DirectCompute)是D3D11新增的主要功能之一。在D3D11的GPU上,compute shader是完整的5.0版本,而在D3D10.x的GPU上,compute shader有个简化的4.x版。两者的具体差别请见Compute Shaders on Downlevel Hardware。
CS 4.x的一个很重要缺点是不支持RWTexture,所以shader无法写入texture,只能写入buffer。(这是NV造成的。AMD的硬件很 早就可以做到写入RWTexture,但因为CS 4.x要求同时兼容NV和AMD,所以就放弃了写入RWTexture的要求。相信用过CUDA 2.0之前的朋友也了解这件事情)结果就是无法把CS 4.x用于post process这样的操作。有个解决方案是compute shader的结果都写到buffer,要让图形流水线用的时候调用一个pixel shader来把buffer转到texture中。CS 4.x可以把texture和buffer作为输入、buffer作为输出,而D3D11下的PS 4.x可以把texture和buffer作为输入、texture作为输出,所以可以把两者结合来实现从texture到texture的流水线。
但是,不管是CS 4.x还是5.0,从CS转回图形流水线的时候,在NV的卡上都会出现一个明显的几毫秒延迟。所以每一帧的切换次数要尽量减少。在AMD卡完全没这个问题。
CS 4.x还有一个重要缺点,每个thread虽然可以读任意地址的shared memory,但只能写入自己对应的shared memory单元,所以没办法用CUDA里面常用的stride布局。(这是AMD的实现限制。还是因为有兼容的要求,所以就算NV能做到也不行了)常见 的做法是,声明一个结构体,里面有自己要用到的所有共享变量。用这样的结构体来声明shared memory,就可以写入多个值。
Multi-threaded
D3D11 加入了显式的multi-threaded支持。它把D3D10的接口分成两部分。负责建立资源的那些函数属于ID3D11Device,剩下的都分到了 ID3D11DeviceContext。ID3D11Device是线程安全的,如果驱动不支持并行建立资源,runtime就会通过加锁来保证线程安 全(除非用D3D11_CREATE_DEVICE_SINGLETHREADED来强制关闭这一点)。ID3D11DeviceContext是没有线 程安全的,得由上层代码自己处理。
D3D11的device context分为Immediate Context和Deferred Context两种。Immediate context的命令都会立刻得到执行,deferred context则是把命令存在列表里,等他被提交的时候才开始执行。因为在调用Draw的时候,CPU需要做一些额外的事情,所以如果Draw call被分散到多个core去执行,是会有性能提升的。
高性能地使用这 个多线程是需要驱动支持的。现在的GPU一般都有多个command unit,但驱动往往不开放多线程的功能。目前不论是D3D11还是D3D10级别的,都不支持Multi-threaded,所有的deferred context都是软件实现的,所以性能并无提高、反而降低。希望某天驱动能完善到支持它的程度,这才能真正让开发人员用上高效的deferred context。
Tessellation
很 多人会说D3D11增加了tessellation shader这个stage,但真相是增加了hull shader、tessellator和domain shader三个stage。Hull shader的输入是patch的控制点(三角形、四边形这样的图元,最多有32个控制点),计算出tessellation等级、确定 tessellation的方法等。它的输出被送给固定单元的tessellation进行细分。Domain shader的输入是细分后的bary centric坐标、来自hull shader的控制点,它负责计算插值后的顶点坐标。
Tessellation早就存在于一些GPU。 D3D9的API中其实就正式存在一些使用patch的能力。比如NVIDIA的Geforce 2就支持PN-Patch,但在Forceware 29.xx之后(如果我没记错的话)就因为效率和使用率问题而禁用了。后来ATI设计的XBox360的GPU里面就有个不可编程的 tessellator,这个架构一直延续到Radeon HD 5000系列为止。和D3D11不同的是,这个tessellator位于VS之前,而不是VS之后。这么做的好处是流水线变简单了,由VS完成DS的功 能即可。但缺点也很明显——性能会受到严重影响:
- tessellation等级必须在另一个pass计算
- 本来应该在per vertex上做的事情(比如乘上wvp)变成要在细分插值后的顶点上作,显著地增加了计算量;要么就还要一个pass来做这件事情
所以D3D11用这种设计对性能提升很有帮助的。
NVIDIA Direct3D SDK 11里特别提供了一个名为Tessellation Pattern Viewer的工具,用来查看在不同参数下,三角形和四边形被tessellate后的拓扑。
Tessellation Pattern
BC6H/BC7
D3D11 增加了BC6H和BC7两种纹理压缩格式,分别擅长HDR压缩和高质量LDR压缩,都能达到8bpp。BC6H和BC7的原理类似,但比原先的BC1-5 复杂了非常多。所以压缩的运算量也大了巨多。比如512×512的原始图片,用D3DX里面提供的BC6H或BC7压缩,需要10分钟左右。解决方法是用 DX SDK提供的BC6HBC7EncoderDecoder11这个例子来进行GPU加速压缩,只要几秒钟即可。更新的版本可以从这里下载到。
下图是用BC6H来压缩一张HDR图片的结果。左边是原图(给定曝光度),中间是误差绝对值,右边是压缩后的图。
BC6H压缩的结果
下图是一个BC3(也就是DXT5)和BC7的压缩误差比较。左边是原图,中间是误差绝对值,右边是压缩后的图。很明显可以看出,BC7的误差远小于BC3,尤其是在边界的地方。
BC3和BC7的比较
介绍了这些D3D11的“基本”概念后,本系列就此打住。希望能给对D3D11一知半解的人有所帮助。
原文链接(一):http://www.cnblogs.com/gongminmin/archive/2011/08/09/2132165.html
原文链接(二):http://www.cnblogs.com/gongminmin/archive/2011/08/12/2135663.html
原文链接(三):http://www.cnblogs.com/gongminmin/archive/2011/08/29/2158037.html
以上是关于关于D3D11,你必须了解的几件事情的主要内容,如果未能解决你的问题,请参考以下文章