Writing to the framebuffer device
Note: I don't know what I'm doing here and figured this out through trial and error - if anyone can add any clarifications or corrections that would be useful
As far as I can tell the framebuffer device in GP2X Linux seems to be set to 16 bit colour mode. This seems to be the fastest mode to use in gph's SDL suggesting they don't change the hardware mode but convert to this depth in software.
If you want to bypass SDL and write to the framebuffer device directly, this code will do it:
#include <sys/mman.h> int fbdev; Uint16 *fb; fbdev=open("/dev/fb0", O_RDWR); fb=(Uint16 *)mmap(0, 320*240*sizeof(uint16), PROT_WRITE, MAP_SHARED, fbdev, 0); fprintf(stderr, "fb opened at %x, fd %d\n", fb, fbdev);
You can now write to the screen at the memory area pointed to by fb. Writing to the screen this way seems faster than gph's SDL.
The rgb encoding is 565 rrrrrggggggbbbbb.
Contents |
Waiting for vsync
static unsigned long devMem = open("/dev/mem", O_RDWR); static volatile unsigned long *gp2x_memregl=(unsigned long *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, devMem, 0xc0000000); static volatile unsigned short *gp2x_memregs=(unsigned short *)gp2x_memregl; void gp2x_video_waitvsync(void) { while(gp2x_memregs[0x1182>>1]&(1<<4)); while(!(gp2x_memregs[0x1182>>1]&(1<<4))); }
This code was obtained from Rlyeh's minilib and fixed for use with firmware 2.0
Flipping framebuffers
Here's how to obtain true double buffering by changing which framebuffer is displayed on screen
static volatile uint16_t *memregs16; static volatile uint32_t *memregs32; int32_t devmem; int32_t devfb0; int32_t devfb1; void fb_flip(uint32_t fb_addr) { memregs16[0x290E>>1] = (uint16_t)(fb_addr & 0xffff); memregs16[0x2910>>1] = (uint16_t)(fb_addr >> 16); memregs16[0x2912>>1] = (uint16_t)(fb_addr & 0xffff); memregs16[0x2914>>1] = (uint16_t)(fb_addr >> 16); } int main() { devmem = open("/dev/mem", O_RDWR); devfb0 = open("/dev/fb0", O_RDWR); devfb1 = open("/dev/fb1", O_RDWR); fb0 = (uint16_t *) mmap(0, 320*240*sizeof(uint16_t), PROT_WRITE, MAP_SHARED, devfb0, 0); fb1 = (uint16_t *) mmap(0, 320*240*sizeof(uint16_t), PROT_WRITE, MAP_SHARED, devfb1, 0); fb_flip((uint32_t) 0x03101000); // flips to fb0 fb_flip((uint32_t) 0x03381000); // flips to fb1 }
Questions
- Does the linux framebuffer map directly to the hardware canvas or does the data get blitted over by the fb driver?
- The ioctl function and the definitions in include/linux/fb.h allow access to framebuffer parameters. Can the hardware mode be changed this way?
- How to wait for vblank and such.