qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: David Turner <digit@google.com>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] Ongoing changes to the displaying code
Date: Fri, 9 Jan 2009 10:28:45 +0100	[thread overview]
Message-ID: <60cad3f0901090128m23977527kf658c15ba90dbaf8@mail.gmail.com> (raw)
In-Reply-To: <4966BEC4.7080903@codemonkey.ws>


[-- Attachment #1.1: Type: text/plain, Size: 2935 bytes --]

Hello everyone,

as the guy who implemented all this in the Android emulator, I'd like to
share a few thoughts.

On Fri, Jan 9, 2009 at 4:04 AM, Anthony Liguori <anthony@codemonkey.ws>wrote:

>
> I assume you're looking to do this in order to support functionality like
> in the Android simulator.  So that if you're using QEMU to emulator a hand
> held device (cell phone, whatever), you can have something that looks like
> that device.
>
> The problem is, your GUI is going to want all the feature of a normal GUI.
>  Context menus, perhaps a tool bar, etc.  Maybe you want animated button
> clicks or even the buttons to make noises when clicked.  Inevitably, it'll
> bloat to a full blown GUI.  Not very useful for us virtualization folks so
> we'll also want our own GUI.  Then things get ugly because should it be one
> GUI or two separate ones?  Another way to do this is to separate out the GUI
> logic so it's not directly tied to QEMU.  This has been discussed many times
> and there are a lot of advantages to using an external GUI.  Namely, you can
> close the window without exiting the simulation.
>

+1 to separate the emulation logic and the display/GUI one. this is exactly
what has been done in the Android emulator, even though the program uses its
own GUI for practical reasons.


> If you build a simple app that exec()'s and connects to QEMU via VNC, and
> use something like gtk-vnc, you could build just what you're looking for
> very easily.  It's all portable to Windows too and LGPL licensed.  You could
> even develop in a higher level language like Python and you'd get to use
> file dialog widgets, context menus, and all that good stuff without worrying
> about recreating that in SDL.
>



> I think that's a better route to go for this sort of thing.  If you think
> it's generally useful, I think it'd also be worthwhile to host within the
> QEMU project.  I just don't think it's the right thing to add into QEMU
> directly.
>

For my specific needs, VNC and a separate GUI application are totally
overkill. However, it is true that QEMU itself absolutely doesn't require to
support any GUI jazz (you should probably let that to forks/GUI wrappers
instead).

On the other hand, it would be nice to have a slightly better way to
decouple display/events between the emulation and user-interaction parts of
the system. For example, I've attached the framebuffer abstraction that I
currently use in the Android emulator source code (it's a well documented
header file).

It's basically a slightly better DisplayState, with explicit
producer/clients relationships and a global fifo used for
initialization/linking. I do not claim it is the absolute best way to do it,
just an example on how this can be implemented.

If someone's interested, I can probably provide a patch against the QEMU svn
sources.

Regards,

- Digit


>
> Regards,
>
> Anthony Liguori
>
>  Regards,
>>
>> Anthony Liguori
>>
>
>
>
>

[-- Attachment #1.2: Type: text/html, Size: 4050 bytes --]

[-- Attachment #2: framebuffer.h --]
[-- Type: text/x-chdr, Size: 7834 bytes --]

/* Copyright (C) 2007-2008 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
*/
#ifndef _QEMU_FRAMEBUFFER_H_
#define _QEMU_FRAMEBUFFER_H_

/* A simple abstract interface to framebuffer displays. this is used to
 * de-couple hardware emulation from final display.
 *
 * Each QFrameBuffer object holds a pixel buffer that is shared between
 * one 'Producer' and one or more 'Clients'
 *
 * The Producer is in charge of updating the pixel buffer from the state
 * of the emulated VRAM. A Client listens to updates to the pixel buffer,
 * sent from the producer through qframebuffer_update()/_rotate() and
 * displays them.
 *
 * note the 'rotation' field: it can take values 0, 1, 2 or 3 and corresponds
 * to a rotation that must be performed to the pixels stored in the framebuffer
 * *before* displaying them a value of 1 corresponds to a rotation of
 * 90 clockwise-degrees, when the framebuffer is rotated 90 or 270 degrees,
 * its width/height are swapped automatically
 *
 * phys_width_mm and phys_height_mm are physical dimensions expressed
 * in millimeters
 *
 * More about the client/producer relationships below.
 */
typedef struct QFrameBuffer   QFrameBuffer;


typedef enum {
    QFRAME_BUFFER_NONE   = 0,
    QFRAME_BUFFER_RGB565 = 1,
    QFRAME_BUFFER_MAX          /* do not remove */
} QFrameBufferFormat;

struct QFrameBuffer {
    int                 width;        /* width in pixels */
    int                 height;       /* height in pixels */
    int                 pitch;        /* bytes per line */
    int                 rotation;     /* rotation to be applied when displaying */
    QFrameBufferFormat  format;
    void*               pixels;       /* pixel buffer */

    int                 phys_width_mm;
    int                 phys_height_mm;

    /* extra data that is handled by the framebuffer implementation */
    void*               extra;

};

/* the default dpi resolution of a typical framebuffer. this is an average
 * between various prototypes being used during the development of the
 * Android system...
 */
#define  DEFAULT_FRAMEBUFFER_DPI   165


/* initialize a framebuffer object and allocate its pixel buffer */
/* this computes phys_width_mm and phys_height_mm assuming a 165 dpi screen */
/* returns -1 in case of error, 0 otherwise */
extern int
qframebuffer_init( QFrameBuffer*       qfbuff,
                   int                 width,
                   int                 height,
                   int                 rotation,
                   QFrameBufferFormat  format );

/* recompute phys_width_mm and phys_height_mm according to the emulated 
 * screen DPI settings */
extern void
qframebuffer_set_dpi( QFrameBuffer*   qfbuff,
                      int             x_dpi,
                      int             y_dpi );

/* alternative to qframebuffer_set_dpi where one can set the physical 
 * dimensions directly in millimeters. for the record 1 inch = 25.4 mm */
extern void
qframebuffer_set_mm( QFrameBuffer*   qfbuff,
                     int             width_mm,
                     int             height_mm );

/* the Client::Update method is called to instruct a client that a given
 * rectangle of the framebuffer pixels was updated and needs to be
 * redrawn.
 */
typedef void (*QFrameBufferUpdateFunc)( void*  opaque, int  x, int  y, 
                                                       int  w, int  h );

/* the Client::Rotate method is called to instruct the client that a
 * framebuffer's internal rotation has changed. This is the rotation
 * that must be applied before displaying the pixels.
 *
 * Note that it is assumed that all framebuffer pixels have changed too
 * so the client should call its Update method as well.
 */
typedef void (*QFrameBufferRotateFunc)( void*  opaque, int  rotation );

/* the Client::Done func tells a client that a framebuffer object was freed.
 * no more reference to its pixels should be done.
 */
typedef void (*QFrameBufferDoneFunc)  ( void*  opaque );

/* add one client to a given framebuffer.
 * the current implementation only allows one client per frame-buffer,
 * but we could allow more for various reasons (e.g. displaying the
 * framebuffer + dispatching it through VNC at the same time)
 */
extern void
qframebuffer_add_client( QFrameBuffer*           qfbuff,
                         void*                   fb_opaque,
                         QFrameBufferUpdateFunc  fb_update,
                         QFrameBufferRotateFunc  fb_rotate,
                         QFrameBufferDoneFunc    fb_done );

/* Producer::CheckUpdate is called to let the producer check the
 * VRAM state (e.g. VRAM dirty pages) to see if anything changed since the
 * last call to the method. When true, the method should call either
 * qframebuffer_update() or qframebuffer_rotate() with the appropriate values.
 */
typedef void (*QFrameBufferCheckUpdateFunc)( void*  opaque );

/* Producer::Invalidate tells the producer that the next call to
 * CheckUpdate should act as if the whole content of VRAM had changed.
 * this is normally done to force client initialization/refreshes.
 */
typedef void (*QFrameBufferInvalidateFunc) ( void*  opaque );

/* the Producer::Detach method is used to tell the producer that the
 * underlying QFrameBuffer object is about to be de-allocated.
 */
typedef void (*QFrameBufferDetachFunc)     ( void*  opaque );

/* set the producer of a given framebuffer */
extern void
qframebuffer_set_producer( QFrameBuffer*                qfbuff,
                           void*                        opaque,
                           QFrameBufferCheckUpdateFunc  fb_check,
                           QFrameBufferInvalidateFunc   fb_invalidate,
                           QFrameBufferDetachFunc       fb_detach );

/* tell a client that a rectangle region has been updated in the framebuffer
 * pixel buffer this is typically called from a Producer::CheckUpdate method
 */
extern void
qframebuffer_update( QFrameBuffer*  qfbuff, int  x, int  y, int  w, int  h );

/* rotate the framebuffer (may swap width/height), and tell all clients.
 * Should be called from a Producer::CheckUpdate method
 */
extern void
qframebuffer_rotate( QFrameBuffer*  qfbuff, int  rotation );

/* finalize a framebuffer, release its pixel buffer. Should be called
 * from the framebuffer object's owner
 */
extern void
qframebuffer_done( QFrameBuffer*   qfbuff );


/* this is called repeatedly by the emulator. for each registered framebuffer,
 * call its producer's CheckUpdate method, if any.
 */
extern void
qframebuffer_check_updates( void );

/* this is called by the emulator. for each registered framebuffer, call
 * its producer's Invalidate method, if any
 */
extern void
qframebuffer_invalidate_all( void );

/*
 * to completely separate the implementation of clients, producers, and skins,
 * we use a simple global FIFO list of QFrameBuffer objects.
 *
 * qframebuffer_fifo_add() is typically called by the emulator initialization
 * depending on the emulated device's configuration
 *
 * qframebuffer_fifo_get() is typically called by a hardware framebuffer
 * emulation.
 */

/* add a new constructed frame buffer object to our global list */
extern void
qframebuffer_fifo_add( QFrameBuffer*  qfbuff );

/* retrieve a frame buffer object from the global FIFO list */
extern QFrameBuffer*
qframebuffer_fifo_get( void );

/* */

#endif /* _QEMU_FRAMEBUFFER_H_ */


  reply	other threads:[~2009-01-09  9:28 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-09  1:52 [Qemu-devel] Ongoing changes to the displaying code Daniel Gutson
2009-01-09  2:50 ` Anthony Liguori
2009-01-09  3:04   ` Anthony Liguori
2009-01-09  9:28     ` David Turner [this message]
2009-01-09 15:20       ` Anthony Liguori
2009-01-09 16:53         ` David Turner
2009-01-09 17:16         ` Ian Jackson
2009-01-09 17:24           ` Anthony Liguori
2009-01-09 17:42             ` Riku Voipio
2009-01-09 18:59               ` Anthony Liguori
2009-01-10  0:01                 ` Jamie Lokier
2009-01-10  1:39                   ` Anthony Liguori
2009-01-12 15:25                 ` Ian Jackson
2009-01-15  8:53                 ` Mark McLoughlin
2009-01-09 17:26           ` David Turner
2009-01-09 19:02             ` Anthony Liguori
2009-01-12 15:31             ` Ian Jackson
2009-01-11  8:22     ` Avi Kivity
2009-01-12 15:33       ` Ian Jackson
2009-01-12 15:57         ` Avi Kivity
2009-01-09 12:04 ` Stefano Stabellini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=60cad3f0901090128m23977527kf658c15ba90dbaf8@mail.gmail.com \
    --to=digit@google.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).