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

Reply via email to