Commit c18a2c36 authored by Stefano Stabellini's avatar Stefano Stabellini Committed by Anthony Liguori
Browse files

sdl zooming



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: default avatarStefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parent 14899cdf
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -165,7 +165,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
@@ -209,7 +209,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 baum.o: CFLAGS += $(SDL_CFLAGS)

+3 −1
Original line number Diff line number Diff line
@@ -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)
+62 −16
Original line number Diff line number Diff line
@@ -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);
    if (guest_screen) {
    SDL_Rect rec;
    rec.x = x;
    rec.y = y;
    rec.w = w;
    rec.h = h;

    if (guest_screen) {
        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, x, y, w, h);
    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) {
        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) {
@@ -164,7 +177,25 @@ static DisplaySurface* sdl_create_displaysurface(int width, int height)
    surface->width = width;
    surface->height = height;
    
    if (hostbpp == 16)
    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 (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;

sdl_zoom.c

0 → 100644
+94 −0
Original line number Diff line number Diff line
/*
 * 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;
}

sdl_zoom.h

0 → 100644
+25 −0
Original line number Diff line number Diff line
/*
 * 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 */
Loading