ddspp icon indicating copy to clipboard operation
ddspp copied to clipboard

get_offset can break with oddly sized mipmap chains.

Open DarioSamo opened this issue 6 months ago • 2 comments

The following file fails to retrieve the correct offset for this DDS file from mipmap level 5 and above.

40E0F5A1#3#0_all.zip

RenderDoc displays it correctly. image image

While if I use get_offset, the result looks broken as the offset is wrong. image

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?

DarioSamo avatar Jul 26 '24 19:07 DarioSamo