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
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