《dx12 龙书》第四部分学习笔记——预备知识(下)

7、多重采样技术的原理

 由于屏幕中显示的像素不可能是无穷小的,所以并不是任意一条直线都能在显示器上“平滑”而完美地呈现出来。即为以像素矩阵 (matrix of pixels, 可以理解为“像素2D数组”)逼近直线的方法所产生的“阶梯” (aliasing, 锯齿状走样)效果。类似地,显示器中呈现的三角形之边也存在着不同程度的锯齿效应。
 通过提高显示器的分辨率就能够缩小像素的大小,继而使上述问题得到显著地改善,使阶梯效应在很大程度上不易被用户所察觉。
 在不能提升显示器分辨率,或在显示器分辨率受限的情况下,我们就可以运用各种反走样(antialiasing, 也有译作抗锯齿、反锯齿、反失真等)技术。有一种名为超级采样(supersampling, 可简记作SSAA,即Super Sample Anti-Aliasing)的反走样技术,它使用4倍于屏幕分辨率大小的后台缓冲区和深度缓冲区。3D场景将以这种更大的分辨率渲染到后台缓冲区中。当数据要从后台缓冲区调往屏幕显示的时候,会将后台缓冲区按4个像素一组进行解析(resolve, 或称降采样,downsample。把放大的采样点数降低回原采样点数):每组用求平均值的方法得到一组相对平滑的像素颜色。因此,超级采样实际上是通过软件的方式提升了画面的分辨率。
 超级采样是一种开销高昂的操作,因为它将像素的处理数量和占用的内存大小都增加到之前的4倍。
 对此,Direct3D还支持一种在性能于效果等方面都较为折中的反走样技术,叫做多重采样(multisampling, 可简记作MSAA,即MultiSample Anti-Aliasing)。这种技术通过跨子像素共享一些计算信息,从而使它比超级采样的开销更低。现假设采用4X多重采样(即每个像素都有4个子像素),并同样使用4倍于屏幕分辨率的后台缓冲区和深度缓冲区。值得注意的是,这种技术并不需要对每一个子像素都进行计算,而是仅计算一次像素中心处的颜色,再基于可视性(每个子像素经深度/模板测试的结果)和覆盖性(子像素的中心在多边形的里面还是外面?)将得到的颜色信息分享给其子像素。下图展示了一个多重采样的实例。
多重采样实例注意:
 超级采样和多重采样的关键区别是显而易见的。对于超级采样来说,图像颜色要根据每一个子像素来计算,因此每个子像素都可能各具不同的颜色。而以多重采样的方式来求取图像颜色时,每个像素只需计算一次,最后,再将得到的颜色数据复制到多边形覆盖的所有可见子像素之中。由于计算图像颜色是图形流水线中开销最大的步骤之一,所以用多重采样来代替超级采样对节省资源而言意义非凡。但是,超级采样的精准度确实更高一筹。
 上图所示的是一种将每个像素都以均匀栅格划分为4个子像素的反锯齿采样模式。实际上,每家硬件厂商所采用的模式(即选定的子像素位置,可以说决定了采样的位置)可能会各不相同,而Direct3D也并没有定义子像素的具体布局。在各种特定的情况下,不同的布局模式各有千秋。

8、利用Direct3D进行多重采样

typedef struct DXGI_SAMPLE_DESC
{UINT Count; UINT Quality;
}DXGI_SAMPLE_DESC;

 Count成员指定了每个像素的采样次数,Quality成员则用于指示用户期望的图像质量级别。采样数量越多或质量级别越高,其渲染操作的代价也就会愈发高昂,所以需要在质量与速度之间做出利弊权衡。至于质量级别的范围,则要取决于纹理格式和每个像素的采样数量。
 根据给定的纹理格式和采样数量,我们就能用ID3D12Device::CheckFeatureSupport方法查询到对应的质量级别:

typedef struct D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS{DXGI_FORMAT Format;UINT SampleCount;D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags;UINT NumQualityLevels;
}D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
msQualityLevels.Format = mBackBufferFormat;
msQualityLevels.SampleCount = 4;
msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
msQualityLevels.NumQualityLevels = 0;
ThrowIfFailed(md3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,&msQualityLevels,sizeof(msQualityLevels)));

 注意,此方法的第二个参数兼具输入和输出的属性。当它作为输入参数时,我们必须指定纹理格式、采样数量以及希望查询的多重采样所支持的标志。接着,待函数执行后便会填写图像质量级别作为输出。对于某种纹理格式和采样数量的组合来讲,其质量级别的有效范围为0至NumQualityLevels-1。
 每个像素的最大采样数量被定义为:
 #define D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT(32)
 但是,考虑到多重采样会占用内存资源,又为了保证程序性能等原因,通常会把采样数量设定为4或8。如果不希望使用多重采样,则可将采样数量设置为1,并令质量级别为0。其实在所有支持Direct3D11的设备上,就已经可以对所有的渲染目标格式用用4X多重采样了。
注意:
 在创建交换链缓冲区和深度缓冲区时都需要填写DXGI_SAMPLE_DESC结构体。当创建后台缓冲区和深度缓冲区时,多重采样的有关设置一定要相同。

9、功能级别

 举例以下参数大致对应于Direct3D9到Direct3D11之间的各种版本:

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;

 “功能级别”为不同级别所支持的功能进行了严格的界定(每个功能级别所支持的特定功能可参见SDK文档)。
 例,一款支持功能级别11的GPU,除了个别特例之外,必须支持完整的Direct3D11功能集。
 功能集使程序员的开发工作更加便捷——只要了解所支持的功能集,就能知道有哪些Direct3D功能可供使用。
 如果用户的硬件不支持某特定功能级别,应用程序理当回退至版本更低的功能级别。在现实的应用程序中,我们往往需要考虑支持稍旧的硬件,以获得更多的用户。

10、DirectX图形基础结构

 DirectX图形基础结构(DirectX Graphics Infrastructure,DXGI,也有译作DirectX图形基础设施)是一种与Direct3D配合使用的API设计DXGI的基本理念是使多种图形API中所共有的底层任务能借助一组通用API来进行处理。例如,为了保证动画的流畅性,2D渲染与3D渲染两组API都要用到交换链和页面翻转功能,这里所用的交换链接口IDXGISwapChain实际上就属于DXGI API。DXGI还用于处理一些其他常用的图形功能,如切换全屏模式,枚举显示适配器、显示设备及其支持的显示模式(分辨率、刷新率等)等这类图形系统信息。除此之外,它还定义了Direct3D支持的各种表面格式信息(DXGI_FORMAT)。
 我们刚刚简单地叙述了DXGI的概念,下面来介绍一些在Direct3D初始化时会用到的相关接口。IDXGIFactory是DXGI中的关键接口之一。通常来说,显示适配器(display adapter) 是一种硬件设备(如独立显卡),然而系统也可以用软件显示适配器来模拟硬件的图形处理功能。一个系统中可能会存在数个适配器(比如装有数块显卡)。适配器用接口IDXGIAdapter来表示。我们可以用下面的代码来枚举一个系统中的所有适配器:

void D3DApp::LogAdapters()
{UINT i = 0;IDXGIAdapter* adapter = nullptr;std::vector<IDXGIAdapter*> adapterList;while (mdxgiFactory->EnumAdapters(i, &adapter) !=DXGI_ERROR_NOT_FOUND){DXGI_ADAPTER_DESC desc;adapter->GetDesc(&desc);std::wstring text = L"***Adapter: ";text += desc.Description;text += L”\n”;OutputDebugString(text.c_str());adapterList.push_back(adapter);++i;}for (size_t i = 0; i < adapterList.size(); ++i){LogAdapterOutputs(adapterList[i]);ReleaseCom(adapterList[i]);}
}

注: D3DAPP类后续会讲到,这里先写着,暂时不介绍
 另外,一个系统也可能装有数个显示设备。我们称每一台显示设备都是一个显示输出(display output, 有的文档也作adapter output, 适配器输出)实例,用IDXGIOutput接口来表示。每个适配器都与一组显示输出相关联。
 每种显示设备都有一系列它所支持的显示模式,可以用下列DXGI_MODE_DESC结构体中的数据成员来加以表示:

#include <minwindef.h>
#include <Dxgiformat.h>
typedef struct DXGI_MODE_DESC
{UINT Width;  //分辨率宽UINT Height;  //分辨率高度DXGI_RATIONAL RefreshRate;  //刷新率,单位为赫兹HzDXGI_FORMAT Format;  //显示格式DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;  //逐行扫描vs.隔行扫描DXGI_MODE_SCALING Scaling;  //图像相对于屏幕的拉伸
} DXGI_MODE_DESC;typedef struct DXGI_RATIONAL
{UINT Numerator;UINT Denominator;
} DXGI_RATIONAL;typedef enum DXGI_MODE_SCANLINE_ORDER
{DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED = 0,DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE = 1,DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST = 2,DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST = 3
} DXGI_MODE_SCANLINE_ORDER;typedef enum DXGI_MODE_SCALING
{DXGI_MODE_SCALING_UNSPECIFIED = 0,DXGI_MODE_SCALING_CENTERED = 1,//不做缩放,将图像显示在屏幕中DXGI_MODE_SCALING_STRETCHED = 2//根据屏幕分辨率对图像进行拉伸
} DXGI_MODE_SCALING;

 一旦确定了显示模式的具体格式(DXGI_FORMAT),我们就能通过下列代码,获得某个显示输出对此格式所支持的全部显示模式:

void D3DApp::LogOutputDisplayModes(IDXGIOutput*output, DXGI_FORMAT format)
{UINT count = 0;UINT flags = 0;// 以nullptr作为参数调用此函数来获取符合条件的显示模式个数output->GetDisplayModeList(format, flags, &count, nullptr);std::vector<DXGI_MODE_DESC> modeList(count);output->GetDisplayModeList(format, flags, &count,&modeList[0]);for (auto& x : modeList){UINT n = x.RefreshRate.Numerator;UINT d = x.RefreshRate.Denominator;std::wstring text =L”Width =+ std::to_wstring(x.Width) + L” ” +L”Height =+ std::to_wstring(x.Height) + L” ”+L”Refresh =+ std::to_wstring(n) + L” /+std::to_wstring(d) +L”\n”;::OutputDebugString(text.c_str());}
}

注: D3DAPP类后续会讲到,这里先写着,暂时不介绍
 在进入全屏模式之时,枚举显示模式就显得尤为重要。为了获得最优的全屏性能,我们所指定的显示模式(包括刷新率)一定要与显示器支持的显示模式完全匹配。根据枚举出来的显示模式进行选定,便可以保证这一点。

11、功能支持的检测

 我们已经通过ID3D12Device::CheckFeatureSupport方法,检测了当前图形驱动对多重采样的支持。然而,这只是此函数对功能支持检测的冰山一角。这个方法的原型为:

#include <winError.h>
#include <minwindef.h>
#include <d3d12.h>HRESULT ID3D12Device::CheckFeatureSupport(D3D12_FEATURE Feature,void *pFeatureSupportData,UINT fEATUREsUPPORTdATASize
);

 1.Feature:枚举类型D3D12_FEATURE中的成员之一,用于指定我们希望检测的功能支持类型。

D3D12_FEATURE_D3D12_OPTIONS  //检测当前图形驱动对Direct3D 12各种功能的支持情况
D3D12_FEATURE_ARCHITECTURE  //检测图形适配器中GPU的硬件体系架构特性
D3D12_FEATURE_FEATURE_LEVELS  //检测对功能级别的支持情况
D3D12_FEATURE_FORMAT_SUPPORT  //检测对给定纹理格式的支持情况(例,指定的格式能否用于渲染目标?或,指定的格式能否用于混合技术?)
D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS  //检测对多重采样功能的支持情况

 2.pFeatureSupportData:指向某种数据结构的指针,该结构中存有检索到的特定功能支持的信息。此结构体的具体类型取决于Feature参数。

Feature参数指定为D3D12_FEATURE_D3D12_OPTIONS传回的是一个D3D12_FEATURE_DATA_D3D12_OPTIONS实例。
Feature参数指定为D3D12_FEATURE_ARCHITECTURE传回的是一个D3D12_FEATURE_DATA_ARCHITECTURE实例。
Feature参数指定为D3D12_FEATURE_FEATURE_LEVELS传回的是一个D3D12_FEATURE_DATA_FEATURE_LEVELS实例。
Feature参数指定为D3D12_FEATURE_FORMAT_SUPPORT传回的是一个D3D12_FEATURE_DATA_FORMAT_SUPPORT实例。
Feature参数指定为D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS传回的是一个D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS实例。

 3.FeatureSupportDataSize:传回pFeatureSupportData参数中的数据结构的大小。
 举例,如何对功能级别的支持情况进行检测:

#include <d3d12.h>typedef struct D3D12_FEATURE_DATA_FEATURE_LEVELS {UINT NumFeatureLevels;const D3D_FEATURE_LEVEL* pFeatureLevelsRequested;D3D_FEATURE_LEVEL MaxSupportedFeatureLevel;
} D3D12_FEATURE_DATA_FEATURE_LEVELS;D3D_FEATURE_LEVEL featureLevels[3] =
{D3D_FEATURE_LEVEL_11_0,  // 首先检测是否支持D3D 11D3D_FEATURE_LEVEL_10_0,  // 其次检测是否支持D3D 10D3D_FEATURE_LEVEL_9_3    // 最后检测是否支持D3D 9.3
};int main()
{D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevelsInfo;featureLevelsInfo.NumFeatureLevels = 3;featureLevelsInfo.pFeatureLevelsRequested = featureLevels;md3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS,&featureLevelsInfo,sizeof(featureLevelsInfo));
}

注意:
 CheckFeatureSupport方法的第二个参数兼有输入和输出的属性。作为输入的时候,先要指定功能级别数组中元素的个数,再令指针指向功能级别数组,其中应包括我们希望检测的一系列硬件支持功能级别。最后,此函数将用MaxSupportedFeatureLevel字段返回当前硬件可支持的最高功能级别。

12、资源驻留

 复杂的游戏会运用大量纹理和3D网格(3d mesh)等资源,但是其中的大多数并不需要总是置于显存中供GPU使用。
 在Direct3D 12中,应用程序通过控制资源在显存中的去留,主动管理资源的驻留情况。该技术的基本思路为使应用程序占用最小的显存空间。这是因为现存的空间有限,很可能不足以容下整个游戏的所有资源,或者用户还有运行中的程序也在同时使用显存。性能优化提示:程序应当避免在短时间内于显存中交换进出相同的资源,这会引起过高的开销。最理想的情况使,所清出的资源在短时间内不会再次使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/458993.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux安全技术与iptables防火墙

一.安全技术&#xff1a; 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全决策依据,…

【leetcode热题100】搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。…

Java技术栈全解析,选修选课系统新篇章

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

MATLAB环境下用于提取冲击信号的几种解卷积方法

卷积混合考虑了信号的时延&#xff0c;每一个单独源信号的时延信号都会和传递路径发生一 次线性瞬时混合&#xff1b;解卷积的过程就是找一个合适的滤波器&#xff0c;进行反卷积运算&#xff0c;得到源信号的近似解。 声音不可避免的会发生衍射、反射等现象&#xff0c;所以&…

JavaScript中call、apply、bind方法的应用与区别

在JavaScript中&#xff0c;call、apply和bind是函数的三个重要方法&#xff0c;它们虽然功能不同&#xff0c;但都可以用来改变函数的执行上下文或者传递参数。本文将分别介绍call、apply和bind方法的应用和区别&#xff0c;并附带示例代码。 一、call方法 call方法的作用是…

假期刷题打卡--Day26

1、MT1212乘法表 请编写一个简单程序&#xff0c;输出九九乘法表。输入n&#xff0c;就输出乘法表到n的地方。 格式 输入格式&#xff1a; 输入整型 输出格式&#xff1a; 输出整型。形式如&#xff1a;1*11 样例 1 输入&#xff1a; 5输出&#xff1a; 1*11 2*12 …

LeetCode、17. 电话号码的字母组合【中等,dfs回溯】

文章目录 前言LeetCode、17. 电话号码的字母组合【中等&#xff0c;dfs回溯】题目与类型思路递归回溯优化&#xff1a;StringBuilder来回溯补充代码&#xff1a;2024.1.31&#xff08;简化&#xff09; 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博…

next项目页面性能调优

next项目页面性能调优 一般来说性能优化可以分为加载时、运行时两部分的优化。 扩展参考链接&#xff1a; 前端性能优化 24 条建议 Webpack 4进阶–从前的日色变得慢 &#xff0c;一下午只够打一次包 Webpack 分包优化首屏加载 参考指标 FCP&#xff08;First Contentful P…

hadoop学习笔记

下载安装伪分布式&#xff1a; 1. 国内源下载地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/ Index of /apache/hadoop/commonhttps://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/ https://mirrors.tuna.tsinghua.edu.cn/apache/hado…

上海泗博HART转ModbusTCP网关HME-635应用案例之组态王和超声波液位计通信

如今工业现场的应用也逐渐把现场的不同应用协议转换成以太网&#xff0c;以此来提升现场的通信速度和质量。Modbus TCP是工业以太网协议的一种&#xff0c;也是现场应用中最常使用的。本应用案例是基于Modbus TCP的组态王和基于HART的超声波液位计之间数据通讯的具体应用。 应用…

【芯片设计- RTL 数字逻辑设计入门 11.2 -- 状态机实现 移位运算与乘法 2】

文章目录 移位运算与乘法parameterparameter 特点parameter 基本语法parameter 示例局部参数局部参数示例 状态机代码实现VCS 仿真结果 文章 【芯片设计- RTL 数字逻辑设计入门 11.1 – 状态机实现 移位运算与乘法 1】 介绍了状态机&#xff0c;本篇文章主要就是使用状态机的方…

c语言--指针数组(详解)

目录 一、什么是指针数组&#xff1f;二、指针数组模拟二维数组 一、什么是指针数组&#xff1f; 指针数组是指针还是数组&#xff1f; 我们类比一下&#xff0c;整型数组&#xff0c;是存放整型的数组&#xff0c;字符数组是存放字符的数组。 那指针数组呢&#xff1f;是存放…