Microsoft DirectX 12 中的资源绑定简介





0/5 (0投票)
Microsoft DirectX 12 中的资源绑定简介
Intel® 开发者区 提供跨平台应用开发工具和操作指南、平台和技术信息、代码示例以及同行专业知识,帮助开发者创新并取得成功。加入我们的社区,了解物联网、Android*、Intel® 实感™ 技术和Windows*,下载工具、访问开发套件、与志同道合的开发者分享想法,并参与黑客松、竞赛、路演和本地活动。
2014 年 3 月 20 日,微软在游戏开发者大会上宣布了 DirectX* 12。通过减少资源开销,DirectX 12 将帮助应用程序运行得更高效,降低能耗,并让游戏玩家在移动设备上玩更长时间。
在 SIGGRAPH 2014 上,Intel 在运行一个简单的“小行星”演示时,在 Microsoft Surface* Pro 3 平板电脑上测量了 CPU 功耗。通过点击一个按钮,演示应用程序就可以从 DirectX 11 API 切换到 DirectX 12 API。该演示以锁定的帧率在太空中绘制大量小行星(https://software.intel.com/en-us/blogs/2014/08/11/siggraph-2014-directx-12-on-intel)。与 DirectX 11 相比,使用 DirectX 12 API 运行时消耗的 CPU 功耗不到一半**,从而使设备运行更凉爽,电池续航时间更长。在典型的游戏场景中,任何 CPU 功耗的节省都可以用于更好的物理效果、AI、寻路或其他 CPU 密集型任务,从而使游戏功能更丰富或能效更高。
工具
要开发 DirectX 12 游戏,您需要以下工具
- Windows* 10 技术预览版
- DirectX 12 SDK
- Visual Studio* 2013
- 支持 DirectX 12 的 GPU 驱动程序
如果您是游戏开发者,请访问 Microsoft 的 DirectX 早期体验计划:https://onedrive.live.com/survey?resid=A4B88088C01D9E9A!107&authkey=!AFgbVA2sYbeoepQ。
在您被接受加入 DirectX 早期体验计划后,将提供安装 SDK 和 GPU 驱动程序的设置说明。
概述
从高层次来看,与 DirectX 10 和 11 相比,DirectX 12 的架构在状态管理以及资源在内存中的跟踪和管理方式方面有所不同。
DirectX 10 引入了状态对象,用于在运行时设置一组状态。DirectX 12 引入了管道状态对象 (PSO),用于设置更大一组状态以及着色器。本文重点介绍处理资源的变更,并将 PSO 中状态分组的描述留给未来的文章。
在 DirectX 11 中,系统负责预测或跟踪资源使用模式,这在广泛使用 DirectX 11 时限制了应用程序的设计。基本上,在 DirectX 12 中,程序员(而不是系统或驱动程序)负责处理以下三种使用模式:
- 资源绑定
DirectX 10 和 11 跟踪资源与图形管道的绑定,以保持应用程序已释放但仍被挂起的 GPU 工作引用的资源。DirectX 12 不跟踪资源绑定。应用程序,或者说程序员,必须处理对象生命周期管理。 - 资源绑定检查
DirectX 12 不会检查资源绑定来判断资源何时可能发生转换。例如,应用程序可能通过渲染目标视图 (RTV) 写入渲染目标,然后通过着色器资源视图 (SRV) 将此渲染目标作为纹理读取。在使用 DirectX 11 API 时,GPU 驱动程序会预期知道何时发生此类资源转换,以避免内存读-修改-写危险。在 DirectX 12 中,您必须通过专用 API 调用来标识和跟踪任何资源转换。 - 映射内存的同步
在 DirectX 11 中,驱动程序处理 CPU 和 GPU 之间映射内存的同步。系统会检查资源绑定,以了解渲染是否需要延迟,因为尚未取消映射为 CPU 访问而映射的资源。在 DirectX 12 中,应用程序需要处理 CPU 和 GPU 对资源的访问同步。同步内存访问的一种机制是请求一个事件,在 GPU 完成处理时唤醒一个线程。
将这些资源使用模式移到应用程序的领域需要一套新的编程接口,这些接口可以处理各种不同的 GPU 架构。
本文的其余部分将描述新的资源绑定机制,第一个构建块是描述符。
描述符
描述符描述存储在内存中的资源。描述符是描述 GPU 对象的一块数据,采用 GPU 特定的不透明格式。描述符的一种简单理解方式是取代 DirectX 11 中旧的“视图”系统。除了 DirectX 11 中不同类型的描述符,如着色器资源视图 (SRV) 和无序访问视图 (UAV) 外,DirectX 12 还提供其他类型的描述符,如采样器和常量缓冲区视图 (CBV)。
例如,SRV 选择要使用的底层资源、要使用的 mipmap/数组切片集以及解释内存的格式。SRV 描述符必须包含 Direct3D* 资源的 GPU 虚拟地址,该资源可能是纹理。应用程序必须确保底层资源尚未被销毁或因其非驻留而不可访问。
图 1 显示了一个表示纹理“视图”的描述符
要创建 DirectX 12 中的着色器资源视图,请使用以下结构和 Direct3D 设备方法
typedef struct D3D12_SHADER_RESOURCE_VIEW_DESC
{
DXGI_FORMAT Format;
D3D12_SRV_DIMENSION ViewDimension;
union
{
D3D12_BUFFER_SRV Buffer;
D3D12_TEX1D_SRV Texture1D;
D3D12_TEX1D_ARRAY_SRV Texture1DArray;
D3D12_TEX2D_SRV Texture2D;
D3D12_TEX2D_ARRAY_SRV Texture2DArray;
D3D12_TEX2DMS_SRV Texture2DMS;
D3D12_TEX2DMS_ARRAY_SRV Texture2DMSArray;
D3D12_TEX3D_SRV Texture3D;
D3D12_TEXCUBE_SRV TextureCube;
D3D12_TEXCUBE_ARRAY_SRV TextureCubeArray;
D3D12_BUFFEREX_SRV BufferEx;
};
} D3D12_SHADER_RESOURCE_VIEW_DESC;
interface ID3D12Device
{
...
void CreateShaderResourceView (
_In_opt_ ID3D12Resource* pResource,
_In_opt_ const D3D12_SHADER_RESOURCE_VIEW_DESC* pDesc,
_In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
};
SRV 的示例代码可能如下所示
// create SRV
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(D3D12_SHADER_RESOURCE_VIEW_DESC));
srvDesc.Format = mTexture->Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
mDevice->CreateShaderResourceView(mTexture.Get(), &srvDesc, mCbvSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
此代码为 2D 纹理创建了一个 SRV,并指定了其格式和 GPU 虚拟地址。`CreateShaderResourceView` 的最后一个参数是一个句柄,指向在调用此方法之前分配的称为描述符堆的东西。描述符通常存储在描述符堆中,详细信息将在下一节介绍。
注意:也可以通过驱动程序版本化的内存(称为根参数)将某些类型的描述符传递给 GPU。稍后将详细介绍。
描述符堆
描述符堆可以被看作是用于存储多个描述符的内存分配。不同类型的描述符堆可以包含一种或多种类型的描述符。以下是当前支持的类型:
Typedef enum D3D12_DESCRIPTOR_HEAP_TYPE
{
D3D12_CBV_SRV_UAV_DESCRIPTOR_HEAP = 0,
D3D12_SAMPLER_DESCRIPTOR_HEAP = (D3D12_CBV_SRV_UAV_DESCRIPTOR_HEAP + 1) ,
D3D12_RTV_DESCRIPTOR_HEAP = ( D3D12_SAMPLER_DESCRIPTOR_HEAP + 1 ) ,
D3D12_DSV_DESCRIPTOR_HEAP = ( D3D12_RTV_DESCRIPTOR_HEAP + 1 ) ,
D3D12_NUM_DESCRIPTOR_HEAP_TYPES = ( D3D12_DSV_DESCRIPTOR_HEAP + 1 )
} D3D12_DESCRIPTOR_HEAP_TYPE;
有一个用于 CBV、SRV 和 UAV 的描述符堆类型。还有用于渲染目标视图 (RTV) 和深度模具视图 (DSV) 的类型。
以下代码创建了一个包含九个描述符的描述符堆——每个描述符都可以是 CBV、SRV 或 UAV
// create shader resource view and constant buffer view descriptor heap
D3D12_DESCRIPTOR_HEAP_DESC descHeapCbvSrv = {};
descHeapCbvSrv.NumDescriptors = 9;
descHeapCbvSrv.Type = D3D12_CBV_SRV_UAV_DESCRIPTOR_HEAP;
descHeapCbvSrv.Flags = D3D12_DESCRIPTOR_HEAP_SHADER_VISIBLE;
ThrowIfFailed(mDevice->CreateDescriptorHeap(&descHeapCbvSrv, __uuidof(ID3D12DescriptorHeap), (void**)&mCbvSrvDescriptorHeap));
描述符堆描述中的前两个条目是描述符的数量以及此描述符堆允许的描述符类型。第三个参数 `D3D12_DESCRIPTOR_HEAP_SHADER_VISIBLE` 将此描述符堆描述为对着色器可见。对未对 GPU 可见的描述符堆,可用于例如在 CPU 上暂存描述符或在着色器中无法选择的 RTV。
尽管此代码设置了使描述符堆对 GPU 可见的标志,但还有一个额外的间接级别。GPU 可以通过描述符表“看到”描述符堆(也有不使用表的根描述符;稍后将详细介绍)。
描述符表
描述符堆的主要目标是分配尽可能多的内存来存储所有描述符,以实现尽可能多的渲染,可能是一个或多个帧。
注意:根据底层硬件的不同,切换描述符堆可能会导致刷新 GPU 管道。因此,应尽量减少切换描述符堆的操作,或将其与将要刷新图形管道的其他操作配对。
描述符表是对描述符堆的偏移。与强制图形管道始终查看整个堆不同,切换描述符表是一种廉价地更改给定着色器使用的资源集的方式。这样,着色器就不必了解如何在堆空间中查找资源。
换句话说,应用程序可以利用多个索引到同一描述符堆的描述符表,供不同的着色器使用,如图 2 所示。
以下代码段使用像素着色器的可见性创建了用于 SRV 和采样器的描述符表。
// define descriptor tables for a SRV and a sampler for pixel shaders
D3D12_DESCRIPTOR_RANGE descRange[2];
descRange[0].Init(D3D12_DESCRIPTOR_RANGE_SRV, 1, 0);
descRange[1].Init(D3D12_DESCRIPTOR_RANGE_SAMPLER, 1, 0);
D3D12_ROOT_PARAMETER rootParameters[2];
rootParameters[0].InitAsDescriptorTable(1, &descRange[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[1].InitAsDescriptorTable(1, &descRange[1], D3D12_SHADER_VISIBILITY_PIXEL);
通过提供 `D3D12_SHADER_VISIBILITY_PIXEL` 标志,将描述符表的可见性限制为像素着色器。以下枚举定义了描述符表不同级别的可见性:
typedef enum D3D12_SHADER_VISIBILITY
{
D3D12_SHADER_VISIBILITY_ALL = 0,
D3D12_SHADER_VISIBILITY_VERTEX = 1,
D3D12_SHADER_VISIBILITY_HULL = 2,
D3D12_SHADER_VISIBILITY_DOMAIN = 3,
D3D12_SHADER_VISIBILITY_GEOMETRY = 4,
D3D12_SHADER_VISIBILITY_PIXEL = 5
} D3D12_SHADER_VISIBILITY;
提供将可见性设置为“所有”的标志会将参数广播到所有着色器阶段,尽管只设置一次。
着色器可以通过描述符表找到资源,但首先需要将描述符表作为根参数在根签名中告知该着色器。
根签名和参数
根签名存储根参数,着色器使用这些根参数来定位它们需要访问的资源。这些参数作为命令列表上的绑定空间,用于收集应用程序需要向着色器提供的资源集合。
根参数可以是:
- 描述符表:如上所述,它们包含指向描述符堆的偏移量加上描述符数量。
- 根描述符:每个根参数只能存储少量描述符。这为应用程序节省了将这些描述符放入描述符堆的麻烦,并消除了一个间接级别。
- 根常量:这些常量直接提供给着色器,无需通过根描述符或描述符表。
为了获得最佳性能,应用程序通常应按变化频率递减的顺序排列根参数的布局。
所有根参数(如描述符表、根描述符和根常量)都嵌入到命令列表中,驱动程序将代表应用程序对它们进行版本化。换句话说,当任何根参数在绘制或分派调用之间发生变化时,硬件将更新根签名的版本号。每次绘制/分派调用都会在任何参数发生变化时获得一个唯一的完整根参数状态集。
根描述符和根常量降低了访问时的 GPU 间接级别,而描述符表允许访问大量数据,但会产生增加的间接级别成本。由于间接级别较高,使用描述符表时,应用程序可以在提交命令列表执行之前初始化内容。此外,所有 DirectX 12 硬件都支持的 Shader Model 5.1 允许着色器动态索引到任何给定的描述符表。因此,着色器可以在着色器执行时选择它想要从描述符表中获取的描述符。应用程序可以创建一个大的描述符表,并始终使用索引(通过类似材质 ID 的方式)来获取所需的描述符。
不同的硬件架构在大量根常量和根描述符与描述符表的使用之间会表现出不同的性能权衡。因此,根据目标硬件平台调整根参数和描述符表的比例将是必要的。
对于应用程序来说,一种完全合理的结果可能是所有绑定类型的组合:根常量、根描述符、用于在发出绘制调用时即时收集的描述符的描述符表,以及大型描述符表的动态索引。
以下代码将上面提到的两个描述符表存储在根签名中作为根参数。
// define descriptor tables for a SRV and a sampler for pixel shaders
D3D12_DESCRIPTOR_RANGE descRange[2];
descRange[0].Init(D3D12_DESCRIPTOR_RANGE_SRV, 1, 0);
descRange[1].Init(D3D12_DESCRIPTOR_RANGE_SAMPLER, 1, 0);
D3D12_ROOT_PARAMETER rootParameters[2];
rootParameters[0].InitAsDescriptorTable(1, &descRange[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[1].InitAsDescriptorTable(1, &descRange[1], D3D12_SHADER_VISIBILITY_PIXEL);
// store the descriptor tables int the root signature
D3D12_ROOT_SIGNATURE descRootSignature;
descRootSignature.Init(2, rootParameters, 0);
ComPtr<ID3DBlob> pOutBlob;
ComPtr<ID3DBlob> pErrorBlob;
ThrowIfFailed(D3D12SerializeRootSignature(&descRootSignature,
D3D_ROOT_SIGNATURE_V1, pOutBlob.GetAddressOf(),
pErrorBlob.GetAddressOf()));
ThrowIfFailed(mDevice->CreateRootSignature(pOutBlob->GetBufferPointer(),
pOutBlob->GetBufferSize(), __uuidof(ID3D12RootSignature),
(void**)&mRootSignature));
PSO 中的所有着色器都需要与 PSO 指定的根签名兼容;否则,PSO 将无法创建。
需要将根签名设置为命令列表或捆绑包。这通过调用来完成
commandList->SetGraphicsRootSignature(mRootSignature);
设置根签名后,需要定义绑定集。在上例中,这将通过以下代码完成
// set the two descriptor tables to index into the descriptor heap
// for the SRV and the sampler
commandList->SetGraphicsRootDescriptorTable(0,
mCbvSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
commandList->SetGraphicsRootDescriptorTable(1,
mSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
在发出绘制调用或分派调用之前,应用程序必须在根签名中的每个槽中设置适当的**参数。在此示例中,第一个槽现在包含一个索引到描述符堆的描述符句柄,该描述符句柄指向 SRV 描述符,第二个槽现在包含一个索引到描述符堆的描述符表,该描述符表指向采样器描述符。
应用程序可以在绘制调用之间更改(例如)第二个槽的绑定。这意味着它只需要为第二个绘制调用绑定第二个槽。
整合所有内容
下面大的源代码片段展示了用于绑定资源的所有机制。该应用程序只使用一个纹理,并且此代码为该纹理提供了采样器和 SRV。
// define descriptor tables for a SRV and a sampler for pixel shaders
D3D12_DESCRIPTOR_RANGE descRange[2];
descRange[0].Init(D3D12_DESCRIPTOR_RANGE_SRV, 1, 0);
descRange[1].Init(D3D12_DESCRIPTOR_RANGE_SAMPLER, 1, 0);
D3D12_ROOT_PARAMETER rootParameters[2];
rootParameters[0].InitAsDescriptorTable(1, &descRange[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[1].InitAsDescriptorTable(1, &descRange[1], D3D12_SHADER_VISIBILITY_PIXEL);
// store the descriptor tables in the root signature
D3D12_ROOT_SIGNATURE descRootSignature;
descRootSignature.Init(2, rootParameters, 0);
ComPtr<ID3DBlob> pOutBlob;
ComPtr<ID3DBlob> pErrorBlob;
ThrowIfFailed(D3D12SerializeRootSignature(&descRootSignature,
D3D_ROOT_SIGNATURE_V1, pOutBlob.GetAddressOf(),
pErrorBlob.GetAddressOf()));
ThrowIfFailed(mDevice->CreateRootSignature(pOutBlob->GetBufferPointer(),
pOutBlob->GetBufferSize(), __uuidof(ID3D12RootSignature),
(void**)&mRootSignature));
// create descriptor heap for shader resource view
D3D12_DESCRIPTOR_HEAP_DESC descHeapCbvSrv = {};
descHeapCbvSrv.NumDescriptors = 1; // for SRV
descHeapCbvSrv.Type = D3D12_CBV_SRV_UAV_DESCRIPTOR_HEAP;
descHeapCbvSrv.Flags = D3D12_DESCRIPTOR_HEAP_SHADER_VISIBLE;
ThrowIfFailed(mDevice->CreateDescriptorHeap(&descHeapCbvSrv, __uuidof(ID3D12DescriptorHeap), (void**)&mCbvSrvDescriptorHeap));
// create sampler descriptor heap
D3D12_DESCRIPTOR_HEAP_DESC descHeapSampler = {};
descHeapSampler.NumDescriptors = 1;
descHeapSampler.Type = D3D12_SAMPLER_DESCRIPTOR_HEAP;
descHeapSampler.Flags = D3D12_DESCRIPTOR_HEAP_SHADER_VISIBLE;
ThrowIfFailed(mDevice->CreateDescriptorHeap(&descHeapSampler, __uuidof(ID3D12DescriptorHeap), (void**)&mSamplerDescriptorHeap));
// skip the code that uploads the texture data into heap
// create sampler descriptor in the sample descriptor heap
D3D12_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D12_SAMPLER_DESC));
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_WRAP;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D12_COMPARISON_ALWAYS;
mDevice->CreateSampler(&samplerDesc,
mSamplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
// create SRV descriptor in the SRV descriptor heap
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(D3D12_SHADER_RESOURCE_VIEW_DESC));
srvDesc.Format = SampleAssets::Textures->Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
mDevice->CreateShaderResourceView(mTexture.Get(), &srvDesc,
mCbvSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
// writing into the command list
// set the root signature
commandList->SetGraphicsRootSignature(mRootSignature);
// other commands here ...
// set the two descriptor tables to index into the descriptor heap
// for the SRV and the sampler
commandList->SetGraphicsRootDescriptorTable(0,
mCbvSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
commandList->SetGraphicsRootDescriptorTable(1,
mSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
静态采样器
既然您已经看到了如何使用描述符堆和描述符表创建采样器,那么在应用程序中还有另一种使用采样器的方法。由于许多应用程序只需要固定数量的采样器,因此可以使用静态采样器作为根参数。
目前,根签名如下所示:
typedef struct D3D12_ROOT_SIGNATURE
{
UINT NumParameters;
const D3D12_ROOT_PARAMETER* pParameters;
UINT NumStaticSamplers;
const D3D12_STATIC_SAMPLER* pStaticSamplers;
D3D12_ROOT_SIGNATURE_FLAGS Flags;
// Initialize struct
void Init(
UINT numParameters,
const D3D12_ROOT_PARAMETER* _pParameters,
UINT numStaticSamplers = 0,
const D3D12_STATIC_SAMPLER* _pStaticSamplers = NULL,
D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_NONE)
{
NumParameters = numParameters;
pParameters = _pParameters;
NumStaticSamplers = numStaticSamplers;
pStaticSamplers = _pStaticSamplers;
Flags = flags;
}
D3D12_ROOT_SIGNATURE() { Init(0,NULL,0,NULL,D3D12_ROOT_SIGNATURE_NONE);}
D3D12_ROOT_SIGNATURE(
UINT numParameters,
const D3D12_ROOT_PARAMETER* _pParameters,
UINT numStaticSamplers = 0,
const D3D12_STATIC_SAMPLER* _pStaticSamplers = NULL,
D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_NONE)
{
Init(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
}
} D3D12_ROOT_SIGNATURE;
一组静态采样器可以独立于根签名中的根参数进行定义。如上所述,根参数定义了一个绑定空间,可以在运行时提供参数,而静态采样器定义上是固定不变的。
由于根签名可以在 HLSL 中编写,因此静态采样器也可以用它来编写。目前,应用程序最多只能有 2032 个唯一的静态采样器。这略低于下一个 2 的幂,允许驱动程序将其中一些槽用于内部使用。
根签名中定义的静态采样器独立于应用程序选择放入描述符堆中的采样器,因此这两种机制可以同时使用。
如果采样器的选择是真正动态的,并且在着色器编译时未知,那么应用程序应在描述符堆中管理采样器。
结论
DirectX 12 提供了对资源使用模式的完全控制。应用程序开发者负责在描述符堆中分配内存,在描述符中描述资源,并让着色器通过描述符表“索引”到描述符堆,而描述符表是通过根签名“告知”着色器的。
此外,根签名可用于使用以下四种选项的任何组合为着色器定义自定义参数空间:
- 根常量
- 静态采样器
- 根描述符
- 描述符表
最终的挑战在于为资源类型及其更新频率选择最理想的绑定形式。
关于作者
Wolfgang 是 Confetti 的首席执行官。Confetti 是一个专注于高级实时图形研究的智囊团,也是视频游戏和电影行业的服务提供商。在共同创立 Confetti 之前,Wolfgang 在 Rockstar 核心技术组 RAGE 担任首席图形程序员四年多。他是 ShaderX 和 GPU Pro 图书系列的创始人兼编辑,是微软 MVP,撰写了多本关于实时渲染的书籍和文章,并且是各种网站和 GDC 的常客。他编辑的一本书——《ShaderX4》——在 2006 年获得了游戏开发者前沿奖。Wolfgang 是业内许多咨询委员会的成员;其中一个委员会是微软的 DirectX 12 图形咨询委员会。他是推动游戏行业的几项未来标准的积极贡献者。您可以在 Twitter 上找到他:wolfgangengel。Confetti 的网站是 www.conffx.com。
致谢
感谢 Chas Boyd、Amar Patel 和 David Reinig 的校对和反馈。
参考资料和相关链接
- Microsoft DirectX 博客:http://blogs.msdn.com/b/directx/
- Twitter 上的 DirectX 12:@DirectX12 https://twitter.com/DirectX12
- Direct3D* 12 - PC 上的主机 API 效率与性能(https://software.intel.com/en-us/articles/console-api-efficiency-performance-on-pcs)
** 性能测试中使用的软件和工作负载可能已针对仅在 Intel 微处理器上进行性能优化。性能测试(如 SYSmark* 和 MobileMark*)是使用特定的计算机系统、组件、软件、操作和功能测量的。对任何这些因素的任何更改都可能导致结果有所不同。您应该咨询其他信息和性能测试,以帮助您全面评估您打算购买的产品,包括该产品与其他产品结合使用的性能。