为何ID3D11DeviceContext::Map得到的映射子资源与原纹理分辨率不一致
现象底层原因
你遇到的是现代图形API的通用显存对齐规则,属于正常设计,并非异常:
GPU访问显存时要求每行数据的起始地址对齐到特定字节边界(通常为2的整数次幂),以此提升显存访问效率、减少带宽浪费,该要求由GPU架构、驱动、纹理格式、纹理绑定标志共同决定。
你给出的案例完全符合64字节对齐规则:
- 1559宽度的BGRA8格式纹理,单像素占4字节,无对齐时行字节数为
1559 * 4 = 6236 - 6236无法被64整除,驱动会自动将行字节数向上取整到最近的64的倍数,也就是6272,对应你拿到的
RowPitch值,折算成像素宽度就是6272 /4 =1568 - 1568宽度的纹理无对齐行字节数刚好为6272,满足对齐要求,因此
RowPitch符合预期。
RowPitch计算通用逻辑
微软官方没有公开固定的RowPitch计算方法,该值由驱动动态生成,但所有实现都会遵循以下逻辑:
- 计算基础行字节数:
基础行字节数 = 纹理宽度 * 单像素字节数 - 确认当前场景下的对齐边界:
- 普通非压缩2D纹理:常见对齐边界为16、32、64字节
- 多采样MSAA纹理:对齐边界通常为256字节及以上
- BC系列块压缩纹理:除了行对齐,还需要满足压缩块的尺寸对齐要求
- 将基础行字节数向上取整到对齐边界的整数倍,最终结果即为返回的
RowPitch值。
你遇到的场景可直接用64字节对齐验证:向上取整公式为 (基础行字节数 + 对齐边界 -1) & ~(对齐边界 -1),代入数值(6236 +63) & ~63 = 6272,和你拿到的结果完全一致。
适配规则建议
如果你要避免对齐带来的差异,可遵循以下规则:
- 生成源纹理时,提前将宽度向上取整到对齐边界对应的像素值,比如64字节对齐的BGRA8格式,像素对齐值为
64 /4 =16,将所有纹理宽度设置为16的整数倍即可保证RowPitch等于宽度*4 - 无论什么场景,访问映射后的子资源数据时,都不要硬编码
RowPitch的计算逻辑,始终使用D3D11_MAPPED_SUBRESOURCE返回的RowPitch值计算行偏移:第y行数据起始地址 = pData + y * RowPitch - 如果需要将映射数据导出为无对齐的连续内存,逐行拷贝有效数据即可,每次拷贝长度为
纹理宽度*单像素字节数,跳过RowPitch末尾的Padding字节即可。
内容的提问来源于stack exchange,提问作者wflznrxkuf
相关产品推荐
相关产品推荐

