This patch adds a rather extensive document explaining the design of our OpenGLES emulation, both on the guest and the host. Change-Id: I13cf1eac21e5a8a0be170b5f90100b04f9ae6d75
594 lines
25 KiB
Plaintext
594 lines
25 KiB
Plaintext
Android Hardware OpenGLES emulation design overview
|
|
===================================================
|
|
|
|
Introduction:
|
|
-------------
|
|
|
|
Hardware GLES emulation in the Android platform is implemented with a mix
|
|
of components, which are:
|
|
|
|
- Several host "translator" libraries. They implement the EGL, GLES 1.1 and
|
|
GLES 2.0 ABIs defined by Khronos, and translate the corresponding function
|
|
calls into calls to the appropriate desktop APIs, i.e.:
|
|
|
|
- Xgl (Linux), AGL (OS X) or WGL (Windows) for EGL
|
|
- desktop GL 2.0 for GLES 1.1 and GLES 2.0
|
|
|
|
_________ __________ __________
|
|
| | | | | | HOST
|
|
|TRANSLATOR |TRANSLATOR| |TRANSLATOR| HOST
|
|
| EGL | | GLES 1.1 | | GLES 2.0 | TRANSLATOR
|
|
|_________| |__________| |__________| LIBRARIES
|
|
| | |
|
|
- - - | - - - - - - - - - | - - - - - - - - - | - - - - -
|
|
| | |
|
|
____v____ ____v_____ _____v____ HOST
|
|
| | | | | | SYSTEM
|
|
| Xgl | | GL 2.0 | | GL 2.0 | LIBRARIES
|
|
|_________| |__________| |__________|
|
|
|
|
|
|
|
|
- Several system libraries inside the emulated guest system that implement
|
|
the same EGL / GLES 1.1 and GLES 2.0 ABIs.
|
|
|
|
They collect the sequence of EGL/GLES function calls and translate then
|
|
into a custom wire protocol stream that is sent to the emulator program
|
|
through a high-speed communication channel called a "QEMU Pipe".
|
|
|
|
For now, all you need to know is that the pipe is implemented with a
|
|
custom kernel driver, and provides for _very_ fast bandwidth. All read()
|
|
and writes() from/to the pipes are essentially instantaneous from the
|
|
guest's point of view.
|
|
|
|
|
|
_________ __________ __________
|
|
| | | | | |
|
|
|EMULATION| |EMULATION | |EMULATION | GUEST
|
|
| EGL | | GLES 1.1 | | GLES 2.0 | SYSTEM
|
|
|_________| |__________| |__________| LIBRARIES
|
|
| | |
|
|
- - - | - - - - - - - - - | - - - - - - - - - | - - - - -
|
|
| | |
|
|
____v____________________v____________________v____ GUEST
|
|
| | KERNEL
|
|
| QEMU PIPE |
|
|
|___________________________________________________|
|
|
|
|
|
- - - - - - - - - - - - - -|- - - - - - - - - - - - - - - -
|
|
|
|
|
v
|
|
EMULATOR
|
|
|
|
- Specific code inside the emulator program that is capable of transmitting
|
|
the wire protocol stream to a special rendering library or process (called
|
|
the "renderer" here), which understands the format.
|
|
|
|
|
|
|
| PROTOCOL BYTE STREAM
|
|
_____v_____
|
|
| |
|
|
| EMULATOR |
|
|
|___________|
|
|
|
|
|
| UNMODIFIED PROTOCOL BYTE STREAM
|
|
_____v_____
|
|
| |
|
|
| RENDERER |
|
|
|___________|
|
|
|
|
|
|
- The renderer decodes the EGL/GLES commands from the wire
|
|
protocol stream, and dispatches them to the translator libraries
|
|
appropriately.
|
|
|
|
|
|
|
| PROTOCOL BYTE STREAM
|
|
_____v_____
|
|
| |
|
|
| RENDERER |
|
|
|___________|
|
|
| | |
|
|
+-----------------+ | +-----------------+
|
|
| | |
|
|
____v____ ___v______ ____v_____
|
|
| | | | | | HOST
|
|
|TRANSLATOR |TRANSLATOR| |TRANSLATOR| HOST
|
|
| EGL | | GLES 1.1 | | GLES 2.0 | TRANSLATOR
|
|
|_________| |__________| |__________| LIBRARIES
|
|
|
|
|
|
|
|
- In reality, the protocol stream flows in both directions, even though most
|
|
of the commands result in data going from the guest to the host. A complete
|
|
picture of the emulation would thus be:
|
|
|
|
|
|
|
|
|
|
|
|
_________ __________ __________
|
|
| | | | | |
|
|
|EMULATION| |EMULATION | |EMULATION | GUEST
|
|
| EGL | | GLES 1.1 | | GLES 2.0 | SYSTEM
|
|
|_________| |__________| |__________| LIBRARIES
|
|
^ ^ ^
|
|
| | |
|
|
- - - | - - - - - - - - - | - - - - - - - - - | - - - - -
|
|
| | |
|
|
____v____________________v____________________v____ GUEST
|
|
| | KERNEL
|
|
| QEMU PIPE |
|
|
|___________________________________________________|
|
|
^
|
|
|
|
|
- - - - - - - - - - - - - -|- - - - - - - - - - - - - - - -
|
|
|
|
|
| PROTOCOL BYTE STREAM
|
|
_____v_____
|
|
| |
|
|
| EMULATOR |
|
|
|___________|
|
|
^
|
|
| UNMODIFIED PROTOCOL BYTE STREAM
|
|
_____v_____
|
|
| |
|
|
| RENDERER |
|
|
|___________|
|
|
^ ^ ^
|
|
| | |
|
|
+-----------------+ | +-----------------+
|
|
| | |
|
|
____v____ ___v______ ____v_____
|
|
| | | | | |
|
|
|TRANSLATOR |TRANSLATOR| |TRANSLATOR| HOST
|
|
| EGL | | GLES 1.1 | | GLES 2.0 | TRANSLATOR
|
|
|_________| |__________| |__________| LIBRARIES
|
|
^ ^ ^
|
|
| | |
|
|
- - - | - - - - - - - - - | - - - - - - - - - | - - - - -
|
|
| | |
|
|
____v____ ____v_____ _____v____ HOST
|
|
| | | | | | SYSTEM
|
|
| Xgl | | GL 2.0 | | GL 2.0 | LIBRARIES
|
|
|_________| |__________| |__________|
|
|
|
|
(NOTE: 'Xgl' is for Linux only, replace 'AGL' on OS X, and 'WGL' on Windows).
|
|
|
|
|
|
Note that, in the above graphics, only the host system libraries at the bottom
|
|
are _not_ provided by Android.
|
|
|
|
|
|
Design Requirements:
|
|
--------------------
|
|
|
|
The above design comes from several important requirements that were decided
|
|
early in the project:
|
|
|
|
1 - The ability to run the renderer in a separate process from the emulator
|
|
itself is important.
|
|
|
|
For various practical reasons, we plan to completely separate the core QEMU
|
|
emulation from the UI window by using two distinct processes. As such, the
|
|
renderer will be implemented as a library inside the UI program, but will
|
|
need to receive protocol bytes from the QEMU process.
|
|
|
|
The communication channel will be either a fast Unix socket or a Win32
|
|
named pipe between these two. A shared memory segment with appropriate
|
|
synchronization primitives might also be used if performance becomes
|
|
an issue.
|
|
|
|
This explains why the emulator doesn't alter or even try to parse the
|
|
protocol byte stream. It only acts as a dumb proxy between the guest
|
|
system and the renderer. This also avoids adding lots of GLES-specific
|
|
code inside the QEMU code base which is terribly complex.
|
|
|
|
2 - The ability to use vendor-specific desktop EGL/GLES libraries is
|
|
important.
|
|
|
|
GPU vendors like NVidia, AMD or ARM all provide host versions of the
|
|
EGL/GLES libraries that emulate their respectivie embedded graphics
|
|
chipset.
|
|
|
|
The renderer library can be configured to use these instead of the
|
|
translator libraries provided with this project. This can be useful to
|
|
more accurately emulate the behaviour of specific devices.
|
|
|
|
Moreover, these vendor libraries typically expose vendor-specific
|
|
extensions that are not provided by the translator libraries. We cannot
|
|
expose them without modifying our code, but it's important to be able
|
|
to do so without too much pain.
|
|
|
|
|
|
Code organization:
|
|
------------------
|
|
|
|
All source code for the components above is spread over multiple directories
|
|
in the Android source trees:
|
|
|
|
- The emulator sources are under $ANDROID/external/qemu, which we'll
|
|
call $QEMU in the rest of this document.
|
|
|
|
- The guest and system libraries are under
|
|
$ANDROID/development/tools/emulator/opengl, which we'll call $EMUGL
|
|
|
|
- The QEMU Pipe kernel driver is under $KERNEL/drivers/misc/qemupipe
|
|
|
|
Where $ANDROID is the top of the open-source Android source tree, and
|
|
$KERNEL is the top of the qemu-specific kernel source tree (using one
|
|
of the android-goldfish-xxxx branches here).
|
|
|
|
The emulator sources related to this projects are:
|
|
|
|
$QEMU/hw/goldfish_pipe.c -> implement QEMU pipe virtual hardware
|
|
$QEMU/hw/opengles.c -> implement GLES initialization
|
|
$QEMU/hw/hw-pipe-net.c -> implements the communication channel
|
|
between the QEMU Pipe and the renderer library
|
|
|
|
The other sources are:
|
|
|
|
$EMUGL/system -> system libraries
|
|
$EMUGL/host -> host libraries (translator + renderer)
|
|
$EMUGL/shared -> shared libraries, used both in the guest and the host
|
|
$EMUGL/tests -> various test programs
|
|
|
|
|
|
Translator libraries:
|
|
---------------------
|
|
|
|
There are three translator host libraries provided by this project:
|
|
|
|
libEGL_translator -> EGL 1.2 translation
|
|
libGLES_CM_translator -> GLES 1.1 translation
|
|
libGLES_V2_translator -> GLES 2.0 translation
|
|
|
|
The full name of the library will depend on the host system.
|
|
For simplicity, only the library name suffix will change (i.e. the
|
|
'lib' prefix is not dropped on Windows), i.e.:
|
|
|
|
libEGL_translator.so -> for Linux
|
|
libEGL_translator.dylib -> for OS X
|
|
libEGL_translator.dll -> for Windows
|
|
|
|
The source code for these libraries is located under the following
|
|
path in the Android source tree:
|
|
|
|
$EMUGL/host/libs/Translator/EGL
|
|
$EMUGL/host/libs/Translator/GLES_CM
|
|
$EMUGL/host/libs/Translator/GLES_V2
|
|
|
|
The translator libraries also use a common routines defined under:
|
|
|
|
$EMUGL/host/libs/Translator/GLcommon
|
|
|
|
|
|
Wire Protocol Overiew:
|
|
----------------------
|
|
|
|
The "wire protocol" is implemented as follows:
|
|
|
|
- EGL/GLES function calls are described through several "specification"
|
|
files, which describes the types, function signatures and various
|
|
attributes for each one of them.
|
|
|
|
- These files are read by a tool called "emugen" which generates C
|
|
source files and headers based on the specification. These correspond
|
|
to both encoding, decoding and "wrappers" (more on this later).
|
|
|
|
- System "encoder" static libraries are built using some of these generated
|
|
files. They contain code that can serialize EGL/GLES calls into simple
|
|
byte messages and send it through a generic "IOStream" object.
|
|
|
|
- Host "decoder" static libraries are also built using some of these
|
|
generated files. Their code retrieves byte messages from an "IOStream"
|
|
object, and translates them into function callbacks.
|
|
|
|
IOStream abstraction:
|
|
- - - - - - - - - - -
|
|
|
|
The "IOStream" is a very simple abstract class used to send byte messages
|
|
both in the guest and host. It is defined through a shared header under
|
|
$EMUGL/host/include/libOpenglRender/IOStream.h
|
|
|
|
Note that despite the path, this header is included by *both* host and guest
|
|
source code. The main idea around IOStream's design is that to send a message,
|
|
one does the following:
|
|
|
|
1/ call stream->allocBuffer(size), which returns the address of a
|
|
memory buffer of at least 'size' bytes.
|
|
|
|
2/ write the content of the serialized command (usually a header + some
|
|
payload) directly into the buffer
|
|
|
|
3/ call stream->commitBuffer() to send it.
|
|
|
|
Alternatively, one can also pack several commands into a single buffer with
|
|
stream->alloc() and stream->flush(), as in:
|
|
|
|
1/ buf1 = stream->alloc(size1)
|
|
2/ write first command bytes into buf1
|
|
3/ buf2 = stream->alloc(size2)
|
|
4/ write second command bytes into buf2
|
|
5/ stream->flush()
|
|
|
|
Finally, there are also explict read/write methods like stream->readFully()
|
|
or stream->writeFully() which can be used when you don't want an intermediate
|
|
buffer. This is used in certain cases by the implementation, e.g. to avoid
|
|
an intermediate memory copy when sending texture data from the guest to the
|
|
host.
|
|
|
|
The host IOStream implementations are under $EMUGL/shared/OpenglCodecCommon/,
|
|
see in particular:
|
|
|
|
$EMUGL/shared/OpenglCodecCommon/TcpStream.cpp -> using local TCP sockets
|
|
$EMUGL/shared/OpenglCodecCommon/UnixStream.cpp -> using Unix sockets
|
|
$EMUGL/shared/OpenglCodecCommon/Win32PipeStream.cpp -> using Win32 named pipes
|
|
|
|
The guest IOStream implementation uses the TcpStream.cpp above, as well as
|
|
an alternative QEMU-specific source:
|
|
|
|
$EMUGL/system/OpenglSystemCommon/QemuPipeStream.cpp -> uses QEMU pipe from the guest
|
|
|
|
The QEMU Pipe implementation is _significantly_ faster (about 20x) due to
|
|
several reasons:
|
|
|
|
- all succesful read() and write() operations through it are instantaneous
|
|
from the guest's point of view.
|
|
|
|
- all buffer/memory copies are performed directly by the emulator, and thus
|
|
much faster than performing the same thing inside the kernel with emulated
|
|
ARM instructions.
|
|
|
|
- it doesn't need to go through a kernel TCP/IP stack that will wrap the
|
|
data into TCP/IP/MAC packets, send them to an emulated ethernet device,
|
|
which is itself connected to an internal firewall implementation that
|
|
will unwrap the packets, re-assemble them, then send them through BSD
|
|
sockets to the host kernel.
|
|
|
|
However, would it be necessary, you could write a guest IOStream implementation
|
|
that uses a different transport. If you do, please look at
|
|
$EMUGL/system/OpenglCodecCommon/HostConnection.cpp which contains the code
|
|
used to connect the guest to the host, on a per-thread basis.
|
|
|
|
|
|
Source code auto-generation:
|
|
- - - - - - - - - - - - - -
|
|
|
|
The 'emugen' tool is located under $EMUGL/host/tools/emugen. There is a README
|
|
file that explains how it works.
|
|
|
|
You can also look at the following specifications files:
|
|
|
|
For GLES 1.1:
|
|
$EMUGL/system/GLESv1_enc/gl.types
|
|
$EMUGL/system/GLESv1_enc/gl.in
|
|
$EMUGL/system/GLESv1_enc/gl.attrib
|
|
$EMUGL/system/GLESv1_enc/gl.addon
|
|
|
|
For GLES 2.0:
|
|
$EMUGL/system/GLESv2_enc/gl2.types
|
|
$EMUGL/system/GLESv2_enc/gl2.in
|
|
$EMUGL/system/GLESv2_enc/gl2.attrib
|
|
$EMUGL/system/GLESv2_enc/gl2.addon
|
|
|
|
For EGL:
|
|
$EMUGL/system/renderControl_enc/renderControl.types
|
|
$EMUGL/system/renderControl_enc/renderControl.in
|
|
$EMUGL/system/renderControl_enc/renderControl.attrib
|
|
$EMUGL/system/renderControl_enc/renderControl.addon
|
|
|
|
Note that the EGL specification files are under a directory named
|
|
"renderControl_enc" and have filenames that begin with "renderControl"
|
|
|
|
This is mainly for historic reasons now, but is also related to the fact that
|
|
this part of the wire protocol contains support functions/calls/specifications
|
|
that are not part of the EGL specification itself, but add a few features
|
|
required to make everything works. For example, they have calls related to
|
|
the "gralloc" system library module used to manage graphics surfaces at a
|
|
lower level than EGL.
|
|
|
|
Generally speaking, guest encoder sources are located under directories
|
|
named $EMUGL/system/<name>_enc/, while the corresponding host decoder
|
|
sources will be under $EMUGL/host/libs/<name>_dec/
|
|
|
|
However, all these sources use the same spec files located under the
|
|
encoding directories. The decoders may even need to include a few
|
|
non-auto-generated header files from the encoder directories.
|
|
|
|
|
|
|
|
System libraries:
|
|
-----------------
|
|
|
|
Meta EGL/GLES system libraries, and egl.cfg:
|
|
- - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
It is important to understand that the emulation-specific EGL/GLES libraries
|
|
are not directly linked by applications at runtime. Instead, the system
|
|
provides a set of "meta" EGL/GLES libraries that will load the appropriate
|
|
hardware-specific libraries on first use.
|
|
|
|
More specifically, the system libEGL.so contains a "loader" which will try
|
|
to load:
|
|
|
|
- hardware-specific EGL/GLES libraries
|
|
- the software-based rendering libraries (called "libagl")
|
|
|
|
The system libEGL.so is also capable of merging the EGL configs of both the
|
|
hardware and software libraries transparently to the application. The system
|
|
libGLESv1_CM.so and libGLESv2.so, work with it to ensure that the thread's
|
|
current context will be linked to either the hardware or software libraries
|
|
depending on the config selected.
|
|
|
|
For the record, the loader's source code in under
|
|
frameworks/base/opengl/libs/EGL/Loader.cpp. It depends on a file named
|
|
/system/lib/egl/egl.cfg which must contain two lines that look like:
|
|
|
|
0 1 <name>
|
|
0 0 android
|
|
|
|
The first number in each line is a display number, and must be 0 since the
|
|
system's EGL/GLES libraries don't support anything else.
|
|
|
|
The second number must be 1 to indicate hardware libraries, and 0 to indicate
|
|
a software one. The line corresponding to the hardware library, if any, must
|
|
always appear before the one for the software library.
|
|
|
|
The third field is a name corresponding to a shared library suffix. It really
|
|
means that the corresponding libraries will be named libEGL_<name>.so,
|
|
libGLESv1_CM_<name>.so and libGLESv2_<name>.so. Moreover these libraries must
|
|
be placed under /system/lib/egl/
|
|
|
|
The name "android" is reserved for the system software renderer.
|
|
|
|
The egl.cfg that comes with this project uses the name "emulation" for the
|
|
hardware libraries. This means that it provides an egl.cfg file that contains
|
|
the following lines:
|
|
|
|
0 1 emulation
|
|
0 0 android
|
|
|
|
See $EMUGL/system/egl/egl.cfg and more generally the following build files:
|
|
|
|
$EMUGL/system/egl/Android.mk
|
|
$EMUGL/system/GLESv1/Android.mk
|
|
$EMUGL/system/GLESv2/Android.mk
|
|
|
|
to see how the libraries are named and placed under /system/lib/egl/ by the
|
|
build system.
|
|
|
|
|
|
Emulation libraries:
|
|
- - - - - - - - - - -
|
|
|
|
The emulator-specific libraries are under the following:
|
|
|
|
$EMUGL/system/egl/
|
|
$EMUGL/system/GLESv1/
|
|
$EMUGL/system/GLESv2/
|
|
|
|
The code for GLESv1 and GLESv2 is pretty small, since it mostly link against
|
|
the static encoding libraries.
|
|
|
|
The code for EGL is a bit more complex, because it needs to deal with
|
|
extensions dynamically. I.e. if an extension is not available on the host
|
|
it shouldn't be exposed by the library at runtime. So the EGL code queries
|
|
the host for the list of available extensions in order to return them to
|
|
clients. Similarly, it must query the list of valid EGLConfigs for the
|
|
current host system.
|
|
|
|
|
|
"gralloc" module implementation:
|
|
- - - - - - - - - - - - - - - - -
|
|
|
|
In addition to EGL/GLES libraries, the Android system requires a
|
|
hardware-specific library to manage graphics surfaces at a level lower than
|
|
EGL. This library must be what is called in Android land as a "HAL module".
|
|
|
|
A "HAL module" must provide interfaces defined by Android's HAL
|
|
(Hardware Abstraction Library). These interface definitions can be found
|
|
under $ANDROID/hardware/libhardware/include/
|
|
|
|
Of all possible HAL modules, the "gralloc" one is used by the system's
|
|
SurfaceFlinger to allocate framebuffers and other graphics memory regions,
|
|
as well as eventually lock/unlock/swap them when needed.
|
|
|
|
The code under $EMUGL/system/gralloc/ implements the module required by the
|
|
GLES emulation project. It's not very long, but there are a few things to
|
|
notice here:
|
|
|
|
- first, it will probe the guest system to determine if the emulator that
|
|
is running the virtual device really supports GPU emulation. In certain
|
|
circumstances this may not be possible.
|
|
|
|
If this is the case, then the module will redirect all calls to the
|
|
"default" gralloc module that is normally used by the system when
|
|
software-only rendering is enabled.
|
|
|
|
The probing happens in the function "fallback_init" which gets called
|
|
when the module is first opened. This initializes the 'sFallback' variable
|
|
to a pointer to the default gralloc module when required.
|
|
|
|
- second, this module is used by SurfaceFlinger to display "software surfaces",
|
|
i.e. those that are backed by system memory pixel buffers, and written to
|
|
directly through the Skia graphics library (i.e. the non-accelerated ones).
|
|
|
|
the default module simply copies the pixel data from the surface to the
|
|
virtual framebuffer i/o memory, but this project's gralloc module sends it
|
|
to the renderer through the QEMU Pipe instead.
|
|
|
|
It turns out that this results in _faster_ rendering/frame-rates overall,
|
|
because memory copies inside the guest are slow, while QEMU pipe transfers
|
|
are done directly in the emulator.
|
|
|
|
|
|
Host Renderer:
|
|
--------------
|
|
|
|
The host renderer library is located under $EMUGL/host/libs/libOpenglRender,
|
|
and it provides an interface described by the headers under
|
|
$EMUGL/host/include/libOpenglRender/render_api.h (e.g. for use by the emulator).
|
|
|
|
In a nutshell, the rendering library is responsible for the following:
|
|
|
|
- Providing a virtual off-screen video surface where everything will get
|
|
rendered at runtime. Its dimensions are fixed by the call to
|
|
initOpenglRender() that must happen just after the library is
|
|
initialized.
|
|
|
|
- Provide a way to display the virtual video surface on a host application's
|
|
UI. This is done by calling createOpenGLSubWindow() which takes as argument
|
|
the window ID or handle of a parent window, some display dimensions and
|
|
a rotation angle. This allows the surface to be scaled/rotated when it is
|
|
displayed, even if the dimensions of the video surface do not change.
|
|
|
|
- Provide a way to listen to incoming EGL/GLES commands from the guest.
|
|
This is done by providing a so-called "port number" to initOpenglRender().
|
|
|
|
By default, the port number corresponds to a local TCP port number that the
|
|
renderer will bind to and listen. Every new connection to this port will
|
|
correspond to the creation of a new guest host connection, each such
|
|
connection corresponding to a distinct thread in the guest system.
|
|
|
|
For performance reasons, it is possible to listen to either Unix sockets
|
|
(on Linux and OS X), or to a Win32 named pipe (on Windows). To do so, one
|
|
had to call setStreamType() between library initialization
|
|
(i.e. initLibrary()) and construction (i.e. initOpenglRender()).
|
|
|
|
Note that in these modes, the port number is still used to differentiate
|
|
between several emulator instances. These details are normally handled by
|
|
the emulator code so you shouldn't care too much.
|
|
|
|
Note that an earlier version of the interface allowed a client of the renderer
|
|
library to provide its own IOStream implementation. However, this wasn't very
|
|
convenient for a number of reasons. This maybe something that could be done
|
|
again if it makes sense, but for now the performance numbers are pretty good.
|
|
|
|
|
|
Host emulator:
|
|
--------------
|
|
|
|
The code under $QEMU/android/opengles.c is in charge of dynamically loading
|
|
the rendering library and initializing / constructing it properly.
|
|
|
|
QEMU pipe connections to the 'opengles' service are piped through the code
|
|
in $QEMU/android/hw-pipe-net.c. Look for the openglesPipe_init() function,
|
|
which is in charge of creating a connection to the renderer library
|
|
(either through a TCP socket, or a Unix pipe depending on configuration.
|
|
support for Win32 named pipes hasn't been implemented yet in the emulator)
|
|
whenever a guest process opens the "opengles" service through /dev/qemu_pipe.
|
|
|
|
There is also some support code for the display of the GLES framebuffer
|
|
(through the renderer library's subwindow) under $QEMU/skin/window.
|
|
|
|
Note that at the moment, scaling and rotation are supported. However,
|
|
brightness emulation (which used to modify the pixel values from the
|
|
hardware framebuffer before displaying them) doesn't work.
|
|
|
|
Another issue is that it is not possible to display anything on top of the
|
|
GL subwindow at the moment. E.g. this will obscure the emulated trackball
|
|
image (that is normally toggled with Ctrl-T during emulation, or enabled
|
|
by pressing the Delete key).
|
|
|