今天要学习的这篇文章写的算是比较早的了,大概在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):最佳范例 学习笔记的更多相关文章

  1. DirectX Graphics Infrastructure (DXGI) 全屏设置相关问题

    原文地址: https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx 未完待续... DXGI是在 ...

  2. DirectX 9 UI三种设计学习笔记:文章4章Introducing DirectInput+文章5章Wrapping Direct3D

           本文从哈利_创.转载请注明出处.有问题欢迎联系本人!        邮箱:2024958085@qq.com 上一期的地址: DX 9 UI设计学习笔记之二 第4章 Introducin ...

  3. DirectX 总结和DirectX 9.0 学习笔记

    转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...

  4. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第四章:Direct 3D初始化

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第四章:Direct 3D初始化 学习目标 对Direct 3D编程在 ...

  5. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 全书总结

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 全书总结 本系列文章中可能有很多翻译有问题或者错误的地方:并且有些章节 ...

  6. RESTful接口设计原则/最佳实践(学习笔记)

    RESTful接口设计原则/最佳实践(学习笔记) 原文地址:http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api 1 ...

  7. Spring Boot学习笔记2——基本使用之最佳实践[z]

    前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...

  8. DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  9. DirectX 11游戏编程学习笔记之1: 开场白

    本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com           这是我之前的博客系列"DirectX9.0c游戏开发手记之'龙书'第二版学习笔记 ...

随机推荐

  1. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

  2. nodejs之get/post请求的几种方式

    最近一段时间在学习前端向服务器发送数据和请求数据,下面总结了一下向服务器发送请求用get和post的几种不同请求方式: 1.用form表单的方法:(1)get方法 前端代码: <form act ...

  3. 写出易调试的SQL

    h4 { background: #698B22 !important; color: #FFFFFF; font-family: "微软雅黑", "宋体", ...

  4. Loadrunner Http Json接口压力测试

    前天接到了一个测试任务,要求测试一下ES(elsticsearch)在不同并发下的查询效率.如图: 业务场景是在客户端根据具体车牌查询相关车辆信息,结果返回前10条记录. 从图中可以看到,接口的请求参 ...

  5. .NET应用程序域

    在.NET平台下,可执行程序并没有直接承载在Windows进程中,而非托管程序是直接承载的..NET可执行程序承载在进程的一个逻辑分区中,称之为应用程序域(AppDomain).一个进程可以包含多个应 ...

  6. pandas基础-Python3

    未完 for examples: example 1: # Code based on Python 3.x # _*_ coding: utf-8 _*_ # __Author: "LEM ...

  7. BPM任务管理解决方案分享

    一.方案概述任务是企业管理者很多意志的直接体现,对于非常规性事务较多的企业,经常存在各类公司下达的各种任务跟进难.监控难等问题,任务不是完成效果不理解,就是时间超期,甚至很多公司管理层下达的任务都不了 ...

  8. H3 BPM引擎API接口

    引擎API接口通过 Engine 对象进行访问,这个是唯一入口. 示例1:获取组织机构对象 this.Engine.Organization.GetUnit("组织ID"); 示例 ...

  9. FineReport关于tomcat集群部署的方案

    多台服务器集群后,配置权限.数据连接.模板.定时调度等,只能每台服务器一个个配置,不会自动同步到所有服务器. 针对上述情况,在FineReport中提供新集群部署插件,将xml配置文件.finedb/ ...

  10. 从myeclipse导入eclipse,不能识别为web项目(java项目转为web项目)

    1.进入项目目录,找到.project文件,打开. 2.找到<natures>...</natures>代码段. 3.在第2步的代码段中加入如下标签内容并保存:         ...