Direct3D 10系统(四)

Direct3D 10系统(四)  

作者:David Blythe
本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。欢迎大家和我多多交流。
翻译:clayman
Blog:http://blog.csdn.net/soilwork
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 ,来获得一致的行为。从长远来看,硬件将会支持异常机制。
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值