From patchwork Wed Jun 16 16:22:48 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Pidancet X-Patchwork-Id: 55912 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 422551007D3 for ; Thu, 17 Jun 2010 02:30:18 +1000 (EST) Received: from localhost ([127.0.0.1]:42544 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OOvVG-0001c0-VW for incoming@patchwork.ozlabs.org; Wed, 16 Jun 2010 12:30:15 -0400 Received: from [140.186.70.92] (port=47406 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OOvK8-0004CY-2s for qemu-devel@nongnu.org; Wed, 16 Jun 2010 12:18:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OOvK6-0002PX-Dz for qemu-devel@nongnu.org; Wed, 16 Jun 2010 12:18:43 -0400 Received: from smtp02.citrix.com ([66.165.176.63]:37041) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OOvK6-0002PH-5q for qemu-devel@nongnu.org; Wed, 16 Jun 2010 12:18:42 -0400 X-IronPort-AV: E=Sophos;i="4.53,426,1272859200"; d="scan'208";a="101811456" Received: from ftlpmailmx01.citrite.net ([10.9.154.223]) by FTLPIPO02.CITRIX.COM with ESMTP/TLS/RC4-MD5; 16 Jun 2010 12:18:40 -0400 Received: from [10.80.248.100] (10.9.154.239) by FTLPMAILMX01.citrite.net (10.9.154.223) with Microsoft SMTP Server id 8.2.254.0; Wed, 16 Jun 2010 12:18:40 -0400 Message-ID: <4C18FA58.5080808@citrix.com> Date: Wed, 16 Jun 2010 17:22:48 +0100 From: Julian Pidancet User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100330 Shredder/3.0.4 MIME-Version: 1.0 To: Stefano Stabellini References: <1276596347-9410-1-git-send-email-kraxel@redhat.com> <1276596347-9410-6-git-send-email-kraxel@redhat.com> In-Reply-To: X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. Cc: Gerd Hoffmann , "qemu-devel@nongnu.org" Subject: [Qemu-devel] Re: [PATCH 5/5] linux fbdev display driver. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org On 06/16/2010 01:44 PM, Stefano Stabellini wrote: > > the patch still doesn't use the display allocator interface, but it > shouldn't be difficult to implement support for it on top of this patch, > so it is fine by me. > This patch adds display allocator support in the fbdev driver. This way we avoid memcpying when the guest surface is compatible with the physical surface. diff --git a/fbdev.c b/fbdev.c index 54f2381..83104c0 100644 --- a/fbdev.c +++ b/fbdev.c @@ -69,11 +69,10 @@ static int fb_switch_state = FB_ACTIVE; static DisplayChangeListener *dcl; static QemuPfConv *conv; static PixelFormat fbpf; -static int resize_screen; -static int redraw_screen; static int cx, cy, cw, ch; static int debug = 0; static Notifier exit_notifier; +uint8_t *guest_surface; /* fwd decls */ static int fbdev_activate_vt(int tty, int vtno, bool wait); @@ -786,10 +785,10 @@ static void fbdev_render(DisplayState *ds, int x, int y, int w, int h) uint8_t *src; int line; - if (!conv) + if (!conv || !guest_surface) return; - src = ds_get_data(ds) + y * ds_get_linesize(ds) + src = guest_surface + y * ds_get_linesize(ds) + x * ds_get_bytes_per_pixel(ds); dst = fb_mem + y * fb_fix.line_length + x * fbpf.bytes_per_pixel; @@ -819,46 +818,50 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h) if (fb_switch_state != FB_ACTIVE) return; - if (resize_screen) { - if (debug) - fprintf(stderr, "%s: handle resize\n", __FUNCTION__); - resize_screen = 0; - cx = 0; cy = 0; - cw = ds_get_width(ds); - ch = ds_get_height(ds); - if (ds_get_width(ds) < fb_var.xres) { - cx = (fb_var.xres - ds_get_width(ds)) / 2; - } - if (ds_get_height(ds) < fb_var.yres) { - cy = (fb_var.yres - ds_get_height(ds)) / 2; - } + if (guest_surface != NULL) { + fbdev_render(ds, x, y, w, h); + } +} - if (conv) { - qemu_pf_conv_put(conv); - } - conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf); - if (conv == NULL) { - fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n"); - } +static void fbdev_setdata(DisplayState *ds) +{ + if (conv) { + qemu_pf_conv_put(conv); } - if (redraw_screen) { - if (debug) - fprintf(stderr, "%s: handle redraw\n", __FUNCTION__); - redraw_screen = 0; - fbdev_cls(); - x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds); + conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf); + if (conv == NULL) { + fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n"); } - fbdev_render(ds, x, y, w, h); + guest_surface = ds_get_data(ds); } static void fbdev_resize(DisplayState *ds) { - if (debug) - fprintf(stderr, "%s: request resize+redraw\n", __FUNCTION__); - resize_screen++; - redraw_screen++; + int is_video_ptr; + + if (fb_switch_state == FB_ACTIVE) { + fbdev_cls(); + } + + is_video_ptr = ds_get_data(ds) >= fb_mem + fb_mem_offset && + ds_get_data(ds) < fb_mem + fb_fix.smem_len + fb_mem_offset; + + if (ds_get_bits_per_pixel(ds) != fbpf.bits_per_pixel || + ds_get_linesize(ds) != fb_fix.line_length || + !is_video_ptr) { + cx = 0; cy = 0; + if (ds_get_width(ds) < fb_var.xres) { + cx = (fb_var.xres - ds_get_width(ds)) / 2; + } + if (ds_get_height(ds) < fb_var.yres) { + cy = (fb_var.yres - ds_get_height(ds)) / 2; + } + fbdev_setdata(ds); + } else { + guest_surface = NULL; + } } static void fbdev_refresh(DisplayState *ds) @@ -866,21 +869,17 @@ static void fbdev_refresh(DisplayState *ds) switch (fb_switch_state) { case FB_REL_REQ: fbdev_switch_release(); + vga_hw_invalidate(); case FB_INACTIVE: return; case FB_ACQ_REQ: fbdev_switch_acquire(); - redraw_screen++; - if (debug) - fprintf(stderr, "%s: request redraw\n", __FUNCTION__); + vga_hw_invalidate(); case FB_ACTIVE: break; } vga_hw_update(); - if (redraw_screen) { - fbdev_update(ds, 0, 0, 0, 0); - } } static void fbdev_exit_notifier(Notifier *notifier) @@ -888,8 +887,58 @@ static void fbdev_exit_notifier(Notifier *notifier) fbdev_cleanup(); } +static DisplaySurface *fbdev_create_displaysurface(int width, int height) +{ + DisplaySurface *surface = qemu_mallocz(sizeof (DisplaySurface)); + + surface->width = width; + surface->height = height; + + surface->pf = fbpf; + surface->linesize = fb_fix.line_length; + + if (fb_switch_state == FB_INACTIVE) { + surface->flags = QEMU_ALLOCATED_FLAG; + surface->data = qemu_mallocz(surface->linesize * surface->height); + } else { + surface->flags = QEMU_REALPIXELS_FLAG; + surface->data = fb_mem; + + if (width < fb_var.xres) + surface->data += ((fb_var.xres - width) / 2) * fbpf.bytes_per_pixel; + if (height < fb_var.yres) + surface->data += ((fb_var.yres - height) / 2) * fb_fix.line_length; + } + + return surface; +} + +static void fbdev_free_displaysurface(DisplaySurface *surface) +{ + if (surface == NULL) + return; + + if (surface->flags & QEMU_ALLOCATED_FLAG) { + qemu_free(surface->data); + } + + surface->data = NULL; + + qemu_free(surface); +} + +static DisplaySurface *fbdev_resize_displaysurface(DisplaySurface *surface, + int width, + int height) +{ + fbdev_free_displaysurface(surface); + return fbdev_create_displaysurface(width, height); +} + void fbdev_display_init(DisplayState *ds, const char *device) { + DisplayAllocator *da; + if (dcl != NULL) { if (debug) fprintf(stderr, "%s: already active\n", __FUNCTION__); @@ -910,7 +959,17 @@ void fbdev_display_init(DisplayState *ds, const char *device) dcl->dpy_update = fbdev_update; dcl->dpy_resize = fbdev_resize; dcl->dpy_refresh = fbdev_refresh; + dcl->dpy_setdata = fbdev_setdata; register_displaychangelistener(ds, dcl); + + da = qemu_mallocz(sizeof (DisplayAllocator)); + da->create_displaysurface = fbdev_create_displaysurface; + da->resize_displaysurface = fbdev_resize_displaysurface; + da->free_displaysurface = fbdev_free_displaysurface; + + if (register_displayallocator(ds, da) == da) { + dpy_resize(ds); + } } void fbdev_display_uninit(void)