Path: chuka.playstation.co.uk!news From: "Derek da Silva" Newsgroups: scee.yaroze.freetalk.english Subject: Re: Performance Date: Wed, 25 Jun 2003 11:32:47 +0100 Organization: PlayStation Net Yaroze (SCEE) Lines: 492 Message-ID: References: NNTP-Posting-Host: pc-62-30-77-144-az.blueyonder.co.uk X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2800.1158 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 It's always nice to see a new gravgirl build. I've loved this sort of game ever since playing mars lander on my acorn electron. Looking good. Hope you find those extra hsyncs.. Derek "Andrew Partington" wrote in message news:bcpukl$9hi2@www.netyaroze-europe.com... > Hi all, > > Can anyone tell me just what kind of performance is theoretically > possible from the Yaroze libs with regard to 2D sprites? Surely 440+ > scaled/rotated sprites, plus 768 transparent GsBOXF's per frame (most of > which there is a ScaleMatrix() operation for) isn't enough to choke the > GPU? Yet that is what seems to be happening for me. > > Those figures are probably the maximum for any given scene, in practice > I see pretty bad performance hits at around half to three-quarters of > that - not exactly demo reel material! All this seems due to the amount > of scaled sprites making up the background, when you zoom in to their > natural size (64*64) performance is acceptable - and when you commment > out the call to GsSortSprite inside the inner loop of the map routine, > performance is ace (well, duh! ;) ) > > So, am I running up against the texture cache problem again? If so, > what is the best way to organise textures in VRAM to avoid this problem > for a given texture depth? (Latest BG textures are 4-bit versions). > > Or do I need a DrawSync() somewhere along the line to let the GPU sort > itself out, or something similar? Somebody else here said they had a > problem when they were sorting >5 of the same type of sprite in a row > (when not using the fixed version of the sprite routine). > > Attached is my BG code, feel free to use/abuse it, but if anyone can > tell me any way at all of optimising it, (or even if you find it useful > (ha!!)) please let me know! > > Or is a port to PS2/Linux on the cards? :) At least most of it is > nicely modular now so I can use it as a framework for any other 2D game > I attempt... > > Latest build in my ftp area: > > http://www.netyaroze-europe.com/~partinga/ftp > > Cheers, > > AndyP > > > ---------------------------------------------------------------------------- ---- > /** > * > * ZoomRotating map, and GsMAP/GsBG initialisation stuff > * (c) 2000 Andrew Partington. All rights reserved. > * > */ > > #include > #include > #include > #include "map.h" > #include "globals.h" > #include "GsTools.h" > #include "collision.h" > > > /*=====================================================================* > * Initialise GsCELL background tile descriptors > *--------------------------------------------------- > * Args: GsIMAGE* img - pointer to image data containing background gfx > * GsCELL* cells - pointer to the array of GsCELL structs (of the right size) > * int sizex - number of blocks going across > * int sizey - number of blocks going down > * int offsetX - number of pixels to offset in texture page (x) > * int offsetY > *--------------------------------------------------- > * Info: The GsCELL struct contains an x and y position into a texture, > * and the pointers in the GsIMAGE struct of the gfx stuff. This info > * must be set up for EACH TILE. > * 3/9/2000: Added support for multiple graphics within a single > * texture page. > *======================================================================*/ > > void initCells(GsCELL* cells,GsIMAGE* img,int sizex,int sizey, int offsetX, int offsetY) > { > int x,y,ptr; > GsCELL wcell; > int xOffset = offsetX / 16; //GsBG stuff is fixed size on Yaroze :-( > int yOffset = offsetY / 16; > > ptr=0; > > for(y=yOffset;y { > for(x=xOffset;x { > wcell=cells[ptr]; > wcell.u=(x<<4); //Assume 16-pixel spacing > wcell.v=(y<<4); //i.e. multiply every block by 16 > wcell.cba=GetClut(img->cx,img->cy); > wcell.flag=0; > wcell.tpage=GetTPage(img->pmode,0,img->px,img->py); > cells[ptr]=wcell; > ptr++; > } > } > } > > > /* > * Initialise GsMAP struct > *-------------------------- > * Args: GsMAP* mapInfo - ptr to GsMAP struct > * GsCELL* cells - ptr to bg tile info > * u_short* mapdata - ptr to map data > * sizex - no. of blocks in map (horizontally) > * sizey - no, of blocks in map (vertically) > *---------------------------- > */ > void initMap(GsMAP* mapinfo,GsCELL* cells,u_short* mapdata,int sizex,int sizey) > { > mapinfo->cellw=16; //Doesn't matter, they're gonna be > mapinfo->cellh=16; // 16 anyway... :( > mapinfo->ncellw=sizex; //width of map (cells) > mapinfo->ncellh=sizey; //height of map (cells) > mapinfo->base=cells; //pointer to cell array > mapinfo->index=mapdata; //pointer to map data > } > > > /** > * > * Initialise GsBG background - link the image and map data in with the > * background data > * > * > * in: GsBG* bg: Main background structure - holds image and map data pointers etc > * GsMAP* map: Pointer to the map data > * GsIMAGE* img: Pointer to the tile image data > * int sizex: Number of tiles to display horizontally > * int sizey: Number of tiles to display vertically > */ > void initBgrnd(GsBG* bg,GsMAP* mapinfo,GsIMAGE* img,int sizex,int sizey) > { > bg->map=mapinfo; > bg->attribute=(img->pmode<<24); //shift pmode left 24 bits to set attribute > bg->x=0; > bg->y=0; > bg->w = sizex << 4; //display size is in pixels... > bg->h = sizey << 4; > bg->scrollx=0; > bg->scrolly=0; > bg->r=128; > bg->g=128; > bg->b=128; > bg->mx=0; > bg->my=0; > bg->scalex=ONE; > bg->scaley=ONE; > bg->rotate=0; > } > > > > > > /** > * Allocate space in memory for an array of sprites, > * then populate the array. > * > * For each piece of map data, create a sprite for it, > * then set the appropriate texture page coordinates > * for the sprite. > * > * Offset X and Y are used to grab graphics data from > * parts of the texture page if they are used for other > * stuff too. > */ > void allocateBackgroundObject(MapGraphicsData* background, > GsIMAGE* imageData, > int blocksX, > int blocksY, > int blockSizeX, > int blockSizeY, > int offsetX, > int offsetY) > { > int i=0; > int x=0; > int y=0; > int xOffset = offsetX / blockSizeX; > int yOffset = offsetY / blockSizeY; > > > GsSPRITE sprite; > background->numberOfBlocksX = blocksX; > background->numberOfBlocksY = blocksY; > background->blockSizeX = blockSizeX; > background->blockSizeY = blockSizeY; > > background->spriteData = (GsSPRITE*) malloc((blocksX * blocksY) * sizeof(GsSPRITE)); > > for(y = yOffset; y < blocksY + yOffset; y++) > { > for(x = xOffset; x < blocksX + xOffset; x++) > { > sprite = InitSprite(imageData, x * blockSizeX, y * blockSizeY, blockSizeX, blockSizeY); > sprite.u = x * blockSizeX; //Adjust texturemap coordinates to point > sprite.v = y * blockSizeY; // to the correct area for the block > > > //recalculate texture page if out of range of > // the u/v texture page coordinates > // so we can support sprite banks that go > // outside a single texture page > if(x * blockSizeX >= 255) //can increment more than one texture page, > { // and there are 4 sprites/tpage... > sprite.tpage++; //Just increment texture page by 1 > sprite.u &= 255; // if the next page is to the right > } > > if(y * blockSizeY >= 255) > { > sprite.tpage += 16; // effectively, y * xSize + x, but can just > sprite.v &= 255; // increment by 16 to get next Y texture page > } > > > > // if(imageData->pmode & 3 == 0) > // { > sprite.attribute = 0x00000020; > // } > > // else > // { > // sprite.attribute += (SPRITE_ON+TRANS_OFF+TRANS_NORMAL+MODE_7_ON); > // } > > background->spriteData[i++] = sprite; > } > } > } > > > > /** > * > * Free resources dynamically allocated to this background > * (i.e. the array of sprites which make up the map) > */ > void freeMapGraphicsData(MapGraphicsData* mapGraphicsData) > { > free(mapGraphicsData->spriteData); > } > > > > > /** > * > * Draw sprite-based backgound object. > * > * Info: To set up zoomrotation around the centre > * of the background, each sprite that makes up the > * background must have its mx and my values set relative > * to the origin of the map. > * > * +mx | -mx mx and my get progressively closer to, > * +my | +my and further away from the origin with each > * | sprite drawn, depending on the sign of the mx and my value. > * -----O----- The coordinates of O can be set by setting the > * +mx | -mx usual X and Y coordinates of each sprite to > * -my | -my the desired position. Fortunately, mx and my > * | values can be used for X/Y positioning as well! > * > * > * *** OPTIMISATION MEASURES *** > * > * - Most values have been changed to long, in order to fit the register size > * - Got rid of array indexing in favour of pointer arithmetic (reputed to be slightly faster) > * - Doing majority of dereferencing before the inner/outer loops (again, reputed to result in a speed increase) > * > */ > void drawBackgroundObjectUsingCollisionArray(BackgroundObject* background, CollisionObject* collisionArray, int* cameraStatus, GsOT* WorldOT, int priority) > { > //If the size of the map is greater than or equal to the screen, truncate to size of screen. > //If the size of the map is greater than or equal to the display size, truncate to display size > //If the display size is greater than the size of the map, repeat the data > > > register long x = 0; > register long y = 0; > register long index; > register long indextemp; > > long originXCopy; > long originYCopy; > > register long offsetX = 0; > register long offsetY = 0; > long offsetXCopy; //Copy of the above calcs to avoid doing any > long offsetYCopy; // divides later on... > > long pixelXScroll; //How many pixels to scroll each block in the map before > long pixelYScroll; // looking up a new one on the X or Y axis > > > register GsSPRITE* spriteRef = (GsSPRITE*) background->mapGraphics->spriteData; > u_short* mapDataRef = (u_short*) background->mapData; > long BGScaleX = background->scaleX; > long BGScaleY = background->scaleY; > long BGRotate = background->rotate; > long BGPosX = background->xPos; > long BGPosY = background->yPos; > long BGOriginX = background->originX; > long BGOriginY = background->originY; > long BGSizeX = background->backgroundSizeX; > long BGSizeY = background->backgroundSizeY; > long BGBlockSizeX = background->mapGraphics->blockSizeX; > long BGBlockSizeY = background->mapGraphics->blockSizeY; > > long BGDisplaySizeX = background->displaySizeX; > long BGDisplaySizeY = background->displaySizeY; > > long oldIndex = NULL_BLOCK; > int BGCollisionArrayIndex = 0; > > > register GsSPRITE* workSpriteRef; > > //offsetX and offsetY are indices to a piece of map data, created by taking the > // X and Y coordinates and dividing them by the blocksize, to get the nearest block. > > offsetX = background->scrollX >> 6; // / BGBlockSizeX; > offsetY = background->scrollY >> 6; // / BGBlockSizeY; > > if(offsetX < 0) > { > offsetX = BGSizeX + offsetX; > } > > if(offsetY < 0) > { > offsetY = BGSizeY + offsetY; > } > > offsetX = offsetX & BGSizeX - 1; // offsetX %= BGSizeX; > offsetY = offsetY & BGSizeY - 1; // offsetY %= BGSizeY; > > offsetXCopy = offsetX; //Copy of the above calcs to avoid doing any > offsetYCopy = offsetY; // divides later on... > > > //By doing a MOD (%) with the scroll value and the block size, we get the > // remainder part of the above calculation, i.e. how many pixels to scroll > // the block. > pixelXScroll = background->scrollX & BGBlockSizeX - 1; > pixelYScroll = background->scrollY & BGBlockSizeY - 1; > > > originXCopy = BGOriginX; //Take a copy of the origin coords so we > originYCopy = BGOriginY; // can just replace the copies without recalculating them > > > > > for(y=0;y { > //optimisation measure - move multiplication out of inner loop > indextemp = offsetY * BGSizeX; > > for(x=0;x { > //Get the index to the sprite indicated by the 2D map data array > index = *(mapDataRef+(indextemp + offsetX)); > > if(index != NULL_BLOCK) > { > //Attempt to minimise memory access to the blocks > // by only getting a new block if the index points > // to a differnt block - should save time when rendering > // multiple blocks of the same type > if(index != oldIndex) > { > oldIndex = index; > > workSpriteRef = (spriteRef + (index & MAP_BLOCK_DATA_MASK)); //background->mapGraphics->spriteData[index]; > workSpriteRef->x = BGOriginX + BGPosX; //put all sprites at the same coordinates, > workSpriteRef->y = BGOriginY + BGPosY; // but use mx and my to offset them > workSpriteRef->scalex = BGScaleX; // from this origin. > workSpriteRef->scaley = BGScaleY; > workSpriteRef->rotate = BGRotate; > } > > workSpriteRef->mx = originXCopy + pixelXScroll; //mx and my are positions relative to the > workSpriteRef->my = originYCopy + pixelYScroll; // origin specified at xPos and yPos > workSpriteRef->attribute = 0x00000020; > > if(collisionArray != NULL > && workSpriteRef->mx >= COLLISION_MIN_BOUNDS_X > && workSpriteRef->mx <= COLLISION_MAX_BOUNDS_X > && workSpriteRef->my >= COLLISION_MIN_BOUNDS_Y > && workSpriteRef->my <= COLLISION_MAX_BOUNDS_Y) > { > // workSpriteRef->attribute = 0x00000000; > > //Store x,y and index values in the next free element in each array > // mx and my are coords relative to centre of sprite > if(BGCollisionArrayIndex < MAX_COLLISION_ARRAY_ELEMENTS) > { > (collisionArray + BGCollisionArrayIndex)->x = workSpriteRef->x; > (collisionArray + BGCollisionArrayIndex)->y = workSpriteRef->y; > (collisionArray + BGCollisionArrayIndex)->xPos = workSpriteRef->mx; > (collisionArray + BGCollisionArrayIndex)->yPos = workSpriteRef->my; > (collisionArray + BGCollisionArrayIndex)->type = index; > BGCollisionArrayIndex++; > } > > // scannerState = SCANNER_DANGER; > } > > > GsSortSprite(workSpriteRef, WorldOT, background->priority); > } > > > originXCopy -= BGBlockSizeX; > > if(offsetX++ < 0) > { > offsetX += BGSizeX; > } > > offsetX = offsetX & (BGSizeX - 1); // offsetX %= BGSizeX; > } > > if(offsetY++ < 0) > { > offsetY += BGSizeY; > } > > offsetY = offsetY & (BGSizeY -1); //offsetY %= BGSizeY; > > offsetX = offsetXCopy; > > originXCopy = BGOriginX; > > originYCopy -= BGBlockSizeY; > } > > } > > > >