Swapping palettes for each texture

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

Moderators: cheriff, TyRaNiD

Post Reply
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Swapping palettes for each texture

Post by gotmilk065 »

I've come to the conclusion that 32-bit textures take up way too much RAM, so I wanted to try a different approach.

Let's say I had an 8-bit PCX file, which, being a PCX file, would be a completely 8-bit image. Now, with my old implementation, I would upsample the texture to a 32-bit image, then use that to render. However, I see now the amount of RAM that wastes.. Can somebody give me an example of swapping the palette whenever a texture is to be rendered?

Thanks :)
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

pspsdk/samples/gu/clut/
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Post by gotmilk065 »

Raphael wrote:pspsdk/samples/gu/clut/
Thanks, I'll take a look later today :D
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Post by gotmilk065 »

Alright, well I've come to a bit of a problem.

What's the format that sceGuClutLoad asks for?

Right now, my palette is stored as a pointer to a series of bytes that go as RGBRGBRGB.. etc. How would it be converted into the proper format?
psPea
Posts: 60
Joined: Sat Sep 01, 2007 12:51 pm

Post by psPea »

sceGuClutMode sets the clut mode (line 125 of the sample)
psp doesn't support 24 bbp you'll have to add an alpha channel


>Right now, my palette is stored as a pointer to a series of bytes that go as RGBRGBRGB.. etc. How would it be converted into the proper format?
you could use the GU_RGBA(r,g,b,a) macro
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Post by gotmilk065 »

Okay; here's the issue.

The palette switches, sometimes, but it fails half the time, the correct palette will flash on and off every frame or so, it's really annoying. This is Quake, attempting to get Half-Life maps loading. The previous implementation I had would upsample the 8-bit textures to 32-bit textures and render them as such, but it took up far too much RAM, and now I decided to try this.

http://www.youtube.com/watch?v=32QDVXlJof4

I also put some good music on the video, so yay!
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

Well... we see how the textures flicker, but we can't say what the reason is, since we don't know how you handle the palettes.

Do you have them in sys ram or vram?
Do you have all palettes in their own location and upload from there
or do you copy to your global palette each texture swap?
Do you set the parameters for sceGuClut* correctly?
...
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Post by gotmilk065 »

Raphael wrote:Do you have them in sys ram or vram?
System RAM.
Raphael wrote:Do you have all palettes in their own location and upload from there
Yes.
Raphael wrote:or do you copy to your global palette each texture swap?
Every time I bind the texture, I swap by doing this:

Code: Select all

void VID_SetPaletteHL&#40;unsigned char* palette&#41;
&#123;
	ScePspRGBA8888 ALIGNED&#40;16&#41;	d_8to24tableHL&#91;palette_size&#93;;
	
	// Convert the palette to PSP format.
	for &#40;ScePspRGBA8888* color = &d_8to24tableHL&#91;0&#93;; color < &d_8to24tableHL&#91;palette_size&#93;; ++color&#41;
	&#123;
		const unsigned int r = *palette++;
		const unsigned int g = *palette++;
		const unsigned int b = *palette++;
		*color = GU_RGBA&#40;r, g, b, 0xff&#41;;
	&#125;

	// Upload the palette.
	sceGuClutMode&#40;GU_PSM_8888, 0, palette_size - 1, 0&#41;;
	sceKernelDcacheWritebackRange&#40;d_8to24tableHL, sizeof&#40;d_8to24tableHL&#41;&#41;;
	sceGuClutLoad&#40;palette_size / 8, d_8to24tableHL&#41;;
&#125;
Raphael wrote:Do you set the parameters for sceGuClut* correctly?
...
Yeah.

EDIT:
In case you're wondering, here's me binding them:

Code: Select all

void GL_Bind &#40;int texture_index&#41;
&#123;

	// Which texture is it?
	const gltexture_t& texture = gltextures&#91;texture_index&#93;;
	
	if &#40;texture.palette&#41;
		VID_SetPaletteHL&#40;texture.palette&#41;;
	else
		VID_SetPaletteTX&#40;&#41;;
	
	// Binding the currently bound texture?
	if &#40;currenttexture == texture_index&#41;
	&#123;
		// Don't bother.
		return;
	&#125;

	// Remember the current texture.
	currenttexture = texture_index;
	
	// Set the texture mode.
	if &#40;texture.palette&#41;
		sceGuTexMode&#40;GU_PSM_T8, texture.mipmaps , 0, GU_TRUE&#41;;
	else
		sceGuTexMode&#40;texture.format, texture.mipmaps , 0, GU_TRUE&#41;;

	if &#40;texture.mipmaps > 0 && r_mipmaps.value > 0&#41;
    &#123;
		float slope = 0.4f;
		sceGuTexSlope&#40;slope&#41;; // the near from 0 slope is the lower &#40;=best detailed&#41; mipmap it uses
        sceGuTexFilter&#40;GU_LINEAR_MIPMAP_LINEAR, GU_LINEAR_MIPMAP_LINEAR&#41;;
		sceGuTexLevelMode&#40;int&#40;r_mipmaps_func.value&#41;, r_mipmaps_bias.value&#41;;
	&#125;
	else
		sceGuTexFilter&#40;texture.filter, texture.filter&#41;;
		
	// Set the texture image.
	const void* const texture_memory = texture.vram ? texture.vram &#58; texture.ram;
	sceGuTexImage&#40;0, texture.width, texture.height, texture.width, texture_memory&#41;;
&#125;
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

gotmilk065 wrote:

Code: Select all

void VID_SetPaletteHL&#40;unsigned char* palette&#41;
&#123;
	ScePspRGBA8888 ALIGNED&#40;16&#41;	d_8to24tableHL&#91;palette_size&#93;;
	
	// Convert the palette to PSP format.
	for &#40;ScePspRGBA8888* color = &d_8to24tableHL&#91;0&#93;; color < &d_8to24tableHL&#91;palette_size&#93;; ++color&#41;
	&#123;
		const unsigned int r = *palette++;
		const unsigned int g = *palette++;
		const unsigned int b = *palette++;
		*color = GU_RGBA&#40;r, g, b, 0xff&#41;;
	&#125;

	// Upload the palette.
	sceGuClutMode&#40;GU_PSM_8888, 0, palette_size - 1, 0&#41;;
	sceKernelDcacheWritebackRange&#40;d_8to24tableHL, sizeof&#40;d_8to24tableHL&#41;&#41;;
	sceGuClutLoad&#40;palette_size / 8, d_8to24tableHL&#41;;
&#125;
Raphael wrote:Do you set the parameters for sceGuClut* correctly?
...
Yeah.
There you go. Not really.
sceGuClutMode Parameter 2 is a mask parameter for the palette index read from the texture. As long as palette_size is exactly 256 this will work out perfectly well, for anything else it will fail. It doesn't really make sense to depend the index mask on the size, unless you have an T16 or T32 texture map. So just use 0xff there.

Apart from that, you should know that what you do there is gonna cause glitches obviously, as soon as you end up overwriting the stack where you place the palette before GU gets to use it (ie, the next texture is processed before GU got to render the previous one, hence ending up using the *wrong* palette data). This is because sceGu* functions are asynchronous, meaning that the pointer and it's data you give there *must* stay valid for the remainder of the whole frame (which it currently isn't, as its a local variable for that function, ie on stack).
Two solution options:
1. Use sceGuGetMemory to allocate the temporary palette in the current display list
2. allocate memory for the psp palette in your texture structure (256*4 bytes) and fill that with the right palette data on texture load time, then use that pointer (would also save you the need to convert the palette on each texture bind).


What does VID_SetPaletteTX() do exactly? Set a dummy palette? You don't have to, as GU won't use any palette information as soon as the texture format is non-paletted.
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Post by gotmilk065 »

Raphael wrote: There you go. Not really.
sceGuClutMode Parameter 2 is a mask parameter for the palette index read from the texture. As long as palette_size is exactly 256 this will work out perfectly well, for anything else it will fail. It doesn't really make sense to depend the index mask on the size, unless you have an T16 or T32 texture map. So just use 0xff there.
Ooo Okay, thanks.
Raphael wrote: Apart from that, you should know that what you do there is gonna cause glitches obviously, as soon as you end up overwriting the stack where you place the palette before GU gets to use it (ie, the next texture is processed before GU got to render the previous one, hence ending up using the *wrong* palette data). This is because sceGu* functions are asynchronous, meaning that the pointer and it's data you give there *must* stay valid for the remainder of the whole frame (which it currently isn't, as its a local variable for that function, ie on stack).
Two solution options:
1. Use sceGuGetMemory to allocate the temporary palette in the current display list
2. allocate memory for the psp palette in your texture structure (256*4 bytes) and fill that with the right palette data on texture load time, then use that pointer (would also save you the need to convert the palette on each texture bind).
Useful information, mate, thanks! I think I'll take option 2. I actually was going to do that originally, but decided on this to test, and when the method I'm using now didn't work, I figured there was a problem in general, lol, so I didn't bother switching.
Raphael wrote: What does VID_SetPaletteTX() do exactly? Set a dummy palette? You don't have to, as GU won't use any palette information as soon as the texture format is non-paletted.
Nah, it's to revert to the Quake palette, to retain a bit of backwards compatibility with Quake and so the textures on the viewmodels would render correctly when they use the Quake palette.
gotmilk065
Posts: 21
Joined: Sat Nov 28, 2009 10:56 am

Post by gotmilk065 »

Sweet, got it working!

Thanks again Raph, you're a lifesaver :D
Post Reply