CFYC's Guide to PS2Linux Programming, Part #1
Lionel Lemarié - firstname.lastname@example.org
Last update: 2002-08-13
This is Part #1 of a series of guides to using Linux (for Playstation 2) to develop small/simple graphical applications. This series aims to make the users aware of the PS2 architecture and to provide a solid ground of understanding as to how to design an application to take advantage of this hardware.
This document is currently in the process of being written, it is online for testing purposes only and is not the full version.
You can find the latest version here: http://playstation2-linux.com/download/cfyc/guide_ps2_programming_01.html.
Please do check out the Tips & Tricks page, as I will populate it with a list of what you absolutly have to know, and try to clear up some misconceptions I have witnessed so far.
Should you have any comments, feedback, or insults, please do not hesitate to post them in the forums in the CFYC project or to contact me directly by e-mail.
Chapter #1 - Introduction to the Guide - the general idea
This Guide is aimed at people wanting to get the best out of the kit. A good application has to be designed properly in order to take advantage of the hardware. In the following chapters, we will cover:
- Setting up the devices (GS, VUs, SPR, pads)
- Loading a texture in VRAM
- Building a DMA packet to send a sprite via PATH3, using the texture.
- Using scratchpad for better memory access performance.
- Coding and uploading a VU1 micro-program.
- Building a DMA packet to send geometry via PATH1, using the texture.
- displaying text on the screen.
- Using VU0 to offload calculations from the main CPU.
- Using Interlock to speed things up (VU0/CPU).
- Using interrupts (if it turns out to be possible at all).
Each part of the Guide includes a step by step chapter, concretely demonstrating how to use what is explained.
I strongly recommend you make a local copy of the pdf hardware manuals from disc 1 and to keep them handy, as I will reference them as much as possible.
The general idea is that at all times, the different parts of the PS2 should be kept busy. This is not an easy task to design the application taking everything in consideration, so you have to study the general architecture of the console before even attempting to do anything.
The console has the following devices: (eeuser_e.pdf, p16)
- GS, which is the graphics chip. It draws 2D primitives (points, lines, triangles, strips and sprites). There are three PATHs to reach it:
- PATH1: Mainly intended for geometry. You send the 3d data of your model to VU1, which transforms it and sends it to the GIF via a dedicated bus. You want to use it as much as possible.|
- PATH2: Not interesting for now. Mainly used to grab the VRAM back to main memory.
- PATH3: Mainly intended for texture and pre-transformed geometry uploads (HUD, text, ...).
- VU0: Ideally used for vertex deformation (e.g. skinning), physics, possibly AI, particle systems...|
- VU1: Ideally used for transform and lighting and special effects (e.g. cartoon rendering).
|CPU||The CPU side in that case won't have too much to do, mainly setting up buffers to be sent.|
|VU0||VU0 will do the rotation matrix calculations, camera movements, that kind of things.|
|VU1||VU1 will do the transform and lighting. Don't even think about doing on the CPU, it's a waste of time.|
|ScratchPad||You can store your matrices, model data, temporary variables in there. ScratchPad is generally good for you, it doesn't have any cache issues and Linux doesn't mess with it...|
- you initialise the console,
- prebuild a GIF packet once and for all to draw the background sprite (we'll see later for optimisations here) in SPRmem,
- prebuild a DMA packet once and for all for your model in SPRmem,
- prebuild a GIF packet once and for all for the textures in main memory,
- prebuild a DMA packet once and for all for the tranformation matrices, the data will be updated on each frame,
- then in a loop,
First of all, it will obviously deal with the input from the player. Then visibility test (e.g. quadtree), stitch a bunch of prebuilt DMA packets together sorted by texture usage. A bit of IA as well, to make it sound cool.|
|VU0||All the (visible) cars DMA packets are sent to VU0 to update position, direction, speed, all that. Collision detection could be done here, but that means that you have to find out roughly potentially colliding cars on CPU, because chances are they will not all fit in memory at once.|
|VU1||VU1 will do procedural terrain generation while the CPU and VU0 are busy doing physics (that's a nice name for a textured grid, isn't it ?). Then it will generate triangle strips from the position and direction of each car and send a few particles, generate pedestrians, and other eye candies.|
|ScratchPad||You can use the SPR to efficiently exchange data between CPU and VU0 at high rate, without having to deal with cache issues.|
So again, basically,|
- initialise the lot,
- load all the textures in main memory, in DMA packets ready to send,
- prebuild DMA packet that will hold the data for the cars, making structures with pointers to the data inside the packet,
- prebuild some separate packets that VU1 will use to generate the road grid, they're separate from each other so you can do visibility tests on them,
- then in a loop,
Step by step, Part #1
Setting up the devices
Source taken from harness.c in the base code (not available yet).
Open the pad devices to be able to read the data with a read command later.
pad_fd = open( PS2_DEV_PAD0,O_RDWR ); pad_fd = open( PS2_DEV_PAD1,O_RDWR );
if (read(pad_fd[id],pad,32)!=8) pad->button = 0xFFFF;
vu0_fd = open( PS2_DEV_VPU0,O_RDWR ); vu1_fd = open( PS2_DEV_VPU1,O_RDWR );
vu0mem = mmap( 0, 8192, PROT_READ|PROT_WRITE, MAP_SHARED, vu0_fd, 0 ); vu1mem = mmap( 0, 32768, PROT_READ|PROT_WRITE, MAP_SHARED, vu1_fd, 0 );
spr_fd = open( PS2_DEV_SPR, O_RDWR );
sprmem = mmap( (void*)0x70000000, 16384, PROT_READ|PROT_WRITE, MAP_SHARED, spr_fd, 0 );
gs_fd = open( PS2_DEV_GS, O_RDWR );
err=ioctl( gs_fd, PS2IOC_GSCREENINFO, &old_screeninfo);
event_fd = open( PS2_DEV_EVENT, O_RDWR );