子资源(Direct3D 12 图形)

介绍如何将资源划分为子资源,以及如何引用单个、多个或切片子资源。

子资源示例

如果某个资源包含缓冲区,则它仅包含索引编号为 0 的一个子资源。 如果该资源包含纹理(或纹理数组),则引用子资源更为复杂。

某些 API 会访问整个资源(例如,ID3D12GraphicsCommandList::CopyResource 方法),而其他 API 会访问一部分资源(例如,ID3D12Resource::ReadFromSubresource 方法)。 访问资源部分的方法通常使用视图说明 ((如 D3D12_TEX2D_ARRAY_SRV 结构) )来指定要访问的子资源。 有关完整列表,请参阅子资源 API 部分。

子资源索引

若要编制特定子资源的索引,请先编制 mip 级别的索引,因为已编制每个数组项的索引。

子资源索引

Mip 切片

Mip 切片包括数组中的每个纹理的一个 mipmap 级别,如下图所示。

子资源 mip 切片

数组切片

假设一个纹理数组,每个纹理包含 mipmap,则一个数组切片将包括一个纹理及其所有 mip 级别,如下图所示。

子资源数组切片

平面切片

通常,平面格式不用于存储 RGBA 数据,但在(可能是 24bpp RGB 数据)的情况下,一个平面可以表示红色图像,一个平面可以表示绿色图像,一个平面可以表示蓝色图像。 虽然一个平面不一定是一种颜色,但两种或更多颜色可以组合到一个平面中。 更为典型的是,平面数据用于子采样的 YCbCr 和深度模具数据。 深度模具是完全支持 mipmap、数组和多个平面的唯一格式(通常,平面 0 用于深度,而平面 1 用于模具)。

下面显示了包含两个深度模具图像的数组的子资源索引,每个都有三个 mip 级别。

深度模具索引

子采样的 YCbCr 支持数组且具有平面,但不支持 mipmap。 YCbCr 图像具有两个平面,一个平面用于人眼最敏感的亮度 (Y),一个平面用于人眼不太敏感的色度(Cb 和 Cr,交错)。 此格式支持压缩色度值,以便在不影响亮度的情况下压缩图像,并且是出于此原因的常见视频压缩格式(尽管它用于压缩静态映像)。 下图显示了 NV12 格式,注意色度已压缩为亮度分辨率的四分之一,这意味着每个平面的宽度是相同的,并且色度平面是亮度平面高度的一半。 平面将作为子资源按照相同的方式编入索引到上述深度模具示例中。

nv12 格式

平面格式存在于 Direct3D 11 中,但无法单独处理各个平面,例如复制或映射操作。 已在 Direct3D 12 中对此进行更改,以便每个平面收到自己的子资源 ID。 比较以下两种方法来计算子资源 ID。

Direct3D 11

inline UINT D3D11CalcSubresource( UINT MipSlice, UINT ArraySlice, UINT MipLevels )
{
    return MipSlice + (ArraySlice * MipLevels); 
}

Direct3D 12

inline UINT D3D12CalcSubresource( UINT MipSlice, UINT ArraySlice, UINT PlaneSlice, UINT MipLevels, UINT ArraySize )
{ 
    return MipSlice + (ArraySlice * MipLevels) + (PlaneSlice * MipLevels * ArraySize); 
}

大多数硬件假设始终在平面 N-1 后立即分配平面 N 的内存。

使用子资源的替代方法是应用可以在每个平面上分配完全不同的资源。 在这种情况下,应用程序了解到数据是平面的,并且使用多个资源来表示它。

多个子资源

着色器资源视图可以使用上述切片之一选择子资源的任何矩形区域,并在视图结构 ((如 D3D12_TEX2D_ARRAY_SRV) )中明智地使用字段,如图所示。

多个子资源选择

呈现器目标视图只能使用单个子资源或 mip 切片,并且不能包含多个 mip 切片中的子资源。 也就是说,呈现器目标视图中的每个纹理的大小必须相同。 着色器资源视图可以选择子资源的任何矩形区域,如下图所示。

子资源 API

以下 API 引用并使用子资源:

枚举:

以下结构包含 PlaneSlice 索引,大多数包含 MipSlice 索引。

以下结构包含 ArraySlice 索引,大多数包含 MipSlice 索引。

以下结构包含 MipSlice 索引,但既不包含 ArraySlice,也不包含 PlaneSlice 索引。

以下结构也引用子资源:

方法:

纹理必须处于 D3D12_RESOURCE_STATE_COMMON 状态,才能通过 WriteToSubresourceReadFromSubresource 进行 CPU 访问,才能合法;但缓冲区不这样做。 对资源的 CPU 访问通常通过 Map/Unmap 完成。

资源绑定