ddspp
ddspp copied to clipboard
get_offset can break with oddly sized mipmap chains.
The following file fails to retrieve the correct offset for this DDS file from mipmap level 5 and above.
RenderDoc displays it correctly.
While if I use get_offset, the result looks broken as the offset is wrong.
After tracking this down, I found out the get_offset implementation makes a few assumptions about how to downscale the mip0 size that might break when the texture uses non-power of two sizes.
I wrote this hacky workaround that only works with 4x4 block sizes to confirm my theory, and the texture loading was fixed.
unsigned long long mipChainSize = 0;
for (unsigned int m = 0; m < desc.numMips; ++m)
{
unsigned int blocksWide = (3 + std::max(desc.width >> m, 1U)) / 4;
unsigned int blocksTall = (3 + std::max(desc.height >> m, 1U)) / 4;
mipChainSize += blocksWide * blocksTall * desc.bitsPerPixelOrBlock;
//unsigned long long mipSize = mip0Size >> 2 * m; // Divide by 2 in width and height
//mipChainSize += mipSize > desc.bitsPerPixelOrBlock ? mipSize : desc.bitsPerPixelOrBlock;
}
offset += mipChainSize * slice;
for (unsigned int m = 0; m < mip; ++m)
{
unsigned int blocksWide = (3 + std::max(desc.width >> m, 1U)) / 4;
unsigned int blocksTall = (3 + std::max(desc.height >> m, 1U)) / 4;
offset += blocksWide * blocksTall * desc.bitsPerPixelOrBlock;
//unsigned long long mipSize = mip0Size >> 2 * m; // Divide by 2 in width and height
//offset += mipSize > desc.bitsPerPixelOrBlock ? mipSize : desc.bitsPerPixelOrBlock;
}
So it seems like the issue is tied potentially to the offset computation not handling the cases where the size rounds down.
I can look into making a fix but I'm not sure I understand the issue correctly quite yet. Any input on this?