PS2 Linux Programming
Capturing The Screen To a File
In this tutorial a method for capturing the on screen graphics to a Truevision TGA image file is added to the SPS2 wrapper class. The image size is determined by the video mode being used and the image colour depth can be set to either 24 bit RGB or 32 bit RGBA. The core functionality of the method is taken from a post by Sparky on Playstation2-linux.com and thanks go to Sparky for this code (Playstation2-linux.com/projects/sps2demo).
Under normal circumstances image data is transferred in the host-to-local direction which is to GS memory. In order to download the frame buffer to main memory, the transmission direction for image data must be changed to local–to-host. This means that the transmission direction of both VIF1 and the VIF1 FIFO must be changed to local-to-host and changed back again at the end of the download. The process for accomplishing this is described on page 79 of the GS Users Manual and is embedded within the accompanying tutorial code.
The screen capture functionality is contained within the method ScreenShot() of the CSPS2Manager class. It should be noted that this method will only be called occasionally during the life of the application and is therefore not critical to the application’s speed – it is therefore not necessary to optimise the operational speed of this method.
The ScreenShot() method takes a single parameter, this being either IMAGE_RGBA or IMAGE_RGB for an RGBA or RGB output file respectively. At the start of ScreenShot() a TGA image file header is written to the output image file that is opened, the dimensions and colour depth being determined from the current video mode being used and the colour depth being requested.
Some temporary memory space is used by the screen shot method for building the DMA chain that is sent to VIF1 and for downloading the lines of frame buffer data into. These temporary storage areas are created using the getTempPage() method which is part of the VIFDynamicDMA memory management class.
Once the TGA header is written to the file, the frame buffer contents are downloaded into memory one horizontal line at a time. The image data is written to the file after swapping the red and the blue channels. Downloading the frame buffer is accomplished by the method DownloadVram() which will be investigated below.
DownloadVram() takes the following 8 parameters:
PDmaBase – is the base address of the memory used to build the DMAC chain.
PMemBase – is the base address of the memory used to accept the downloaded frame buffer data.
addr – is the base address of GS memory to be accessed. This is set to 0 to indicate that the first frame buffer at the start of GS memory is being downloaded.
bufw – is the frame buffer width in units of 64 pixels. The buffer width is 640 pixels so bufw is set to 10 (10*64 = 640)
x, y – is the start position of the frame buffer to be downloaded.
w, h – is the area of the frame buffer to be downloaded.
Notice that the frame buffer is accessed from the bottom up and stored in the TGA file in that order – this is the way that image data must be stored according to the TGA image file format.
The frame buffer is downloaded via path 2 which is from the GS via the GIF and VIF1 to main memory. In order to control and configure this process some VIF codes and GS registers must be set. These are described below.
Towards the start of the DownloadVram() method four VIF codes are built into a qward – NOP, MSKPATH3(0x8000), FLUSHA, and DIRECT(6). MSKPATH3(0x8000) disables transfer processing to the GIF via path 3 after any current transfer, FLUSHA waits for the state in which there is no transfer request from path3 after the end of any micro program in VU1 and also waits for the end of any transfer to the GIF from path 1 and path 2. DIRECT(6) transfers the following 6 qwords of data directly to the GIF. The purpose of the MSKPATH3 and FLUSHA VIF codes is to ensure that the VIF and transfer paths are idle before the download process is started.
Following the VIF codes a GIF packet is constructed to set four registers in A_D mode. The only one that is new is writing to the FINISH register – data must be written to the FINISH register (the value does not matter) in order to activate the FINISH event. The FINISH event is indicated by the FINISH field of the control status register, CSR becoming 1. In order to “catch” the FINISH event, it is necessary to disable interrupt generation with a “di” instruction and enable interrupt generation again (“ei” instruction) after the FINISH event has been detected. The FINISH event gets lost (and the FINISH Event wait loop never exist) if interrupts are not disabled.
Once the VIF packet is constructed, it is sent via DMA transfer to VIF1. The method then waits for the DMA process to complete and for the GS to complete loading the register data, this being indicated by the appropriate FINISH event. Finally, the method waits for the VIF1 FIFO to become idle. At this point it is possible to change the transmission direction of VIF1 to VIF1-to-memory and the VIF1 FIFO to local-to-host. The DMA transfer can then be set up to download the appropriate part of the frame buffer into memory. On completion of the download, the VIF1 and VIF1 FIFO transmission directions are restored to normal and path 3 transfers are re-enabled to complete the process.
In the example code, some arbitrary graphics are drawn on screen. The screen is captured by pressing L2 on the controller attached to port 1. Notice that the screen capture method will determine and use a file name that is free – the method will not overwrite any existing screen-shot files.
A method has been added to the SPS2 wrapper class to capture the screen to a Truevision TGA image file in either 24 bit RGB or 32 bit RGBA format.
Dr Henry S Fortuna
University of Abertay Dundee