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_ */
next prev parent 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).