(三) Direct3D 上下文管理(下) ---微软官方文档翻译

Direct3D 上下文管理(下)


原文链接: https://msdn.microsoft.com/en-us/library/windows/hardware/ff540762(v=vs.85).aspx


5.创建驱动端的surface结构体
(1)DirectDraw在调用DdCreateSurface函数并且为surface分配内存之后,紧接着调用驱动的D3dCreateSurfaceEx函数。运行时只针对被标记为DDSCAPS_TEXTURE, DDCAPS_EXECUTEBUFFER,DDCAPS_3DEVICE,DDCAPS_ZBUFFER的那些surface.
(2)在调用D3dCreateSurfaceEx之前,运行时为surface分配一个整数值作为句柄。这一值被存放在DDRAW_SURFACE_MORE结构体的dwSurfaceHandle成员中。

 这一整数值从1开始而且尽量保持比较小(0是一个无效的surface句柄)。需要注意的是,驱动可以保持一个指向自己结构的指针的数组,当其接收一个超越该数组大小的句柄时,驱动可重新分配数组并继续执行。
 
 在句柄通过D3dCreateSurfaceEx对驱动可见之前,Direct3的运行时并不向驱动传送句柄。然而,驱动必须足够健壮去处理超出范围的数值,或者在句柄表中的slot.

  注意,尽管0是一个无效的句柄值,在句柄表中可以被重复利用用于其他目的,Perm3 sample驱动使用0保存当前数组的长度。
 
6.指向DirectDraw surface的指针
(1)驱动开发者可能试图在自己内部私有的驱动端的surface结构中管理一个指向DirectDrawSurface数据结构的指针。然而,这一操作在windows 2000和更高的版本不会成功,因为对于DirectDraw内核态的数据结构的访问是通过一个隔离用户模式和驱动模式的结构体的管理方案实现的。EngLockDirectDrawSurface提供了一个指向该结构的指针,该指针在
   EngUnlockDirectDrawSurface被调用之前一直是有效的。
        (2)在Lock/Unlock函数对之外,即使在相同的位置,也不能保证该结构一定存在。
        (3)另外,这些lock/unlock对阻止执行。如果驱动自己处理自己对于surface结构体的拷贝,则不需要使用lock函数。更新驱动端的surface结构体中的数据发生在低频率的调用函数中,如D3dCreateSurfaceEx. 这样就会导致高频率的被调用的函数如D3dDrawPrimitives2中会执行更少的代码。


7.D3dCreateSurfaceEx句柄
某些情况下,会出现针对一些无效的或者被销毁的surface, D3dCreateSurfaceEx被调用。此时如果视频内存的surface中的fpVidMem为0时,驱动可以完全忽略任何D3dCreateSurfaceEx的调用。 不过驱动可以通过fpVidMem为0的系统内存的surface获取一个D3dCreateSurfaceEx调用,也就是说系统内存surface正在被销毁的过程中红。驱动这时需要任何与该surface相关的驱动端的数据。
   (1)D3dCreateSurfaceEx 与 Backing surface
D3dCreateSurfaceEx也可被一些backing surface调用,这些surface都是系统内存中对于持续的已管理的surface的拷贝。这就允许驱动分为surface配一个驱动端的结构体并对D3DDP2OP_TEXBLT做出回应。

基于backing surface要求的格式和属性,D3dCreateSurfaceEx永远不能失败,因为仿真的代码可以支持和处理surface.不过,其他一些其他情况下失败是有效的。例如,当D3dCreateSurfaceEx处理自己的数据结构并且内存不足时可以调用失败。

对于backing surface, D3dCreateSurfaceEx不可对不支持的像素格式调用失败。这类surface可能被创建用于软件的光栅化。对于不支持的格式,驱动在处理的时候忽略即可。(或者说,驱动可以创建驱动端的数据结构,但是相关的句柄不会被随后发送到驱动)。

对于backing surface, D3dCreateSurfaceEx引起的失败吗可以传到应用程序;驱动可以在只仿真的模式下潜在的影响应用程序。一个驱动对这样情况的回应可以通过用ddtest.exe来测试。运行ddtest.exe会创建一个驱动不支持但是DirectDraw仿真层支持的格式的surface文理(这些格式可以在DirectDraw SDK文档中找到)。
  


(2)D3dCreateSurfaceEx与复合surface
与在DirectDraw文档中描述的创建和销毁DirectDraw surface的描述一样,创建一个复合的surface会引起一组surface传送到DdCreateSurface函数.然而,即使在复合的情况下,只有指向根surface的指针传向Dd3dCreateSurfaceEx.驱动很必要遍历附加到根surface的surface链表并为所有附加的surface创建在驱动端的拷贝。如果驱动想要处理对于cub maps 和MIP maps的创建时,这是一个比较复杂的操作。

对于DirectDraw surface的附加分两种形式,一种是显示的,一种是隐式的。隐式的附加发生在复合surface的创建过程中,附加和被附加的surface都是通过CreateSurface创建的。显示的附加发生在不同的CreateSurface调用并通过AddAttachedSurface显示的添加。

DirectX 运行时在何时以及如何调用驱动的D3dCreateSurfaceEx以及驱动如何处理surfaces都取决于surface是显示还是隐式的被添加的。当两个surface是显示附加的,这两个surface分别由不同的CreateSurface调用创建,且每一个surface会在surface被附加之前调用D3dCreateSurfaceEx. 而隐式的附加的surface,对于整个surface链,只有一次CreateSurface和D3dCreateSurfaceEx被调用。因此,当调用D3dCreateSurfaceEx时,必须运行被添加的surface去确定句柄并且为每一个surface在驱动端创建相应的数据结构。不过,被附加的surface有可能是由显示和隐式的surface混合而成的。通过D3dCreateSurfaceEx,驱动的显示附加的surface应该已经被通知,避免重复处理这些surface。

驱动可以通过DD_ATTACHLIST数据结构中的dwFlags来区分显示和隐式的附加。如果该值被设备DDAL_IMPLICIT,便是隐式的附加。如果该值未被设置,则是显示附加。通过检测这一值,驱动确定只将surface作为父surface的一部分处理还是大单独处理每一个surface。
  

(3)D3dCreateSurfaceEx与MIP maps
在MIP map的么一个等级均是与不同的句柄值相关联的。这些句柄可能不是连续的,不过Direct3D DDI 这样设计使得只有最顶层的surface的句柄才作为参数传送到应用程序端的SetTexture接口,同时当前的层次的surface的详细信息用一个文理状态指明。最自然的处理的MIP maps的方式是建立一个驱动端的数据结构来表示整个MIP map.
  

(4)D3dCreateSurfaceEx与Flip
DirectDraw surface结构体的涉及主要是为了表示概念上的surface,并不必要指明在video memory中的位置。主要的抽象作用用在初始的flipping链中,在flipping链中,应用程序可以使用一个常量surface对象来代表back 缓冲区,尽管back缓冲区可能在视频memory中被移动并作为DdFlip函数的结果。

DdFip函数获取一圈surfaces,并在圈内顺序的重新分配视频内存的指针。对于两个surface对象的特殊情况,该处理过程只处理其自身的视频内存的指针。另外,DirectDraw运行时针对每一个surface相对应的D3dCreateSurfaceEx句柄进行处理,同时处理每一个surface对应的驱动端拥有的存储在dwReserved1成员中的上下文。这一行为对于对于DirectX 7.0的驱动 和有效的嵌入DirectDrawSurface的指针会有一些有趣的结果。

考虑两个surface对象A和B, 分别拥有相关的句柄Ha和Hb, 和fpVidMem的值分别为Fa和Fb. 更进一步假设,应用程序利用A执行在flipping链中的back buffer. 在调用DdFlip的时候,句柄和两个fpVidMem的值都被交换,于是surface A对应的值变为Hb和Fb, surface B对应的值变为Ha和Fa. 应用程序尝试滑倒back buffer,此时即A surface中Fb处的视频内存。

绘制的命令是与驱动相关的,都取决于与每一个surface相关的句柄(当前是Hb, 不是Ha)。如果驱动仅仅存储一个指向DirectDraw surface结构体的指针会怎么样呢? 驱动找到Hb,然后找存储的指向surface B的指针,该指针当前的fpVidMem的值为Fa. 此时从Fa对应的视频内存开始绘制。如果,驱动在自己的结构体中存储surface的数据,而不是根据指向DirectDrawsurface 结构体的指针,此时Hb对应的fpVidMem的值依然为Fb,且绘制会发生在正确的Surface。后面一种方式便是当前的DDI实现的版本。
 

 (5)D3dCreateSurfaceEx句柄与DirectDraw DDI
句柄在来自由DirectDraw管理的DDRAW_DDSURFACE_MORE和DDRAW_DDSURFACE_LCL结构体中并不是完全没有用的。这些结构体的名字对于DD_SURFACE_MORE和DD_SURFACE_LOCAL结构体是必要的别名。像DdBlt和DdFlip这些DDI,驱动接收的都是surface结构体的指针,而且驱动必须能够利用这些结构体来代替其自身的表示。
  

(6)关于合适恢复复合Flip链的考虑
当一个原始的复合surface被创建时,很有可能并没有包含一个附加的Z-buffer。当一个surface被恢复时,很有可能应用程序已经附加了Z-buffer.驱动开发者在调用D3dCreateSurfaceEx遍历surface链表时应该注意这一区别。

在Perm3 sample驱动中的一个典型的技术是,当D3dCreateSurfaceEx被调用的时候,将该surface的dwReserved1标记。驱动只有在fpVidMem的值不为0的时候标记。这是因为,fpVidMem可以为0, 因为应用程序可能恢复一个带有显示的附加的Z-buffer后缓冲的surface,但是Z-buffer并未恢复。在后续的调用过程中,app恢复Z-buffer,驱动然后对其进行标记。如果在恢复初始的链之前恢复Z-buffer,驱动会在D3dCreateSurfacfeEx被调用的时候接收到已经被标记的,附加到后缓冲的Z-buffer.
  

(7)丢弃surface, 句柄与上下文
一些surface应该在上下文中被引用(比如渲染目标,Z-buffer或者是文理),一般把这些surface的句柄都存放在驱动的上下文中。与驱动有关的surface可能会被销毁变成lost surfaces.驱动上下文依然存在,但是对于lost surfaces可能并不存在有效的句柄。运行时保证了在这种情况下不会有绚烂指令发送到上下文中,但是同样也要处理在开始渲染之前如何将上下文与恢复的surfaces相关联的问题。运行时同时也保证了lost surfaces的句柄不被改变。反过来也确保了如果上下文保持对齐surfaces的句柄的话,这些surface总是在渲染在当前上下文可以恢复之前用相同的句柄值重新创建或者恢复。

一些驱动开发者可能想要通过直接在上下文中存储surface数据优化状态,而不是通过每一次调用D3dDrawPrimitives来完成。


注:由于笔者水平有限,难免有误,望多海涵并批评指正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值