forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Help with converting direct vram writing to GU.

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Thu Aug 24, 2006 1:30 pm    Post subject: Help with converting direct vram writing to GU. Reply with quote

I'm a complete newbie when it comes to programming video. I have successfully been able to display images by writing directly to vram. However, I would like to get even better performance but really I have no clue. Would the people here help me out on my quest to using the graphics unit properly.

Here is my original code that writes to vram for my game:
Code:
int video_copy_screen(s_screen* src)
{
   char *sp;
   Color *dp;

   int width, height;
   
   // Determine width and height
   width = screen_w;
   if(width > src->width) width = src->width;
   height = screen_h;
   if(height > src->height) height = src->height;

   if(!width || !height) return 0;

   // Copy to linear video ram
   sp = src->data;
   dp = getVramDisplayBuffer()+((SCREEN_WIDTH-screen_w)/2)+((SCREEN_HEIGHT-screen_h)/2)*LINESIZE;
   do{
      int x;
      for(x=0;x<width;x++) {
         dp[x] = palette[((int)(sp[x])) & 0xFF];
      }
      sp += src->width;
      dp += SCREEN_PITCH;
   }while(--height);

   if(pspFpsEnabled) getFPS();
   return 1;
}


And here was my attempt at converting the code to the GU:
Code:

int video_copy_screen(s_screen* src)
{
   char *sp;
   Color *dp;
   int width, height;

   Image* image = (Image*) malloc(sizeof(Image));
    if (!image) return 0;

   // Determine width and height
   width = screen_w;
   if(width > src->width) width = src->width;
   height = screen_h;
   if(height > src->height) height = src->height;

   if(!width || !height) return 0;

    image->imageWidth = width;
    image->imageHeight = height;
    image->textureWidth = getNextPower2(width);
    image->textureHeight = getNextPower2(height);
   
   image->data = (Color*) memalign(16, image->textureWidth * image->textureHeight * sizeof(Color));
    if (!image->data) return 0;
    memset(image->data, 0, image->textureWidth * image->textureHeight * sizeof(Color));

   sp = src->data;
   dp = image->data + ((SCREEN_WIDTH-screen_w)/2)+((SCREEN_HEIGHT-screen_h)/2) * image->textureWidth;
   do{
      int x;
      for(x=0;x<width;x++) {
         dp[x] = palette[sp[x]];
      }
      sp += src->width;
      dp += image->textureWidth;
   }while(--height);

   if(pspFpsEnabled) getFPS();
   blitImageToScreen(0, 0, 480, 272, image, 0, 0);
   flipScreen();
   freeImage(image);
   return 1;
}


Now when writing to vram I am getting about 60~70 fps. With the new code I'm only getting about ~38 fps.

Can some guide me in properly using the GU to get better performance than the original code.

blitImageToScreen, getNextPower2, flipScreen and freeImage is based on graphics.c from luaplayer.

s_screen is a struct that contains two ints for width and height and char array for the data.
Back to top
View user's profile Send private message Visit poster's website
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Thu Aug 24, 2006 5:18 pm    Post subject: Reply with quote

Not really surprised. You're copying the entire frame from your palettised texture into a 32bit texture, then blitting that, instead of just copying it once. Plus you've added a bunch of dynamic memory allocation too.

To get the real speed you should store the palettised version at the right size in vram, and blit vram->vram.

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Fri Aug 25, 2006 2:47 am    Post subject: Reply with quote

Jim wrote:
To get the real speed you should store the palettised version at the right size in vram, and blit vram->vram.


ok then. What I would need to do is create two vram pointers (using some GU function for sp,dp) and palletize src->data into the vram pointer. Then use some GU function (like sceGuCopyImage) to blit the vram pointer to vram?

Code:


   sp = src->data;
   dp = ((SCREEN_WIDTH-screen_w)/2)+((SCREEN_HEIGHT-screen_h)/2)*LINESIZE;
   do{
      int x;
      for(x=0;x<width;x++) {
         dp[x] = palette[((int)(src->data[x])) & 0xFF];
      }
      src->data += src->width;
      dp += SCREEN_PITCH;
   }while(--height);



Thank you for your reply and help Jim.
Back to top
View user's profile Send private message Visit poster's website
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Fri Aug 25, 2006 8:21 am    Post subject: Reply with quote

It looks like your source data is a palette index texture with a 32bit palette lookup table. You'd have to check, but I'm sure the PSP can handle this kind of format natively, so you don't need to do the unpacking yourself.

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Fri Aug 25, 2006 12:42 pm    Post subject: Reply with quote

You are correct but the palette table is only 8-bit and I've been unsuccessfull in getting the image to display natively without unpacking the data.

However, I've progressed a bit in trying to use the method you stated above. To just copy the main data without adding dynamic memory allocation and just blit ram-vram.


Code:

int video_copy_screen(s_screen* src)
{
   char *sp;
   char *dp;
   int width, height;

   // Determine width and height
   width = screen_w;
   if(width > src->width) width = src->width;
   height = screen_h;
   if(height > src->height) height = src->height;

   if(!width || !height) return 0;

   sp = src->data;
   dp = src->data + 512 * 272 * 2;
   
   int x,y;

   for(y=0; y<height; y++){
      for(x=0;x<width;x++) {
         dp[x+512*272*2] = palette[sp[x]];
      }
      sp += src->width;
      dp += image->textureWidth;
   }

   if(pspFpsEnabled) getFPS();

   Color* vram = getVramDrawBuffer();
   sceKernelDcacheWritebackInvalidateAll();
   guStart();
   sceGuCopyImage(GU_PSM_8888, 0, 0, width, height, src->textureWidth, dp, 0, 0, LINESIZE, vram);
   sceGuFinish();
   sceGuSync(0,0);
   flipScreen();
     return 1;
}



Lastly, here is the image that is being displayed on the PSP.

Back to top
View user's profile Send private message Visit poster's website
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Sat Aug 26, 2006 10:54 am    Post subject: Reply with quote

ok... starting from scratch I'm able to display my image perfectly! I found out how to use the GU functions by referencing DoomPSP video implementation! But I'm not sure if some functions that I'm using are necessary...

The src->data that I'm using is an 8-bit texture and I think one way to increase performance is to lower the bit level from 32 to 8. But I'm not sure what to do next....


Code:

int video_copy_screen(s_screen* src)
{
   int width, height;
   
   // Determine width and height
   width = screen_w;
   if(width > src->width) width = src->width;
   height = screen_h;
   if(height > src->height) height = src->height;

   if(!width || !height) return 0;

   if(pspFpsEnabled) getFPS();

   sceKernelDcacheWritebackAll();
   sceGuStart(0,list);
   sceGuClearColor(0xff000000);
   sceGuClearDepth(0);
   sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
 
   sceGuClutMode(GU_PSM_8888,0,0xff,0); // 32-bit palette
   sceGuClutLoad((32),palette); // upload 32*8 entries (256)

   sceGuTexMode(GU_PSM_T8,0,0,0); 
   sceGuTexImage(0,512,512,width, src->data);
   sceGuTexFunc(GU_TFX_REPLACE,0);
   sceGuTexFilter(GU_LINEAR,GU_LINEAR);
   sceGuTexOffset(0,0);
   sceGuAmbientColor(0xffffffff);

   // render sprite

   sceGuColor(0xffffffff);
   struct Vertex *vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
   vertices[0].u = 0;
   vertices[0].v = 0;
   vertices[0].x = 0;
   vertices[0].y = 0;
   vertices[0].z = 0;
   vertices[1].u = width;
   vertices[1].v = height;
   vertices[1].x = SCREEN_WIDTH;
   vertices[1].y = SCREEN_HEIGHT;
   vertices[1].z = 0;
   sceGuDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,0,vertices);

   sceGuFinish();
   sceGuSync(0,0);
   
   sceGuSwapBuffers();
   
   return 1;
}


However, the performance is still lacking. I'm getting 50 fps at best. So my next setup is to allocate my struct (screen) into video memory then blit from there to see if things speed up. Any recommendations? Thank You very much for your help so far Jim!
Back to top
View user's profile Send private message Visit poster's website
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sat Aug 26, 2006 5:12 pm    Post subject: Reply with quote

It's this 'src->data' that needs to be in vram for max speed. Unless it's changing dynamically, copy it into vram first, once only. Ideally swizzle it too.

Jim
[/i]
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Sat Aug 26, 2006 8:04 pm    Post subject: Reply with quote

Jim I was want to start off by thank you for your all your help. And I have good news!

Previously the most I could get at 222 was 35~40 fps and at 333 a solid 60 (These number would dip depending on the mod being used). But now I'm getting 105 fps and 165 respectivaly to each of the CPU speeds. I never imagined using the GPU would make such a difference!

Just in case you were wondering where all this work was going... Its for my Beats of Rage/OpenBoR Port.

Lastly, I tried to swizzle as well but my image would look off horizontally.... Not sure why this was happening?
Back to top
View user's profile Send private message Visit poster's website
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sun Aug 27, 2006 12:08 pm    Post subject: Reply with quote

http://wiki.ps2dev.org/psp:ge_faq.
You just need to make sure your textures are a multiple of 16bytes wide and 8rows high. Swizzled graphics are far faster than normal ones.

Glad to hear things are moving along :D

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Mon Aug 28, 2006 8:27 am    Post subject: Reply with quote

I have tried to swizzle the graphics and I'm seeing around 7~10 fps less then having them not swizzled?
Back to top
View user's profile Send private message Visit poster's website
chp



Joined: 23 Jun 2004
Posts: 313

PostPosted: Mon Aug 28, 2006 4:28 pm    Post subject: Reply with quote

Briefly looking at your code I see that you copy the entire screen in one single sprite. This is not good for the GE cache as it has to refill many more times than you want it to. Try splitting the copy into slices of 32 source-pixels each. Take a look at the blit-sample in pspsdk if you need more information. With 8-bit source data, you should be able to hit around 1000 fps if going vram->vram or 500 fps from ram (not swizzled).
_________________
GE Dominator
Back to top
View user's profile Send private message
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Tue Aug 29, 2006 6:52 am    Post subject: Reply with quote

I should of updated the post with the new code prior to stating 150 fps. But yeah I was amazed how slicing could give such a boost (went from 50 fps to 150).

Now I have two questions. The first is should I move each slice into vram as the whole image is too big to fit into vram?

The second question is... for the life of me I can't seem to figure out why I cant change GU_TEXTURE_32BITF | GU_VERTEX_32BITF to GU_TEXTURE_16BIT | GU_VERTEX_16BIT. When I do all I see is a blank screen. Is it because I have not initilized the right settings?


Here is the initilizing code:
Code:


#define FRAMEBUFFER_SIZE (LINESIZE*SCREEN_HEIGHT*4)

void initGraphics()
{
        dispBufferNumber = 0;

        sceGuInit();

        guStart();
        sceGuDrawBuffer(GU_PSM_8888, (void*)FRAMEBUFFER_SIZE, LINESIZE);
        sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, (void*)0, LINESIZE);
        sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
        sceGuDepthBuffer((void*) (FRAMEBUFFER_SIZE*2), LINESIZE);
        sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2));
        sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);
        sceGuDepthRange(0xc350, 0x2710);
        sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
        sceGuEnable(GU_SCISSOR_TEST);
        sceGuAlphaFunc(GU_GREATER, 0, 0xff);
        sceGuEnable(GU_ALPHA_TEST);
        sceGuDepthFunc(GU_GEQUAL);
        sceGuEnable(GU_DEPTH_TEST);
        sceGuFrontFace(GU_CW);
        sceGuShadeModel(GU_SMOOTH);
        sceGuEnable(GU_CULL_FACE);
        sceGuEnable(GU_TEXTURE_2D);
        sceGuEnable(GU_CLIP_PLANES);
        sceGuTexMode(GU_PSM_8888, 0, 0, 0);
        sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
        sceGuTexFilter(GU_NEAREST, GU_NEAREST);
        sceGuAmbientColor(0xffffffff);
        sceGuEnable(GU_BLEND);
        sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
        sceGuFinish();
        sceGuSync(0, 0);

        sceDisplayWaitVblankStart();
        sceGuDisplay(GU_TRUE);
        initialized = 1;
}




Here is the blit function that I use now with 32 pixels/slices:
Code:

void blitAlphaImageToScreen(int sx, int sy, s_screen* source, int dx, int dy)
{
        if (!initialized) return;

        sceKernelDcacheWritebackInvalidateAll();
        guStart();

      sceGuClutMode(GU_PSM_8888,0,0xff,0); // 32-bit palette
      sceGuClutLoad((32),palette); // upload 32*8 entries (256)

      sceGuTexMode(GU_PSM_T8,0,0,0); 
      sceGuTexImage(0,512,512,source->width, source->data);
      sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
       
        int j = 0;
        while (j < source->width) {
                Vertex* vertices = (Vertex*) sceGuGetMemory(2 * sizeof(Vertex));
                int sliceWidth = 32;
                if (j + sliceWidth > source->width) sliceWidth = source->width - j;
                vertices[0].u = sx + j;
                vertices[0].v = sy;
                vertices[0].x = dx + j;
                vertices[0].y = dy;
                vertices[0].z = 0;
                vertices[1].u = sx + j + sliceWidth;
                vertices[1].v = sy + source->height;
                vertices[1].x = dx + j + sliceWidth;
                vertices[1].y = dy + source->height;
                vertices[1].z = 0;
                sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices);
                j += sliceWidth;
        }

        sceGuFinish();
        sceGuSync(0, 0);
}


Thank you again for all your help!
Back to top
View user's profile Send private message Visit poster's website
Aion



Joined: 24 Jul 2006
Posts: 40
Location: Montreal

PostPosted: Tue Aug 29, 2006 9:51 am    Post subject: Reply with quote

Did you change the declaration of the "Vertex" structure to match the 16bits vertex format?

And did you wanted to change the vertex color mode, or the vertex coordinates ? Because "GU_VERTEX_32BITF" is used for coordinates, while stuff like "GU_COLOR_8888" is used for color mode of the vertex.
Back to top
View user's profile Send private message
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Tue Aug 29, 2006 11:23 am    Post subject: Reply with quote

Aion wrote:
Did you change the declaration of the "Vertex" structure to match the 16bits vertex format?

And did you wanted to change the vertex color mode, or the vertex coordinates ? Because "GU_VERTEX_32BITF" is used for coordinates, while stuff like "GU_COLOR_8888" is used for color mode of the vertex.



I didn't know that for 16 bit the vertex need to be changed. But it does make sense as I'm using..

Code:

typedef struct
{
   float u,v;
   float x,y,z;
} Vertex;


Which must be for 32 bit mode. While I'm assuming...

Code:

typedef struct
{
    unsigned short u, v;
    short x, y, z;
} Vertex;


Must be for 16 bit mode.

And yes, Vertex would be used for coordinates.

Thank You Aion for point this out!


**Updated** Yep that did it! But the performance increase wasn't much.
Back to top
View user's profile Send private message Visit poster's website
Aion



Joined: 24 Jul 2006
Posts: 40
Location: Montreal

PostPosted: Tue Aug 29, 2006 11:38 am    Post subject: Reply with quote

I'm not 100% certain, but it seems that using 16bits fixed point coordinates wouldn't increase performances greatly, since you do not have that many vertex to transfer each frame.

The point of going from 32bits to 16bits is to reduce memory transfer. So it would have a significant gain in vertex/texture color because of the amount of data involve, but not on vertex since in your case, there are so little.

Btw, changing vertex coordinate to 16bits means that it's now using a fixed integer of 1:15 (1-integer 15-fractional)

BTw, why do you wish to have such a high refresh rate? Usually we lock at 60, since the psp screen only refresh 60 time per seconds and we wait for it to not be currently drawing, to avoid graphical glitches (imagine that you have a red screen, then in the middle of the screen refresh, you change it to blue, you'll end up with a top half of red, and bottom of blue, for a split second)
Back to top
View user's profile Send private message
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Tue Aug 29, 2006 12:00 pm    Post subject: Reply with quote

Well the goal was to increase the fps on my port. Previously I could attain 60 fps but it would decrease down to as low as 15 fps depending on how many objects were on screen.

I'm trying to reduce the amount of times it decreases. As for graphical glitches there are none surprisingly. But I found if I lock the refresh rate to 60 fps (sceDisplayWaitVblankStart after each blit) There are times that the performance is worse than writing directly to vram!

However, I've never written any code for gpu processesing before PSP (execept directly to vram). I appreciate all the help everyone has given. This has been a great learning experience!

Hopefully my questions sounded intellegent to say the least. ;)
Back to top
View user's profile Send private message Visit poster's website
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Tue Aug 29, 2006 5:41 pm    Post subject: Reply with quote

Quote:
sceDisplayWaitVblankStart after each blit

Surely you mean 'just before every call to sceGuSwapBuffers'? You definitely don't want to call that function after every blit!

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
Aion



Joined: 24 Jul 2006
Posts: 40
Location: Montreal

PostPosted: Tue Aug 29, 2006 10:51 pm    Post subject: Reply with quote

Yeah, after each buffer swap. I was thinking of it in term of being done blitting in the backbuffer and then swapping :)
Back to top
View user's profile Send private message
Tinnus



Joined: 29 Jul 2006
Posts: 67

PostPosted: Wed Aug 30, 2006 12:09 am    Post subject: Reply with quote

Not AFTER each buffer swap.

It should be BEFORE each buffer swap.
_________________
Let's see what the PSP reserves... well, I'd say anything is better than Palm OS.
Back to top
View user's profile Send private message
Aion



Joined: 24 Jul 2006
Posts: 40
Location: Montreal

PostPosted: Wed Aug 30, 2006 12:57 am    Post subject: Reply with quote

*sigh*

Sorry for the semantic, between the end of the backbuffer blitting and the swapping.

I did code it right :P
Back to top
View user's profile Send private message
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Wed Aug 30, 2006 2:12 am    Post subject: Reply with quote

Jim wrote:
Quote:
sceDisplayWaitVblankStart after each blit

Surely you mean 'just before every call to sceGuSwapBuffers'? You definitely don't want to call that function after every blit!

Jim


Thats what i meant. I should of been more clear. Originally I placed it after every blit just to see that It impacted the performance greatly (makes sense). I then re-ordered to the following...

First is sceDisplayWaitVblankStart
Second is sceGuSwapBuffers
Third is call blit function.

This way I will always blit to the back buffer then on the next go around it will vwait and swap then right to the back buffer again.
Back to top
View user's profile Send private message Visit poster's website
Tinnus



Joined: 29 Jul 2006
Posts: 67

PostPosted: Wed Aug 30, 2006 7:06 am    Post subject: Reply with quote

I think that could potentially cause problems like a 1 frame dalay in the display. You should do:

- blit to the backbuffer
- WaitVBlankStart
- SwapBuffers
_________________
Let's see what the PSP reserves... well, I'd say anything is better than Palm OS.
Back to top
View user's profile Send private message
SamuraiX



Joined: 31 Jan 2006
Posts: 76
Location: USA

PostPosted: Fri Sep 01, 2006 5:32 am    Post subject: Reply with quote

I just wanted to thank all of you for your help. Everything is running great and fast!

Thank You... Jim!!!, Aion, chp and Tinnus

This thread can be closed now.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group