4.1.4交换链和翻页_4.1.12

4.1.4交换链和翻页

为了避免在动画中闪烁,最好将整个动画帧绘制到称为后缓冲区的离屏纹理中。一旦整个场景被绘制到给定动画帧的后台缓冲区,它将作为一个完整的帧呈现给屏幕;通过这种方式,观看者不会在画框被观看时观看 - 观看者只能看到完整的画面。为实现这一点,硬件维护两个纹理缓冲区,一个称为前端缓冲区,另一个称为后端缓冲区。前端缓冲区存储当前显示在监视器上的图像数据,而下一帧动画正被绘制到后台缓冲区。在帧被绘制到后台缓冲区后,后台缓冲区和前台缓冲区的角色相反:后台缓冲区成为前台缓冲区,前台缓冲区成为下一帧动画的后台缓冲区。交换后台和前台缓冲区的角色称为present.Presenting是一个高效的操作,因为指向当前前台缓冲区的指针和指向当前后台缓冲区的指针只需要交换。图4.1说明了这个过程。


图4.1。 对于帧n,当前正在显示缓冲区A,并且我们将下一帧渲染到缓冲区B,该缓冲区充当当前后端缓冲区。 一旦帧完成,指针交换,缓冲区B成为前端缓冲区,缓冲区A成为新的后端缓冲区。 然后,我们将下一帧n + 1渲染到缓冲区A.一旦帧完成,指针就交换,缓冲区A成为前端缓冲区,缓冲区B再次成为后端缓冲区。


前端和后端缓冲区形成交换链。 在Direct3D中,交换链由IDXGISwapChain接口表示。 该接口存储正面和背面缓冲区纹理,并提供调整缓冲区大小(IDXGISwapChain :: ResizeBuffers)和显示(IDXGISwapChain :: Present)的方法。

使用两个缓冲区(正面和背面)称为双缓冲。 可以使用两个以上的缓冲区; 使用三个缓冲区称为三重缓冲区。 然而,两个缓冲区通常就足够了。


尽管后台缓冲区是一个纹理(因此一个元素应该称为纹理元素),但我们经常将元素称为一个像素,因为在后台缓冲区的情况下,它会存储颜色信息。 有时,即使不存储颜色信息(例如,“法线贴图的像素”),人们也会调用像素的纹理元素。


4.1.5深度缓冲
深度缓冲区是不包含图像数据的纹理的示例,而是关于特定像素的深度信息。可能的深度值范围从0.0到1.0,其中0.0表示观看视锥体中可能对观察者最接近的物体,1.0表示视锥体中观察到的最远的物体。深度缓冲区中的每个元素与后台缓冲区中的每个像素之间存在一一对应关系(即,后台缓冲区中的第i个元素对应于深度缓冲区中的第i个元素)。因此,如果后台缓冲区的分辨率为1280×1024,则会有1280×1024个深度条目。

图4.2显示了一个简单的场景,其中一些对象部分遮盖了它们后面的对象。为了让Direct3D确定一个对象的哪些像素位于另一个像素的前面,它使用了一种称为深度缓冲或z缓冲的技术。让我们强调,通过深度缓冲,我们绘制对象的顺序并不重要。


图4.2。 一组彼此部分混淆的对象。

为了处理深度问题,可能会建议按照最远到最近的顺序绘制场景中的对象。通过这种方式,近物体将被涂在远物体上,并且应该呈现正确的结果。这是一个画家如何绘制一个场景。但是,此方法有其自身的问题 - 按照从前到后的顺序排列大型数据集并交叉几何。此外,图形硬件为我们提供了免费的深度缓冲。

为了说明深度缓冲如何工作,让我们看一个例子。考虑图4.3,它显示了观众看到的音量和该音量的2D侧视图。从图中可以看出,三个不同的像素竞争渲染到视图窗口上的像素P上。 (当然,我们知道最接近的像素应该渲染到P,因为它隐藏了背后的像素,但是计算机没有。)首先,在任何渲染发生之前,后台缓冲区被清除为默认颜色,深度缓冲区被清除为默认值 - 通常为1.0(像素可以具有的最远深度值)。现在,假设对象按照圆柱体,球体和圆锥体的顺序渲染。下表总结了像素P及其对应的深度值d如何在绘制对象时更新;其他像素会发生类似的过程。


图4.3。 视图窗口对应于我们生成的3D场景的2D图像(后台缓冲区)。 我们看到可以将三个不同的像素投影到像素P.直觉告诉我们P1应该被写入P,因为它离观察者更近并且阻挡另外两个像素。 深度缓冲算法提供了用于在计算机上确定这一点的机械过程。 请注意,我们将显示与正在查看的3D场景相关的深度值,但实际上,当存储在深度缓冲区中时,它们会被标准化为范围[0.0,1.0]。


如你所见,当我们找到深度值较小的像素时,我们只更新深度缓冲区中的像素及其对应的深度值。 通过这种方式,在说完之后,最接近观看者的像素将是渲染的像素。 (如果你仍然不确信,你可以尝试切换绘图顺序并再次通过这个例子。)
总而言之,深度缓冲通过计算每个像素的深度值并执行深度测试而起作用。 深度测试比较竞争写入到后缓冲区上的特定像素位置的像素的深度。 深度值最接近观看者的像素获胜,这是写入后台缓冲区的像素。 这是有道理的,因为最接近观看者的像素遮挡了它后面的像素。

深度缓冲区是一个纹理,所以它必须以特定的数据格式创建。 用于深度缓冲的格式如下所示:

1. DXGI_FORMAT_D32_FLOAT_S8X24_UINT:指定一个32位浮点深度缓冲区,其中8位(无符号整数)为模板缓冲区保留,映射到[0,255]范围,24位不用于填充。
2. DXGI_FORMAT_D32_FLOAT:指定一个32位浮点深度缓冲区。
3. DXGI_FORMAT_D24_UNORM_S8_UINT:指定映射到[0,1]范围的无符号24位深度缓冲区,并为映射到[0,255]范围的模板缓冲区保留8位(无符号整数)。

4. DXGI_FORMAT_D16_UNORM:指定映射到[0,1]范围的无符号16位深度缓冲区。

应用程序不需要有模板缓冲区,但如果有,模板缓冲区总是附加到深度缓冲区。 例如,32位格式
DXGI_FORMAT_D24_UNORM_S8_UINT

深度缓冲区使用24位,模板缓冲区使用8位。 为此,深度缓冲区更好地称为深度/模板缓冲区。 使用模板缓冲区是一个更高级的主题,将在第11章中解释。

4.1.6资源和描述符

在渲染过程中,GPU将向资源(例如,后台缓冲区,深度/模板缓冲区)写入数据,并从资源中读取数据(例如描述表面外观的纹理,存储几何图形三维位置的缓冲区现场)。在我们发出绘图命令之前,我们需要将资源绑定(或链接)到将在绘图调用中引用的渲染管道。有些资源可能会因每次绘制调用而改变,因此如有必要,我们需要更新每次绘制调用的绑定。但是,GPU资源不会直接绑定。相反,资源是通过一个描述符对象来引用的,它可以被认为是描述GPU资源的轻量级结构。本质上,它是一种间接的层面;给定一个资源描述符,GPU可以获取实际的资源数据并知道关于它的必要信息。我们通过指定将在绘制调用中引用的描述符将资源绑定到渲染管道。

为什么要使用描述符进行这种额外级别的间接寻址?原因是GPU资源本质上是通用的内存块。资源保持通用,因此可以在渲染管道的不同阶段使用它们;一个常见的例子是使用纹理作为渲染目标(即,Direct3D绘制到纹理中)并且稍后作为着色器资源(即纹理将被采样并用作着色器的输入数据)。资源本身并不表示它是否被用作渲染目标,深度/模板缓冲区或着色器资源。另外,也许我们只想将资源数据的一个子区域绑定到渲染管道 - 在给定整个资源的情况下,我们该怎么做?而且,资源可以用无类型的格式创建,所以GPU甚至不会知道资源的格式。

这是描述符出现的地方。除了标识资源数据外,描述符还描述了GPU的资源:它们告诉Direct3D资源将如何使用(即,您将绑定到哪个管道的哪个阶段),如果适用,我们可以指定我们想要在描述符中绑定的资源的子区域,并且如果在创建时将资源格式指定为无类型,那么现在我们必须在创建描述符时指定类型。

视图是描述符的同义词。 术语“视图”在以前的Direct3D版本中使用,它仍然用于Direct3D 12 API的某些部分。 我们在本书中互换使用; 例如,常量缓冲区视图和常量缓冲区描述符意味着同样的事情。
描述符有一个类型,类型意味着资源将如何使用。 我们在本书中使用的描述符类型有:
1. CBV / SRV / UAV描述符描述常量缓冲区,着色器资源和无序访问视图资源。
2.采样器描述符描述采样器资源(用于纹理化)。
3. RTV描述符描述渲染目标资源。
4. DSV描述符描述深度/模板资源。

描述符堆是描述符的数组; 它是您的应用程序使用的特定类型的所有描述符的内存支持。 对于每种类型的描述符,您都需要一个单独的描述符堆。 您也可以创建多个相同描述符类型的堆。

我们可以有多个描述符引用相同的资源。例如,我们可以有多个描述符引用资源的不同子区域。另外,如前所述,资源可以绑定到渲染管线的不同阶段。对于每个阶段,我们需要一个单独的描述符。对于使用纹理作为渲染目标和着色器资源的示例,我们需要创建两个描述符:一个RTV类型描述符和一个SRV类型描述符。同样,如果您使用无类型格式创建资源,则可以将纹理的元素视为浮点值或整数,例如;这需要两个描述符,其中一个描述符指定浮点格式,另一个描述符指定整数格式。
描述符应该在初始化时创建。这是因为有一些类型检查和验证发生,最好在初始化时而不是运行时执行。

2009年8月的SDK文档说:“创建完全类型的资源会将资源限制为其创建的格式。 “因此,如果您真的需要它们提供的灵活性(能够以多种视图以多种方式重新解释数据),您应该只创建一个无类型资源;”否则,请创建一个完整类型的资源。

4.1.7多重抽样理论

由于显示器上的像素不是无限小,因此在计算机显示器上无法完美呈现任意线条。 图4.4说明了一个“阶梯”(混叠)效应,当通过像素矩阵逼近一条线时会出现这种效应。 三角形的边缘会出现类似的锯齿效应。


图4.4。 在顶部,我们观察到混叠(当尝试用像素矩阵表示一条线时的阶梯效果)。在底部,我们看到一条反锯齿线,该线通过采样并使用其相邻像素来生成像素的最终颜色; 这会产生更平滑的图像并淡化楼梯效果。

通过增加显示器分辨率来缩小像素大小可以显着减轻问题,而楼梯效应在很大程度上不会被注意到。

当增加显示器分辨率是不可能或不够的时候,我们可以应用抗锯齿技术。一种称为超采样的技术通过使后缓冲区和深度缓冲区大于屏幕分辨率4倍来工作。然后以更高的分辨率将3D场景渲染到后台缓冲区。然后,当需要向屏幕显示后台缓冲区时,后台缓冲区将被解析(或缩减采样),以便将4个像素块的颜色平均到一起以获得平均的像素颜色。实际上,超采样通过增加软件中的分辨率来工作。

超采样是昂贵的,因为它将像素处理和存储量增加了四倍。 Direct3D支持一种折衷的抗混叠技术,称为多重采样,它在子像素之间共享一些计算信息,使其比超级采样更便宜。假设我们使用4倍多重采样(每个像素4个子像素),多重采样还使用比屏幕分辨率大4倍的后台缓冲区和深度缓冲区;然而,不是计算每个子像素的图像颜色,而是在像素中心每像素只计算一次图像颜色,然后根据可见性(深度/模板测试评估每个子像素)和覆盖范围与子像素共享该颜色信息(子像素中心位于多边形的内部还是外部?)。图4.5显示了一个例子。


图4.5。 我们考虑一个穿过多边形边缘的像素。 (a)像素中心评估的绿色存储在多边形覆盖的三个可见子像素中。 第四象限中的子像素未被多边形覆盖,因此不会用绿色更新 - 它只是保持先前绘制的几何图形或“清除”操作计算的以前的颜色。 (b)为了计算分辨的像素颜色,我们对四个子像素(三个绿色像素和一个白色像素)进行平均,以获得沿着多边形边缘的浅绿色。 这可以通过稀释沿多边形边缘的阶梯效果,获得更平滑的图像。

观察超采样和多采样之间的关键区别。 使用超级取样,图像颜色是按每个子像素计算的,因此每个子像素可能具有不同的颜色。 使用多重采样(图4.5)时,图像颜色每个像素计算一次,该颜色被复制到多边形覆盖的所有可见子像素中。 由于计算图像颜色是图形管线中最昂贵的步骤之一,因此超采样对超采样的节省显着。 另一方面,超级取样更准确。

在图4.5中,我们展示了一个细分为四个均匀网格模式的子像素的像素。 由于Direct3D没有定义子像素的位置,因此所使用的实际模式(子像素所在的位置)可能因硬件供应商而异。某些模式在某些情况下比其他模式效果更好。

4.1.8 Direct3D中的多重采样

在下一节中,我们将被要求填写一个DXGI_SAMPLE_DESC结构。 这个结构有两个成员,定义如下:

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_LEVELS_FLAG 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)));

请注意,第二个参数既是输入参数,也是输出参数。 对于输入,我们必须指定纹理格式,样本数量和我们想要查询多重采样支持的标志。 该功能将填写质量水平作为输出。 纹理格式和样本数量组合的有效质量级别从零到NumQualityLevels-1。

每个像素可以采样的最大采样数由以下定义:

#define D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT ( 32 )

但是,为了保持多采样的性能和内存成本合理,采样数为4或8是很常见的。 如果您不希望使用多重采样,请将采样计数设置为1,质量级别设置为0.所有支持Direct3D 11的设备都支持所有渲染目标格式的4倍多重采样。

DXGI_SAMPLE_DESC结构需要为交换链缓冲区和深度缓冲区填写。 后台缓冲区和深度缓冲区必须使用相同的多重采样设置创建。

4.1.9功能级别

Direct3D 11引入了功能级别的概念(用D3D_FEATURE_LEVEL枚举类型代码表示),它大致对应于从版本9到版本11的各种Direct3D版本:

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必须支持整个Direct3D 11功能集,只有少数例外(有些事情像多重采样计数仍需要查询,因为它们允许在不同的Direct3D 11硬件之间变化)。功能集使开发变得更加简单 - 一旦您知道了支持的功能集,就可以了解您可以使用的Direct3D功能。

 如果用户的硬件不支持某个功能级别,则应用程序可能会回退到较旧的功能级别。例如,为了支持更广泛的受众,应用程序可能支持Direct3D 11,10和9.3级硬件。应用程序会检查从最新到最旧的功能级别支持:也就是说,应用程序首先会检查是否支持Direct3D 11,第二个Direct3D 10,最后是Direct3D 9.3。在本书中,我们总是需要支持功能级别D3D_FEATURE_LEVEL_11_0。但是,真实世界的应用程序确实需要担心支持旧硬件以最大限度地提高受众。

4.1.10 DirectX图形基础结构
DirectX图形基础结构(DXGI)是与Direct3D一起使用的API。 DXGI的基本思想是,一些与图形相关的任务对于多个图形API是通用的。例如,2D渲染API需要交换链和页面翻转以获得与3D渲染API一样多的平滑动画;因此交换链接口IDXGISwapChain(§4.1.4)实际上是DXGI API的一部分。 DXGI处理其他常见的图形功能,如全屏模式转换,枚举图形系统信息,如显示适配器,监视器和支持的显示模式(分辨率,刷新率等)。它还定义了各种支持的表面格式(DXGI_FORMAT)。

我们简要介绍一下在我们的Direct3D初始化过程中将使用的一些DXGI概念和接口。其中一个关键的DXGI接口是IDXGIFactory接口,主要用于创建IDXGISwapChain接口和枚举显示适配器。显示适配器实现图形功能。通常,显示适配器是硬件的物理部分(例如,图形卡);但是,系统也可以具有模拟硬件图形功能的软件显示适配器。系统可以有几个适配器(例如,如果它有几个图形卡)。适配器由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]);
}

}

该方法的输出示例如下:

***Adapter: NVIDIA GeForce GTX 760

***Adapter: Microsoft Basic Render Driver

“Microsoft Basic Render Driver”是Windows 8及更高版本附带的软件适配器。

一个系统可以有多个监视器。 监视器是显示输出的一个例子。 输出由IDXGIOutput接口表示。 每个适配器都与一系列输出相关联。 例如,考虑一个带有两个图形卡和三个显示器的系统,其中两个显示器连接到一个图形卡,第三个显示器连接到另一个图形卡。 在这种情况下,一个适配器具有两个与其关联的输出,另一个适配器具有与其关联的一个输出。 我们可以使用以下代码枚举与适配器关联的所有输出:

void D3DApp::LogAdapterOutputs(IDXGIAdapter* adapter)
{
UINT i = 0;
IDXGIOutput* output = nullptr;
while(adapter->EnumOutputs(i, &output) !=
DXGI_ERROR_NOT_FOUND)
{
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
std::wstring text = L”***Output: “;
text += desc.DeviceName;
text += L”\n”;
OutputDebugString(text.c_str());
LogOutputDisplayModes(output,
DXGI_FORMAT_B8G8R8A8_UNORM);
ReleaseCom(output);
++i;
}

}

请注意,根据文档,“Microsoft Basic Render Driver”没有显示输出。

每台显示器都有一套它支持的显示模式。 显示模式是指DXGI_MODE_DESC中的以下数据:

typedef struct DXGI_MODE_DESC
{
UINT Width; // Resolution width
UINT Height; // Resolution height
DXGI_RATIONAL RefreshRate;
DXGI_FORMAT Format; // Display format
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
//Progressive vs. interlaced
DXGI_MODE_SCALING Scaling; // How the image is
stretched
// over the monitor.
} 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;

修复显示模式格式,我们可以使用以下代码获得输出支持的所有支持的显示模式列表:

void D3DApp::LogOutputDisplayModes(IDXGIOutput*
output, DXGI_FORMAT format)
{
UINT count = 0;
UINT flags = 0;
// Call with nullptr to get list count.
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());
}

}

此代码的一些输出示例如下所示:

***Output: \.\DISPLAY2
… Width =1920 Height =1080 Refresh =59950/1000

Width = 1920 Height = 1200 Refresh = 59950/1000

枚举显示模式在进入全屏模式时尤其重要。 为了获得最佳的全屏性能,指定的显示模式(包括刷新率)必须与显示器支持的显示模式完全匹配。

指定枚举显示模式保证了这一点。 有关DXGI的更多参考资料,我们建议您阅读以下文章“DXGI概述”,“DirectX图形基础架构:最佳实践”和“DXGI 1.4改进”

DXGI Overview:http://msdn.microsoft.com/enus/ library/windows/desktop/bb205075(v=vs.85).aspx
DirectX Graphics Infrastructure: Best Practices: http://msdn.microsoft.com/enus/
library/windows/desktop/ee417025(v=vs.85).aspx

DXGI 1.4 Improvements:https://msdn.microsoft.com/enus/ library/windows/desktop/mt427784%28v=vs.85%29.aspx

4.1.11检查功能支持

我们已经使用ID3D12Device :: CheckFeatureSupport方法来检查当前图形驱动程序的多重采样支持。 但是,这只是我们可以使用此功能检查的一项功能支持。 这种方法的原型如下:

HRESULT ID3D12Device::CheckFeatureSupport(
D3D12_FEATURE Feature,
void *pFeatureSupportData,

UINT FeatureSupportDataSize);

1.特征:D3D12_FEATURE枚举类型的成员,标识我们要检查支持的特征的类型:
1. D3D12_FEATURE_D3D12_OPTIONS:检查是否支持各种Direct3D 12功能。
2. D3D12_FEATURE_ARCHITECTURE:检查对硬件体系结构功能的支持。
3. D3D12_FEATURE_FEATURE_LEVELS:检查功能级别支持。
4. D3D12_FEATURE_FORMAT_SUPPORT:检查给定纹理格式的功能支持(例如,格式是否可用作渲染目标,该格式是否可用于混合)。

5. D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS:检查多重采样功能支持。

2. pFeatureSupportData:指向数据结构以检索功能支持信息的指针。 您使用的结构类型取决于您为Feature参数指定的内容:
1.如果您指定了D3D12_FEATURE_D3D12_OPTIONS,则传递一个实例
的D3D12_FEATURE_DATA_D3D12_OPTIONS。
2.如果指定了D3D12_FEATURE_ARCHITECTURE,则传递D3D12_FEATURE_DATA_ARCHITECTURE的一个实例。
3.如果指定了D3D12_FEATURE_FEATURE_LEVELS,则传递D3D12_FEATURE_DATA_FEATURE_LEVELS的一个实例。
4.如果指定了D3D12_FEATURE_FORMAT_SUPPORT,则传递D3D12_FEATURE_DATA_FORMAT_SUPPORT的实例。

5.如果您指定了D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,则传递D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS的一个实例。

3. FeatureSupportDataSize:传递给pFeatureSupportData参数的数据结构的大小。

ID3D12Device :: CheckFeatureSupport函数检查对许多功能的支持,其中很多功能我们不需要检查本书并且是高级的; 有关每个功能结构的数据成员的详细信息,请参阅SDK文档。 但是,作为示例,我们在下面显示如何检查支持的功能级别(§4.1.9):

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, // First check D3D 11
support
D3D_FEATURE_LEVEL_10_0, // Next, check D3D 10
support
D3D_FEATURE_LEVEL_9_3 // Finally, check D3D 9.3
support
};
D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevelsInfo;
featureLevelsInfo.NumFeatureLevels = 3;
featureLevelsInfo.pFeatureLevelsRequested =
featureLevels;
md3dDevice->CheckFeatureSupport(
D3D12_FEATURE_FEATURE_LEVELS,
&featureLevelsInfo,

sizeof(featureLevelsInfo));

请注意,第二个参数既是输入参数,也是输出参数。 对于输入,我们指定要素级数组中的元素数(NumFeatureLevels),以及指向特征级数组(pFeatureLevelsRequested)的指针,其中包含我们要检查硬件支持的特征级别列表。 该函数通过MaxSupportedFeatureLevel字段输出最大支持的功能级别。

4.1.12居留
一个复杂的游戏将使用很多资源,如纹理和3D网格,但GPU中通常不需要这些资源中的大部分。例如,如果我们想象一个拥有大洞穴的室外森林的游戏,那么在玩家进入洞穴之前不需要洞穴资源,当玩家进入洞穴时,不再需要森林资源。
在Direct3D 12中,应用程序通过从GPU内存中驱逐资源并根据需要再次将它们驻留在GPU上来管理资源驻留(本质上,无论资源是否位于GPU内存中)。 基本思想是尽量减少应用程序使用的GPU内存量,因为可能不足以存储整个游戏的所有资源,或者用户运行其他需要GPU内存的应用程序。 作为一个性能说明,应用程序应该避免在短时间内将相同的资源进出GPU内存的情况,因为这会带来开销。 理想情况下,如果你要驱逐一个资源,那么这个资源不应该需要一段时间。 游戏级别/区域变化是改变资源驻留时间的好例子。

默认情况下,当一个资源被创建时,它被设置为驻留,并在被销毁时被驱逐。但是,应用程序可以使用以下方法手动控制驻留:

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

对于这两种方法,第二个参数都是ID3D12Pageable资源的数组,第一个参数是数组中的资源数。

在本书中,为了简单起见,由于我们的演示与游戏相比较小,我们不管理居住。 有关更多信息,请参阅驻留文档:

https://msdn.microsoft.com/enus/ library/windows/desktop/mt186622%28v=vs.85%29.aspx

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值