为什么函数 ID3D11DeviceContext::Map 有时会生成与我的纹理分辨率不同的映射子资源?

Why does the function ID3D11DeviceContext::Map sometimes produce a mapped subresource with a different resolution to my texture?

在现有渲染纹理上使用 Map 函数时,在某些情况下,输出 RowPitchDepthPitch 会发生变化,从而产生略微不同的分辨率。

例如,如果源纹理(BGRA 8 位)的分辨率为 1559x1080,位深度为 4,则生成的 D3D11_MAPPED_SUBRESOURCE 的分辨率为 1568x1080 (通过将输出 RowPitch ( 6272 ) 除以 BitDepth (4) 计算得出)。

但是,如果源纹理的分辨率为 1568x1080,则映射的子资源将具有预期的 RowPitch 6272。

虽然我能想到很多改变的原因(即优化 MipMap 级别、适应现有的内存限制),但我想了解为什么以及计算输出的确切算法是什么 RowPitch这样我们就可以对源纹理执行规则。

根据您的回答,我猜您 运行 这是在比较现代的 x86-64 CPU.

根据您给出的值的一些基本数学计算,您的 PC 的算法如下所示:

RowPitch = AlignUp((BytesPerTexel * TextureWidth), 64);

此处,AlignUp 将第一个参数四舍五入为大于或等于第一个参数可被第二个参数整除的最小值。

值 64 不是任意的 - 它可以是 CPU 上缓存行的大小,也可以是从 CPU 到 GPU 的单个 PCI 传输的最大大小。由于 Map 返回的指针位于 CPU 上,我猜测它与缓存行大小匹配,在这种情况下,它可能会根据您所使用的确切 CPU 而有所不同运行 上。

至于具体的实施细节,您必须让 Microsoft 工程师插话。不过,总的来说,这似乎是最有可能的解释。

在解决纹理大小问题方面,最好的选择实际上是在很大程度上忽略它。 D3D 和 GPU 将忽略超出纹理宽度但在行间距内的数据。只需将纹理宽度作为写入边界,将行距作为元素大小即可。

值得注意的是,这种情况一直自动发生 - 如果您有一个 C 结构数组,每个结构的大小都不能被它们的对齐方式整除,编译器将在结构之间插入填充以保留它们对齐。同样的事情发生在这里,但编译器无法对你隐藏它。

RowPitch和DepthPitch确实可以按一定尺寸对齐(各种原因)。

这不会改变纹理的分辨率,它只是在每行末尾添加了一些填充数据。

没有确定行距值的算法,因为它会根据 GPU manufacturer/model/driver。

所以唯一确定的方法就是通过map函数查询如果rowpitch == pixelsize*width(或者你自定义的pitch,一些图像API也在CPU中应用padding),你可以这样做一个完整的 memcpy,如果不是,你必须每行复制一行。

附带说明一下,我检查了我的机器,Intel 和 Nvidia 卡都报告了 128 的对齐,但正如所说,它可以改变,所以你不应该依赖你得到的值并期望它们会是在另一台机器上也是一样。