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 

Some suggestions

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



Joined: 20 Aug 2005
Posts: 4
Location: Calgary Canada

PostPosted: Sun Aug 21, 2005 1:08 am    Post subject: Some suggestions Reply with quote

I don't know how much overhead there is in LUA itself (i.e., how much critical optimization in the C functions would actually help), but skimming through the code I can see a lot of places where there's a lot of cycles burnt.

1. Because you're using both VRAM and system RAM for graphics, you have to needlessly check everytime whether-or-not the operation is being performed against the screen (into VRAM) or against something else (in system RAM). Considering it has 2MB, isn't it being a little restrictive using it exclusively for the ~256KB frame buffer? It would be a lot faster to just use VRAM exclusively, and just have an error if the user tries to load more graphics than memory permits.

Either that, or go the AMOS/Darkbasic way and start making more libraries that use and manage VRAM themselves (like sprites with collision detection and scrolling tilemapped playfields).

2. Every single graphics command, including pixel() is bounds checking. While this is the safest practice against novice programmers, it adds a lot of overhead (e.g., compare filling the screen with fillScreenRect versus doing it a pixel-at-a-time within LUA). Perhaps a Blitz like FastWitePixel and FastReadPixel function could be made that does not do this and only draws to the screen (to also avoid the overhead of that test).

3. Unless perfectly optimized, MUL and DIV should be avoided at the top loop in drawing functions. For example, in fillScreenRect, instead of doing a PSP_LINE_SIZE * whatever each pixel, you calculate the pixels skipped per line (which is the image width minus the rect width).

Code:

void fillScreenRect(u16 color, int x0, int y0, int width, int height)
{
   sceKernelDcacheWritebackInvalidateAll();
   if (!initialized) return;
   u16* vram = getVramDrawBuffer();
   int x, y;
   int xSkip, screenPos;
   xSkip = PSP_LINE_SIZE - width;
   screenPos = (PSP_LINE_SIZE * y0) + x0;

   for (y = 0; y < height; y++) {
      for (x = 0; x < width; x++) {
         vram[screenPos++] = color;
      }
      screenPos += xSkip;
   }
   sceKernelDcacheWritebackInvalidateAll();
}


Also <<1 is much faster than *2. Should test this, but it may be faster to do this for Y:

Code:

((y << 9) - (y << 5))


Regarding the drawLine, the fastest Bresenham code is this. (Note: neither of these are actually tested on the PSP, but shuold work):

Code:

    public void lineFast(int x0, int y0, int x1, int y1, Color color)
    {
        int pix = color.getRGB();
        int dy = y1 - y0;
        int dx = x1 - x0;
        int stepx, stepy;

        if (dy < 0) { dy = -dy;  stepy = -raster.width; } else { stepy = raster.width; }
        if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }
        dy <<= 1;
        dx <<= 1;

        y0 *= raster.width;
        y1 *= raster.width;
        raster.pixel[x0+y0] = pix;
        if (dx > dy) {
            int fraction = dy - (dx >> 1);
            while (x0 != x1) {
                if (fraction >= 0) {
                    y0 += stepy;
                    fraction -= dx;
                }
                x0 += stepx;
                fraction += dy;
                raster.pixel[x0+y0] = pix;
            }
        } else {
            int fraction = dx - (dy >> 1);
            while (y0 != y1) {
                if (fraction >= 0) {
                    x0 += stepx;
                    fraction -= dy;
                }
                y0 += stepy;
                fraction += dx;
                raster.pixel[x0+y0] = pix;
            }
        }
    }


4. How about a poke and peek like function (even if its just to the screen). If I wanted, to say, fill the screen with random dots, it'd be faster to do 'for i=vramDrawBuffer,vramDrawBuffer+130559 do; poke(i, random(0,65535)); end' This, of course, is still dependant upon how fast random() is...

5. Does Luaplayer support lua binary modules? It may be an interesting way to go, then different modules could be created for different needs. I just don't know if the PSP's DRM with stop this possibility... but for example.

ok, str = loadmodule("luadebuggfx") loads standard Lua graphics routines

ok, str = loadmodule("luafastgfx") loads graphics routines that are VRAM only and have all bounds (x<0) checking removed for speed.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
chaos



Joined: 10 Apr 2005
Posts: 135

PostPosted: Sun Aug 21, 2005 11:53 am    Post subject: Reply with quote

some great suggestions, makes me want to compile my own version of luaplayer. :)
_________________
Chaosmachine Studios: High Quality Homebrew.
Back to top
View user's profile Send private message
Shine



Joined: 03 Dec 2004
Posts: 728
Location: Germany

PostPosted: Mon Aug 22, 2005 11:09 am    Post subject: Reply with quote

1. Yes, using VRAM is a good idea, feel free to enhance the graphics functions to cache images in VRAM :-)

2. The check for valid x and y position are very fast compared to the conversion from double to int when calling the function from Lua (every number in Lua is double), so this is not very much faster.

3. I've optimized it, but it looks like it is only faster when accessing main memory, but when accessing VRAM it is not faster, perhaps because VRAM is not cached, so the CPU waits mainly for memory access and the calculation doesn't hurt. But accessing the main memory is now twice as fast.

Your draw line function is not very much faster, about 15 %, but I've included it.

4. poke and peek would compromise the security, so I don't add it. And it would be not faster, because the double numbers has to be converted the same way as in pixel(x, y, color).

5. loadmodules could compromise the security, too.
Back to top
View user's profile Send private message
nonarKitten



Joined: 20 Aug 2005
Posts: 4
Location: Calgary Canada

PostPosted: Tue Aug 23, 2005 10:44 am    Post subject: Reply with quote

I'd love to try compiling my own version for experiment, but haven't quite figured out how to do so on my Mac just yet.

Edit: I've read somewhere that double-precision really hurts on the MIPS3 architecture. It might be beneficial to go to single, if possible.

While integers might be better for somethings, fp mul and div are faster than integer mul and div. Where they're used may affect speed (for example it may be better to multiply the Y with PSP_LINE_SIZE as a float before converting to an integer.) e.g., (my C memory is rather rusty, so I can't say if this is correct or not).

Code:

(in lua.h)
/* type of numbers in Lua */
#ifndef LUA_NUMBER
typedef single lua_Number;
#else
typedef LUA_NUMBER lua_Number;
#endif

(elsewhere...)

#define PSP_LINE_SIZE_FP 512.0
#define SCREEN_AREA 130560

static *u16 VramDrawBuffer;

void flipScreen() {
   if (!initialized) return;
   sceGuSwapBuffers();
   sceDisplaySetFrameBuf(VramDrawBuffer, PSP_LINE_SIZE, 1, 1);
   dispBufferNumber ^= 1;
   VramDrawBuffer = getVramDrawBuffer();
}

void initGraphics() {
   ...
   VramDrawBuffer = getVramDrawBuffer();
   ...
}

typedef struct
{
   int textureWidth;
   lua_Number textureWidth_fp; // same as above, in floatingpoint
   int imageWidth;  // the image width
   int imageHeight;
   int imageArea; // width * height precomputed
   u16* data;
} Image;

static int Image_pixel (lua_State *L) {
   int argc = lua_gettop(L);
   if(argc != 3 && argc != 4) return luaL_error(L, "Image:pixel(x, y, [color]) takes two or three arguments, and must be called with a colon.");
   SETDEST
   lua_Number ypos = luaL_checknumber(L, 2)
   ypos *= (dest)?dest->textureWidth_fp:PSP_LINE_SIZE_FP;

   int x = luaL_checkint(L, 1);
   int xpos = x + (int)ypos;
   if(x<0 || xpos<0) return 0;

   int color = (argc == 4)?*toColor(L, 3):0;

   if(dest) {
      if (x<dest->imageWidth && xpos<dest->imageArea)) {
         if(argc==3) {
            *pushColor(L) = dest->data[xpos];
            return 1;
         } else {
            dest->data[xpos]=color;
            return 0;
         }
      }

   } else {
      if (x<SCREEN_WIDTH && xpos<SCREEN_AREA) {
         if(argc==3) {
            *pushColor(L) = VramDrawBuffer[xpos];
            return 1;
         } else {
            VramDrawBuffer[xpos] = color;
            return 0;
         }
      }
   }
}


P.S. I'm rather obesessed with speeding up the pixel functions to make starfields smooth. Anyway, that's enough for now, back to trying to get the tool chain working...
_________________
"Knowledge without wisdom is like a bunch of books strapped on the back of an ass."
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
nevyn



Joined: 31 Jul 2005
Posts: 136
Location: Sweden

PostPosted: Wed Aug 24, 2005 8:53 am    Post subject: Reply with quote

nonarKitten wrote:
I'd love to try compiling my own version for experiment, but haven't quite figured out how to do so on my Mac just yet.

Just open up the Terminal and type the following:
curl -O http://www.oopo.net/consoledev/files/psptoolchain-20050801.tgz
tar -xzvf psptoolchain-20050801.tgz
cd psptoolchain
sudo ./toolchain.sh
cd `mkdir -pv ~/Projects/PSP`
svn checkout svn://svn.pspdev.org/pspware/trunk/LuaPlayer

should work. You'll need the Developer Tools installed, of course... And svn. And wget from http://macosx.forked.net/download.php?j=http://macosx.forked.net/p/wget-1.8.1.pkg.tgz . (don't mess with fink or darwinports, unless you /like/ torture.) IM me if that still doesn't work :)
Back to top
View user's profile Send private message Send e-mail Visit poster's website
nonarKitten



Joined: 20 Aug 2005
Posts: 4
Location: Calgary Canada

PostPosted: Wed Aug 24, 2005 10:25 am    Post subject: Reply with quote

Ye haw! Got it working - now I can profile all my wacky ideas before bothering anyone. Thanks! Svn is the key - get's everything I need all at once instead of compile-what-am-I-missing-go-get-and-recompile...
_________________
"Knowledge without wisdom is like a bunch of books strapped on the back of an ass."
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Shine



Joined: 03 Dec 2004
Posts: 728
Location: Germany

PostPosted: Fri Aug 26, 2005 11:58 am    Post subject: Reply with quote

nonarKitten wrote:
I've read somewhere that double-precision really hurts on the MIPS3 architecture. It might be beneficial to go to single, if possible.


Yes, you are right, I've changed it and calculating 10000 sin values and adding it is now 4.3 times faster than before.

nonarKitten wrote:

While integers might be better for somethings, fp mul and div are faster than integer mul and div. Where they're used may affect speed (for example it may be better to multiply the Y with PSP_LINE_SIZE as a float before converting to an integer.) e.g., (my C memory is rather rusty, so I can't say if this is correct or not).


I don't think that a floating point mul is faster than an integer mul, but if you measure it, I'll change it.

nonarKitten wrote:

P.S. I'm rather obesessed with speeding up the pixel functions to make starfields smooth.


I don't know why, but looks like the speed of the conversion from float to int for the pixel function is much faster, or perhaps the new PSPSDK and compiler changes are faster, but with version 0.9 I can display only less than 30 stars in one vsync, but with the new version more than 200 stars are no problem. I've ported my PS2 starfield code (which was originally written by Sjeep) for testing:

Code:

size = 200
zMax = 5
speed = 0.1

width = 480
height = 272

starfield = {}
math.randomseed(os.time())

function createStar(i)
   starfield[i] = {}
   starfield[i].x = math.random(2*width) - width
   starfield[i].y = math.random(2*height) - height
   starfield[i].z = zMax
end

for i = 1, size do
   createStar(i)
   starfield[i].z = math.random(zMax)
end

white = Color.new(255, 255, 255)
black = Color.new(0, 0, 0)

while true do
   screen:clear(black)
   for i = 1, size do
      starfield[i].z = starfield[i].z - speed
      if starfield[i].z < speed then createStar(i) end
      x = width / 2 + starfield[i].x / starfield[i].z
      y = height / 2 + starfield[i].y / starfield[i].z
      if x < 0 or y < 0 or x >= width or y >= height then
         createStar(i)
      else
         screen:pixel(x, y, white)
      end
   end
   screen:print(272, 264, "Starfield for PSP by Shine", white)
   screen.waitVblankStart()
   screen.flip()
   if Controls.read():start() then break end
end
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Lua Player 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