android: Add OpenGLES emulation support.
BEWARE: Not production quality. This is a working patch. The final
version will probably be splitted into separate patches.
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index f97ecb6..8fcf46d 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -16,6 +16,8 @@
obj-$(CONFIG_ANDROID_PIPE) += android_pipe.o
obj-$(CONFIG_ANDROID_PIPE) += android_pipe_test.o
+obj-$(CONFIG_ANDROID_PIPE) += android_net_pipe.o
+obj-$(CONFIG_ANDROID_PIPE) += android_opengles.o
obj-$(CONFIG_ANDROID_PIPE) += android_adb_dbg.o
obj-$(CONFIG_ANDROID_PIPE) += android_adb.o
diff --git a/hw/misc/android_net_pipe.c b/hw/misc/android_net_pipe.c
new file mode 100644
index 0000000..90d1364
--- /dev/null
+++ b/hw/misc/android_net_pipe.c
@@ -0,0 +1,489 @@
+/* Copyright (C) 2014 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.
+**
+** Description
+**
+** Implementation of 'tcp' and 'unix' Android pipes. These can be used
+** to connect a guest process directly with a host TCP or Unix socket.
+**
+** For TCP, connections are limited to localhost (127.0.0.1) ports for
+** security reasons (doing otherwise might allow any application to
+** sneakily connect to the Internet when running under emulation).
+**
+** This is also used by the 'opengles' Android pipe service to send
+** wire protocol data to the GPU emulation libraries.
+*/
+
+#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+#include "hw/misc/android_pipe.h"
+#include "hw/misc/android_opengles.h"
+
+#include <errno.h>
+//#include <sys/select.h>
+
+/* Set to 1 or 2 for debug traces */
+#define DEBUG 1
+
+#if DEBUG >= 1
+# define D(...) printf(__VA_ARGS__), printf("\n")
+#else
+# define D(...) ((void)0)
+#endif
+
+#if DEBUG >= 2
+# define DD(...) printf(__VA_ARGS__), printf("\n")
+# define DDASSERT(cond) _ANDROID_ASSERT(cond, "Assertion failure: ", #cond)
+# define DDASSERT_INT_OP(cond,val,op) _ANDROID_ASSERT_INT_OP(cond,val,op)
+#else
+# define DD(...) ((void)0)
+# define DDASSERT(cond) ((void)0)
+# define DDASSERT_INT_OP(cond,val,op) ((void)0)
+#endif
+
+#define DDASSERT_INT_LT(cond,val) DDASSERT_INT_OP(cond,val,<)
+#define DDASSERT_INT_LTE(cond,val) DDASSERT_INT_OP(cond,val,<=)
+#define DDASSERT_INT_GT(cond,val) DDASSERT_INT_OP(cond,val,>)
+#define DDASSERT_INT_GTE(cond,val) DDASSERT_INT_OP(cond,val,>=)
+#define DDASSERT_INT_EQ(cond,val) DDASSERT_INT_OP(cond,val,==)
+#define DDASSERT_INT_NEQ(cond,val) DDASSERT_INT_OP(cond,val,!=)
+
+enum {
+ STATE_INIT,
+ STATE_CONNECTING,
+ STATE_CONNECTED,
+ STATE_CLOSING_GUEST,
+ STATE_CLOSING_SOCKET
+};
+
+typedef struct {
+ void *hwpipe;
+ int state;
+ int wakeWanted;
+ int wakeActual;
+ int fd;
+} NetPipe;
+
+/* Free a network pipe */
+static void net_pipe_free(NetPipe *pipe)
+{
+ /* Close the socket */
+ int fd = pipe->fd;
+ if (fd >= 0) {
+ qemu_set_fd_handler(fd, NULL, NULL, NULL);
+ closesocket(fd);
+ pipe->fd = -1;
+ }
+ g_free(pipe);
+}
+
+static void net_pipe_read_handler(void* opaque);
+static void net_pipe_write_handler(void* opaque);
+
+static void net_pipe_reset_state(NetPipe *pipe)
+{
+ IOHandler *read_handler = NULL;
+ IOHandler *write_handler = NULL;
+
+ if ((pipe->wakeWanted & PIPE_WAKE_WRITE) != 0) {
+ write_handler = net_pipe_write_handler;
+ }
+
+ if (pipe->state == STATE_CONNECTED &&
+ (pipe->wakeWanted & PIPE_WAKE_READ) != 0) {
+ read_handler = net_pipe_read_handler;
+ }
+ qemu_set_fd_handler(pipe->fd, read_handler, write_handler, pipe);
+}
+
+static void net_pipe_close_from_socket(void *opaque)
+{
+ NetPipe *pipe = opaque;
+
+ /* If the guest already ordered the pipe to be closed,
+ * delete immediately */
+ if (pipe->state == STATE_CLOSING_GUEST) {
+ net_pipe_free(pipe);
+ return;
+ }
+
+ /* Force the closure of the pipe channel - if a guest is blocked
+ * waiting for a wake signal, it will receive an error. */
+ if (pipe->hwpipe != NULL) {
+ android_pipe_close(pipe->hwpipe);
+ pipe->hwpipe = NULL;
+ }
+
+ pipe->state = STATE_CLOSING_SOCKET;
+ net_pipe_reset_state(pipe);
+}
+
+/* Called when data arrives on the pipe's socket. */
+static void net_pipe_read_handler(void* opaque)
+{
+ NetPipe *pipe = opaque;
+
+ pipe->wakeActual |= PIPE_WAKE_READ;
+ if ((pipe->wakeWanted & PIPE_WAKE_READ) != 0) {
+ android_pipe_wake(pipe->hwpipe, pipe->wakeActual);
+ pipe->wakeWanted &= ~PIPE_WAKE_READ;
+ }
+ net_pipe_reset_state(pipe);
+}
+
+/* Called when the pipe's file socket becomes writable. */
+static void net_pipe_write_handler(void* opaque)
+{
+ NetPipe *pipe = opaque;
+
+ pipe->wakeActual |= PIPE_WAKE_WRITE;
+ if ((pipe->wakeWanted & PIPE_WAKE_WRITE) != 0) {
+ android_pipe_wake(pipe->hwpipe, pipe->wakeActual);
+ pipe->wakeWanted &= ~PIPE_WAKE_WRITE;
+ }
+ net_pipe_reset_state(pipe);
+}
+
+static void net_pipe_close_from_guest(void *opaque)
+{
+ NetPipe *pipe = opaque;
+ net_pipe_free(pipe);
+}
+
+static int net_pipe_ready_send(NetPipe *pipe)
+{
+ if (pipe->state == STATE_CONNECTED) {
+ return 0;
+ } else if (pipe->state == STATE_CONNECTING) {
+ return PIPE_ERROR_AGAIN;
+ } else if (pipe->hwpipe == NULL) {
+ return PIPE_ERROR_INVAL;
+ } else {
+ return PIPE_ERROR_IO;
+ }
+}
+
+static int net_pipe_send_buffers(void* opaque,
+ const AndroidPipeBuffer *buffers,
+ int num_buffers)
+{
+ NetPipe *pipe = opaque;
+
+ int ret = net_pipe_ready_send(pipe);
+ if (ret != 0) {
+ return ret;
+ }
+
+ const AndroidPipeBuffer* buff = buffers;
+ const AndroidPipeBuffer* buff_end = buff + num_buffers;
+ int count = 0;
+ for (; buff < buff_end; ++buff) {
+ count += buff->size;
+ }
+
+ buff = buffers;
+
+ int buff_start = 0;
+ ret = 0;
+ while (count > 0) {
+ int avail = buff->size - buff_start;
+ ssize_t len = send(pipe->fd, (const void*)(buff->data + buff_start), avail, 0);
+
+ if (len > 0) {
+ /* the write succeeded */
+ buff_start += len;
+ if (buff_start >= buff->size) {
+ buff++;
+ buff_start = 0;
+ }
+ count -= (int)len;
+ ret += (int)len;
+ continue;
+ }
+ if (len == 0) {
+ /* reached the end of stream? */
+ if (ret == 0) {
+ ret = PIPE_ERROR_IO;
+ }
+ break;
+ }
+ if (ret > 0) {
+ break;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ ret = PIPE_ERROR_AGAIN;
+ } else {
+ ret = PIPE_ERROR_IO;
+ }
+ break;
+ }
+ return ret;
+}
+
+static int net_pipe_recv_buffers(void *opaque,
+ AndroidPipeBuffer *buffers,
+ int num_buffers)
+{
+ NetPipe *pipe = opaque;
+
+ AndroidPipeBuffer* buff = buffers;
+ AndroidPipeBuffer* buff_end = buff + num_buffers;
+
+ int count = 0;
+ for (; buff < buff_end; ++buff) {
+ count += buff->size;
+ }
+
+ buff = buffers;
+
+ int ret = 0;
+ int buff_start = 0;
+ while (count > 0) {
+ int avail = buff->size - buff_start;
+ ssize_t len = recv(pipe->fd, (void*)(buff->data + buff_start), avail, 0);
+
+ if (len > 0) {
+ /* the read succeeded. */
+ buff_start += len;
+ if (buff_start >= buff->size) {
+ buff++;
+ buff_start = 0;
+ }
+ count -= (int) len;
+ ret += (int) len;
+ continue;
+ }
+
+ if (len == 0) {
+ /* reached the end of stream? */
+ if (ret == 0)
+ ret = PIPE_ERROR_IO;
+ break;
+ }
+
+ if (ret > 0) {
+ /* if data was already read, just return it. */
+ break;
+ }
+
+ /* need to return an appropriate error code. */
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ ret = PIPE_ERROR_AGAIN;
+ } else {
+ ret = PIPE_ERROR_IO;
+ }
+ break;
+ }
+ return ret;
+}
+
+static unsigned net_pipe_poll(void *opaque)
+{
+ NetPipe *pipe = opaque;
+#if 1
+ return pipe->wakeActual;
+#else
+ unsigned result = 0;
+
+ do {
+ fd_set read_fds, write_fds;
+ struct timeval tv = {0, 0};
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&write_fds);
+ FD_SET(fd, &read_fds);
+ FD_SET(fd, &write_fds);
+ ret = select(fd + 1, &read_fds, &write_fds, NULL, &tv);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret == 1) {
+ if (FD_ISSET(fd, &read_fds)) {
+ result |= PIPE_WAKE_READ;
+ }
+ if (FD_ISSET(fd, &write_fds)) {
+ result |= PIPE_WAKE_WRITE;
+ }
+ }
+#endif
+ return 0;
+}
+
+static void net_pipe_wake_on(void *opaque, int flags)
+{
+ NetPipe *pipe = opaque;
+
+ DD("%s: flags=%d", __FUNCTION__, flags);
+
+ pipe->wakeWanted |= flags;
+ pipe->wakeActual &= ~flags;
+ net_pipe_reset_state(pipe);
+}
+
+/* Called when the pipe finished connecting to its target. |fd| will be -1
+ * to indicate that the connection failed. */
+static void net_pipe_connect_handler(int fd, void* opaque)
+{
+ NetPipe *pipe = opaque;
+
+ if (fd < 0) {
+ net_pipe_close_from_socket(pipe);
+ return;
+ }
+
+ pipe->state = STATE_CONNECTED;
+ net_pipe_reset_state(pipe);
+}
+
+static void *net_pipe_init_from(void *hwpipe,
+ const char* args,
+ bool is_unix)
+{
+ if (args == NULL || args[0] == '\0') {
+ D("%s: Missing address!", __FUNCTION__);
+ return NULL;
+ }
+
+ NetPipe *pipe = (NetPipe *)g_new0(NetPipe, 1);
+ pipe->hwpipe = hwpipe;
+ pipe->state = STATE_CONNECTING;
+
+ Error *err = NULL;
+
+ if (is_unix) {
+ D("%s: Unix path is '%s'", __FUNCTION__, args);
+ pipe->fd = unix_nonblocking_connect(args,
+ net_pipe_connect_handler,
+ pipe,
+ &err);
+ if (pipe->fd < 0) {
+ D("%s: Could not connect pipe to %s: %s\n",
+ __FUNCTION__, args, error_get_pretty(err));
+ }
+ } else {
+ D("%s: TCP port is '%s'", __FUNCTION__, args);
+
+ char address[64];
+ snprintf(address, sizeof(address), "127.0.0.1:%s", args);
+
+ pipe->fd = inet_nonblocking_connect(address,
+ net_pipe_connect_handler,
+ pipe,
+ &err);
+ if (pipe->fd < 0) {
+ D("%s: Could not connect pipe to %s: %s\n",
+ __FUNCTION__, address, error_get_pretty(err));
+ }
+ }
+
+ if (pipe->fd < 0) {
+ error_free(err);
+ g_free(pipe);
+ return NULL;
+ }
+
+ return pipe;
+}
+
+static void *net_pipe_init_tcp(void *hwpipe, void *opaque, const char *args)
+{
+ return net_pipe_init_from(hwpipe, args, false);
+}
+
+#ifndef _WIN32
+static void *net_pipe_init_unix(void *hwpipe, void *opaque, const char *args)
+{
+ return net_pipe_init_from(hwpipe, args, true);
+}
+#endif
+
+static const AndroidPipeFuncs net_pipe_tcp_funcs = {
+ net_pipe_init_tcp,
+ net_pipe_close_from_guest,
+ net_pipe_send_buffers,
+ net_pipe_recv_buffers,
+ net_pipe_poll,
+ net_pipe_wake_on,
+ NULL, /* we can't save these */
+ NULL, /* we can't load these */
+};
+
+#ifndef _WIN32
+static const AndroidPipeFuncs net_pipe_unix_funcs = {
+ net_pipe_init_unix,
+ net_pipe_close_from_guest,
+ net_pipe_send_buffers,
+ net_pipe_recv_buffers,
+ net_pipe_poll,
+ net_pipe_wake_on,
+ NULL, /* we can't save these */
+ NULL, /* we can't load these */
+};
+#endif
+
+static void *opengles_pipe_init(void *hwpipe,
+ void *opaque,
+ const char *args)
+{
+ char server_addr[PATH_MAX];
+ android_gles_server_path(server_addr, sizeof(server_addr));
+ NetPipe *pipe;
+#ifndef _WIN32
+ // Use a Unix pipe on Posix systems.
+ pipe = (NetPipe *)net_pipe_init_unix(hwpipe, opaque, server_addr);
+#else
+ // Use a TCP pipe on Windows.
+ pipe = (NetPipe *)net_pipe_init_tcp(hwpipe, opaque, server_addr);
+#endif
+ if (!pipe) {
+ return NULL;
+ }
+
+ // Disable TCP nagle algorithm to improve through put of small
+ // packets.
+ socket_set_nodelay(pipe->fd);
+
+#ifdef _WIN32
+ // On Windows, adjust buffer sizes.
+ int sndbuf = 128 * 1024;
+ int len = sizeof(sndbuf);
+ if (setsockopt(pipe->fd,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ (char *)&sndbuf,
+ (int) sizeof(sndbuf)) == SOCKET_ERROR) {
+ D("Failed to set SO_SNDBUF to %d error=0x%x\n",
+ sndbuf, WSAGetLastError());
+ }
+#endif
+ return pipe;
+}
+
+static const AndroidPipeFuncs opengles_pipe_funcs = {
+ opengles_pipe_init,
+ net_pipe_close_from_guest,
+ net_pipe_send_buffers,
+ net_pipe_recv_buffers,
+ net_pipe_poll,
+ net_pipe_wake_on,
+ NULL, /* we can't save these */
+ NULL, /* we can't save these */
+};
+
+void
+android_net_pipe_init(void)
+{
+ android_pipe_add_type("tcp", NULL, &net_pipe_tcp_funcs);
+#ifndef _WIN32
+ android_pipe_add_type("unix", NULL, &net_pipe_unix_funcs);
+#endif
+ android_pipe_add_type("opengles", NULL, &opengles_pipe_funcs);
+}
+
diff --git a/hw/misc/android_opengles.c b/hw/misc/android_opengles.c
new file mode 100644
index 0000000..6e12303
--- /dev/null
+++ b/hw/misc/android_opengles.c
@@ -0,0 +1,375 @@
+/*
+ * ARM Android emulator OpenGLES backend
+ *
+ * Copyright (c) 2014 Android Open Source Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Handle connections to the 'opengles' pipe from Android guests and route
+ * traffic over this pipe to the GPU emulation libraries.
+ */
+
+#include "hw/misc/android_opengles.h"
+#include "hw/misc/android_pipe.h"
+#include "qemu/compiler.h"
+#include "qemu-common.h"
+
+#include <limits.h>
+
+#ifdef _WIN32
+#include <errno.h>
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+
+// #define DEBUG_OPENGLES
+
+#ifdef DEBUG_OPENGLES
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "adb_debug: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+// Loading shared libraries and probing their symbols.
+typedef struct DynamicLibrary DynamicLibrary;
+
+static DynamicLibrary* dynamic_library_open(const char* library_name)
+{
+ char path[PATH_MAX];
+
+#ifdef _WIN32
+ static const char kDllExtension[] = ".dll";
+#elif defined(__APPLE__)
+ static const char kDllExtension[] = ".dylib";
+#else
+ static const char kDllExtension[] = ".so";
+#endif
+ if (!strchr(library_name, '.')) {
+ snprintf(path, sizeof path, "%s%s", library_name, kDllExtension);
+ } else {
+ snprintf(path, sizeof path, "%s", library_name);
+ }
+#ifdef _WIN32
+ return (DynamicLibrary*)LoadLibrary(path);
+#else
+ return (DynamicLibrary*)dlopen(path, RTLD_NOW);
+#endif
+}
+
+static void dynamic_library_close(DynamicLibrary* library)
+{
+#ifdef _WIN32
+ if (library) {
+ FreeLibrary((HMODULE)library);
+ }
+#else
+ if (library) {
+ dlclose(library);
+ }
+#endif
+}
+
+static void* dynamic_library_probe(DynamicLibrary* library,
+ const char* symbol)
+{
+ if (!library || !symbol || !symbol[0]) {
+ return NULL;
+ }
+#ifdef _WIN32
+ return GetProcAddress((HMODULE)library, symbol);
+#else
+ return dlsym(library, symbol);
+#endif
+}
+
+//
+// Loading the GPU shared libraries
+//
+
+// Name of the GLES rendering library we're going to use.
+#if UINTPTR_MAX == UINT32_MAX
+#define RENDERER_LIB_NAME "libOpenglRender"
+#elif UINTPTR_MAX == UINT64_MAX
+#define RENDERER_LIB_NAME "lib64OpenglRender"
+#else
+#error Unknown UINTPTR_MAX
+#endif
+
+// NOTE: The declarations below should be equivalent to those in
+// <libOpenglRender/render_api_platform_types.h>
+#ifdef _WIN32
+typedef HDC FBNativeDisplayType;
+typedef HWND FBNativeWindowType;
+#elif defined(__linux__)
+// Really a Window, which is defined as 32-bit unsigned long on all platforms
+// but we don't want to include the X11 headers here.
+typedef uint32_t FBNativeWindowType;
+#elif defined(__APPLE__)
+typedef void* FBNativeWindowType;
+#else
+#warning "unsupported platform"
+#endif
+
+// List of GPU emulation library functions.
+#define RENDERER_FUNCTIONS_LIST \
+ FUNCTION_(int, initLibrary, (void)) \
+ FUNCTION_(int, setStreamMode, (int mode)) \
+ FUNCTION_(int, initOpenGLRenderer, (int width, int height, char* addr, size_t addrLen)) \
+ FUNCTION_(void, getHardwareStrings, (const char** vendors, const char** renderer, const char** version)) \
+ FUNCTION_(void, setPostCallback, (AndroidGLESOnPostFunc onPost, void* onPostContext)) \
+ FUNCTION_(int, createOpenGLSubwindow, (FBNativeWindowType window, int x, int y, int width, int height, float zRot)) \
+ FUNCTION_(int, destroyOpenGLSubwindow, (void)) \
+ FUNCTION_(void, setOpenGLDisplayRotation, (float zRot)) \
+ FUNCTION_(void, repaintOpenGLDisplay, (void)) \
+ FUNCTION_(int, stopOpenGLRenderer, (void)) \
+
+// Name of static variable that points to symbol |name| in the GPU
+// emulation library.
+#define EMUGL_WRAPPER(name) emugl_ ## name
+
+// Define the corresponding function pointers as global variables, with
+// an 'emugl_' prefix.
+#define FUNCTION_(ret, name, sig) \
+ static ret (*EMUGL_WRAPPER(name)) sig = NULL;
+RENDERER_FUNCTIONS_LIST
+#undef FUNCTION_
+
+
+// Define a function that initializes the function pointers by looking up
+// the symbols from the shared library.
+static int init_opengles_emulation_functions(DynamicLibrary* library)
+{
+ void *symbol;
+
+#define FUNCTION_(ret, name, sig) \
+ symbol = dynamic_library_probe(library, #name); \
+ if (!symbol) { \
+ DPRINTF("GLES emulation: Could not find required symbol (%s): %s\n", #name); \
+ return -1; \
+ } \
+ EMUGL_WRAPPER(name) = symbol;
+
+RENDERER_FUNCTIONS_LIST
+#undef FUNCTION_
+
+ return 0;
+}
+
+// list of constants to be passed to setStreamMode, which determines how
+// to send/receive wire protocol data to/from the library.
+// DEFAULT -> try to use the best for the current platform.
+// TCP -> use a TCP socket to send the protocol bytes to the library.
+// UNIX -> use a Unix domain socket (faster than TCP, but Unix-only).
+// WIN32_PIPE -> use a Win32 PIPE (unsupported by the library for now!).
+enum {
+ STREAM_MODE_DEFAULT = 0,
+ STREAM_MODE_TCP = 1,
+ STREAM_MODE_UNIX = 2,
+ STREAM_MODE_WIN32_PIPE = 3,
+};
+
+struct AndroidGLES {
+ bool init;
+ DynamicLibrary* renderer_lib;
+ bool renderer_started;
+ char renderer_address[256];
+};
+
+static AndroidGLES sState = {
+ .init = false,
+ .renderer_lib = NULL,
+ .renderer_started = false,
+};
+
+AndroidGLES* android_gles_init(void)
+{
+ AndroidGLES* state = &sState;
+
+ if (state->init) {
+ return state;
+ }
+
+ // Try to load the library.
+ state->renderer_lib = dynamic_library_open(RENDERER_LIB_NAME);
+ if (!state->renderer_lib) {
+ DPRINTF("Could not load GPU emulation library!\n");
+ return NULL;
+ }
+
+ // Resolve all required symbols from it.
+ if (init_opengles_emulation_functions(state->renderer_lib) < 0) {
+ DPRINTF("OpenGLES emulation library mismatch. Bes ure to use the correct version!\n");
+ goto BAD_EXIT;
+ }
+
+ // Call its initialization function.
+ if (!EMUGL_WRAPPER(initLibrary)()) {
+ DPRINTF("OpenGLES initialization failed!\n");
+ goto BAD_EXIT;
+ }
+
+#ifdef _WIN32
+ // NOTE: Win32 PIPE support is still not implemented.
+ EMUGL_WRAPPER(setStreamMode)(STREAM_MODE_TCP);
+#else
+ EMUGL_WRAPPER(setStreamMode)(STREAM_MODE_UNIX);
+#endif
+
+ state->init = true;
+ return state;
+
+BAD_EXIT:
+ DPRINTF("OpenGLES library could not be initialized\n");
+ dynamic_library_close(state->renderer_lib);
+
+ state->renderer_lib = NULL;
+ return NULL;
+}
+
+static void extract_base_string(char* dst, const char* src, size_t dstSize)
+{
+ const char* begin = strchr(src, '(');
+ const char* end = strrchr(src, ')');
+
+ if (!begin || !end) {
+ pstrcpy(dst, dstSize, src);
+ return;
+ }
+ begin += 1;
+
+ // "foo (bar)"
+ // ^ ^
+ // b e
+ // = 5 8
+ // substring with NUL-terminator is end-begin+1 bytes
+ if (end - begin + 1 > dstSize) {
+ end = begin + dstSize - 1;
+ }
+
+ pstrcpy(dst, end - begin + 1, begin);
+}
+
+void android_gles_get_hardware_strings(char *vendor,
+ size_t vendor_buffer_size,
+ char *renderer,
+ size_t renderer_buffer_size,
+ char *version,
+ size_t version_buffer_size)
+{
+ const char *vendor_src, *renderer_src, *version_src;
+ AndroidGLES *state = &sState;
+
+ if (!state->renderer_started) {
+ DPRINTF("Can't get OpenGL ES hardware strings when renderer not started");
+ vendor[0] = renderer[0] = version[0] = '\0';
+ return;
+ }
+
+ EMUGL_WRAPPER(getHardwareStrings)(&vendor_src,
+ &renderer_src,
+ &version_src);
+ if (!vendor_src) vendor_src = "";
+ if (!renderer_src) renderer_src = "";
+ if (!version_src) version_src = "";
+
+ /* Special case for the default ES to GL translators: extract the strings
+ * of the underlying OpenGL implementation. */
+ if (strncmp(vendor_src, "Google", 6) == 0 &&
+ strncmp(renderer_src, "Android Emulator OpenGL ES Translator", 37) == 0) {
+ extract_base_string(vendor, vendor_src, vendor_buffer_size);
+ extract_base_string(renderer, renderer_src, renderer_buffer_size);
+ extract_base_string(version, version_src, version_buffer_size);
+ } else {
+ pstrcpy(vendor, vendor_buffer_size, vendor_src);
+ pstrcpy(renderer, renderer_buffer_size, renderer_src);
+ pstrcpy(version, version_buffer_size, version_src);
+ }
+}
+
+int android_gles_start(AndroidGLES* state, int width, int height)
+{
+ if (!state->renderer_lib) {
+ DPRINTF("Can't start OpenGLES renderer without support libraries\n");
+ return -1;
+ }
+
+ if (state->renderer_started) {
+ // Already started.
+ return 0;
+ }
+
+ if (!EMUGL_WRAPPER(initOpenGLRenderer)(
+ width,
+ height,
+ state->renderer_address,
+ sizeof(state->renderer_address))) {
+ DPRINTF("Can't start OpenGLES renderer !?\n");
+ return -1;
+ }
+
+ state->renderer_started = true;
+ return 0;
+}
+
+void android_gles_set_post_callback(AndroidGLES* state,
+ AndroidGLESOnPostFunc on_post,
+ void* on_post_context)
+{
+ if (state->renderer_lib) {
+ EMUGL_WRAPPER(setPostCallback)(on_post, on_post_context);
+ }
+}
+
+int android_gles_show_window(AndroidGLES* state,
+ void* window,
+ int x,
+ int y,
+ int width,
+ int height,
+ float rotation)
+{
+ if (state->renderer_started) {
+ int success = EMUGL_WRAPPER(createOpenGLSubwindow)(
+ (FBNativeWindowType)(uintptr_t)window,
+ x,
+ y,
+ width,
+ height,
+ rotation);
+ return success ? 0 : -1;
+ } else {
+ return -1;
+ }
+}
+
+void android_gles_hide_window(AndroidGLES* state)
+{
+ if (state->renderer_started) {
+ EMUGL_WRAPPER(destroyOpenGLSubwindow)();
+ }
+}
+
+void android_gles_redraw_window(AndroidGLES* state) {
+ if (state->renderer_started) {
+ EMUGL_WRAPPER(repaintOpenGLDisplay)();
+ }
+}
+
+void android_gles_server_path(char* buff, size_t buff_size)
+{
+ AndroidGLES *state = &sState;
+ pstrcpy(buff, buff_size, state->renderer_address);
+}
diff --git a/include/hw/misc/android_opengles.h b/include/hw/misc/android_opengles.h
new file mode 100644
index 0000000..5a5b59b
--- /dev/null
+++ b/include/hw/misc/android_opengles.h
@@ -0,0 +1,149 @@
+/*
+ * ARM Android emulator OpenGLES backend
+ *
+ * Copyright (c) 2014 Android Open Source Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Handle connections to the 'opengles' pipe from Android guests and route
+ * traffic over this pipe to the GPU emulation libraries.
+ */
+
+ #ifndef _HW_MISC_ANDROID_OPENGLES_H
+ #define _HW_MISC_ANDROID_OPENGLES_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Declarations related to Android-specific GPU emulation support.
+ *
+ * This works as follows:
+ *
+ * - GPU emulation support is implemented by an external shared library
+ * (e.g. libOpenglRender.so on Linux), which provides a small set of
+ * well-known entry points.
+ *
+ * - QEMU itself acts as a 'dumb pipe' between the guest system, and
+ * the GPU emulation library. More specifically:
+ *
+ * o The guest EGL/GLES system libraries marshall all requests into
+ * a specific wire protocol stream of bytes. The corresponding data is
+ * sent directly to QEMU through the "opengles" Android pipe service.
+ *
+ * o QEMU sends the data directly to the GPU emulation library,
+ * without trying to process or interpret it. Note that traffic goes
+ * both ways.
+ *
+ * This design avoids the need for a specific GPU driver in the kernel,
+ * or any knowledge of the wire protocol being used in QEMU itself.
+ *
+ * - The GPU emulation library will display an OpenGL window _on_ _top_ of
+ * the current window, which will hide the framebuffer completely.
+ *
+ * To do so, QEMU needs to provide the platform-specific 'id' of the
+ * current window. See android_gles_show_window() documentation for
+ * more details.
+ */
+
+/* Opaque data structure modelling the state of GPU emulation support for
+ * Android. */
+typedef struct AndroidGLES AndroidGLES;
+
+/* Initialize the Android GPU emulation support. This function tries to
+ * locate, load and initialize the GPU emulation library, and returns,
+ * on success, a new AndroidGLES instance that can be used to call other
+ * functions below. Return NULL/errno on failure.
+ */
+AndroidGLES* android_gles_init(void);
+
+/* Start GPU emulation support. Returns 0 on success, -1/errno on failure. */
+int android_gles_start(AndroidGLES* state, int width, int height);
+
+/* Retrieve the Vendor/Renderer/Version strings describing the underlying GL
+ * implementation. The call only works while the renderer is started.
+ *
+ * Each string is copied into the corresponding buffer. If the original
+ * string (including NUL terminator) is more than xxBufSize bytes, it will
+ * be truncated. In all cases, including failure, the buffer will be NUL-
+ * terminated when this function returns.
+ */
+void android_gles_get_hardware_strings(char *vendor,
+ size_t vendor_buffer_size,
+ char *renderer,
+ size_t renderer_buffer_size,
+ char *version,
+ size_t version_buffer_size);
+
+/* Pointer type to a function used to retrieve the content of
+ * GPU framebuffer content. This is used in the Android emulator
+ * to support displaying the framebuffer content to a remote device
+ * for multi-touch support.
+ * |context| is a client-provided value passed to
+ * android_gles_set_post_callback().
+ */
+typedef void (*AndroidGLESOnPostFunc)(void *context,
+ int width,
+ int height,
+ int ydir,
+ int format,
+ int type,
+ unsigned char *pixels);
+
+/* Enable GPU framebuffer retrieval. If |on_post| is not NULL, it will
+ * be called periodically when the framebuffer content changes. Note that
+ * each call can be very expensive, depending on the host GPU.
+ * Set |on_post| to NULL to disable the feature at runtime.
+ */
+void android_gles_set_post_callback(AndroidGLES *gles,
+ AndroidGLESOnPostFunc on_post,
+ void* on_post_context);
+
+/* Show an OpenGL window on top of the current QEMU UI window, at a
+ * specific location.
+ * |gles| is the current AndroidGLES state.
+ * |window| is a platform-specific identifier for the current UI window
+ * (see note below).
+ * |x|, |y|, |width| and |height| provide the location and size of the
+ * OpenGL window, relative to the current one.
+ * |rotation| is used to provide a rotation angle. Valid values are
+ * 0, 90, 180 and 270.
+ * Returns 0 on success, -1/errno on failure.
+ *
+ * NOTE: The exact type and meaning of |window| depends on the platform:
+ * - On Windows, this is the HWND of the current UI window.
+ * - On Linux, it's the X11 Window identifier (really a uint32_t cast
+ * to void*).
+ * - On OS X, it's a NSWindow* value.
+ */
+int android_gles_show_window(AndroidGLES *gles,
+ void *window,
+ int x,
+ int y,
+ int width,
+ int height,
+ float rotation);
+
+/* Hide the OpenGL window. */
+void android_gles_hide_window(AndroidGLES *gles);
+
+void android_gles_redraw_window(AndroidGLES *gles);
+
+/* Stop GPU emulation support. */
+void android_gles_stop(AndroidGLES *gles);
+
+/* Write the local GPU server path into buffer |buff| of
+ * |buff_size| bytes. Result is zero-terminated. */
+void android_gles_server_path(char *buff, size_t buff_size);
+
+#endif /* _HW_MISC_ANDROID_OPENGLES_H */
diff --git a/include/hw/misc/android_pipe.h b/include/hw/misc/android_pipe.h
index 962f2e9..cfba64a 100644
--- a/include/hw/misc/android_pipe.h
+++ b/include/hw/misc/android_pipe.h
@@ -222,6 +222,7 @@
extern void android_throttle_init(void);
extern void android_adb_dbg_backend_init(void);
extern void android_adb_backend_init(void);
+extern void android_net_pipe_init(void);
extern bool adb_server_init(int port);