diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 8a0ac9ead..bd851add6 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -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(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) {