Direct3d 12概念点

组件对象模型COM

        COM对象的智能指针,可使用ComPtr类。当一个ComPtr实例超出作用域范围时,它会自动调用相应COM对象的Release方法,省掉了我们手动释放的麻烦。

#include <wrl.h>      

交换链(swap chain)

前台缓冲区(front buffer)后台缓冲区(back buffer)。当后台缓冲区动画帧绘制完毕时,后台会变成前台,呈现绘制好的画面,而前台会变成后台进行下一帧的绘制。使用两个缓冲区的情况称为双缓冲(double buffering),三个缓冲区称为三重缓冲(triple buffering),对于一般应用而言只需要两个缓冲区即可。

深度缓冲区(depth buffer)

存储的时特定像素的深度信息。深度值的范围为[0,1],0代表观察者在视锥体中能看到离自己最近的物体,1则代表观察者在视锥体中可以看到离自己最远的物体。深度缓冲区中的元素与后台缓冲区的像素一一对应,即后台缓冲区第i行第j列的元素对应深度缓冲区中第i行第j列的元素。所以,如果后台缓冲区的分辨率是1920 x 1080,则深度缓冲区就应该有1920 x 1080个深度元素。

Direct3D采用了深度缓冲(depth buffering)或z缓冲(z-buffering,z指z坐标)来确定不同物体间的像素前后顺序。注意:如果使用了深度缓冲,则物体的绘制顺序也就无关紧要了。

龙书中没有提到开启深度测试是否也可以无视半透明物体的渲染顺序问题,此处有待验证。

深度测试的方法是两两比较法,具有最小深度值的像素将被写入后台缓冲区,而不是按照由远及近的原则(实际上正是为了解决由远及近的渲染方式引起的大量能耗才发明的深度缓冲技术) 。

多重采样(MSAA)

超级采样(SSAA,Super Sample Anti-Aliasing),使用4倍于屏幕分辨率大小的后台缓冲区和深度缓冲区,当数据要从后台缓冲区调往前台缓冲区时,会将后台缓冲区按4个像素一组进行降采样(downsample),把放大的采样点数压缩回原采样大小,用求平均值的方法得到一种相对平滑的像素颜色。但是此种方法开销过大,因为它将像素的处理数量和占用的内存大小都增加到了之前的4倍。

Direct3D支持一种在行能与效果方面都较为这种的抗锯齿技术,名为多重采样(MSAA,MultiSample Anti-Aliasing)。多重采样与超级采样的区别在于,多重采样只对边缘进行抗锯齿,而超级采样这种比较老套的方式需要对每个像素进行多次计算。

在Direct3D中,使用DXGI_SAMPLE_DESC结构体进行多重采样,原型如下:

typedef struct DXGI_SAMPLE_DESC
{
    UINT Count;                         //指定了每个像素的采样次数
    UINT Quality;                       //指示用户期望的图像质量级别
}DXGI_SAMPLE_DESC;

在创建交换链缓冲区和深度缓冲区时都需要填写这个结构体。Direct3d 12不支持MSAA交换链。

 功能级别(feature level)

从Direct3D 11开始引进了功能级别概念,主要是为了支持不同的电脑配置(这一点有点像unityshader中的fallback)。我目前的版本功能级别大致包含如下:

typedef enum D3D_FEATURE_LEVEL { 
  D3D_FEATURE_LEVEL_9_1   = 0x9100,
  D3D_FEATURE_LEVEL_9_2   = 0x9200,
  D3D_FEATURE_LEVEL_9_3   = 0x9300,
  D3D_FEATURE_LEVEL_10_0  = 0xa000,
  D3D_FEATURE_LEVEL_10_1  = 0xa100,
  D3D_FEATURE_LEVEL_11_0  = 0xb000,
  D3D_FEATURE_LEVEL_11_1  = 0xb100,
  D3D_FEATURE_LEVEL_12_0  = 0xc000,
  D3D_FEATURE_LEVEL_12_1  = 0xc100
} D3D_FEATURE_LEVEL;

就发表这篇文章的时间而言,还是有很多游戏是基于dx9制作的,现实中也应该考虑到稍旧的电脑设备,所以在编写架构时,应当将低功能级别加入考虑以获得更多用户。

DirectX图形基础结构

DXGI(DirectX Graphic Infrastructure)是一种与Direct3D配合使用的API。设计DXGI的基本理念是使多种图形API中所共有的底层任务能借助一组通用API来进行处理。例如2D和3D渲染中都会用到的交换链接口IDXGISwapChain就属于DXGI API。

IDXGIFactory是DXGI中的关键接口之一,主要用于创建IDXGISwapChain接口以及枚举显示适配器。显示适配器(如独显)用接口IDXGIAdapter表示。一个系统也可能存在多个显示设备(显示器),用IDXGIOutput接口表示。每个适配器都与一组显示输出相关联,例如三台显示器和两块显卡,一块显卡与两台显示器相关联,另一块显卡与剩下的一台显示器相关联。

资源驻留

这一点比较像渲染流水线中的裁剪,只有位于玩家视锥范围内的场景才会被渲染,资源驻留的原理与此类似,比如玩家在洞穴内部时不会用到洞穴外部的资源。Direct3D 12中,应用程序通过控制资源在显存中的去留,主动管理资源的驻留情况(即Residency,无论资源是否已位于显存中,都可对其进行管理)。该技术的基本思路为使应用程序占用最小的显存空间

一般来说,资源在创建时就会驻留在显存中,而当它被销毁时则清出。但是通过下面的方法,我们就可以自己来控制资源的驻留:

HRESULT ID3D12Device::MakeResident
(
UINT NumObjects,                                //该数组中资源的数量
ID3D12Pageable *const *ppObjects                //ID3D12Pageable资源数组
);


HRESULT ID3D12Device::Evict
(
UINT NumObjects,
ID3D12Pageable *const *ppObjects
);

程序应该避免在短时间内于显存中交换进出相同的资源,这会引起过高的开销。最理想的情况是,所清理出的资源在短时间内不会再次使用。游戏关卡或游戏场景的切换便是一个很好的例子。

CPU与GPU间的交互

cpu与gpu,两者并行工作,时而也需要同步(CPU递交指令给GPU,GPU进行渲染,CPU等待GPU渲染完成) 。

为了获得最佳性能,最好的情况是二者尽量同时工作,少同步。

命令队列和命令列表

借助Direct3D API ,CPU可以利用命令列表(command list)将命令提交到这个队列中去,当一系列命令被提交至命令队列时,它们不会被GPU立刻执行,因为GPU可能还在处理先前的命令。对于游戏这种程序来说,最好保持CPU和GPU同时工作,充分利用资源。

CPU与GPU之间的同步

假设队列中有一条命令A,希望GPU在处理完命令A后CPU再执行下一个动作(比如对一个资源A进行修改,希望GPU先对其修改,完了之后再返回给CPU修改),这时需要用到围栏(fence)强制CPU等待。围栏用ID3D12Fence接口来表示,此技术用于实现CPU和GPU的同步。

资源转换

为了防止出现resource hazard,DX针对资源设计了一组相关状态,资源在创建时会处于默认状态,该状态会一直持续到应用程序通过DX将其转换为另一种状态为止。例如,对某个资源(纹理)执行写操作时,需要将它的状态转换为渲染目标状态;对该资源进行读操作时,再把它的状态变为着色器资源状态。

资源转换的操作会造成程序性能的下降,自动跟踪状态转换的系统也会强行增加程序的额外开销。

命令与多线程 

如果只靠一个命令列表来绘制整个场景会占用不少的CPU时间,可以采取并行创建命令列表的思路,例如创建4条线程,每条分别负责构建一个命令列表来绘制25的场景。

注意:

1.多线程无法同时共享相同的命令列表,它们之间是互相独立的。

2.多线程无法同时共享同一个命令分配器,也不能同时调用同一命令分配器的方法,每个线程仅使用属于自己的命令分配器。

3.多线程可以同时访问一个命令队列,也能同时调用它的方法,每个线程都可以同时向命令队列提交它们自己所生成的命令列表。

4.出于性能原因,应用程序必须在初始化期间,指出用于并行记录命令的命令列表最大数量。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值