qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] sdl zooming


From: Stefano Stabellini
Subject: [Qemu-devel] [PATCH] sdl zooming
Date: Wed, 24 Jun 2009 11:58:25 +0100
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

Hi all,
this patch implements zooming capabilities for the sdl interface.
A new sdl_zoom_blit function is added that is able to scale and blit a
portion of a surface into another.
This way we can enable SDL_RESIZABLE and have a real_screen surface with
a different size than the guest surface and let sdl_zoom_blit take care
of the problem.

Signed-off-by: Stefano Stabellini <address@hidden>

---

diff --git a/Makefile b/Makefile
index 781e7ed..58faff9 100644
--- a/Makefile
+++ b/Makefile
@@ -162,7 +162,7 @@ OBJS+=$(addprefix audio/, $(AUDIO_OBJS))
 
 OBJS+=keymaps.o
 ifdef CONFIG_SDL
-OBJS+=sdl.o x_keymap.o
+OBJS+=sdl.o sdl_zoom.o x_keymap.o
 endif
 ifdef CONFIG_CURSES
 OBJS+=curses.o
@@ -206,7 +206,9 @@ cocoa.o: cocoa.m
 
 keymaps.o: keymaps.c keymaps.h
 
-sdl.o: sdl.c keymaps.h sdl_keysym.h
+sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h
+
+sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h
 
 sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS)
 
diff --git a/console.h b/console.h
index 4172175..3518339 100644
--- a/console.h
+++ b/console.h
@@ -75,6 +75,7 @@ void kbd_put_keysym(int keysym);
 
 #define QEMU_BIG_ENDIAN_FLAG    0x01
 #define QEMU_ALLOCATED_FLAG     0x02
+#define QEMU_REALPIXELS_FLAG    0x04
 
 struct PixelFormat {
     uint8_t bits_per_pixel;
@@ -172,7 +173,8 @@ static inline int is_surface_bgr(DisplaySurface *surface)
 
 static inline int is_buffer_shared(DisplaySurface *surface)
 {
-    return (!(surface->flags & QEMU_ALLOCATED_FLAG));
+    return (!(surface->flags & QEMU_ALLOCATED_FLAG) &&
+            !(surface->flags & QEMU_REALPIXELS_FLAG));
 }
 
 static inline void register_displaychangelistener(DisplayState *ds, 
DisplayChangeListener *dcl)
diff --git a/sdl.c b/sdl.c
index 178b553..d81399e 100644
--- a/sdl.c
+++ b/sdl.c
@@ -32,6 +32,7 @@
 #include "console.h"
 #include "sysemu.h"
 #include "x_keymap.h"
+#include "sdl_zoom.h"
 
 static DisplayChangeListener *dcl;
 static SDL_Surface *real_screen;
@@ -54,20 +55,29 @@ static int guest_cursor = 0;
 static int guest_x, guest_y;
 static SDL_Cursor *guest_sprite = 0;
 static uint8_t allocator;
-static uint8_t hostbpp;
+static SDL_PixelFormat host_format;
+static int scaling_active = 0;
 
 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
 {
     //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
+    SDL_Rect rec;
+    rec.x = x;
+    rec.y = y;
+    rec.w = w;
+    rec.h = h;
+
     if (guest_screen) {
-        SDL_Rect rec;
-        rec.x = x;
-        rec.y = y;
-        rec.w = w;
-        rec.h = h;
-        SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
-    }
-    SDL_UpdateRect(real_screen, x, y, w, h);
+        if (!scaling_active) {
+            SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
+        } else {
+            if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 
0) {
+                fprintf(stderr, "Zoom blit failed\n");
+                exit(1);
+            }
+        }
+    } 
+    SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
 }
 
 static void sdl_setdata(DisplayState *ds)
@@ -92,7 +102,7 @@ static void do_sdl_resize(int new_width, int new_height, int 
bpp)
 
     //    printf("resizing to %d %d\n", w, h);
 
-    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
+    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
     if (gui_fullscreen)
         flags |= SDL_FULLSCREEN;
     if (gui_noframe)
@@ -110,7 +120,10 @@ static void do_sdl_resize(int new_width, int new_height, 
int bpp)
 static void sdl_resize(DisplayState *ds)
 {
     if  (!allocator) {
-        do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+        if (!scaling_active)
+            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+        else if (real_screen->format->BitsPerPixel != 
ds_get_bits_per_pixel(ds))
+            do_sdl_resize(real_screen->w, real_screen->h, 
ds_get_bits_per_pixel(ds));
         sdl_setdata(ds);
     } else {
         if (guest_screen != NULL) {
@@ -163,8 +176,26 @@ static DisplaySurface* sdl_create_displaysurface(int 
width, int height)
 
     surface->width = width;
     surface->height = height;
+    
+    if (scaling_active) {
+        if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
+            surface->linesize = width * 4;
+            surface->pf = qemu_default_pixelformat(32);
+        } else {
+            surface->linesize = width * host_format.BytesPerPixel;
+            surface->pf = sdl_to_qemu_pixelformat(&host_format);
+        }
+#ifdef WORDS_BIGENDIAN
+        surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+        surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+        surface->data = (uint8_t*) qemu_mallocz(surface->linesize * 
surface->height);
+
+        return surface;
+    }
 
-    if (hostbpp == 16)
+    if (host_format.BitsPerPixel == 16)
         do_sdl_resize(width, height, 16);
     else
         do_sdl_resize(width, height, 32);
@@ -174,9 +205,9 @@ static DisplaySurface* sdl_create_displaysurface(int width, 
int height)
     surface->data = real_screen->pixels;
 
 #ifdef WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+    surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
 #else
-    surface->flags = QEMU_ALLOCATED_FLAG;
+    surface->flags = QEMU_REALPIXELS_FLAG;
 #endif
     allocator = 1;
 
@@ -188,6 +219,9 @@ static void sdl_free_displaysurface(DisplaySurface *surface)
     allocator = 0;
     if (surface == NULL)
         return;
+
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
     qemu_free(surface);
 }
 
@@ -482,8 +516,8 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, 
int x, int y, int state
 static void toggle_full_screen(DisplayState *ds)
 {
     gui_fullscreen = !gui_fullscreen;
-    do_sdl_resize(real_screen->w, real_screen->h, 
real_screen->format->BitsPerPixel);
     if (gui_fullscreen) {
+        scaling_active = 0;
         gui_saved_grab = gui_grab;
         sdl_grab_start();
     } else {
@@ -675,6 +709,18 @@ static void sdl_refresh(DisplayState *ds)
                 }
             }
             break;
+       case SDL_VIDEORESIZE:
+        {
+           SDL_ResizeEvent *rev = &ev->resize;
+            int bpp = real_screen->format->BitsPerPixel;
+            if (bpp != 16 && bpp != 32)
+                bpp = 32;
+            do_sdl_resize(rev->w, rev->h, bpp);
+            scaling_active = 1;
+            vga_hw_invalidate();
+            vga_hw_update();
+            break;
+        }
         default:
             break;
         }
@@ -783,7 +829,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, 
int no_frame)
         exit(1);
     }
     vi = SDL_GetVideoInfo();
-    hostbpp = vi->vfmt->BitsPerPixel;
+    host_format = *(vi->vfmt);
 
     dcl = qemu_mallocz(sizeof(DisplayChangeListener));
     dcl->dpy_update = sdl_update;
diff --git a/sdl_zoom.c b/sdl_zoom.c
new file mode 100644
index 0000000..56d3604
--- /dev/null
+++ b/sdl_zoom.c
@@ -0,0 +1,94 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sdl_zoom.h"
+#include "osdep.h"
+#include <stdint.h>
+
+static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+
+#define BPP 32
+#include  "sdl_zoom_template.h"
+#undef BPP
+#define BPP 16
+#include  "sdl_zoom_template.h"
+#undef BPP
+
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, int smooth,
+                  SDL_Rect *in_rect)
+{
+    SDL_Rect zoom, src_rect;
+    int extra;
+
+    /* Grow the size of the modified rectangle to avoid edge artefacts */
+    src_rect.x = (in_rect->x > 0) ? (in_rect->x - 1) : 0;
+    src_rect.y = (in_rect->y > 0) ? (in_rect->y - 1) : 0;
+
+    src_rect.w = in_rect->w + 1;
+    if (src_rect.x + src_rect.w > src_sfc->w)
+        src_rect.w = src_sfc->w - src_rect.x;
+
+    src_rect.h = in_rect->h + 1;
+    if (src_rect.y + src_rect.h > src_sfc->h)
+        src_rect.h = src_sfc->h - src_rect.y;
+
+    /* (x,y) : round down */
+    zoom.x = (int)(((float)(src_rect.x * dst_sfc->w)) / (float)(src_sfc->w));
+    zoom.y = (int)(((float)(src_rect.y * dst_sfc->h)) / (float)(src_sfc->h));
+
+    /* (w,h) : round up */
+    zoom.w = (int)( ((double)((src_rect.w * dst_sfc->w) + (src_sfc->w - 1))) /
+                     (double)(src_sfc->w));
+
+    zoom.h = (int)( ((double)((src_rect.h * dst_sfc->h) + (src_sfc->h - 1))) /
+                     (double)(src_sfc->h));
+
+    /* Account for any (x,y) rounding by adding one-source-pixel's worth
+     * of destination pixels and then edge checking.
+     */
+
+    extra = ((dst_sfc->w-1) / src_sfc->w) + 1;
+
+    if ((zoom.x + zoom.w) < (dst_sfc->w - extra))
+        zoom.w += extra;
+    else
+        zoom.w = dst_sfc->w - zoom.x;
+
+    extra = ((dst_sfc->h-1) / src_sfc->h) + 1;
+
+    if ((zoom.y + zoom.h) < (dst_sfc->h - extra))
+        zoom.h += extra;
+    else
+        zoom.h = dst_sfc->h - zoom.y;
+
+    /* The rectangle (zoom.x, zoom.y, zoom.w, zoom.h) is the area on the
+     * destination surface that needs to be updated.
+     */
+    if (src_sfc->format->BitsPerPixel == 32)
+        sdl_zoom_rgb32(src_sfc, dst_sfc, smooth, &zoom);
+    else if (src_sfc->format->BitsPerPixel == 16)
+        sdl_zoom_rgb16(src_sfc, dst_sfc, smooth, &zoom);
+    else {
+        fprintf(stderr, "pixel format not supported\n");
+        return -1;
+    }
+
+    /* Return the rectangle of the update to the caller */
+    *in_rect = zoom;
+
+    return 0;
+}
+
diff --git a/sdl_zoom.h b/sdl_zoom.h
new file mode 100644
index 0000000..33dc634
--- /dev/null
+++ b/sdl_zoom.h
@@ -0,0 +1,25 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _SDL_zoom_h
+#define _SDL_zoom_h
+
+#include <SDL/SDL.h>
+
+#define SMOOTHING_OFF          0
+#define SMOOTHING_ON           1
+
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc,
+                  int smooth, SDL_Rect *src_rect);
+
+#endif /* _SDL_zoom_h */
diff --git a/sdl_zoom_template.h b/sdl_zoom_template.h
new file mode 100644
index 0000000..64bbca8
--- /dev/null
+++ b/sdl_zoom_template.h
@@ -0,0 +1,225 @@
+/*
+ * SDL_zoom_template - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#if BPP == 16
+#define SDL_TYPE Uint16
+#elif BPP == 32
+#define SDL_TYPE Uint32
+#else
+#error unsupport depth
+#endif
+
+/*  
+ *  Simple helper functions to make the code looks nicer
+ *
+ *  Assume spf = source SDL_PixelFormat
+ *         dpf = dest SDL_PixelFormat
+ *
+ */
+#define getRed(color)   (((color) & spf->Rmask) >> spf->Rshift)
+#define getGreen(color) (((color) & spf->Gmask) >> spf->Gshift)
+#define getBlue(color)  (((color) & spf->Bmask) >> spf->Bshift)
+#define getAlpha(color) (((color) & spf->Amask) >> spf->Ashift)
+
+#define setRed(r, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Rmask))) + \
+              (((r) & (dpf->Rmask >> dpf->Rshift)) << dpf->Rshift); \
+} while (0);
+
+#define setGreen(g, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Gmask))) + \
+              (((g) & (dpf->Gmask >> dpf->Gshift)) << dpf->Gshift); \
+} while (0);
+
+#define setBlue(b, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Bmask))) + \
+              (((b) & (dpf->Bmask >> dpf->Bshift)) << dpf->Bshift); \
+} while (0);
+
+#define setAlpha(a, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Amask))) + \
+              (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \
+} while (0);
+
+static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int 
smooth,
+                                   SDL_Rect *dst_rect)
+{
+    int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, 
sstep, sstep_jump;
+    SDL_TYPE *c00, *c01, *c10, *c11, *sp, *csp, *dp;
+    int d_gap;
+    SDL_PixelFormat *spf = src->format;
+    SDL_PixelFormat *dpf = dst->format;
+
+    if (smooth) { 
+        /* For interpolation: assume source dimension is one pixel.
+         * Smaller here to avoid overflow on right and bottom edge.
+         */
+        sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+        sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+    } else {
+        sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+        sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+    }
+
+    if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+        return (-1);
+    }
+    if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+        free(sax);
+        return (-1);
+    }
+
+    sp = csp = (SDL_TYPE *) src->pixels;
+    dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch +
+                       dst_rect->x * dst->format->BytesPerPixel);
+
+    csx = 0;
+    csax = sax;
+    for (x = 0; x <= dst->w; x++) {
+        *csax = csx;
+        csax++;
+        csx &= 0xffff;
+        csx += sx;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y <= dst->h; y++) {
+        *csay = csy;
+        csay++;
+        csy &= 0xffff;
+        csy += sy;
+    }
+
+    d_gap = dst->pitch - dst_rect->w * dst->format->BytesPerPixel;
+
+    if (smooth) {
+        csay = say;
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0; y < dst_rect->h ; y++) {
+            /* Setup colour source pointers */
+            c00 = csp + sstep_jump;
+            c01 = c00 + 1;
+            c10 = (SDL_TYPE *) ((Uint8 *) csp + src->pitch) + sstep_jump;
+            c11 = c10 + 1;
+            csax = sax + dst_rect->x; 
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Interpolate colours */
+                ex = (*csax & 0xffff);
+                ey = (*csay & 0xffff);
+                t1 = ((((getRed(*c01) - getRed(*c00)) * ex) >> 16) +
+                     getRed(*c00)) & (dpf->Rmask >> dpf->Rshift);
+                t2 = ((((getRed(*c11) - getRed(*c10)) * ex) >> 16) +
+                     getRed(*c10)) & (dpf->Rmask >> dpf->Rshift);
+                setRed((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getGreen(*c01) - getGreen(*c00)) * ex) >> 16) +
+                     getGreen(*c00)) & (dpf->Gmask >> dpf->Gshift);
+                t2 = ((((getGreen(*c11) - getGreen(*c10)) * ex) >> 16) +
+                     getGreen(*c10)) & (dpf->Gmask >> dpf->Gshift);
+                setGreen((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getBlue(*c01) - getBlue(*c00)) * ex) >> 16) +
+                     getBlue(*c00)) & (dpf->Bmask >> dpf->Bshift);
+                t2 = ((((getBlue(*c11) - getBlue(*c10)) * ex) >> 16) +
+                     getBlue(*c10)) & (dpf->Bmask >> dpf->Bshift);
+                setBlue((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getAlpha(*c01) - getAlpha(*c00)) * ex) >> 16) +
+                     getAlpha(*c00)) & (dpf->Amask >> dpf->Ashift);
+                t2 = ((((getAlpha(*c11) - getAlpha(*c10)) * ex) >> 16) +
+                     getAlpha(*c10)) & (dpf->Amask >> dpf->Ashift);
+                setAlpha((((t2 - t1) * ey) >> 16) + t1, dp); 
+
+                /* Advance source pointers */
+                csax++; 
+                sstep = (*csax >> 16);
+                c00 += sstep;
+                c01 += sstep;
+                c10 += sstep;
+                c11 += sstep;
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointer */
+            csay++;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+            /* Advance destination pointers */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+
+
+    } else {
+        csay = say;
+
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0 ; y < dst_rect->h ; y++) {
+            sp = csp + sstep_jump;
+            csax = sax + dst_rect->x;
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Draw */
+                *dp = *sp;
+
+                /* Advance source pointers */
+                csax++;
+                sstep = (*csax >> 16);
+                sp += sstep;
+
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointers */
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+
+            /* Advance destination pointer */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+    }
+
+    free(sax);
+    free(say);
+    return (0);
+}
+
+#undef SDL_TYPE
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]