Possible bug in unswizzle, or am I doing something wrong?

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
noxa
Posts: 39
Joined: Sat Aug 05, 2006 9:03 am
Contact:

Possible bug in unswizzle, or am I doing something wrong?

Post by noxa »

Hello smart PSP guys :)

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 &#40;log2_w <= 4&#41;
		return offset;
 
	unsigned w_mask = &#40;1 << log2_w&#41; - 1;
 
	unsigned mx = offset & 0xf;
	unsigned by = offset & &#40;~7 << log2_w&#41;;
	unsigned bx = offset & &#40;&#40;w_mask & 0xf&#41; << 7&#41;;
	unsigned my = offset & 0x70;
 
	return by | &#40;bx >> 3&#41; | &#40;my << &#40;log2_w - 4&#41;&#41; | mx;
&#125;
As the comment for it says, it's essentially the swizzle function but with the rotation flipped.

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
	// &#40;w_mask & 0xF&#41; =  0x0000000F = 000000001111b
	// << 7 =            0x00000780 = 011110000000b
	// offset =          0x00000800 = 100000000000b
	// return            0x00000000 = 0

	// Modified unswizzle
	// &#40;w_mask & 0x1F&#41; = 0x0000001F = 000000011111b
	// << 7 =            0x00000780 = 111110000000b
	// offset =          0x00000800 = 100000000000b
	// return            0x00000800 = 2048
You can see the before and after here:
Image

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 :)
Post Reply