Direct3D 12中Subresource(子资源)相关技术问题咨询
Direct3D 12 子资源(Subresource)常见问题解析
1. 获取多子资源纹理的子资源数量与起始偏移量
计算子资源总数:子资源数量由纹理的
D3D12_RESOURCE_DESC参数隐式决定,无需额外存储,可通过以下规则计算:- 1D纹理:
子资源数 = MipLevels × DepthOrArraySize(DepthOrArraySize为数组元素个数) - 2D纹理:
- 普通纹理/纹理数组:
子资源数 = MipLevels × DepthOrArraySize - 立方体贴图(
MiscFlags含D3D12_RESOURCE_MISC_TEXTURECUBE):子资源数 = MipLevels × 6(每个面为独立单元) - 立体纹理(
MiscFlags含D3D12_RESOURCE_MISC_STEREO):子资源数 = MipLevels × DepthOrArraySize × 2(左右眼各为一个单元)
- 普通纹理/纹理数组:
- 3D纹理:
子资源数 = MipLevels(每个Mip层级包含完整深度切片)
你可以通过资源的GetDesc()方法获取D3D12_RESOURCE_DESC结构体,代入上述公式计算总数。
- 1D纹理:
获取每个子资源的起始偏移:使用
ID3D12Device::GetCopyableFootprints函数,将FirstSubresource设为0,NumSubresources设为计算出的总数量,函数会返回一个D3D12_PLACED_SUBRESOURCE_FOOTPRINT数组,其中每个元素的Offset字段就是对应子资源在资源堆中的起始字节偏移。示例代码:D3D12_RESOURCE_DESC desc = pTexture->GetDesc(); UINT totalSubresources; // 根据纹理类型计算子资源总数 if (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D) { if (desc.MiscFlags & D3D12_RESOURCE_MISC_TEXTURECUBE) { totalSubresources = desc.MipLevels * 6; } else if (desc.MiscFlags & D3D12_RESOURCE_MISC_STEREO) { totalSubresources = desc.MipLevels * desc.DepthOrArraySize * 2; } else { totalSubresources = desc.MipLevels * desc.DepthOrArraySize; } } // 其他纹理类型的计算逻辑... std::vector<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> footprints(totalSubresources); std::vector<UINT> numRows(totalSubresources); std::vector<UINT64> rowBytes(totalSubresources); UINT64 totalSize = 0; pDevice->GetCopyableFootprints(&desc, 0, totalSubresources, 0, footprints.data(), numRows.data(), rowBytes.data(), &totalSize); // 遍历获取每个子资源的偏移 for (UINT i = 0; i < totalSubresources; ++i) { UINT64 subresourceOffset = footprints[i].Offset; // 处理偏移逻辑 }
2. 创建包含2个子资源的提交纹理
子资源数量由纹理的Mip层级、数组大小等参数决定,以下两种常见方式可创建含2个子资源的纹理:
- 方式1:2D纹理数组(1个Mip层级):设置
DepthOrArraySize为2,MipLevels为1,这样子资源数为1×2=2,对应数组的两个元素。 - 方式2:普通2D纹理(2个Mip层级):设置
MipLevels为2,DepthOrArraySize为1,子资源数为2×1=2,对应两个Mip层级。
以下是方式1的示例代码:
D3D12_RESOURCE_DESC texDesc = {}; texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; texDesc.Width = 512; texDesc.Height = 512; texDesc.DepthOrArraySize = 2; // 数组元素个数为2 texDesc.MipLevels = 1; texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; texDesc.SampleDesc.Count = 1; texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; texDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource* pTexture = nullptr; HRESULT hr = pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&pTexture) );
3. 子资源(Subresource)的本质
子资源是Direct3D对资源内部独立可操作单元的抽象,和你之前理解的“手动划分缓冲段”不同,它是由资源的类型和创建参数隐式定义的:
- 对于缓冲资源:通常仅包含1个子资源,因为缓冲是线性字节流,Direct3D不将手动划分的分段视为子资源(
CopyBufferRegion是手动操作分段,不属于子资源范畴)。 - 对于纹理资源:子资源对应纹理的最小独立单元,比如:
- 单个Mip层级的单个数组元素(2D纹理数组)
- 立方体贴图单个面的单个Mip层级
- 3D纹理的单个Mip层级
- 立体纹理单个数组元素的单个眼视图的Mip层级
子资源的核心价值在于支持细粒度的资源操作,比如单独更新某个Mip层级、复制纹理数组中的特定元素,CopyTextureRegion、UpdateSubresources等API均基于子资源实现精准操作。
内容的提问来源于stack exchange,提问作者YoonSeok OH
相关产品推荐
相关产品推荐

