I recently had the need to unswizzle textures. I looked at the wiki and found the following page that I'm sure most of you are familiar with:
http://wiki.ps2dev.org/psp:ge_faq
On it, there is the unswizzle function:
Code: Select all
unsigned unswizzle(unsigned offset, unsigned log2_w)
{
if (log2_w <= 4)
return offset;
unsigned w_mask = (1 << log2_w) - 1;
unsigned mx = offset & 0xf;
unsigned by = offset & (~7 << log2_w);
unsigned bx = offset & ((w_mask & 0xf) << 7);
unsigned my = offset & 0x70;
return by | (bx >> 3) | (my << (log2_w - 4)) | mx;
}
When I tried using this, however, I got some weird behavior: the image, when unswizzled, was shifted to the left by half of its width. The rest of the resulting image (the entire right side) was grey (which happens to correspond to the 0xCD pattern that the debug malloc puts in to the memory).
After some inspection, I found that the problem was that whenever the unswizzle operation got to offset 2048 in the source stream, it would reset the offset to 0 (line size is 128 * 4 = 512, so this is the 5th row, so this corresponds to the second column of blocks).
Since the vertical direction was fine, and the data in the blocks was fine, the culprit was probably bx in the code above. After watching the values when the reset happened, I changed the 0xF to an 0x1F. Reasoning follows, for a 128x128 image with 4 bytes per pixel (taken from the psp-programming.com NeHe conversions :)
Code: Select all
// Original unswizzle did this
// w_mask = 0x000001FF = 000111111111b
// (w_mask & 0xF) = 0x0000000F = 000000001111b
// << 7 = 0x00000780 = 011110000000b
// offset = 0x00000800 = 100000000000b
// return 0x00000000 = 0
// Modified unswizzle
// (w_mask & 0x1F) = 0x0000001F = 000000011111b
// << 7 = 0x00000780 = 111110000000b
// offset = 0x00000800 = 100000000000b
// return 0x00000800 = 2048
So my question is, is the code wrong or is it possible that what I'm doing is somehow affecting things?
If the code is wrong, why would it be different than the swizzle function - or is swizzle broken too? I'm pretty sure someone would have mentioned it...
Just thought I'd bring it to your attention. If anything, maybe this will help anyone trying to do something similar and searching the forums in the future :)