DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx 。
我本意是记录下学习笔记,但可能写成了翻译,但这也没有办法的事,MSDN的写作风格就是简单凝练,缺少参考索引,所以看MSDN往往也就是读完正文,点点加有超链接的名词,顶多再跑跑例程而已。
Microsoft DirectX Graphics Infrastructure(DXGI)是从WIndows Vista时代开始引入的一个子系统,它封装了一些Direct3D 10, 10.1, 11和11.1需要的低层次(low-level)任务。对于使用Direct3D 9的程序员,DXGI包括绝大部分之前打包进Direct3D 9 的enumeration,生成swap-chain和presentation相关API。当你要把应用迁移到DXGI,Direct3D 10.x和Direct3D 11.x,你必须充分考察一些事项以保证程序正常运行。
这篇文章主要讨论以下事项:
- 全屏相关琐事
- 多显示器
- 窗口样式和DXGI
- 多线程和DXGI
- 伽马(Gamma)和DXGI
- DXGI 1.1
- DXGI 1.2
全屏相关琐事
从Direct3D 9迁移到DXGI、Direct3D 10.x或者Direct3D 11.x,会给窗口模式到全屏模式转换的操作带来很多状况。这主要是因为Direct3D 9不像使用DXGI的程序那样需要那么多的手动操作,DXGI给开发者提供了很多可以追踪窗口样式和状态的细节操作。当古老的模式转换程序在新平台运行的时候,总是会引起一些意想不到的问题。
Direct3D 9通常通过设置front buffer分辨率来转换窗口模式到全屏模式,并强迫设备进入全屏独占模式再设置back buffer与其匹配。还有一条单独路径用于处理窗口尺寸,因为它们必须处理窗口进程接收到的WM_SIZE信号。
DXGI结合了两种情况的处理,试图简化处理流程。例如窗口模式下边缘被拉扯时,应用接收到WM_SIZE信号。DXGI拦截该信号,并修改front buffer。开发者只需要针对back buffer调用IDXGISwapChain::ResizeBuffers调整尺寸与随WM_SIZE信号所传入参数一致。当应用需要在全屏及窗口模式间切换时,只需调用IDXGISwapChain:SetFullscreenState。DXGI自动调整front buffer并发送WM_SIZE信号。应用再次调用ResizeBuffers,就像窗口边缘被拖拽时一样。
上述解释的方法论使用了一条独特的路径。DXGI默认设置桌面分辨率为全屏分辨率。但很多应用要为全屏切换到某个特殊分辨率。DXGI为这种情况准备了IDXGISwapChain::ResizeTarget。在调用SetFullscreenState之前调用。虽然可以以相反的顺序调用,但会多发送WM_SIZE一次,课程会引起闪烁。在调用SetFullScreenState之后还是要调用ResizeTarget,只不过参数DXGI_MODE_DESC的RefreshRate子项设为空。这是个非操作指令,但这可以避免刷新率相关的琐事,我们接下来就聊聊这个。
全屏模式时,桌面窗口管理器是禁用的。此时DXGI不会像窗口模式那样用blit,而是使用翻转去显示back buffer。如果特定的需求不满足,效益是不明确的。为了确定DXGI会用翻转代替blit,front buffer和back buffer必须保持一致。如果此前应用正确处理了WM_SIZE,两个buffer格式必然一直,也就没什么好担心的了。
大多数应用的主要问题是刷新率。刷新率必须是swap chain正在使用的IDXGIOutput对象的枚举值之一(IDXGIOutput可以枚举系统支持的所有刷新率)。如果在调用ReisizeTarget的时候,DXGI_MODE_DESC结构的RefreshRate子项置空,就能在调用后在子项中返回由系统指定的数值。注意不要以为某个刷新率会一直被支持而直接把它写在程序里。开发者经常希望获得一个60Hz的刷新率,而不知道系统真实支持刷新率只是60Hz的近似值,如果强行在程序里写入60Hz这个固定数值,那程序肯定会放弃翻转,而改用blit。
最后还要注意个问题,开发者经常要面对的需求是在全屏模式下改变分辨率。有时调用ResizeTarget和SetFullscreenState返回成功,但全屏分辨率依然是桌面分辨率。或者开发者给swap chain指定了一个分辨率,但DXGI却不管这些,还是把全屏分辨率设定为桌面分辨率。除非还调用了其他指令,DXGI就是默认把桌面分辨率设为全屏分辨率。在创建全屏swap chain时DXGI_SWAP_CHAIN_DESC结构的Flags子项一定要设为DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH,以重写DXGI的默认行为。这个flag
也可以在ResizeTarget函数里动态调用。
多显示器
在多显示器情况下,DXGI要遵循两条准则。
第一条应用于再多显示器上创建两个以上全屏swap chain。当创建这种应用的时候,最好的办法是先设置他们的swap chain为窗口模式再设为全屏模式。如果swap chain在创建时被设为全屏模式,那么第二个swap chain会引起第一个swap chain模式转变,有可能会让它退出全屏模式。
第二条应用于输出(DXGI术语里的output往往是指显示器)。当创建swap chain时一定要小心输出设备。在DXGI使用环境中设置全屏时,IDXGIOutput对象控制控制着swap chain使用的显示器。Direct3D 9就没输出设备的概念。
窗口样式和DXGI
Direct3D 9应用在窗口模式与全屏模式切换时有很多工作要做。像改变窗口样式:填减边框、滚动条之类的。当应用迁移到DXGI,Direct3D 10.x或者Direct3D 11.x的时候,这些工作都被安排在适当的位置。因变化的不同,也有可能出现意想不到的情况。例如:当迁移到窗口模式时,应用不再有窗口框架或窗口边框相应处理程序。这是因为DXGI自动化了一部分工作,隐藏了相关过程。可以手动设置DXGI,但也可能引起期望外的状况。
通常我们建议尽量减少人力工作,将工作尽可能交给DXGI。但如果确实需要手动处理窗口的行为属性,可以用IDXGIFactory::MakeWindowAssociation禁掉一部分自动功能。
多线程和DXGI
还得特别注意在多线程编程时使用DXGI不能引起死锁。因为DXGI与窗口化的紧密互动关系,它偶尔会发送窗口信号给相关应用窗口。DXGI需要窗口在继续执行前响应它的信号,它会用SenMessage函数,这是个同步调用。应用必须在SendMessage返回前处理窗口信号。
如果在一个程序里,DXGI调用和消息泵在一个线程里(或者程序本身就是单线程的),这种情况没太多要担心的。这种情况下,SendMessage会调用窗口的WindowProc(创建窗口的时候在描述结构里填写的那个)。这样就绕过了消息泵,并且允许在调用SendMessage后继续执行应用。IDXGISwapChain和IDXGISwapChain::Present都属于DXGI调用,DXGI会因为ResizeBuffers或ResizeTarget推迟工作直到Present被调用。
如果DXGI调用和消息泵不在同一线程,一定要注意避免死锁。当消息泵和SendMessage在不同的线程,SendMessage把信号添加到信号队列,然后等待窗口处理这个信号。如果窗口例程没有被消息泵调用,这个消息可能永远不会被处理并且DXGI要一直等下去了。
例如,一个程序消息泵在一个线程,渲染在另一个,它可能要改变模式。消息泵线程告诉渲染线程要改变模式了,然后等在那里一直等到改变完成。然而,这个渲染县城调用了DXGI函数,它又调用了SendMessage,就一直锁定在这里等待消息泵处理这个信号。一个死锁发生了,因为两个线程在互相等待。为了避免这样,永远都不要锁定消息泵。如果一个锁定无法避免,那么所有DXGI交互都应该与消息泵发生在同一个线程。
伽马(Gamma)和DXGI
虽然在Direct3D 10.x和Direct3D 11.x里,gamma最好用SRGB材质处理,但是对于不想使用2.2这个值或者渲染标的不支持SRGB的程序员来说,gamma校正还是很有用的。用DXGI设置gamma校正的时候一定要注意两个问题:第一校正值传入IDXGIOutput:SetGammaControl是float值,不是WORD值。同样从Direct3D 9迁移来的程序不要试图将传入SetGammaControl的值转换成WORD值。
第二件事,在转换为全屏模式后,因为使用的IDXGIOutput对象的因素,SetGammaControl可能看上去没有效果。当转换为全屏模式后,DXGI创建了一个新的输出对象,并且将这个对象应用于之后的输出相关操作。使用全屏前枚举出来的对象调用SetGammaControl是不对的,当前处在生效状态的对象已经变成其他的对象了。为了避免这种情况要在调用SetGammaControl之前调用IDXGISwapChain::GetContainingOutput来获取当前对象,从而得到正确的行为。
要想获取正确使用Gamma的相关知识,请浏览Using gamma correction。
DXGI 1.1
包括在Windows 7和安装在Windows Vista(KB971644)的Direct3D 11运行时包括DXGI 1.1。这个升级包增加了一些新格式的定义(特别是BGRA,10-bit X2 bias和Direct3D 11的BC6H和BC7纹理压缩接口),还有些用于美剧远程桌面链接的DXGI工厂接口适配器(CreateDXGIFactory1, IDXGIFactory1,IDXGIAdapter1)。
当时用Direct3D 11,调用D3D11CreateDevice或者D3D11CreateDeviceAndSwapChain并传入空IDXGIAdapter指针,运行时会默认使用DXGI 1.1。不支持在同一个进程内混用1.0和1.1版本。在同一进程内昏庸DXGI对象实例也被不支持。因此, 当你使用DirectX11时,显示使用DXGI.DLL里的CreateDXFactory1入口点创建IDXGIFactory1的DXGI接口使来保证应用一直使用了1.1版本。
DXGI 1.2
Windows 8里包括Direct3D 11.1运行时同时也包括1.2版本。
1.2版本同时启用了以下这些特点:
- 立体渲染
- 16位像素格式
支持DXGI_FORMAT_B5G6R5_UNORM和DXGI_FORMAT_B5G5R5A1_UNORM全部特性
添加了一个新的DXGI_FORMAT_B5G5R5A1_UNORM格式
- 视频格式
- 新DXGI接口
DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记的更多相关文章
- DirectX Graphics Infrastructure (DXGI) 全屏设置相关问题
原文地址: https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx 未完待续... DXGI是在 ...
- DirectX 9 UI三种设计学习笔记:文章4章Introducing DirectInput+文章5章Wrapping Direct3D
本文从哈利_创.转载请注明出处.有问题欢迎联系本人! 邮箱:2024958085@qq.com 上一期的地址: DX 9 UI设计学习笔记之二 第4章 Introducin ...
- DirectX 总结和DirectX 9.0 学习笔记
转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第四章:Direct 3D初始化
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第四章:Direct 3D初始化 学习目标 对Direct 3D编程在 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 全书总结
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 全书总结 本系列文章中可能有很多翻译有问题或者错误的地方:并且有些章节 ...
- RESTful接口设计原则/最佳实践(学习笔记)
RESTful接口设计原则/最佳实践(学习笔记) 原文地址:http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api 1 ...
- Spring Boot学习笔记2——基本使用之最佳实践[z]
前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...
- DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...
- DirectX 11游戏编程学习笔记之1: 开场白
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 这是我之前的博客系列"DirectX9.0c游戏开发手记之'龙书'第二版学习笔记 ...
随机推荐
- 配置android sdk 环境
1:下载adnroid sdk安装包 官方下载地址无法打开,没有vpn,使用下面这个地址下载,地址:http://www.android-studio.org/
- [APUE]文件和目录(中)
一.link.unlink.remove和rename 一个文件可以有多个目录项指向其i节点.使用link函数可以创建一个指向现存文件连接 #include <unistd.h> int ...
- 创建 OVS Local Network - 每天5分钟玩转 OpenStack(129)
上一节我们完成了 OVS 的准备工作,本节从最基础的 local network 开始学习.local network 不会与宿主机的任何物理网卡连接,流量只被限制在宿主机内,同时也不关联任何的 VL ...
- MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决
一.简介 MySQL是最流行的开放源码SQL数据库管理系统,它是由MySQL AB公司开发.发布并支持的.有以下特点: MySQL是一种数据库管理系统. MySQL是一种关联数据库管理系统. MySQ ...
- Xcode 锁终端
锁终端 输入: <1>cd /Applications/Xcode.app 回车 结果显示: Xcode.app 输入: <2>sudo chown -hR root:whee ...
- GCC学习(1)之MinGW使用
GCC学习(1)之MinGW使用 因为后续打算分享一些有关GCC的使用心得的文章,就把此篇当作一个小预热,依此来了解下使用GNU工具链(gcc.gdb.make等)在脱离IDE的情况下如何开发以及涉及 ...
- 树莓派3B的食用方法-1(装系统 网线ssh连接)
首先要有一个树莓派3B , 在某宝买就行, 这东西基本上找到假货都难,另外国产和英国也没什么差别,差不多哪个便宜买哪个就行. 不要买店家的套餐,一个是配的东西有些不需要,有的质量也不好. 提示:除了G ...
- 烂泥:数据库管理之phpmyadmin免密码配置
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 其实这篇文章很早就想写了,但是一直没有时间.刚好今天下午稍微空了点,就把这篇文章整理出来 ...
- 记从安装centos系统在到使用mono3.2部署MVC过程遇到的问题
一.安装虚拟机并安装配置系统 我不太愿意去下载vmware就用系统里面自带的Hyper-V 系统我选择了最新版本的CentOs6.4 下载地址:http://mirrors.163.com/cento ...
- ucos实时操作系统学习笔记——任务间通信(队列)
ucos操作系统中的queue机制同样使用了event机制来实现,其实和前面的sem,mutex实现类似,所不同的是对sem而言,任务想获得信号量,对mutex而言,任务想获得的是互斥锁.任务间通信的 ...