Hello tableteers, I've done some initial experiments hacking my N800/OS2008 and ran into a couple of issues:
When using the supplied SDL library for doing timer-based frame rendering, there seems to be - heavy tearing - significant overhead due to X server (rendering pipe is : SDL -> X -> Framebuffer) [Note: yes, I'm aware that doing full screen blits is evil on the N800 due to limited framebuffer -> video RAM bus bandwidth.] Q: Is this expected behaviour? What could I do about the tearing? What about the Xomap overhead? == I've read a lot of bits on the web 'bout mplayer, vsync, omapfb etc. and tried to assemble a minimal example of using direct framebuffer access for gfx output. Q: I can't get the tearing away (only fixed at certain line positions). What am I doing wrong? Q: Also, frame rate is sluggish, though CPU load is much lower than SDL/X. Ok, my FB example is not threaded like the SDL timer example .. is that the reason for framerate even < 15/s? Q: btw - how can I shutdown Maemo Launcher/Hildon/Matchbox/Xomap? Whenever I do one of /etc/init.d/maemo-launcher stop /etc/init.d/x-server stop the device will automatically reboot. == I wondered if there would be any plans to make SDL run directly on framebuffer .. if not, I'd maybe give it a try. Q: Where can I find the sources to the OS2008 SDL? Thx and cheers, tgo ========================================= SDL Test ===> Makefile: ## ## produce ARM11 target optimized code ## use hardware FP, but use soft FP ABI for math lib ## OPT_FLAGS = -O3 -fomit-frame-pointer -mcpu=arm1136j-s -mfpu=vfp -mfloat-abi=softfp ## ## SDL compile/link flags ## SDL_FLAGS = `sdl-config --cflags` `sdl-config --libs` ## ## compiler command ## CC = gcc -Wall $(OPT_FLAGS) $(SDL_FLAGS) all: sdl_timer sdl_timer: sdl_timer.c $(CC) sdl_timer.c -o sdl_timer ===> Source: // // minimal timer based SDL fullscreen test for N800 // // the test seems to indicate 2 problems: // // 1) heavy tearing // 2) significant overhead due to X server (rendering pipe is : SDL -> X -> Framebuffer) // /* Mem: 90376K used, 36452K free, 0K shrd, 716K buff, 42956K cached Load average: 1.01 0.64 0.44 PID USER STATUS VSZ PPID %CPU %MEM COMMAND 756 root SW< 11368 338 21.8 8.9 Xomap 1831 root SW 12532 1365 7.3 9.8 sdl_timer 1815 root RW 1960 1799 3.0 1.5 top 78 root SW< 0 6 2.7 0.0 OMAP McSPI/0 1032 user SW< 32052 957 2.1 25.2 maemo-launcher 376 root SW< 0 6 1.6 0.0 cx3110x ... */ #include <stdlib.h> #include <string.h> #include <unistd.h> #include "SDL.h" #define HRES 800 #define VRES 480 #define BPP 16 // // frame render callback // Uint32 renderFrame (Uint32 interval, void *param) { static int col = 0; // get screen surface from parameter SDL_Surface *screen = (SDL_Surface*) param; // lock surface if needed if (SDL_MUSTLOCK(screen)) { if (SDL_LockSurface(screen) < 0) { fprintf (stderr, "unable to lock surface\n"); exit(1); } } // "render" whole frame in single color memset(screen->pixels, ++col, HRES * BPP / 8 * VRES); // unlock surface if needed if (SDL_MUSTLOCK(screen)) { SDL_UnlockSurface(screen); } // update whole screen SDL_UpdateRect(screen, 0, 0, HRES, VRES); // continue firing return interval; } int main (int argc, char** argv) { // initialize SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { fprintf (stderr, "unable to initialize SDL : %s\n", SDL_GetError()); exit(1); } // register SDL cleanup atexit (SDL_Quit); // set mouse pointer invisible SDL_ShowCursor (SDL_DISABLE); // set video mode to fullscreen SDL_Surface *screen = SDL_SetVideoMode(HRES, VRES, BPP, SDL_SWSURFACE | SDL_FULLSCREEN); if (screen == NULL) { fprintf (stderr, "unable to initialize video : %s\n", SDL_GetError()); exit(1); } // setup frame renderer at rate 17 frames/s (every 60ms) SDL_TimerID tid = SDL_AddTimer (60, (SDL_NewTimerCallback) renderFrame, screen); // run for 60 secs sleep (60); // shutdown frame renderer SDL_bool ret = SDL_RemoveTimer (tid); if (!ret) { fprintf (stderr, "could not shutdown timer : %s\n", SDL_GetError()); exit(1); } // finished return 0; } === ========================================= Framebuffer Test ===> Makefile: ## ## produce ARM11 target optimized code ## use hardware FP, but use soft FP ABI for math lib ## OPT_FLAGS = -O3 -fomit-frame-pointer -mcpu=arm1136j-s -mfpu=vfp -mfloat-abi=softfp ## ## compiler command ## CC = gcc -Wall $(OPT_FLAGS) -lX11 all: fb_minimal fb_minimal: fb_minimal.c $(CC) fb_minimal.c -o fb_minimal ===> Source: ////////////////////////////////////////////////////////////////////////// // // Test for direct framebuffer graphics bypassing X. (tested on N800) // ////////////////////////////////////////////////////////////////////////// /* Mem: 89132K used, 37696K free, 0K shrd, 716K buff, 42116K cached Load average: 0.80 0.25 0.18 PID USER STATUS VSZ PPID %CPU %MEM COMMAND 1686 root RW 3124 1685 6.1 2.4 fb_minimal 1032 user SW< 32052 957 2.2 25.2 maemo-launcher 1687 root RW 1960 1365 2.1 1.5 top 756 root SW< 10492 338 1.1 8.2 Xomap 78 root SW< 0 6 0.9 0.0 OMAP McSPI/0 376 root SW< 0 6 0.3 0.0 cx3110x 346 root SW 776 338 0.1 0.6 bme_RX-34 987 user SW< 27532 957 0.0 21.6 maemo-launcher ... Nokia-N800-50-2:/home/oberstet# time ./fb_minimal real 1m 48.01s user 0m 6.31s sys 0m 0.33s Nokia-N800-50-2:/home/oberstet# */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm-arm/arch-omap/omapfb.h> #include <X11/Xlib.h> #include <X11/Xutil.h> // /scratchbox/compilers/cs2005q3.2-glibc2.5-arm/usr/include/asm-arm/arch-omap/omapfb.h // /scratchbox/compilers/cs2005q3.2-glibc2.5-arm/arm-none-linux-gnueabi/sys-include/asm-arm/arch-omap/omapfb.h #define HRES 800 #define VRES 480 #define BPP 16 #define LOOPN 1000 #define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200 #define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400 int main (int argc, char** argv) { ////////////////////////////////////////////////////////////////////////// // // setup X stuff (we pull up a "pseudo X window" in fullscreen, so our // framebuffer graphics will not be overwritten by X server - otherwise // we had to shutdown X server). // ////////////////////////////////////////////////////////////////////////// // setup display, screen and window Display *display = XOpenDisplay (getenv ("DISPLAY")); if (display == NULL) { fprintf (stderr, "cannot open X display\n"); exit (1); } int screen_num = DefaultScreen (display); Window win = XCreateSimpleWindow(display, RootWindow (display, screen_num), 0, 0, 720, 420, 0, WhitePixel (display, screen_num), BlackPixel (display, screen_num)); XMapWindow (display, win); XSelectInput (display, win, ExposureMask); XFlush (display); XEvent xev; XWindowEvent (display, win, ExposureMask, &xev); // bring window to fullscreen xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.message_type = XInternAtom (display, "_NET_WM_STATE", False); xev.xclient.window = win; xev.xclient.format = 32; xev.xclient.data.l[0] = 1; xev.xclient.data.l[1] = XInternAtom (display, "_NET_WM_STATE_FULLSCREEN", False); xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; if (!XSendEvent (display, DefaultRootWindow (display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev)) { fprintf (stderr, "cannot bring X window to fullscreen\n"); exit (1); } XSync(display, False); ////////////////////////////////////////////////////////////////////////// // // setup framebuffer stuff // ////////////////////////////////////////////////////////////////////////// // open framebuffer device int fbfd = open("/dev/fb0", O_RDWR); if (!fbfd) { fprintf (stderr, "cannot open framebuffer device\n"); exit (1); } // screen size size_t ssize = HRES * BPP / 8 * VRES; // map framebuffer char* fbp = (char*) mmap (0, ssize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if ((int) fbp == -1) { fprintf (stderr, "failed to memory map framebuffer\n"); exit (1); } // setup fullscreen update info struct struct omapfb_update_window update; // copy full screen from fb to lcd video ram update.x = 0; update.y = 0; update.width = HRES; update.height = VRES; // request native pixel format, tearsync and vsync update.format = OMAPFB_COLOR_RGB565 | OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC; ////////////////////////////////////////////////////////////////////////// // // render loop // ////////////////////////////////////////////////////////////////////////// int n; for (n = 0; n < LOOPN; ++n) { // wait for fb->lcd video ram transfer complete ioctl (fbfd, OMAPFB_SYNC_GFX); // "render" whole frame in single color memset (fbp, n, ssize); // wait for vsync ioctl (fbfd, OMAPFB_VSYNC); // request transfer of fb-> lcd video ram for whole screen ioctl (fbfd, OMAPFB_UPDATE_WINDOW, &update); } ////////////////////////////////////////////////////////////////////////// // // cleanup // ////////////////////////////////////////////////////////////////////////// // cleanup framebuffer stuff munmap (fbp, ssize); close (fbfd); // cleanup X stuff if (display) { XCloseDisplay (display); display = NULL; } // finished return 0; } === _______________________________________________ maemo-developers mailing list maemo-developers@maemo.org https://lists.maemo.org/mailman/listinfo/maemo-developers