Code: Select all
// performance test with VSync IRQ, inspired by the VSync example on the cell add-on CD
//
// compile:
// gcc -I /usr/src/linux-2.6.16-cell-r1/include -lm vsync.c -o vsync
//
// tested on Gentoo, installed with this guide: http://wiki.ps2dev.org/ps3:linux:installing_gentoo
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdint.h>
#include <math.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/kd.h>
#include <sys/time.h>
#include <linux/fb.h>
#include <asm/ps3fb.h>
int width, height, memoryWidth, memoryHeight;
uint32_t* background;
void draw(uint32_t* fb)
{
	int x, y, yp;
	static int t = 0;
	int barHeight = 20;
	float amplitude = ((float) (height - barHeight)) / 2.0;
	float frequency = 40.0;
	// blit background
	for (x = 0; x < width; x++) {
		for (y = 0; y < height; y++) {
			fb[y * memoryWidth + x] = background[y * width + x];
		}
	}
	
	// draw a bar
	yp = sin(((float)t) / frequency) * amplitude + amplitude;
	for (y = yp; y < yp + barHeight; y++) {
		if (y < height && y >= 0) {
			for (x = 0; x < width; x++) {
				fb[y * memoryWidth + x] = 0xffffff;
			}
		}
	}
	t++;
	if (t == height) t = 0;
		
}
void enableCursor(int enable)
{
	int fd = open("/dev/console", O_NONBLOCK);
	if (fd >= 0) {
		ioctl(fd, KDSETMODE, enable ? KD_TEXT : KD_GRAPHICS);
		close(fd);
	}
}
int main(int argc, char *argv[])
{
	int fd;
	void *addr;
	int length;
	struct ps3fb_ioctl_res res;
	int x, y;
	uint32_t frame = 0;
	struct timeval tv;
	uint32_t time;
	int count;
	// switch to graphics mode (disable cursor)
	enableCursor(0);
	
	// access framebuffer
	fd = open("/dev/fb0", O_RDWR);
	ioctl(fd, PS3FB_IOCTL_SCREENINFO, (unsigned long)&res);
	printf("xres: %d, yres: %d, xoff: %d, yoff: %d, num_frames: %d\n",
		res.xres, res.yres, res.xoff, res.yoff, res.num_frames);
	length = res.xres * res.yres * 4 * res.num_frames;
	addr = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, 0);
	// stop flipping in kernel thread with vsync
	ioctl(fd, PS3FB_IOCTL_ON, 0);
	// create test background image
	memoryWidth = res.xres;
	memoryHeight = res.yres;
	width = res.xres - 2 * res.xoff;
	height = res.yres - 2 * res.yoff;
	background = malloc(width * height * 4);
	for (x = 0; x < width; x++) {
		for (y = 0; y < height; y++) {
			int c = (11 * x) & 255;
			background[y * width + x] = x*y << 3;
		}
	}
	// start timing	
	gettimeofday(&tv, NULL);
	time = tv.tv_sec * 1000000 + tv.tv_usec;
	// draw test
	count = 300;
	for (x = 0; x < count; x++) {
		// wait for vsync interrupt */
		uint32_t crt = 0;
		ioctl(fd, FBIO_WAITFORVSYNC, (unsigned long)&crt);
		
		// draw frame
		draw(addr + frame * memoryWidth * 4 * memoryHeight);
		// blit and flip with vsync request */
		ioctl(fd, PS3FB_IOCTL_FSEL, (unsigned long)&frame);
		
		// switch frame
		frame = 1 - frame;
	}
	// end timing	
	gettimeofday(&tv, NULL);
	time = tv.tv_sec * 1000000 + tv.tv_usec - time;
	printf("fps: %d\n", count * 1000000 / time);
	free(background);
	// start flipping in kernel thread with vsync
	ioctl(fd, PS3FB_IOCTL_OFF, 0);
	munmap(NULL, length);
	// close device
	close(fd);
	
	// back to text mode
	enableCursor(1);
	return 0;
}