Import goldfish HAL sources from devices/generic/goldfish

We import all code here so we can customize and keep in sync with what
we do on the host side more easily.
This commit is contained in:
Simon Fels 2017-01-09 08:05:04 +01:00
commit 23392b9732
196 changed files with 62159 additions and 0 deletions

View file

@ -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)

View file

@ -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

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2015 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_EGL_IMAGE_H
#define __COMMON_EGL_IMAGE_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <system/window.h>
struct EGLImage_t
{
EGLDisplay dpy;
EGLenum target;
union
{
android_native_buffer_t *native_buffer;
uint32_t host_egl_image;
};
};
#endif

View file

@ -0,0 +1,186 @@
/*
* 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"
#include <memory>
#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),
m_checksumHelper()
{
}
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, checksumHelper());
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, checksumHelper());
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, checksumHelper());
// TODO: disable checksum as a workaround in a glTexSubImage2D problem
// Uncomment the following line when the root cause is solved
//setChecksumHelper(m_rcEnc);
}
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;
}
void HostConnection::setChecksumHelper(renderControl_encoder_context_t *rcEnc) {
std::unique_ptr<char[]> glExtensions;
int extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS, NULL, 0);
if (extensionSize < 0) {
glExtensions = std::unique_ptr<char[]>(new char[-extensionSize]);
extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS, glExtensions.get(), -extensionSize);
if (extensionSize <= 0) {
glExtensions.reset();
}
}
// check the host supported version
uint32_t checksumVersion = 0;
const char* checksumPrefix = ChecksumCalculator::getMaxVersionStrPrefix();
const char* glProtocolStr = glExtensions.get() ?
strstr(glExtensions.get(), checksumPrefix) : NULL;
if (glProtocolStr) {
uint32_t maxVersion = ChecksumCalculator::getMaxVersion();
sscanf(glProtocolStr+strlen(checksumPrefix), "%d", &checksumVersion);
if (maxVersion < checksumVersion) {
checksumVersion = maxVersion;
}
// The ordering of the following two commands matters!
// Must tell the host first before setting it in the guest
rcEnc->rcSelectChecksumCalculator(rcEnc, checksumVersion, 0);
m_checksumHelper.setVersion(checksumVersion);
}
}

View file

@ -0,0 +1,61 @@
/*
* 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"
#include "ChecksumCalculator.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();
ChecksumCalculator *checksumHelper() { return &m_checksumHelper; }
void flush() {
if (m_stream) {
m_stream->flush();
}
}
private:
HostConnection();
static gl_client_context_t *s_getGLContext();
static gl2_client_context_t *s_getGL2Context();
// setProtocol initilizes GL communication protocol for checksums
// should be called when m_rcEnc is created
void setChecksumHelper(renderControl_encoder_context_t *rcEnc);
private:
IOStream *m_stream;
GLEncoder *m_glEnc;
GL2Encoder *m_gl2Enc;
renderControl_encoder_context_t *m_rcEnc;
ChecksumCalculator m_checksumHelper;
};
#endif

View file

@ -0,0 +1,209 @@
/*
* 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) {
flush();
::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;
if (!buf) {
if (len>0) {
// If len is non-zero, buf must not be NULL. Otherwise the pipe would be
// in a corrupted state, which is lethal for the emulator.
ERR("QemuPipeStream::writeFully failed, buf=NULL, len %d,"
" lethal error, exiting", len);
abort();
}
return 0;
}
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, lethal error, exiting.\n",
strerror(errno));
abort();
}
//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) {
// If len is non-zero, buf must not be NULL. Otherwise the pipe would be
// in a corrupted state, which is lethal for the emulator.
ERR("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
" error, exiting.", len);
abort();
}
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, res);
if (stat == 0) {
// client shutdown;
return NULL;
} else if (stat < 0) {
if (errno == EINTR) {
continue;
} else {
ERR("QemuPipeStream::readFully failed (buf %p, len %zu"
", res %zu): %s, lethal error, exiting.", buf, len, res,
strerror(errno));
abort();
}
} 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;
}

View file

@ -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

View file

@ -0,0 +1,40 @@
/*
* 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;
((void **)__get_tls())[TLS_SLOT_OPENGL] = NULL;
}
}
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;
}

View file

@ -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 __ANDROID__
#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 __ANDROID__
// We have a dedicated TLS slot in bionic
inline EGLThreadInfo* getEGLThreadInfo() {
EGLThreadInfo *tInfo =
(EGLThreadInfo *)(((uintptr_t *)__get_tls())[TLS_SLOT_OPENGL]);
if (!tInfo) {
tInfo = slow_getEGLThreadInfo();
((uintptr_t *)__get_tls())[TLS_SLOT_OPENGL] = (uintptr_t)tInfo;
}
return tInfo;
}
#else
inline EGLThreadInfo* getEGLThreadInfo() {
return slow_getEGLThreadInfo();
}
#endif
#endif // of _THREAD_INFO_H

View file

@ -0,0 +1,114 @@
/*
* 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_frameworkFormat,
int p_format, int p_glFormat, int p_glType) :
fd(p_fd),
magic(BUFFER_HANDLE_MAGIC),
usage(p_usage),
width(p_width),
height(p_height),
frameworkFormat(p_frameworkFormat),
format(p_format),
glFormat(p_glFormat),
glType(p_glType),
ashmemSize(p_ashmemSize),
ashmemBase(0),
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(const 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 frameworkFormat; // format requested by the Android framework
int format; // real internal pixel format format
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)
union {
intptr_t ashmemBase; // CPU address of the mapped ashmem region
uint64_t padding; // enforce same size on 32-bit/64-bit
} __attribute__((aligned(8)));
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__