1 Direct3D 11设备介绍
Direct3D设备可以用来创建和释放对象,渲染图元,与图形驱动和硬件通信。Direct3D 11将设备分离为一个创建资源的设备(device)对象的对象和一个执行渲染的设备环境(device-context)对象。这种划分的设计目的是为了支持多线程之便。
1.1 设备
设备用来创建资源和枚举显示适配器支持的功能。在Direct3D 11中,设备对象由ID3D11Device接口创建。
每个应用程序必须至少有一个设备,大多数应用程序只创建一个设备。通过调用D3D11CreateDevice或者D3D11CreateDeviceAndSwapChain并指定D3D_DRIVER_TYPE标志为一个硬件驱动创建设备。根据功能需求,每个设备可以使用一个或多个设备环境。
1.1.1 由D3D11CreateDevice创建设备对象
HRESULT D3D11CreateDevice(
__in IDXGIAdapter *pAdapter,
__in D3D_DRIVER_TYPE DriverType,
__in HMODULE Software,
__in UINT Flags,
__in const D3D_FEATURE_LEVEL *pFeatureLevels,
__in UINT FeatureLevel,
__in UINT SDKVersion,
__out ID3D11Device **ppDevice,
__out D3D_FEATURE_LEVEL *pFeatureLevel,
__out ID3D11DeviceContext **ppImmediateContext
);
- pAdapter: 指向用来创建设备的显示适配器的指针。NULL表示使用默认的适配器
- DriverType: 指定驱动类型,常用的有D3D_DRIVER_TYPE_HARDWARE,使用硬件驱动
- Software: 实现软件光栅器的DLL的句柄。如果DriverType是D3D_DRIVER_TYPE_SOFTWARE,Software不能为NULL
- Flags: 运行时层标记
- pFeatureLevels:指向D3D特性等级数组的指针,如果为NULL,则使用默认的特性等级数组:
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1,
}
- FeatureLevel: pFeatureLevels中的元素个数
- SDKVersion: SDK版本,使用D3D11_SDK_VERSION
- ppDevice: 返回指向创建的设备对象的指针的地址
- pFeatureLevel: 返回pFeatureLevels数组中第一个测试成功的特性等级
- ppImmediateContext:返回指向创建的设备环境的指针的地址
1.1.2 由D3D11CreateDeviceAndSwapChain创建设备对象
HRESULT D3D11CreateDeviceAndSwapChain(
__in IDXGIAdapter *pAdapter,
__in D3D_DRIVER_TYPE DriverType,
__in HMODULE Software,
__in UINT Flags,
__in const D3D_FEATURE_LEVEL *pFeatureLevels,
__in UINT FeatureLevel,
__in UINT SDKVersion,
__in const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
__out IDXGISwapChain **ppSwapChain,
__out ID3D11Device **ppDevice,
__out D3D_FEATURE_LEVEL *pFeatureLevel,
__out ID3D11DeviceContext **ppImmediateContext
);
D3D11CreateDeviceAndSwapChain比D3D11CreateDevice多了两个参数。
- pSwapChainDesc: 指向交换链描述的指针,
- ppSwapChain: 指向创建的交换链对象的指针的地址
typedef struct DXGI_SWAP_CHAIN_DESC {
DXGI_MODE_DESC BufferDesc;
DXGI_SAMPLE_DESC SampleDesc;
DXGI_USAGE BufferUsage;
UINT BufferCount;
HWND OutputWindow;
BOOL Windowed;
DXGI_SWAP_EFFECT SwapEffect;
UINT Flags;
} DXGI_SWAP_CHAIN_DESC;
- BufferDesc: 描述后缓冲的显示模式
- SampleDesc: 描述多重采样参数
- BufferUsage: 描述表面的用法和CPU访问后缓冲的操作。后缓冲用于着色器输入或渲染对象输出
- BufferCount: 缓冲区个数,包括前缓冲
- OutputWindow: 输出窗口句柄,不能为NULL
- Windowed: true表示窗口模式,false表示全屏模式
- SwapEffect: 枚举类型。描述了提交表面后处理缓冲区内容的可选方法
- Flags: 枚举类型。描述交换链的行为
typedef struct DXGI_MODE_DESC {
UINT Width;
UINT Height;
DXGI_RATIONAL RefreshRate;
DXGI_FORMAT Format;
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
DXGI_MODE_SCALING Scaling;
} DXGI_MODE_DESC, *LPDXGI_MODE_DESC;
显示模式描述
- Width: 分辨率宽
- Height: 分辨率高
- RefreshRate: 结构类型。描述刷新频率
- Format: 结构类型。描述显示模式
- ScanlineOrdering: 枚举类型。描述扫描线绘制模式
- Scaling: 枚举类型。描述缩放模式
1.2设备环境
一个设备环境包含了设备使用的环境或配置。确切的说,设备环境用来设置管线状态,并使用资源生成渲染命令。Direct3D 11实现了两种设备环境,一种是及时渲染,另一种是延迟渲染;两种环境对象都由ID3D11DeviceContext接口实现。
1.3即时环境
即时环境即直接由驱动渲染。即时环境可以从GPU检索数据,每个设备只能有一个即时环境。即时环境可以用来立即渲染一个命令列表。
有两种获得即时环境的方法:
- 通过调用D3D11CreateDevice或D3D11CreateDeviceAndSwapChain
- 通过调用ID3D11Device::GetImmediateContext
1.4延迟环境
延迟环境将GPU命令记录到一个命令列表。延迟环境主要用于多线程,而对于单线程的应用是不需要的。延迟环境一般由辅助线程使用而不是主线程。当创建一个延迟环境时,不会继承即时环境的任何状态。
为获得延迟环境,可以通过调用ID3D11Device::CreateDeferredContext.
任何环境(即时或者延迟)都可以用于任何线程,只要保证每个线程每次只用一个环境。
1.5关于线程
Direct3D 11和之前版本Direct3D在线程模型上的不同:
所有ID3D11Device接口的方法都是线程自由(free-threaded)的。所谓线程自由是指多个线程同时调用函数是安全的。
- 所有ID3D11DeviceChild的派生接口(ID3D11Buffer, ID3D11Query等)都是线程自由的。
- Direct3D 11将资源创建和渲染分离为两个接口。Map, Unmap, Begin, End和GetData由ID3D11DeviceContext实现,因为ID3D11Device定义了很严格的操作顺序。ID3D11Resource和ID3D11Asynchronous接口的方法也是线程自由的。
- ID3D11DeviceContext的方法不是线程自由的,即,它们需要单线程。每次只有一个线程可以安全的调用它的任何方法(Draw, Copy, Map等)。
- 一般的,线程自由减少了同步元操作的次数和持续时间。使用同步的应用程序保存很长时间,这会直接影响程序所能达到的并发程度。
ID3D10Device接口方法没有设计成线程自由的。ID3D10Device实现了所有的创建和渲染功能(跟Direct3D 9中的ID3D9Device一样)。Map和Unmap在ID3D10Resource的派生接口中实现。Begin, End和GetData在ID3D10Asynchronous的派生接口中实现。
2软件层
Direct3D 11的运行时由层构成,包括核层的基础功能及外层的可选创建和辅助开发功能。该部分介绍每个层的功能。
一般的,层增加功能,但不改变现有的行为。例如,不管调试层是否实例化,核函数的返回值都是一样的,虽然调试层的实例化会带来额外的调试输出。
层的创建是在创建设备时,通过调用D3D11CreateDevice或D3D11CreateDeviceAndSwapChain并提供一个或多个D3D11_CREATE_DEVICE_TYPE值。
2.1 核层
核层是默认存在的;只提供很少的API和设备驱动间的映射,减少高频率调用的开销。由于核层对性能的重要性,它只执行重要的验证。其他的层是可选的。
2.2 调试层
调试层提供了大量的附件参数和一致性验证(比如检验着色器连接和资源绑定,检验参数一致性和报告错误描述)。
要创建支持调试层的设备,必须安装DirectX SDK(来获得D3D11SDKLayers.dll),然后再调用D3D11CreateDevice或D3D11CreateDeviceAndSwapChain时指定D3D11_CREATE_DEVICE_DEBUG标记。注意运行具有调试层的应用程序会很慢。
3 创建交换链
void mCreateSwapChain()
{
ID3D11Device *device = 0;
DXGI_SWAP_CHAIN_DESC sd;
IDXGIDevice *dxgiDevice = 0;
//通过检索IDXGIDevice接口的GUID,返回device对象上的指向IDXGIDevice接口的指针
device->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
IDXGIAdapter *dxgiAdapter = 0;
//得到dxgiDevice对象的父对象dxgiAdapter
dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter);
IDXGIFactory *dxgiFactory = 0;
//得到dxgiAdapter对象的父对象dxgiFactory
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
IDXGISwapChain *swapChain;
dxgiFactory->CreateSwapChain(device, &sd, &swapChain);
dxgiDevice->Release();
dxgiAdapter->Release();
dxgiFactory->Release();
}
注:本文翻译整理自DXSDK文档,参考有 Introduction to 3D Game Programming with DirectX 11, MSDN库