DirectX11动态纹理Map/Unmap上传后渲染噪点问题求助
问题根因
你的代码存在两个核心错误,直接导致动态纹理渲染花屏:
- 错误修改Map返回的结构体参数:
D3D11_MAPPED_SUBRESOURCE是Map调用成功后由D3D运行时/驱动填充的输出参数,你在数据拷贝完成后手动修改本地变量的RowPitch、DepthPitch字段完全没有任何作用——这两个值代表GPU端纹理内存的真实行/深度跨度,修改栈上的本地变量不会改变GPU内存布局。 - 未考虑动态纹理的行对齐要求:D3D11动态纹理的内存行跨度(即
RowPitch)几乎永远不会等于纹理宽度 * 单像素字节数,驱动会将每行内存对齐到特定边界(通常为16字节/256字节,由硬件和驱动决定),行尾会预留未使用的填充字节。你直接按照连续内存整块拷贝源数据,会导致第一行之后的所有像素数据错位写入填充区,最终出现噪点、花屏现象。
你之前使用不可变纹理时渲染正常,是因为创建纹理阶段传入D3D11_SUBRESOURCE_DATA初始数据时,驱动会在内部自动完成源数据到GPU对齐内存的拷贝,不需要手动处理行对齐;但Map/Unmap流程是直接将GPU端已对齐的内存指针映射到CPU地址空间,必须手动处理行偏移。
修复方案
删除手动修改RowPitch、DepthPitch的无效代码,改为按行拷贝数据,拷贝时目标地址使用Map返回的真实行跨度做偏移:
D3D11_MAPPED_SUBRESOURCE subResource = {}; HRESULT mapResult = ImmediateContext->Map(dx11Texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource); if (SUCCEEDED(mapResult)) { const UINT singlePixelBytes = GraphicsFormatUtils::get_format_size(texture->get_format()); const UINT srcRowBytes = texture->get_width() * singlePixelBytes; uint8_t* dstPtr = static_cast<uint8_t*>(subResource.pData); const uint8_t* srcPtr = static_cast<const uint8_t*>(desc.DataSet[0]); // 逐行拷贝,跳过每行末尾的驱动对齐填充字节 for (UINT rowIdx = 0; rowIdx < texture->get_height(); ++rowIdx) { Memory::copy(dstPtr, srcPtr, srcRowBytes); dstPtr += subResource.RowPitch; // 目标指针按GPU实际行跨度偏移 srcPtr += srcRowBytes; // 源指针按像素真实行宽偏移 } ImmediateContext->Unmap(dx11Texture, 0); }
额外排查项
如果修复后仍有异常,逐一核对以下配置:
- 动态纹理创建参数必须匹配:
Usage字段设置为D3D11_USAGE_DYNAMIC,CPUAccessFlags必须包含D3D11_CPU_ACCESS_WRITE,BindFlags仅保留D3D11_BIND_SHADER_RESOURCE即可,不要添加其他不兼容的标记。 - 源数据格式必须和纹理创建时指定的
DXGI_FORMAT完全匹配,避免出现RGBA/BGRA顺序混淆、通道位数不匹配的问题。 - 不要在调用
Map前提前初始化或修改subResource结构体的任何字段,所有字段值以Map调用成功后运行时填充的结果为准。
内容的提问来源于stack exchange,提问作者Barış Üçkardeş
相关产品推荐
相关产品推荐

