| View previous topic :: View next topic |
| Author |
Message |
blasty
Joined: 22 Aug 2005 Posts: 9
|
Posted: Mon Aug 22, 2005 12:22 am Post subject: Confusion about GU Texture swizzling |
|
|
Hi,
I need to get some things straight I guess. Today I have been busy porting my 2D GFX functions to use the GU instead of writing directly to VRAM (and use a doublebuffer technique). as example I took the "blit" demo from the PSPSDK samples directory. This one renders a flat 480x272 texture to the screen. I got this all nicely working, only there was one downside, the animation of my stuff wasn't 100% smooth. Someone suggested I might needed to flush the caches using sceKernelDcacheWritebackAll(); But this didn't change a thing..
Then I read on this forum about texture swizzling. I enabled swizzling in sceGuTexMode(); and took the example function from [here] (thanks chp). Now comes my actual problem, I don't know how to use this function properly. it requires a input and output pointer which are chars. My texture is in raw 16bit format..
My code looks (shortened) like this:
| Code: |
static unsigned short __attribute__((aligned(16))) pixels[512*272]; // display buffer
static unsigned int __attribute__((aligned(16))) list[262144];
// Setup GU
sceGuStart(GU_DIRECT,list);
sceGuDrawBuffer(GU_PSM_5551,(void*)0,512);
sceGuDispBuffer(480,272,(void*)0x88000,512);
sceGuDepthBuffer((void*)0x110000,512);
sceGuOffset(2048 - (480/2),2048 - (272/2));
sceGuViewport(2048,2048,480,272);
sceGuDepthRange(0xc350,0x2710);
sceGuScissor(0,0,480,272);
sceGuEnable(GU_SCISSOR_TEST);
sceGuFrontFace(GU_CW);
sceGuEnable(GU_TEXTURE_2D);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
sceGuFinish();
sceGuSync(0,0);
sceDisplayWaitVblankStart();
sceGuDisplay(1);
struct Vertex* vertices;
unsigned short *texture;
texture = malloc(sizeof(pixels));
// swizzle texture
swizzle(texture, &pixels, 480*2, 272); // pixel width = 2 bytes, so x2
sceGuStart(GU_DIRECT,list);
// setup the source buffer as a 512x512 texture, but only copy 480x272
sceGuTexMode(GU_PSM_5551,0,0,GU_TRUE);
sceGuTexImage(0,512,512,512,texture);
sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
sceGuTexFilter(GU_NEAREST,GU_NEAREST);
sceGuTexScale(1.0f/512.0f,1.0f/512.0f); // scale UVs to 0..1
sceGuTexOffset(0.0f,0.0f);
sceGuAmbientColor(0xffffffff);
for (j = 0; j < 480; j = j+SLICE_SIZE) {
vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
vertices[0].u = j; vertices[0].v = 0;
vertices[0].color = 0;
vertices[0].x = j; vertices[0].y = 0; vertices[0].z = 0;
vertices[1].u = j+SLICE_SIZE; vertices[1].v = 272;
vertices[1].color = 0;
vertices[1].x = j+SLICE_SIZE; vertices[1].y = 272; vertices[1].z = 0;
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_COLOR_5551|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
}
sceGuFinish();
sceGuSync(0,0);
|
This doesn't give the wanted result. I see parts of my image data back, but it's not ordered properly. Does anyone have a clue what I'm missing/doing wrong here?
Any help would be highly appreciated! |
|
| Back to top |
|
 |
chp
Joined: 23 Jun 2004 Posts: 313
|
Posted: Mon Aug 22, 2005 2:13 am Post subject: |
|
|
Quite simple: You're swizzling it as a 480x272 16-bit, while it's clearly a 512x272 16-bit. That will shift all the blocks because of the dead data read.
If you wanted to swizzle just part of a texture, you'd have to take into account the buffer-width aswell. The swizzle functions I wrote do not at the moment. _________________ GE Dominator |
|
| Back to top |
|
 |
blasty
Joined: 22 Aug 2005 Posts: 9
|
Posted: Mon Aug 22, 2005 2:37 am Post subject: |
|
|
Damn. that was quite obvious actually. just fixed that bug in the source.
But still my texture still doesn't come out correct.. It's divided in 4 vertical lines and seems to skip a row of pixels (so is black in end result) each time. veeery strange. |
|
| Back to top |
|
 |
blasty
Joined: 22 Aug 2005 Posts: 9
|
Posted: Tue Aug 23, 2005 7:40 pm Post subject: |
|
|
| NOBODY has an idea what I am doing wrong here? Furthermore, I have looked through the PSPWARE SVN directory to see if any of the projects used texture swizzling.. but NONE of them does. Why?? Am I the only person experiencing heavy frame tearing when copying a 480x272 texture a few times every second? I have fiddled around with this for 12+ hours now, and I'm getting kind of fed up with it. Without swizzling my code looks exactly the same except for the memory getting malloc()'d and the swizzle parameter not being set in sceGuTexMode(); (oh, and the reference to "pixels" insteaf of "texture", kinda obvious). A working example or explanation why my stuff is so slow would be highly appreciated. |
|
| Back to top |
|
 |
Panajev2001a
Joined: 20 Aug 2005 Posts: 100
|
Posted: Sat Aug 27, 2005 7:48 pm Post subject: |
|
|
Try this function: it is the original function chp optimized for the Wiki submission and I did a small few changes to it (no divides, but shifts instead, etc...).
| Code: | void swizzle_fast(u8* out, const u8* in, unsigned int width, unsigned int height)
{
unsigned int blockx, blocky;
unsigned int i,j;
unsigned int width_blocks = (width >> 4);
unsigned int height_blocks = (height >> 3);
unsigned int src_pitch = (width-16) >> 2;
unsigned int src_row = width << 3;
const u8* ysrc = in;
u32* dst = out;
for (blocky = 0; blocky < height_blocks; ++blocky)
{
const u8* xsrc = ysrc;
for (blockx = 0; blockx < width_blocks; ++blockx)
{
const u32* src = (u32*)xsrc;
for (j = 0; j < 8; ++j)
{
*(dst++) = *(src++);
*(dst++) = *(src++);
*(dst++) = *(src++);
*(dst++) = *(src++);
src += src_pitch;
}
xsrc += 16;
}
ysrc += src_row;
}
} |
The best thing would be to swizzle outside of your PSP program, presenting the texture as already swizzled when you load them up. |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Sat Aug 27, 2005 10:38 pm Post subject: |
|
|
| Panajev2001a wrote: | | Try this function: it is the original function chp optimized for the Wiki submission and I did a small few changes to it (no divides, but shifts instead, etc...). |
Most compilers replace division by power-of-two integer numbers by shifts. Check the compiler or objdump output to be sure. |
|
| Back to top |
|
 |
Panajev2001a
Joined: 20 Aug 2005 Posts: 100
|
Posted: Sun Aug 28, 2005 12:06 am Post subject: |
|
|
| holger wrote: | | Panajev2001a wrote: | | Try this function: it is the original function chp optimized for the Wiki submission and I did a small few changes to it (no divides, but shifts instead, etc...). |
Most compilers replace division by power-of-two integer numbers by shifts. Check the compiler or objdump output to be sure. |
I tend not to trust the compiler ;). |
|
| Back to top |
|
 |
ector
Joined: 12 May 2005 Posts: 195
|
Posted: Sun Aug 28, 2005 1:46 am Post subject: |
|
|
| holger wrote: | | Panajev2001a wrote: | | Try this function: it is the original function chp optimized for the Wiki submission and I did a small few changes to it (no divides, but shifts instead, etc...). |
Most compilers replace division by power-of-two integer numbers by shifts. Check the compiler or objdump output to be sure. |
That's true for left-shifts, but rightshifts aren't as simple. You must use unsigned variables for the compiler to be able to fully replace a division with a rightshift, otherwise it has to add fixup code to account for the fact that -1 >> 1 == -1 and not 0 as would be expected. _________________ http://www.dtek.chalmers.se/~tronic/PSPTexTool.zip Free texture converter for PSP with source. More to come. |
|
| Back to top |
|
 |
blasty
Joined: 22 Aug 2005 Posts: 9
|
Posted: Wed Aug 31, 2005 8:11 pm Post subject: |
|
|
boohoo, I'm still camping around with this problem. I tried Panajev's function also, but basically it does the same as chp's one. To clarify a little, I have redrawn the result of what I get when I swizzle my textures. It looks like [this], but it's supposed to look like [this]. (yes, a white rectangle ;))
My code looks still the same except for the bug/mistake I fixed regarding to the swizzle(); call. (the one chp mentioned earlier in this thread) |
|
| Back to top |
|
 |
ector
Joined: 12 May 2005 Posts: 195
|
Posted: Thu Sep 01, 2005 3:22 am Post subject: |
|
|
The width of your image has to be a multiple of 32 bytes. You can't just try to swizzle a 23x20 pixel image and expect it to come out right.. _________________ http://www.dtek.chalmers.se/~tronic/PSPTexTool.zip Free texture converter for PSP with source. More to come. |
|
| Back to top |
|
 |
blasty
Joined: 22 Aug 2005 Posts: 9
|
Posted: Thu Sep 01, 2005 6:41 am Post subject: |
|
|
| Heh, I guess I was a little vague. This is just a quick cut and paste of the result. the texture itself is 512x512. |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Mon Oct 03, 2005 11:35 am Post subject: |
|
|
Did you ever manage to fix your problem?
I'm having trouble swizzling anything. I'm trying to do a 128*128 texture, but its not working. I went back to trying to swizzle the texture that came with the cube demo instead to try and find out what I'm doing wrong, but thats still not happening. Anything obviously wrong with the following?
| Code: |
extern unsigned char logo_start[];
const unsigned short swizzleData[64*64] = {0};
...
swizzle(swizzleData,logo_start, 64, 64);
...
sceGuTexMode(GU_PSM_4444,0,0,TRUE);
sceGuTexImage(0,64,64,64,swizzleData);
|
_________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Mon Oct 03, 2005 5:32 pm Post subject: |
|
|
| you must not declare arrays that you are intending to change as "const", you want to use "static" instead. |
|
| Back to top |
|
 |
chp
Joined: 23 Jun 2004 Posts: 313
|
Posted: Mon Oct 03, 2005 7:00 pm Post subject: |
|
|
I can spot one problem in your code, and that is that you are passing texel-width to swizzle(), when the code in itself assumes byte-width, so the width for a 64x64 16-bit texture is in fact 128 (64 texels times 2 bytes).
I'll take a look at making a "complete" approach on the wiki soon, which will make understanding the code more clear, like passing a pixelformat to make width independent, and support swizzling just part of a texture. _________________ GE Dominator |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Mon Oct 03, 2005 7:21 pm Post subject: |
|
|
Hi chp,
if you change the calling convention of the swizzle/tile function, so that the texture stride is passed as argument and not calculated internally you avoid bugs like this and would even allow more flexible use...
btw. Using the VFPU you can make the inner loop a single load/store-128bit-vector pair. |
|
| Back to top |
|
 |
chp
Joined: 23 Jun 2004 Posts: 313
|
Posted: Tue Oct 04, 2005 12:02 am Post subject: |
|
|
But since people mistake the width as texel-width, it does show that it's unclear now aswell, doesn't it? One good approach would perhaps be to make the prototype identical to sceGuCopyImage() (from my perspective, I guess you want something else :)), since people know atleast somewhat how to use it and what the parameters mean.
Optimizing using VFPU is of secondary interest right now actually. The question is if it's any gain, depending on how we can pipeline memory-accesses from the VFPU, or if any gain can be had since you'll probably be cache-tied when reading the source-data anyway. One approach would be to switch approach and read data in a linear fashion and write in blocks. This could improve performance more than using 128-bit read/writes since we might not have to refill the cache as often. _________________ GE Dominator |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Tue Oct 04, 2005 4:07 am Post subject: |
|
|
Thanks for clearing up the width parameter for me. And I can't believe I made such a stupid mistake leaving that 'const' there... The perils of Copy & Paste. _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Tue Oct 04, 2005 4:11 am Post subject: |
|
|
| chp wrote: |
Optimizing using VFPU is of secondary interest right now actually. The question is if it's any gain, depending on how we can pipeline memory-accesses from the VFPU, or if any gain can be had since you'll probably be cache-tied when reading the source-data anyway. One approach would be to switch approach and read data in a linear fashion and write in blocks. This could improve performance more than using 128-bit read/writes since we might not have to refill the cache as often.
|
By setting the cache policy bit in the sw.q instruction you can bypass the cache entirely, you can also avoid cache pollution by using the uncached high memory address space. In our pspgl experiments uncached word writes to the GE command buffer were more performant than cached ones, I assume there is a write combiner unit in the uncached write path. |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Tue Oct 04, 2005 4:22 am Post subject: |
|
|
| Code: |
extern unsigned char logo_start[];
static unsigned short swizzleData[64*64] = {0};
...
swizzle(swizzleData,logo_start, 64*2, 64);
//swizzle_fast(swizzleData,logo_start, 64*2, 64);
...
sceGuTexMode(GU_PSM_4444,0,0,TRUE);
sceGuTexImage(0,64,64,64,swizzleData);
|
Odd that this still shows a corrupt image... _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
ector
Joined: 12 May 2005 Posts: 195
|
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Tue Oct 04, 2005 4:41 am Post subject: |
|
|
No, I wasn't. I just tried adding it here:
sceGuTexFlush();
sceGuTexImage(0,64,64,64,swizzleData);
But that made it look worse... _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Tue Oct 04, 2005 4:44 am Post subject: |
|
|
| You also need to flush DCache before calling the TexImage function. |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Tue Oct 04, 2005 5:09 am Post subject: |
|
|
From this in another post:
| Quote: | | sceKernelDcacheWritebackAll() before calling the glTex*() functions, glFinish() after the vertex render functions before you are moving to the next texture on the same texture object. |
I made this:
| Code: |
void GameMain(void)
{
sceGuStart(GU_DIRECT,list);
//Clear screen and depth buffers.
sceGuClearColor(0xff000000);
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
//Read in the user input
GetInput();
//Setup model matrix for the cube. Projection and View already done once since camera is static.
sceGumMatrixMode(GU_MODEL);
sceGumLoadIdentity();
{
ScePspFVector3 pos = { g_fTranslateX, g_fTranslateY, g_fTranslateZ };
ScePspFVector3 rot = {
g_fRotateX * (M_PI/180.0f),
g_fRotateY * (M_PI/180.0f),
g_fRotateZ * (M_PI/180.0f) };
sceGumRotateXYZ(&rot);
sceGumTranslate(&pos);
}
// setup texture
sceGuTexMode(GU_PSM_4444,0,0,TRUE);
//-------------ADDED THESE LINES----------------
sceKernelDcacheWritebackAll();
sceGuTexFlush();
//Set current texturemap.
sceGuTexImage(0,64,64,64,swizzleData);
//Set how textures are applied.
sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
//Set how the texture is filtered.
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
sceGuTexScale(1.0f,1.0f);
//?Where to start the texture when drawing?
sceGuTexOffset(0.0f,0.0f);
//?Set the ambient light colour?
sceGuAmbientColor(0xffffffff);
//Draw array of vertices forming the cube.
sceGumDrawArray(GU_TRIANGLES,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,12*3,0,vertices);
//Finish current display list and go back to the parent context.
sceGuFinish();
//Wait until display list has finished executing. Pass (0,0)
sceGuSync(0,0);
//Wait for the screen to finish drawing, (the next Vertical Refresh will be starting)
sceDisplayWaitVblankStart();
//Swap display and draw buffer so we see what we just drew.
sceGuSwapBuffers();
}
|
The black bits are gone, but the texture still isn't right. I also tried moving those lines above sceGuTexMode(GU_PSM_4444,0,0,TRUE); but that didn't help either. _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Tue Oct 04, 2005 5:36 pm Post subject: |
|
|
call sceGuTexFlush() after sceGuTexImage() and before sceGumDrawArray(), otherwise it does not makes much sense. In Addition to sceGuTexFlush() it may even make more sense to call also sceGuTexSync(), in order to force the GE to wait until the texture transfer is finished before starting to render.
So the entire sequence looks like:
| Code: |
/* paint your texture, and swizzle if you want to */
sceKernelDcacheWritebackAll(); /* get all data into memory */
/* upload your texture to VRAM if you want to, e.g. using CopyImage() */
TexImage(); /* set up DMA pointers of GE for texture access */
TexFlush(); /* start DMA transfer */
/* ... do other things ...*/
TexSync(); /* let the GE wait for end of DMA transfer */
DrawArray(); /* trigger vertex array rendering */
|
|
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Wed Oct 05, 2005 2:19 am Post subject: |
|
|
Thanks again for your help. That all makes good sense. After implementing the calls in the order you suggest, I really don't know why its still not working, but I don't want to keep bothering you guys with it. I guess I'll keep plugging away and see if I get anywhere eventually. _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Wed Oct 05, 2005 3:31 am Post subject: |
|
|
Has anyone got any example code of doing this stuff so that it works? Maybe looking at a working implementation would point out an obvious error in my code.
Thanks! _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Fri Oct 07, 2005 2:34 pm Post subject: |
|
|
| ashleydb wrote: | Has anyone got any example code of doing this stuff so that it works? Maybe looking at a working implementation would point out an obvious error in my code.
Thanks! |
Anyone? Please? ;) _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Fri Oct 07, 2005 5:37 pm Post subject: |
|
|
| what about the cube sample in gu/samples/ ? |
|
| Back to top |
|
 |
ashleydb
Joined: 03 Oct 2005 Posts: 26 Location: USA
|
Posted: Sat Oct 08, 2005 3:03 am Post subject: |
|
|
It doesn't swizzle anything. That is the demo I'm trying to edit. Unless it is swizzled and I'm trying to swizzle it again... _________________ www.PSP-Files.com - PSP News, Hacks etc.
www.HiAsh.com - My work and stuff |
|
| Back to top |
|
 |
holger
Joined: 18 Aug 2005 Posts: 204
|
Posted: Sat Oct 08, 2005 4:01 am Post subject: |
|
|
| haven't you been talking about cache inconsistency problems? |
|
| Back to top |
|
 |
|