You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用DirectStorage加载纹理到D3D12_TEXTURE2D的报错求助

错误原因分析

这个错误的核心是你分配的DirectStorage目标缓冲区大小不足以容纳D3D12纹理子资源的对齐后数据,具体原因包括:

  1. 手动计算缓冲区大小时,仅按纹理像素的原始尺寸(宽×高×单像素字节数)累加,忽略了D3D12对纹理行间距(RowPitch)和子资源布局的强制内存对齐要求——GPU要求纹理行间距必须是D3D12_TEXTURE_DATA_PITCH_ALIGNMENT(通常是256或4096字节)的倍数,这会导致每个子资源的实际占用空间比原始像素数据大。
  2. 使用DSTORAGE_REQUEST_DESTINATION_MULTIPLE_SUBRESOURCES时,DirectStorage会按照D3D12标准的子资源布局写入数据,但你创建的缓冲区总大小没有匹配这个布局的总开销,尤其是多mipmap层级的纹理,每个mip的子资源都有独立的对齐开销,总大小是所有子资源对齐后大小的总和,而非原始像素总和。
  3. D3D12MA分配缓冲区时,可能错误地设置了资源大小参数,导致实际分配的内存小于纹理子资源布局所需的总空间。
解决方法

1. 用官方API计算准确的纹理子资源总大小

绝对不要手动计算纹理内存大小,必须使用D3D12CalcSubresourceFootprints函数获取符合D3D12对齐要求的子资源布局,并累加得到总缓冲区大小:

// 从DirectXTex获取的纹理元数据生成D3D12资源描述
D3D12_RESOURCE_DESC texDesc = {};
texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
texDesc.Width = metadata.width;
texDesc.Height = metadata.height;
texDesc.MipLevels = metadata.mipLevels;
texDesc.Format = metadata.format;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
texDesc.Flags = D3D12_RESOURCE_FLAG_NONE;

UINT numSubresources = D3D12CalcSubresourceCount(
    texDesc.MipLevels, 
    texDesc.ArraySize, 
    texDesc.SampleDesc.Count
);

D3D12_SUBRESOURCE_FOOTPRINT footprints[128]; // 按需调整数组大小
UINT rowCounts[128];
UINT64 rowSizesInBytes[128];
UINT64 totalBufferSize = D3D12CalcSubresourceFootprints(
    &texDesc,
    0,                  // 起始子资源索引
    numSubresources,
    0,                  // 缓冲区基地址偏移
    footprints,
    rowCounts,
    rowSizesInBytes
);

用计算出的totalBufferSize作为D3D12MA分配缓冲区的大小。

2. 匹配DirectStorage请求的子资源目标布局

设置DSTORAGE_REQUEST_DESTINATION_MULTIPLE_SUBRESOURCES时,需为DSTORAGE_REQUEST::Destinations数组填充每个子资源的偏移和大小,这些值必须和D3D12CalcSubresourceFootprints返回的footprints[i].Offset和footprints[i].SizeInBytes完全对应:

DSTORAGE_REQUEST request = {};
request.DestinationType = DSTORAGE_REQUEST_DESTINATION_MULTIPLE_SUBRESOURCES;
request.DestinationsCount = numSubresources;
request.Destinations = new DSTORAGE_SUBRESOURCE_DESTINATION[numSubresources];

for (UINT i = 0; i < numSubresources; ++i) {
    request.Destinations[i].Offset = footprints[i].Offset;
    request.Destinations[i].Size = footprints[i].SizeInBytes;
    request.Destinations[i].Destination = dstBuffer; // 你的DirectStorage目标缓冲区
}

3. 检查D3D12MA的缓冲区分配参数

分配DirectStorage目标缓冲区时,确保资源描述的Width(缓冲区字节数)设置为totalBufferSize,并满足DirectStorage的资源要求:

D3D12_RESOURCE_DESC bufferDesc = {};
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
bufferDesc.Width = totalBufferSize;
bufferDesc.Height = 1;
bufferDesc.DepthOrArraySize = 1;
bufferDesc.MipLevels = 1;
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
bufferDesc.SampleDesc.Count = 1;
bufferDesc.SampleDesc.Quality = 0;
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
bufferDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; // DirectStorage要求

D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD; // 或根据需求用DEFAULT堆

ComPtr<D3D12MA::Allocation> alloc;
ComPtr<ID3D12Resource> dstBuffer;
allocator->CreateResource(
    &allocDesc,
    &bufferDesc,
    D3D12_RESOURCE_STATE_UNORDERED_ACCESS, // DirectStorage写入前的状态
    nullptr,
    &alloc,
    IID_PPV_ARGS(&dstBuffer)
);

4. 验证CopyTextureRegion的参数正确性

执行纹理拷贝时,源的PlacedFootprint必须严格使用D3D12CalcSubresourceFootprints返回的对应子资源数据,禁止手动修改偏移或行间距:

for (UINT i = 0; i < numSubresources; ++i) {
    D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
    srcLoc.pResource = dstBuffer.Get();
    srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
    srcLoc.PlacedFootprint = footprints[i];
    // 注意:这里的Offset要和缓冲区的基地址偏移一致,若缓冲区是Placed资源需调整,Upload堆则直接用footprints的Offset

    D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
    dstLoc.pResource = texResource.Get(); // 你的目标Texture2D
    dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
    dstLoc.SubresourceIndex = i;

    commandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
}

内容的提问来源于stack exchange,提问作者Shark_Bladder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 03:03:36