From 5cc6dcb71c2f2f24e54bf1ab9f09d8e560e8e4d9 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 9 Feb 2013 22:55:07 +0200 Subject: [PATCH] use offscreen blitting when SDL_DOUBLEBUF is not set otherwise many games suffer flicker. Provide an option to support old behavior. --- README.OMAP | 12 +++++ src/video/omapdss/config.c | 7 +++ src/video/omapdss/linux/fbdev.c | 11 +++++ src/video/omapdss/linux/fbdev.h | 1 + src/video/omapdss/osdl.h | 3 ++ src/video/omapdss/osdl_video.c | 8 +++ src/video/omapdss/sdlif.c | 87 ++++++++++++++++++++++++++++----- 7 files changed, 118 insertions(+), 11 deletions(-) diff --git a/README.OMAP b/README.OMAP index 1c04162..96af240 100644 --- a/README.OMAP +++ b/README.OMAP @@ -75,6 +75,15 @@ SDL_OMAP_FORCE_DOUBLEBUF: Note that if app isn't updating whole buffer each frame, it will glitch. This is the same as specifying SDL_DOUBLEBUF to SDL_SetVideoMode. +SDL_OMAP_FORCE_DIRECTBUF: + When double buffering is not used, this option forces all blits to go + directly to the framebuffer (SDL_UpdateRect[s]() has no effect), which will + give speed but may cause flickering. Otherwise all blits will go to offscreen + buffer and SDL_UpdateRect[s]() is needed to update the screen (this is how + standard SDL works too). + When double buffering is used, this option has no effect (all blits always + go to back buffer that's displayed after flip). + SDL_OMAP_NO_TS_TRANSLATE: Disable automatic touchscreen screen -> layer coordinate translation, return real screen coordinates. @@ -97,6 +106,9 @@ force_vsync = 1/0 # same as SDL_OMAP_FORCE_DOUBLEBUF force_doublebuf = 1/0 +# same as SDL_OMAP_FORCE_DIRECTBUF +force_directbuf = 1/0 + # same as SDL_OMAP_NO_TS_TRANSLATE no_ts_translate = 1/0 diff --git a/src/video/omapdss/config.c b/src/video/omapdss/config.c index 0b7146a..10a9036 100644 --- a/src/video/omapdss/config.c +++ b/src/video/omapdss/config.c @@ -91,6 +91,10 @@ void omapsdl_config(struct SDL_PrivateVideoData *pdata) pdata->cfg_force_doublebuf = !!strtol(p, NULL, 0); continue; } + else if (check_token_eq(&p, "force_directbuf")) { + pdata->cfg_force_directbuf = !!strtol(p, NULL, 0); + continue; + } else if (check_token_eq(&p, "no_ts_translate")) { pdata->cfg_no_ts_translate = !!strtol(p, NULL, 0); continue; @@ -116,6 +120,9 @@ void omapsdl_config_from_env(struct SDL_PrivateVideoData *pdata) tmp = getenv("SDL_OMAP_FORCE_DOUBLEBUF"); if (tmp != NULL) pdata->cfg_force_doublebuf = !!strtol(tmp, NULL, 0); + tmp = getenv("SDL_OMAP_FORCE_DIRECTBUF"); + if (tmp != NULL) + pdata->cfg_force_directbuf = !!strtol(tmp, NULL, 0); tmp = getenv("SDL_OMAP_NO_TS_TRANSLATE"); if (tmp != NULL) pdata->cfg_no_ts_translate = !!strtol(tmp, NULL, 0); diff --git a/src/video/omapdss/linux/fbdev.c b/src/video/omapdss/linux/fbdev.c index ec3d5c7..7e8a962 100644 --- a/src/video/omapdss/linux/fbdev.c +++ b/src/video/omapdss/linux/fbdev.c @@ -175,6 +175,17 @@ int vout_fbdev_get_fd(struct vout_fbdev *fbdev) return fbdev->fd; } +void *vout_fbdev_get_active_mem(struct vout_fbdev *fbdev) +{ + int i; + + i = fbdev->buffer_write - 1; + if (i < 0) + i = fbdev->buffer_count - 1; + + return (char *)fbdev->mem + fbdev->fb_size * i; +} + struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int bpp, int buffer_cnt) { struct vout_fbdev *fbdev; diff --git a/src/video/omapdss/linux/fbdev.h b/src/video/omapdss/linux/fbdev.h index 88cd519..ac2ae15 100644 --- a/src/video/omapdss/linux/fbdev.h +++ b/src/video/omapdss/linux/fbdev.h @@ -9,6 +9,7 @@ void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp, void vout_fbdev_clear(struct vout_fbdev *fbdev); void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count); int vout_fbdev_get_fd(struct vout_fbdev *fbdev); +void *vout_fbdev_get_active_mem(struct vout_fbdev *fbdev); int vout_fbdev_save(struct vout_fbdev *fbdev); int vout_fbdev_restore(struct vout_fbdev *fbdev); void vout_fbdev_finish(struct vout_fbdev *fbdev); diff --git a/src/video/omapdss/osdl.h b/src/video/omapdss/osdl.h index 3ca1bf5..6b78977 100644 --- a/src/video/omapdss/osdl.h +++ b/src/video/omapdss/osdl.h @@ -27,6 +27,7 @@ struct SDL_PrivateVideoData { struct vout_fbdev *fbdev; + void *front_buffer; void *saved_layer; /* physical screen size, should match touchscreen */ int phys_w, phys_h; @@ -42,6 +43,7 @@ struct SDL_PrivateVideoData { unsigned int app_uses_flip:1; unsigned int cfg_force_vsync:1; unsigned int cfg_force_doublebuf:1; + unsigned int cfg_force_directbuf:1; unsigned int cfg_no_ts_translate:1; unsigned int cfg_ts_force_tslib:1; }; @@ -51,6 +53,7 @@ void *osdl_video_set_mode(struct SDL_PrivateVideoData *pdata, int width, int height, int bpp, int *doublebuf, const char *wm_title); void *osdl_video_flip(struct SDL_PrivateVideoData *pdata); +void *osdl_video_get_active_buffer(struct SDL_PrivateVideoData *pdata); int osdl_video_detect_screen(struct SDL_PrivateVideoData *pdata); int osdl_video_pause(struct SDL_PrivateVideoData *pdata, int is_pause); void osdl_video_finish(struct SDL_PrivateVideoData *pdata); diff --git a/src/video/omapdss/osdl_video.c b/src/video/omapdss/osdl_video.c index fe9a29c..5a291a7 100644 --- a/src/video/omapdss/osdl_video.c +++ b/src/video/omapdss/osdl_video.c @@ -454,6 +454,14 @@ void *osdl_video_flip(struct SDL_PrivateVideoData *pdata) return ret; } +void *osdl_video_get_active_buffer(struct SDL_PrivateVideoData *pdata) +{ + if (pdata->fbdev == NULL) + return NULL; + + return vout_fbdev_get_active_mem(pdata->fbdev); +} + int osdl_video_pause(struct SDL_PrivateVideoData *pdata, int is_pause) { struct omapfb_state *state = pdata->saved_layer; diff --git a/src/video/omapdss/sdlif.c b/src/video/omapdss/sdlif.c index 96388f2..27a730f 100644 --- a/src/video/omapdss/sdlif.c +++ b/src/video/omapdss/sdlif.c @@ -133,7 +133,10 @@ static SDL_Surface *omap_SetVideoMode(SDL_VideoDevice *this, SDL_Surface *curren } } - doublebuf = (flags & SDL_DOUBLEBUF) ? 1 : 0; + /* always use doublebuf, when SDL_DOUBLEBUF is not set, + * we'll have to blit manually on UpdateRects() */ + doublebuf = 1; + fbmem = osdl_video_set_mode(pdata, pdata->border_l, pdata->border_r, pdata->border_t, pdata->border_b, width, height, bpp, &doublebuf, this->wm_title); @@ -143,11 +146,24 @@ static SDL_Surface *omap_SetVideoMode(SDL_VideoDevice *this, SDL_Surface *curren pdata->border_l, pdata->border_r, pdata->border_t, pdata->border_b); return NULL; } - if ((flags & SDL_DOUBLEBUF) && !doublebuf) { - log("doublebuffering could not be set\n"); - flags &= ~SDL_DOUBLEBUF; + pdata->front_buffer = osdl_video_get_active_buffer(pdata); + if (pdata->front_buffer == NULL) { + err("osdl_video_get_active_buffer failed\n"); + return NULL; + } + + if (!doublebuf) { + if (flags & SDL_DOUBLEBUF) { + log("doublebuffering could not be set\n"); + flags &= ~SDL_DOUBLEBUF; + } + /* XXX: could just malloc a back buffer here instead */ + pdata->cfg_force_directbuf = 1; } + if (!(flags & SDL_DOUBLEBUF) && pdata->cfg_force_directbuf) + fbmem = pdata->front_buffer; + flags |= SDL_FULLSCREEN | SDL_HWSURFACE; unhandled_flags = flags & ~(SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF); if (unhandled_flags != 0) { @@ -187,10 +203,27 @@ static void omap_UnlockHWSurface(SDL_VideoDevice *this, SDL_Surface *surface) static int omap_FlipHWSurface(SDL_VideoDevice *this, SDL_Surface *surface) { struct SDL_PrivateVideoData *pdata = this->hidden; + static int warned; trace("%p", surface); - surface->pixels = osdl_video_flip(pdata); + if (surface != this->screen) { + if (!warned) { + err("flip surface %p which is not screen %p?\n", + surface, this->screen); + warned = 1; + } + return; + } + + if (surface->flags & SDL_DOUBLEBUF) + surface->pixels = osdl_video_flip(pdata); + else { + if (surface->pixels != pdata->front_buffer) + memcpy(surface->pixels, pdata->front_buffer, + surface->pitch * surface->h); + } + pdata->app_uses_flip = 1; return 0; @@ -217,15 +250,47 @@ static int omap_SetColors(SDL_VideoDevice *this, int firstcolor, int ncolors, SD static void omap_UpdateRects(SDL_VideoDevice *this, int nrects, SDL_Rect *rects) { struct SDL_PrivateVideoData *pdata = this->hidden; + SDL_Surface *screen = this->screen; + Uint16 *src, *dst; + int i, x, y, w, h; trace("%d, %p", nrects, rects); - /* for doublebuf forcing on apps */ - if (nrects == 1 && rects->x == 0 && rects->y == 0 - && !pdata->app_uses_flip && (this->screen->flags & SDL_DOUBLEBUF) - && rects->w == this->screen->w && rects->h == this->screen->h) - { - this->screen->pixels = osdl_video_flip(pdata); + if (screen->flags & SDL_DOUBLEBUF) { + if (nrects == 1 && rects->x == 0 && rects->y == 0 + && (rects->w == screen->w || rects->w == 0) + && (rects->h == screen->h || rects->h == 0) + && !pdata->app_uses_flip) + { + screen->pixels = osdl_video_flip(pdata); + } + return; + } + + src = screen->pixels; + dst = pdata->front_buffer; + if (src == dst) + return; + + for (i = 0; i < nrects; i++) { + /* this supposedly has no clipping, but we'll do it anyway */ + x = rects[i].x, y = rects[i].y, w = rects[i].w, h = rects[i].h; + if (x < 0) + w += x, x = 0; + else if (x + w > screen->w) + w = screen->w - x; + if (w <= 0) + continue; + + if (y < 0) + h += y, y = 0; + else if (y + h > screen->h) + h = screen->h - y; + + for (; h > 0; y++, h--) + memcpy(dst + y * screen->pitch / 2 + x, + src + y * screen->pitch / 2 + x, + w * 2); } } -- 2.39.5