diff options
Diffstat (limited to 'tools/emulator/opengl/system/OpenglSystemCommon')
9 files changed, 707 insertions, 0 deletions
diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/Android.mk b/tools/emulator/opengl/system/OpenglSystemCommon/Android.mk new file mode 100644 index 000000000..61987489c --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) + +$(call emugl-begin-shared-library,libOpenglSystemCommon) +$(call emugl-import,libGLESv1_enc libGLESv2_enc lib_renderControl_enc) + +LOCAL_SRC_FILES := \ + HostConnection.cpp \ + QemuPipeStream.cpp \ + ThreadInfo.cpp + +$(call emugl-export,C_INCLUDES,$(LOCAL_PATH) bionic/libc/private) + +$(call emugl-end-module) diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h b/tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h new file mode 100644 index 000000000..3c8cb5535 --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h @@ -0,0 +1,41 @@ +/* +* Copyright 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef _SYSTEM_COMMON_EGL_CLIENT_IFACE_H +#define _SYSTEM_COMMON_EGL_CLIENT_IFACE_H + +struct EGLThreadInfo; // defined in ThreadInfo.h + +typedef struct { + EGLThreadInfo* (*getThreadInfo)(); + const char* (*getGLString)(int glEnum); +} EGLClient_eglInterface; + +typedef struct { + void* (*getProcAddress)(const char *funcName); + void (*init)(); + void (*finish)(); +} EGLClient_glesInterface; + +// +// Any GLES/GLES2 client API library should define a function named "init_emul_gles" +// with the following prototype, +// It will be called by EGL after loading the GLES library for initialization +// and exchanging interface function pointers. +// +typedef EGLClient_glesInterface *(*init_emul_gles_t)(EGLClient_eglInterface *eglIface); + +#endif diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/HostConnection.cpp b/tools/emulator/opengl/system/OpenglSystemCommon/HostConnection.cpp new file mode 100644 index 000000000..940f5aeab --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/HostConnection.cpp @@ -0,0 +1,153 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "HostConnection.h" +#include "TcpStream.h" +#include "QemuPipeStream.h" +#include "ThreadInfo.h" +#include <cutils/log.h> +#include "GLEncoder.h" +#include "GL2Encoder.h" + +#define STREAM_BUFFER_SIZE 4*1024*1024 +#define STREAM_PORT_NUM 22468 + +/* Set to 1 to use a QEMU pipe, or 0 for a TCP connection */ +#define USE_QEMU_PIPE 1 + +HostConnection::HostConnection() : + m_stream(NULL), + m_glEnc(NULL), + m_gl2Enc(NULL), + m_rcEnc(NULL) +{ +} + +HostConnection::~HostConnection() +{ + delete m_stream; + delete m_glEnc; + delete m_gl2Enc; + delete m_rcEnc; +} + +HostConnection *HostConnection::get() +{ + /* TODO: Make this configurable with a system property */ + const int useQemuPipe = USE_QEMU_PIPE; + + // Get thread info + EGLThreadInfo *tinfo = getEGLThreadInfo(); + if (!tinfo) { + return NULL; + } + + if (tinfo->hostConn == NULL) { + HostConnection *con = new HostConnection(); + if (NULL == con) { + return NULL; + } + + if (useQemuPipe) { + QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE); + if (!stream) { + ALOGE("Failed to create QemuPipeStream for host connection!!!\n"); + delete con; + return NULL; + } + if (stream->connect() < 0) { + ALOGE("Failed to connect to host (QemuPipeStream)!!!\n"); + delete stream; + delete con; + return NULL; + } + con->m_stream = stream; + } + else /* !useQemuPipe */ + { + TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE); + if (!stream) { + ALOGE("Failed to create TcpStream for host connection!!!\n"); + delete con; + return NULL; + } + + if (stream->connect("10.0.2.2", STREAM_PORT_NUM) < 0) { + ALOGE("Failed to connect to host (TcpStream)!!!\n"); + delete stream; + delete con; + return NULL; + } + con->m_stream = stream; + } + + // send zero 'clientFlags' to the host. + unsigned int *pClientFlags = + (unsigned int *)con->m_stream->allocBuffer(sizeof(unsigned int)); + *pClientFlags = 0; + con->m_stream->commitBuffer(sizeof(unsigned int)); + + ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n", con, gettid()); + tinfo->hostConn = con; + } + + return tinfo->hostConn; +} + +GLEncoder *HostConnection::glEncoder() +{ + if (!m_glEnc) { + m_glEnc = new GLEncoder(m_stream); + DBG("HostConnection::glEncoder new encoder %p, tid %d", m_glEnc, gettid()); + m_glEnc->setContextAccessor(s_getGLContext); + } + return m_glEnc; +} + +GL2Encoder *HostConnection::gl2Encoder() +{ + if (!m_gl2Enc) { + m_gl2Enc = new GL2Encoder(m_stream); + DBG("HostConnection::gl2Encoder new encoder %p, tid %d", m_gl2Enc, gettid()); + m_gl2Enc->setContextAccessor(s_getGL2Context); + } + return m_gl2Enc; +} + +renderControl_encoder_context_t *HostConnection::rcEncoder() +{ + if (!m_rcEnc) { + m_rcEnc = new renderControl_encoder_context_t(m_stream); + } + return m_rcEnc; +} + +gl_client_context_t *HostConnection::s_getGLContext() +{ + EGLThreadInfo *ti = getEGLThreadInfo(); + if (ti->hostConn) { + return ti->hostConn->m_glEnc; + } + return NULL; +} + +gl2_client_context_t *HostConnection::s_getGL2Context() +{ + EGLThreadInfo *ti = getEGLThreadInfo(); + if (ti->hostConn) { + return ti->hostConn->m_gl2Enc; + } + return NULL; +} diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/HostConnection.h b/tools/emulator/opengl/system/OpenglSystemCommon/HostConnection.h new file mode 100644 index 000000000..e7a5ac448 --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/HostConnection.h @@ -0,0 +1,55 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __COMMON_HOST_CONNECTION_H +#define __COMMON_HOST_CONNECTION_H + +#include "IOStream.h" +#include "renderControl_enc.h" + +class GLEncoder; +class gl_client_context_t; +class GL2Encoder; +class gl2_client_context_t; + +class HostConnection +{ +public: + static HostConnection *get(); + ~HostConnection(); + + GLEncoder *glEncoder(); + GL2Encoder *gl2Encoder(); + renderControl_encoder_context_t *rcEncoder(); + + void flush() { + if (m_stream) { + m_stream->flush(); + } + } + +private: + HostConnection(); + static gl_client_context_t *s_getGLContext(); + static gl2_client_context_t *s_getGL2Context(); + +private: + IOStream *m_stream; + GLEncoder *m_glEnc; + GL2Encoder *m_gl2Enc; + renderControl_encoder_context_t *m_rcEnc; +}; + +#endif diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.cpp b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.cpp new file mode 100644 index 000000000..50c3d8bb1 --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.cpp @@ -0,0 +1,190 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "QemuPipeStream.h" +#include <hardware/qemu_pipe.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +QemuPipeStream::QemuPipeStream(size_t bufSize) : + IOStream(bufSize), + m_sock(-1), + m_bufsize(bufSize), + m_buf(NULL) +{ +} + +QemuPipeStream::QemuPipeStream(int sock, size_t bufSize) : + IOStream(bufSize), + m_sock(sock), + m_bufsize(bufSize), + m_buf(NULL) +{ +} + +QemuPipeStream::~QemuPipeStream() +{ + if (m_sock >= 0) { + ::close(m_sock); + } + if (m_buf != NULL) { + free(m_buf); + } +} + + +int QemuPipeStream::connect(void) +{ + m_sock = qemu_pipe_open("opengles"); + if (!valid()) return -1; + return 0; +} + +void *QemuPipeStream::allocBuffer(size_t minSize) +{ + size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize); + if (!m_buf) { + m_buf = (unsigned char *)malloc(allocSize); + } + else if (m_bufsize < allocSize) { + unsigned char *p = (unsigned char *)realloc(m_buf, allocSize); + if (p != NULL) { + m_buf = p; + m_bufsize = allocSize; + } else { + ERR("realloc (%d) failed\n", allocSize); + free(m_buf); + m_buf = NULL; + m_bufsize = 0; + } + } + + return m_buf; +}; + +int QemuPipeStream::commitBuffer(size_t size) +{ + return writeFully(m_buf, size); +} + +int QemuPipeStream::writeFully(const void *buf, size_t len) +{ + //DBG(">> QemuPipeStream::writeFully %d\n", len); + if (!valid()) return -1; + + size_t res = len; + int retval = 0; + + while (res > 0) { + ssize_t stat = ::write(m_sock, (const char *)(buf) + (len - res), res); + if (stat > 0) { + res -= stat; + continue; + } + if (stat == 0) { /* EOF */ + ERR("QemuPipeStream::writeFully failed: premature EOF\n"); + retval = -1; + break; + } + if (errno == EINTR) { + continue; + } + retval = stat; + ERR("QemuPipeStream::writeFully failed: %s\n", strerror(errno)); + break; + } + //DBG("<< QemuPipeStream::writeFully %d\n", len ); + return retval; +} + +const unsigned char *QemuPipeStream::readFully(void *buf, size_t len) +{ + //DBG(">> QemuPipeStream::readFully %d\n", len); + if (!valid()) return NULL; + if (!buf) { + if (len>0) ERR("QemuPipeStream::readFully failed, buf=NULL, len %d", len); + return NULL; // do not allow NULL buf in that implementation + } + size_t res = len; + while (res > 0) { + ssize_t stat = ::read(m_sock, (char *)(buf) + len - res, len); + if (stat == 0) { + // client shutdown; + return NULL; + } else if (stat < 0) { + if (errno == EINTR) { + continue; + } else { + ERR("QemuPipeStream::readFully failed (buf %p): %s\n", + buf, strerror(errno)); + return NULL; + } + } else { + res -= stat; + } + } + //DBG("<< QemuPipeStream::readFully %d\n", len); + return (const unsigned char *)buf; +} + +const unsigned char *QemuPipeStream::read( void *buf, size_t *inout_len) +{ + //DBG(">> QemuPipeStream::read %d\n", *inout_len); + if (!valid()) return NULL; + if (!buf) { + ERR("QemuPipeStream::read failed, buf=NULL"); + return NULL; // do not allow NULL buf in that implementation + } + + int n = recv(buf, *inout_len); + + if (n > 0) { + *inout_len = n; + return (const unsigned char *)buf; + } + + //DBG("<< QemuPipeStream::read %d\n", *inout_len); + return NULL; +} + +int QemuPipeStream::recv(void *buf, size_t len) +{ + if (!valid()) return int(ERR_INVALID_SOCKET); + char* p = (char *)buf; + int ret = 0; + while(len > 0) { + int res = ::read(m_sock, p, len); + if (res > 0) { + p += res; + ret += res; + len -= res; + continue; + } + if (res == 0) { /* EOF */ + break; + } + if (errno == EINTR) + continue; + + /* A real error */ + if (ret == 0) + ret = -1; + break; + } + return ret; +} diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h new file mode 100644 index 000000000..57ee399b4 --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __QEMU_PIPE_STREAM_H +#define __QEMU_PIPE_STREAM_H + +/* This file implements an IOStream that uses a QEMU fast-pipe + * to communicate with the emulator's 'opengles' service. See + * <hardware/qemu_pipe.h> for more details. + */ +#include <stdlib.h> +#include "IOStream.h" + +class QemuPipeStream : public IOStream { +public: + typedef enum { ERR_INVALID_SOCKET = -1000 } QemuPipeStreamError; + + explicit QemuPipeStream(size_t bufsize = 10000); + ~QemuPipeStream(); + int connect(void); + + virtual void *allocBuffer(size_t minSize); + virtual int commitBuffer(size_t size); + virtual const unsigned char *readFully( void *buf, size_t len); + virtual const unsigned char *read( void *buf, size_t *inout_len); + + bool valid() { return m_sock >= 0; } + int recv(void *buf, size_t len); + + virtual int writeFully(const void *buf, size_t len); + +private: + int m_sock; + size_t m_bufsize; + unsigned char *m_buf; + QemuPipeStream(int sock, size_t bufSize); +}; + +#endif diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.cpp b/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.cpp new file mode 100644 index 000000000..75da8f29f --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.cpp @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "ThreadInfo.h" +#include "cutils/threads.h" + +thread_store_t s_tls = THREAD_STORE_INITIALIZER; + +static void tlsDestruct(void *ptr) +{ + if (ptr) { + EGLThreadInfo *ti = (EGLThreadInfo *)ptr; + delete ti->hostConn; + delete ti; + } +} + +EGLThreadInfo *slow_getEGLThreadInfo() +{ + EGLThreadInfo *ti = (EGLThreadInfo *)thread_store_get(&s_tls); + if (ti) return ti; + + ti = new EGLThreadInfo(); + thread_store_set(&s_tls, ti, tlsDestruct); + + return ti; +} diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h b/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h new file mode 100644 index 000000000..032873340 --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h @@ -0,0 +1,59 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef _THREAD_INFO_H +#define _THREAD_INFO_H + +#include "HostConnection.h" +#include <pthread.h> +#ifdef HAVE_ANDROID_OS +#include <bionic_tls.h> +#endif + +struct EGLContext_t; + +struct EGLThreadInfo +{ + EGLThreadInfo() : currentContext(NULL), hostConn(NULL), eglError(EGL_SUCCESS) {} + + EGLContext_t *currentContext; + HostConnection *hostConn; + int eglError; +}; + + +EGLThreadInfo *slow_getEGLThreadInfo(); + +#ifdef HAVE_ANDROID_OS + // We have a dedicated TLS slot in bionic + inline EGLThreadInfo* getEGLThreadInfo() { + EGLThreadInfo *tInfo = + (EGLThreadInfo *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]); + if (!tInfo) { + tInfo = slow_getEGLThreadInfo(); + ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)tInfo; + } + return tInfo; + } +#else + inline EGLThreadInfo* getEGLThreadInfo() { + return slow_getEGLThreadInfo(); + } +#endif + + + + +#endif // of _THREAD_INFO_H diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h b/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h new file mode 100644 index 000000000..e879409cb --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h @@ -0,0 +1,106 @@ +/* +* Copyright 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __GRALLOC_CB_H__ +#define __GRALLOC_CB_H__ + +#include <hardware/hardware.h> +#include <hardware/gralloc.h> +#include <cutils/native_handle.h> + +#define BUFFER_HANDLE_MAGIC ((int)0xabfabfab) +#define CB_HANDLE_NUM_INTS(nfds) (int)((sizeof(cb_handle_t) - (nfds)*sizeof(int)) / sizeof(int)) + +// +// Our buffer handle structure +// +struct cb_handle_t : public native_handle { + + cb_handle_t(int p_fd, int p_ashmemSize, int p_usage, + int p_width, int p_height, + int p_glFormat, int p_glType) : + fd(p_fd), + magic(BUFFER_HANDLE_MAGIC), + usage(p_usage), + width(p_width), + height(p_height), + glFormat(p_glFormat), + glType(p_glType), + ashmemSize(p_ashmemSize), + ashmemBase(NULL), + ashmemBasePid(0), + mappedPid(0), + lockedLeft(0), + lockedTop(0), + lockedWidth(0), + lockedHeight(0), + hostHandle(0) + { + version = sizeof(native_handle); + numFds = 0; + numInts = CB_HANDLE_NUM_INTS(numFds); + } + + ~cb_handle_t() { + magic = 0; + } + + void setFd(int p_fd) { + if (p_fd >= 0) { + numFds = 1; + } + else { + numFds = 0; + } + fd = p_fd; + numInts = CB_HANDLE_NUM_INTS(numFds); + } + + static bool validate(cb_handle_t * hnd) { + return (hnd && + hnd->version == sizeof(native_handle) && + hnd->magic == BUFFER_HANDLE_MAGIC && + hnd->numInts == CB_HANDLE_NUM_INTS(hnd->numFds)); + } + + bool canBePosted() { + return (0 != (usage & GRALLOC_USAGE_HW_FB)); + } + + // file-descriptors + int fd; // ashmem fd (-1 of ashmem region did not allocated, i.e. no SW access needed) + + // ints + int magic; // magic number in order to validate a pointer to be a cb_handle_t + int usage; // usage bits the buffer was created with + int width; // buffer width + int height; // buffer height + int glFormat; // OpenGL format enum used for host h/w color buffer + int glType; // OpenGL type enum used when uploading to host + int ashmemSize; // ashmem region size for the buffer (0 unless is HW_FB buffer or + // s/w access is needed) + int ashmemBase; // CPU address of the mapped ashmem region + int ashmemBasePid; // process id which mapped the ashmem region + int mappedPid; // process id which succeeded gralloc_register call + int lockedLeft; // region of buffer locked for s/w write + int lockedTop; + int lockedWidth; + int lockedHeight; + uint32_t hostHandle; +}; + + +#endif //__GRALLOC_CB_H__ |
