Correct pitch usaged for D3D9 updateTexture calls.

+ Add useD3D9Pitch helper function.
+ Add calcRowPitch helper function.
+ Update TextureD3D9::update to consider block compression.
  (Originally, it was not considering block size for updating.)
+ Update TextureD3D9::update to calculate pitch in certain cases.
  (Specifically BC4 and BC5 are known to provide the wrong pitch.)
This commit is contained in:
Trent Reed 2019-02-01 16:35:31 -08:00
parent 5054be0f97
commit a048f9944c
1 changed files with 38 additions and 14 deletions

View File

@ -373,6 +373,34 @@ namespace bgfx { namespace d3d9
;
}
static inline bool useD3D9Pitch(bimg::TextureFormat::Enum _format)
{
// For BC4 and B5 in DX9 LockRect returns wrong number of
// bytes. If actual mip size is used it causes memory corruption.
// http://www.aras-p.info/texts/D3D9GPUHacks.html#3dc
return true
&& _format != bimg::TextureFormat::BC4
&& _format != bimg::TextureFormat::BC5
;
}
static inline uint32_t calcRowPitch(const bimg::ImageBlockInfo& _blockInfo, uint8_t _lod, uint32_t _width)
{
const uint8_t blockWidth = _blockInfo.blockWidth;
const uint8_t blockHeight = _blockInfo.blockHeight;
const uint8_t minBlockX = _blockInfo.minBlockX;
const uint8_t bitsPerPixel = _blockInfo.bitsPerPixel;
// Calculate the row pitch
const uint32_t minBlkWidth = minBlockX;
const uint32_t lodBlkWidth = (((_width >> _lod) + blockWidth - 1) / blockWidth);
const uint32_t rowBlkWidth = bx::max<uint32_t>(minBlkWidth, lodBlkWidth);
const uint32_t pixBlkWidth = rowBlkWidth * blockWidth * blockHeight;
const uint32_t rowPitch = pixBlkWidth * bitsPerPixel / 8u;
return rowPitch;
}
struct RendererContextD3D9 : public RendererContextI
{
RendererContextD3D9()
@ -2961,14 +2989,7 @@ namespace bgfx { namespace d3d9
return;
}
// For BC4 and B5 in DX9 LockRect returns wrong number of
// bytes. If actual mip size is used it causes memory corruption.
// http://www.aras-p.info/texts/D3D9GPUHacks.html#3dc
const bool useMipSize = true
&& imageContainer.m_format != bimg::TextureFormat::BC4
&& imageContainer.m_format != bimg::TextureFormat::BC5
;
const bool useMipSize = useD3D9Pitch(imageContainer.m_format);
for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
{
uint32_t width = ti.width;
@ -3062,11 +3083,14 @@ namespace bgfx { namespace d3d9
void TextureD3D9::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem)
{
const uint32_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) );
const uint32_t rectpitch = _rect.m_width*bpp/8;
const uint32_t srcpitch = UINT16_MAX == _pitch ? rectpitch : _pitch;
const uint32_t dstpitch = s_renderD3D9->m_updateTexturePitch;
uint8_t* bits = s_renderD3D9->m_updateTextureBits + _rect.m_y*dstpitch + _rect.m_x*bpp/8;
const bimg::ImageBlockInfo & blockInfo = bimg::getBlockInfo(bimg::TextureFormat::Enum(m_textureFormat) );
const uint16_t blockHeight = blockInfo.blockHeight;
const uint16_t bpp = blockInfo.bitsPerPixel;
const bool useLockedPitch = useD3D9Pitch(bimg::TextureFormat::Enum(m_textureFormat) );
const uint32_t rectpitch = calcRowPitch(blockInfo, 0, _rect.m_width);
const uint32_t srcpitch = UINT16_MAX == _pitch ? rectpitch : _pitch;
const uint32_t dstpitch = (useLockedPitch) ? s_renderD3D9->m_updateTexturePitch : calcRowPitch(blockInfo, _mip, m_width);
uint8_t* bits = s_renderD3D9->m_updateTextureBits + _rect.m_y*dstpitch/blockHeight + _rect.m_x*blockHeight*bpp/8;
const bool convert = m_textureFormat != m_requestedFormat;
@ -3083,7 +3107,7 @@ namespace bgfx { namespace d3d9
{
uint8_t* src = data;
uint8_t* dst = bits;
for (uint32_t yy = 0, height = _rect.m_height; yy < height; ++yy)
for (uint32_t yy = 0, height = _rect.m_height; yy < height; yy += blockHeight)
{
switch (m_textureFormat)
{