Files
android_development/tools/emulator/opengl/system/egl/egl.cpp
Jesse Hall 56513f5ff4 Move emugl system code to development.git
Because of the way the SDK and Android system images are branched,
host code that goes into the SDK tools can't live in the same
repository as code that goes into the system image. This change keeps
the emugl host code in sdk.git/emulator/opengl while moving the emugl
system code to development.git/tools/emulator/opengl.

A few changes were made beyond simply cloning the directories:

(a) Makefiles were modified to only build the relevant components. Not
    doing so would break the build due to having multiple rule
    definitions.

(b) Protocol spec files were moved from the guest encoder directories
    to the host decoder directories. The decoder must support older
    versions of the protocol, but not newer versions, so it makes
    sense to keep the latest version of the protocol spec with the
    decoder.

(c) Along with that, the encoder is now built from checked in
    generated encoder source rather than directly from the protocol
    spec.  The generated code must be updated manually. This makes it
    possible to freeze the system encoder version without freezing the
    host decoder version, and also makes it very obvious when a
    protocol changes is happening that will require special
    backwards-compatibility support in the decoder/renderer.

(d) Host-only and system-only code were removed from the repository
    where they aren't used.

(e) README and DESIGN documents were updated to reflect this split.

No actual source code was changed due to the above.

Change-Id: I2c936101ea0405b372750d36ba0f01e84d719c43
2012-06-06 09:46:29 -07:00

1255 lines
36 KiB
C++

/*
* 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 "ThreadInfo.h"
#include "eglDisplay.h"
#include "egl_ftable.h"
#include <cutils/log.h>
#include "gralloc_cb.h"
#include "GLClientState.h"
#include "GLSharedGroup.h"
#include "eglContext.h"
#include "ClientAPIExts.h"
#include "GLEncoder.h"
#ifdef WITH_GLES2
#include "GL2Encoder.h"
#endif
#include <system/window.h>
template<typename T>
static T setErrorFunc(GLint error, T returnValue) {
getEGLThreadInfo()->eglError = error;
return returnValue;
}
const char * eglStrError(EGLint err)
{
switch (err){
case EGL_SUCCESS: return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
default: return "UNKNOWN";
}
}
#define LOG_EGL_ERRORS 1
#ifdef LOG_EGL_ERRORS
#define setErrorReturn(error, retVal) \
{ \
ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, error, eglStrError(error)); \
return setErrorFunc(error, retVal); \
}
#define RETURN_ERROR(ret,err) \
ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, err, eglStrError(err)); \
getEGLThreadInfo()->eglError = err; \
return ret;
#else //!LOG_EGL_ERRORS
#define setErrorReturn(error, retVal) return setErrorFunc(error, retVal);
#define RETURN_ERROR(ret,err) \
getEGLThreadInfo()->eglError = err; \
return ret;
#endif //LOG_EGL_ERRORS
#define VALIDATE_CONFIG(cfg,ret) \
if(((int)cfg<0)||((int)cfg>s_display.getNumConfigs())) { \
RETURN_ERROR(ret,EGL_BAD_CONFIG); \
}
#define VALIDATE_DISPLAY(dpy,ret) \
if ((dpy) != (EGLDisplay)&s_display) { \
RETURN_ERROR(ret, EGL_BAD_DISPLAY); \
}
#define VALIDATE_DISPLAY_INIT(dpy,ret) \
VALIDATE_DISPLAY(dpy, ret) \
if (!s_display.initialized()) { \
RETURN_ERROR(ret, EGL_NOT_INITIALIZED); \
}
#define DEFINE_HOST_CONNECTION \
HostConnection *hostCon = HostConnection::get(); \
renderControl_encoder_context_t *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
#define DEFINE_AND_VALIDATE_HOST_CONNECTION(ret) \
HostConnection *hostCon = HostConnection::get(); \
if (!hostCon) { \
ALOGE("egl: Failed to get host connection\n"); \
return ret; \
} \
renderControl_encoder_context_t *rcEnc = hostCon->rcEncoder(); \
if (!rcEnc) { \
ALOGE("egl: Failed to get renderControl encoder context\n"); \
return ret; \
}
#define VALIDATE_CONTEXT_RETURN(context,ret) \
if (!context) { \
RETURN_ERROR(ret,EGL_BAD_CONTEXT); \
}
#define VALIDATE_SURFACE_RETURN(surface, ret) \
if (surface != EGL_NO_SURFACE) { \
egl_surface_t* s( static_cast<egl_surface_t*>(surface) ); \
if (s->dpy != (EGLDisplay)&s_display) \
setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); \
}
EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx) :
dpy(dpy),
config(config),
read(EGL_NO_SURFACE),
draw(EGL_NO_SURFACE),
shareCtx(shareCtx),
rcContext(0),
versionString(NULL),
vendorString(NULL),
rendererString(NULL),
extensionString(NULL)
{
flags = 0;
version = 1;
clientState = new GLClientState();
if (shareCtx)
sharedGroup = shareCtx->getSharedGroup();
else
sharedGroup = GLSharedGroupPtr(new GLSharedGroup());
};
EGLContext_t::~EGLContext_t()
{
delete clientState;
delete [] versionString;
delete [] vendorString;
delete [] rendererString;
delete [] extensionString;
}
// ----------------------------------------------------------------------------
//egl_surface_t
//we don't need to handle depth since it's handled when window created on the host
struct egl_surface_t {
EGLDisplay dpy;
EGLConfig config;
egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType);
virtual ~egl_surface_t();
virtual void setSwapInterval(int interval) = 0;
virtual EGLBoolean swapBuffers() = 0;
EGLint getSwapBehavior() const;
uint32_t getRcSurface() { return rcSurface; }
EGLint getSurfaceType() { return surfaceType; }
EGLint getWidth(){ return width; }
EGLint getHeight(){ return height; }
void setTextureFormat(EGLint _texFormat) { texFormat = _texFormat; }
EGLint getTextureFormat() { return texFormat; }
void setTextureTarget(EGLint _texTarget) { texTarget = _texTarget; }
EGLint getTextureTarget() { return texTarget; }
private:
//
//Surface attributes
//
EGLint width;
EGLint height;
EGLint texFormat;
EGLint texTarget;
protected:
void setWidth(EGLint w) { width = w; }
void setHeight(EGLint h) { height = h; }
EGLint surfaceType;
uint32_t rcSurface; //handle to surface created via remote control
};
egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType)
: dpy(dpy), config(config), surfaceType(surfaceType), rcSurface(0)
{
width = 0;
height = 0;
texFormat = EGL_NO_TEXTURE;
texTarget = EGL_NO_TEXTURE;
}
EGLint egl_surface_t::getSwapBehavior() const {
return EGL_BUFFER_PRESERVED;
}
egl_surface_t::~egl_surface_t()
{
}
// ----------------------------------------------------------------------------
// egl_window_surface_t
struct egl_window_surface_t : public egl_surface_t {
static egl_window_surface_t* create(
EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window);
virtual ~egl_window_surface_t();
virtual void setSwapInterval(int interval);
virtual EGLBoolean swapBuffers();
private:
egl_window_surface_t(
EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window);
EGLBoolean init();
ANativeWindow* nativeWindow;
android_native_buffer_t* buffer;
};
egl_window_surface_t::egl_window_surface_t (
EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window)
: egl_surface_t(dpy, config, surfType),
nativeWindow(window),
buffer(NULL)
{
// keep a reference on the window
nativeWindow->common.incRef(&nativeWindow->common);
EGLint w,h;
nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &w);
setWidth(w);
nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &h);
setHeight(h);
}
EGLBoolean egl_window_surface_t::init()
{
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
}
nativeWindow->lockBuffer(nativeWindow, buffer);
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config,
getWidth(), getHeight());
if (!rcSurface) {
ALOGE("rcCreateWindowSurface returned 0");
return EGL_FALSE;
}
rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
((cb_handle_t*)(buffer->handle))->hostHandle);
return EGL_TRUE;
}
egl_window_surface_t* egl_window_surface_t::create(
EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window)
{
egl_window_surface_t* wnd = new egl_window_surface_t(
dpy, config, surfType, window);
if (wnd && !wnd->init()) {
delete wnd;
wnd = NULL;
}
return wnd;
}
egl_window_surface_t::~egl_window_surface_t() {
DEFINE_HOST_CONNECTION;
if (rcSurface && rcEnc) {
rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
}
if (buffer) {
nativeWindow->cancelBuffer(nativeWindow, buffer);
}
nativeWindow->common.decRef(&nativeWindow->common);
}
void egl_window_surface_t::setSwapInterval(int interval)
{
nativeWindow->setSwapInterval(nativeWindow, interval);
}
EGLBoolean egl_window_surface_t::swapBuffers()
{
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface);
nativeWindow->queueBuffer(nativeWindow, buffer);
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer)) {
buffer = NULL;
setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
}
nativeWindow->lockBuffer(nativeWindow, buffer);
rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
((cb_handle_t *)(buffer->handle))->hostHandle);
return EGL_TRUE;
}
// ----------------------------------------------------------------------------
//egl_pbuffer_surface_t
struct egl_pbuffer_surface_t : public egl_surface_t {
static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config,
EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat);
virtual ~egl_pbuffer_surface_t();
virtual void setSwapInterval(int interval) {}
virtual EGLBoolean swapBuffers() { return EGL_TRUE; }
uint32_t getRcColorBuffer() { return rcColorBuffer; }
private:
egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType,
int32_t w, int32_t h);
EGLBoolean init(GLenum format);
uint32_t rcColorBuffer;
};
egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config,
EGLint surfType, int32_t w, int32_t h)
: egl_surface_t(dpy, config, surfType),
rcColorBuffer(0)
{
setWidth(w);
setHeight(h);
}
egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
{
DEFINE_HOST_CONNECTION;
if (rcEnc) {
if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer);
if (rcSurface) rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
}
}
EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat)
{
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config,
getWidth(), getHeight());
if (!rcSurface) {
ALOGE("rcCreateWindowSurface returned 0");
return EGL_FALSE;
}
rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(),
pixelFormat);
if (!rcColorBuffer) {
ALOGE("rcCreateColorBuffer returned 0");
return EGL_FALSE;
}
rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer);
return EGL_TRUE;
}
egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy,
EGLConfig config, EGLint surfType, int32_t w, int32_t h,
GLenum pixelFormat)
{
egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType,
w, h);
if (pb && !pb->init(pixelFormat)) {
delete pb;
pb = NULL;
}
return pb;
}
static const char *getGLString(int glEnum)
{
EGLThreadInfo *tInfo = getEGLThreadInfo();
if (!tInfo || !tInfo->currentContext) {
return NULL;
}
const char** strPtr = NULL;
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
switch(glEnum) {
case GL_VERSION:
strPtr = &tInfo->currentContext->versionString;
break;
case GL_VENDOR:
strPtr = &tInfo->currentContext->vendorString;
break;
case GL_RENDERER:
strPtr = &tInfo->currentContext->rendererString;
break;
case GL_EXTENSIONS:
strPtr = &tInfo->currentContext->extensionString;
break;
}
if (!strPtr) {
return NULL;
}
if (*strPtr != NULL) {
//
// string is already cached
//
return *strPtr;
}
//
// first query of that string - need to query host
//
DEFINE_AND_VALIDATE_HOST_CONNECTION(NULL);
char *hostStr = NULL;
int n = rcEnc->rcGetGLString(rcEnc, glEnum, NULL, 0);
if (n < 0) {
hostStr = new char[-n+1];
n = rcEnc->rcGetGLString(rcEnc, glEnum, hostStr, -n);
if (n <= 0) {
delete [] hostStr;
hostStr = NULL;
}
}
//
// keep the string in the context and return its value
//
*strPtr = hostStr;
return hostStr;
}
// ----------------------------------------------------------------------------
// The one and only supported display object.
static eglDisplay s_display;
static EGLClient_eglInterface s_eglIface = {
getThreadInfo: getEGLThreadInfo,
getGLString: getGLString
};
#define DBG_FUNC DBG("%s\n", __FUNCTION__)
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
{
//
// we support only EGL_DEFAULT_DISPLAY.
//
if (display_id != EGL_DEFAULT_DISPLAY) {
return EGL_NO_DISPLAY;
}
return (EGLDisplay)&s_display;
}
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
VALIDATE_DISPLAY(dpy,EGL_FALSE);
if (!s_display.initialize(&s_eglIface)) {
return EGL_FALSE;
}
if (major!=NULL)
*major = s_display.getVersionMajor();
if (minor!=NULL)
*minor = s_display.getVersionMinor();
return EGL_TRUE;
}
EGLBoolean eglTerminate(EGLDisplay dpy)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
s_display.terminate();
return EGL_TRUE;
}
EGLint eglGetError()
{
EGLint error = getEGLThreadInfo()->eglError;
getEGLThreadInfo()->eglError = EGL_SUCCESS;
return error;
}
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
{
// search in EGL function table
for (int i=0; i<egl_num_funcs; i++) {
if (!strcmp(egl_funcs_by_name[i].name, procname)) {
return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc;
}
}
//
// Make sure display is initialized before searching in client APIs
//
if (!s_display.initialized()) {
if (!s_display.initialize(&s_eglIface)) {
return NULL;
}
}
// look in gles client api's extensions table
return (__eglMustCastToProperFunctionPointerType)ClientAPIExts::getProcAddress(procname);
// Fail - function not found.
return NULL;
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
{
VALIDATE_DISPLAY_INIT(dpy, NULL);
return s_display.queryString(name);
}
EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
{
VALIDATE_DISPLAY_INIT(dpy, NULL);
if(!num_config) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER);
}
GLint numConfigs = s_display.getNumConfigs();
if (!configs) {
*num_config = numConfigs;
return EGL_TRUE;
}
int i=0;
for (i=0 ; i<numConfigs && i<config_size ; i++) {
*configs++ = (EGLConfig)i;
}
*num_config = i;
return EGL_TRUE;
}
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
int attribs_size = 0;
if (attrib_list) {
const EGLint * attrib_p = attrib_list;
while (attrib_p[0] != EGL_NONE) {
attribs_size += 2;
attrib_p += 2;
}
attribs_size++; //for the terminating EGL_NONE
}
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
*num_config = rcEnc->rcChooseConfig(rcEnc, (EGLint*)attrib_list, attribs_size * sizeof(EGLint), (uint32_t*)configs, config_size);
return EGL_TRUE;
}
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
{
VALIDATE_DISPLAY_INIT(dpy, NULL);
VALIDATE_CONFIG(config, EGL_FALSE);
if (s_display.getConfigAttrib(config, attribute, value))
{
return EGL_TRUE;
}
else
{
RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE);
}
}
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
{
VALIDATE_DISPLAY_INIT(dpy, NULL);
VALIDATE_CONFIG(config, EGL_FALSE);
if (win == 0) {
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
EGLint surfaceType;
if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE;
if (!(surfaceType & EGL_WINDOW_BIT)) {
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
if (static_cast<ANativeWindow*>(win)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
egl_surface_t* surface = egl_window_surface_t::create(
&s_display, config, surfaceType, static_cast<ANativeWindow*>(win));
if (!surface) {
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
}
return surface;
}
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
{
VALIDATE_DISPLAY_INIT(dpy, NULL);
VALIDATE_CONFIG(config, EGL_FALSE);
EGLint surfaceType;
if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE;
if (!(surfaceType & EGL_PBUFFER_BIT)) {
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
int32_t w = 0;
int32_t h = 0;
EGLint texFormat = EGL_NO_TEXTURE;
EGLint texTarget = EGL_NO_TEXTURE;
while (attrib_list[0]) {
switch (attrib_list[0]) {
case EGL_WIDTH:
w = attrib_list[1];
break;
case EGL_HEIGHT:
h = attrib_list[1];
break;
case EGL_TEXTURE_FORMAT:
texFormat = attrib_list[1];
break;
case EGL_TEXTURE_TARGET:
texTarget = attrib_list[1];
break;
default:
break;
};
attrib_list+=2;
}
if (((texFormat == EGL_NO_TEXTURE)&&(texTarget != EGL_NO_TEXTURE)) ||
((texFormat != EGL_NO_TEXTURE)&&(texTarget == EGL_NO_TEXTURE))) {
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
// TODO: check EGL_TEXTURE_FORMAT - need to support eglBindTexImage
GLenum pixelFormat;
if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE)
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config,
surfaceType, w, h, pixelFormat);
if (!surface) {
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
}
//setup attributes
surface->setTextureFormat(texFormat);
surface->setTextureTarget(texTarget);
return surface;
}
EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
{
//XXX: Pixmap not supported. The host cannot render to a pixmap resource
// located on host. In order to support Pixmaps we should either punt
// to s/w rendering -or- let the host render to a buffer that will be
// copied back to guest at some sync point. None of those methods not
// implemented and pixmaps are not used with OpenGL anyway ...
return EGL_NO_SURFACE;
}
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface));
delete surface;
return EGL_TRUE;
}
EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
EGLBoolean ret = EGL_TRUE;
switch (attribute) {
case EGL_CONFIG_ID:
ret = s_display.getConfigAttrib(surface->config, EGL_CONFIG_ID, value);
break;
case EGL_WIDTH:
*value = surface->getWidth();
break;
case EGL_HEIGHT:
*value = surface->getHeight();
break;
case EGL_TEXTURE_FORMAT:
*value = surface->getTextureFormat();
break;
case EGL_TEXTURE_TARGET:
*value = surface->getTextureTarget();
break;
case EGL_SWAP_BEHAVIOR:
*value = surface->getSwapBehavior();
break;
case EGL_LARGEST_PBUFFER:
// not modified for a window or pixmap surface
// and we ignore it when creating a PBuffer surface (default is EGL_FALSE)
if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = EGL_FALSE;
break;
//TODO: complete other attributes
default:
ALOGE("eglQuerySurface %x EGL_BAD_ATTRIBUTE", attribute);
ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE);
break;
}
return ret;
}
EGLBoolean eglBindAPI(EGLenum api)
{
if (api != EGL_OPENGL_ES_API)
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
return EGL_TRUE;
}
EGLenum eglQueryAPI()
{
return EGL_OPENGL_ES_API;
}
EGLBoolean eglWaitClient()
{
return eglWaitGL();
}
EGLBoolean eglReleaseThread()
{
EGLThreadInfo *tInfo = getEGLThreadInfo();
if (tInfo && tInfo->currentContext) {
return eglMakeCurrent(&s_display, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
}
return EGL_TRUE;
}
EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
{
//TODO
ALOGW("%s not implemented", __FUNCTION__);
return 0;
}
EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
{
//TODO
ALOGW("%s not implemented", __FUNCTION__);
return 0;
}
EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface eglSurface, EGLint buffer)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
if (eglSurface == EGL_NO_SURFACE) {
setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
}
if (buffer != EGL_BACK_BUFFER) {
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
}
egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
if (surface->getTextureFormat() == EGL_NO_TEXTURE) {
setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
}
if (!(surface->getSurfaceType() & EGL_PBUFFER_BIT)) {
setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
}
//It's now safe to cast to pbuffer surface
egl_pbuffer_surface_t* pbSurface = (egl_pbuffer_surface_t*)surface;
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcBindTexture(rcEnc, pbSurface->getRcColorBuffer());
return GL_TRUE;
}
EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
//TODO
ALOGW("%s not implemented", __FUNCTION__);
return 0;
}
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
EGLContext_t* ctx = getEGLThreadInfo()->currentContext;
if (!ctx) {
setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
}
if (!ctx->draw) {
setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
}
egl_surface_t* draw(static_cast<egl_surface_t*>(ctx->draw));
draw->setSwapInterval(interval);
rcEnc->rcFBSetSwapInterval(rcEnc, interval); //TODO: implement on the host
return EGL_TRUE;
}
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT);
VALIDATE_CONFIG(config, EGL_NO_CONTEXT);
EGLint version = 1; //default
while (attrib_list && attrib_list[0]) {
if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) version = attrib_list[1];
attrib_list+=2;
}
uint32_t rcShareCtx = 0;
EGLContext_t * shareCtx = NULL;
if (share_context) {
shareCtx = static_cast<EGLContext_t*>(share_context);
rcShareCtx = shareCtx->rcContext;
if (shareCtx->dpy != dpy)
setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT);
}
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT);
uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uint32_t)config, rcShareCtx, version);
if (!rcContext) {
ALOGE("rcCreateContext returned 0");
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
}
EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx);
if (!context)
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
context->version = version;
context->rcContext = rcContext;
return context;
}
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
if (getEGLThreadInfo()->currentContext == context)
{
eglMakeCurrent(dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
}
if (context->rcContext) {
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcDestroyContext(rcEnc, context->rcContext);
context->rcContext = 0;
}
delete context;
return EGL_TRUE;
}
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_SURFACE_RETURN(draw, EGL_FALSE);
VALIDATE_SURFACE_RETURN(read, EGL_FALSE);
if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
uint32_t ctxHandle = (context) ? context->rcContext : 0;
egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw);
uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0;
egl_surface_t * readSurf = static_cast<egl_surface_t *>(read);
uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0;
//
// Nothing to do if no binding change has made
//
EGLThreadInfo *tInfo = getEGLThreadInfo();
if (tInfo->currentContext == context &&
(context == NULL ||
(context && context->draw == draw && context->read == read))) {
return EGL_TRUE;
}
if (context && (context->flags & EGLContext_t::IS_CURRENT) && (context != tInfo->currentContext)) {
//context is current to another thread
setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE);
}
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) {
ALOGE("rcMakeCurrent returned EGL_FALSE");
setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
}
//Now make the local bind
if (context) {
context->draw = draw;
context->read = read;
context->flags |= EGLContext_t::IS_CURRENT;
//set the client state
if (context->version == 2) {
hostCon->gl2Encoder()->setClientState(context->getClientState());
hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup());
}
else {
hostCon->glEncoder()->setClientState(context->getClientState());
hostCon->glEncoder()->setSharedGroup(context->getSharedGroup());
}
}
else {
//release ClientState & SharedGroup
if (tInfo->currentContext->version == 2) {
hostCon->gl2Encoder()->setClientState(NULL);
hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL));
}
else {
hostCon->glEncoder()->setClientState(NULL);
hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr(NULL));
}
}
if (tInfo->currentContext)
tInfo->currentContext->flags &= ~EGLContext_t::IS_CURRENT;
//Now make current
tInfo->currentContext = context;
//Check maybe we need to init the encoder, if it's first eglMakeCurrent
if (tInfo->currentContext) {
if (tInfo->currentContext->version == 2) {
if (!hostCon->gl2Encoder()->isInitialized()) {
s_display.gles2_iface()->init();
hostCon->gl2Encoder()->setInitialized();
ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1);
}
}
else {
if (!hostCon->glEncoder()->isInitialized()) {
s_display.gles_iface()->init();
hostCon->glEncoder()->setInitialized();
ClientAPIExts::initClientFuncs(s_display.gles_iface(), 0);
}
}
}
return EGL_TRUE;
}
EGLContext eglGetCurrentContext()
{
return getEGLThreadInfo()->currentContext;
}
EGLSurface eglGetCurrentSurface(EGLint readdraw)
{
EGLContext_t * context = getEGLThreadInfo()->currentContext;
if (!context)
return EGL_NO_SURFACE; //not an error
switch (readdraw) {
case EGL_READ:
return context->read;
case EGL_DRAW:
return context->draw;
default:
setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
}
EGLDisplay eglGetCurrentDisplay()
{
EGLContext_t * context = getEGLThreadInfo()->currentContext;
if (!context)
return EGL_NO_DISPLAY; //not an error
return context->dpy;
}
EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
EGLBoolean ret = EGL_TRUE;
switch (attribute) {
case EGL_CONFIG_ID:
ret = s_display.getConfigAttrib(context->config, EGL_CONFIG_ID, value);
break;
case EGL_CONTEXT_CLIENT_TYPE:
*value = EGL_OPENGL_ES_API;
break;
case EGL_CONTEXT_CLIENT_VERSION:
*value = context->version;
break;
case EGL_RENDER_BUFFER:
if (!context->draw)
*value = EGL_NONE;
else
*value = EGL_BACK_BUFFER; //single buffer not supported
break;
default:
ALOGE("eglQueryContext %x EGL_BAD_ATTRIBUTE", attribute);
setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
break;
}
return ret;
}
EGLBoolean eglWaitGL()
{
EGLThreadInfo *tInfo = getEGLThreadInfo();
if (!tInfo || !tInfo->currentContext) {
return EGL_FALSE;
}
if (tInfo->currentContext->version == 2) {
s_display.gles2_iface()->finish();
}
else {
s_display.gles_iface()->finish();
}
return EGL_TRUE;
}
EGLBoolean eglWaitNative(EGLint engine)
{
return EGL_TRUE;
}
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
if (eglSurface == EGL_NO_SURFACE)
setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface);
if (d->dpy != dpy)
setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);
// post the surface
d->swapBuffers();
hostCon->flush();
return EGL_TRUE;
}
EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
{
//TODO :later
return 0;
}
EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list)
{
//TODO later
return 0;
}
EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface)
{
//TODO later
return 0;
}
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_NO_IMAGE_KHR);
if (ctx != EGL_NO_CONTEXT) {
setErrorReturn(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
}
if (target != EGL_NATIVE_BUFFER_ANDROID) {
setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
}
android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
if (native_buffer->common.version != sizeof(android_native_buffer_t))
setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
switch (native_buffer->format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RGBA_5551:
case HAL_PIXEL_FORMAT_RGBA_4444:
break;
default:
setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
}
native_buffer->common.incRef(&native_buffer->common);
return (EGLImageKHR)native_buffer;
}
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
{
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
if (native_buffer->common.version != sizeof(android_native_buffer_t))
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
native_buffer->common.decRef(&native_buffer->common);
return EGL_TRUE;
}
#define FENCE_SYNC_HANDLE (EGLSyncKHR)0xFE4CE
EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
const EGLint *attrib_list)
{
// TODO: This implementation could be faster. We should require the host EGL
// to support KHR_fence_sync, or at least pipe the fence command to the host
// and wait for it (probably involving a glFinish on the host) in
// eglClientWaitSyncKHR.
VALIDATE_DISPLAY(dpy, EGL_NO_SYNC_KHR);
if (type != EGL_SYNC_FENCE_KHR ||
(attrib_list != NULL && attrib_list[0] != EGL_NONE)) {
setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
}
EGLThreadInfo *tInfo = getEGLThreadInfo();
if (!tInfo || !tInfo->currentContext) {
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
}
if (tInfo->currentContext->version == 2) {
s_display.gles2_iface()->finish();
} else {
s_display.gles_iface()->finish();
}
return FENCE_SYNC_HANDLE;
}
EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
{
if (sync != FENCE_SYNC_HANDLE) {
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
}
return EGL_TRUE;
}
EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags,
EGLTimeKHR timeout)
{
if (sync != FENCE_SYNC_HANDLE) {
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
}
return EGL_CONDITION_SATISFIED_KHR;
}
EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
EGLint attribute, EGLint *value)
{
if (sync != FENCE_SYNC_HANDLE) {
setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
}
switch (attribute) {
case EGL_SYNC_TYPE_KHR:
*value = EGL_SYNC_FENCE_KHR;
return EGL_TRUE;
case EGL_SYNC_STATUS_KHR:
*value = EGL_SIGNALED_KHR;
return EGL_TRUE;
case EGL_SYNC_CONDITION_KHR:
*value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
return EGL_TRUE;
default:
setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
}
}