You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
628 lines
20 KiB
628 lines
20 KiB
/*
|
|
* 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.
|
|
*/
|
|
|
|
//
|
|
// WARNING -------------------------- WARNING
|
|
// This code meant to be used for testing purposes only. It is not production
|
|
// level quality.
|
|
// Use on your own risk !!
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include "egl_dispatch.h"
|
|
#include "egl_ftable.h"
|
|
#include <log/log.h>
|
|
#include "ServerConnection.h"
|
|
#include "ThreadInfo.h"
|
|
#include <pthread.h>
|
|
#include "gl_wrapper_context.h"
|
|
#include "gl2_wrapper_context.h"
|
|
|
|
#define GLES_EMUL_TARGETS_FILE "/system/etc/gles_emul.cfg"
|
|
// implementation libraries;
|
|
#define GLESv1_enc_LIB "/system/lib/libGLESv1_enc.so"
|
|
#define GLESv2_enc_LIB "/system/lib/libGLESv2_enc.so"
|
|
#define GLES_android_LIB "/system/lib/egl/libGLES_android.so"
|
|
// driver libraries;
|
|
#define GLESv1_DRIVER "/system/lib/egl/libGLESv1_CM_emul.so"
|
|
#define GLESv2_DRIVER "/system/lib/egl/libGLESv2_emul.so"
|
|
|
|
|
|
static struct egl_dispatch *s_dispatch = NULL;
|
|
pthread_once_t dispatchTablesInitialized = PTHREAD_ONCE_INIT;
|
|
|
|
static bool s_needEncode = false;
|
|
|
|
static gl_wrapper_context_t *g_gl_dispatch = NULL;
|
|
static gl2_wrapper_context_t *g_gl2_dispatch = NULL;
|
|
|
|
template <class T>
|
|
int initApi(const char *driverLibName, const char *implLibName, T **dispatchTable, T *(*accessor)())
|
|
{
|
|
void *driverLib = dlopen(driverLibName, RTLD_NOW | RTLD_LOCAL);
|
|
if (driverLib == NULL) {
|
|
ALOGE("failed to load %s : %s\n", driverLibName, dlerror());
|
|
return -1;
|
|
}
|
|
|
|
typedef T *(*createFcn_t)(void *, T *(*accessor)());
|
|
createFcn_t createFcn;
|
|
createFcn = (createFcn_t) dlsym(driverLib, "createFromLib");
|
|
if (createFcn == NULL) {
|
|
ALOGE("failed to load createFromLib constructor function\n");
|
|
return -1;
|
|
}
|
|
|
|
void *implLib = dlopen(implLibName, RTLD_NOW | RTLD_LOCAL);
|
|
if (implLib == NULL) {
|
|
ALOGE("couldn't open %s", implLibName);
|
|
return -2;
|
|
}
|
|
*dispatchTable = createFcn(implLib, accessor);
|
|
if (*dispatchTable == NULL) {
|
|
return -3;
|
|
}
|
|
|
|
// XXX - we do close the impl library since it doesn't have data, as far as we concern.
|
|
dlclose(implLib);
|
|
|
|
// XXX - we do not dlclose the driver library, so its not initialized when
|
|
// later loaded by android - is this required?
|
|
ALOGD("loading %s into %s complete\n", implLibName, driverLibName);
|
|
return 0;
|
|
|
|
}
|
|
|
|
static gl_wrapper_context_t *getGLContext()
|
|
{
|
|
return g_gl_dispatch;
|
|
}
|
|
|
|
static gl2_wrapper_context_t *getGL2Context()
|
|
{
|
|
return g_gl2_dispatch;
|
|
}
|
|
|
|
const char *getProcName()
|
|
{
|
|
static constexpr size_t kMaxProcessNameLength = 100;
|
|
static const char procname[kMaxProcessNameLength]{0};
|
|
|
|
int rc = pthread_getname_np(pthread_self(), procname, kMaxProcessNameLength);
|
|
|
|
if (rc == 0) {
|
|
return procname;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
|
|
bool isNeedEncode()
|
|
{
|
|
const char *procname = getProcName();
|
|
if (procname == NULL) return false;
|
|
ALOGD("isNeedEncode? for %s\n", procname);
|
|
// check on our whitelist
|
|
FILE *fp = fopen(GLES_EMUL_TARGETS_FILE, "rt");
|
|
if (fp == NULL) {
|
|
ALOGE("couldn't open %s\n", GLES_EMUL_TARGETS_FILE);
|
|
return false;
|
|
}
|
|
|
|
char line[100];
|
|
bool found = false;
|
|
size_t procnameLen = strlen(procname);
|
|
|
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
if (strlen(line) >= procnameLen &&
|
|
!strncmp(procname, line, procnameLen)) {
|
|
char c = line[procnameLen];
|
|
if (c == '\0' || c == ' ' || c == '\t' || c == '\n') {
|
|
found = true;
|
|
ALOGD("should use encoder for %s\n", procname);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
return found;
|
|
}
|
|
|
|
void initDispatchTables()
|
|
{
|
|
//
|
|
// Load our back-end implementation of EGL/GLES
|
|
//
|
|
ALOGD("Loading egl dispatch for %s\n", getProcName());
|
|
|
|
void *gles_android = dlopen("/system/lib/egl/libGLES_android.so", RTLD_NOW | RTLD_LOCAL);
|
|
if (!gles_android) {
|
|
fprintf(stderr,"FATAL ERROR: Could not load libGLES_android lib\n");
|
|
exit(-1);
|
|
}
|
|
|
|
//
|
|
// Load back-end EGL implementation library
|
|
//
|
|
s_dispatch = create_egl_dispatch( gles_android );
|
|
if (!s_dispatch) {
|
|
fprintf(stderr,"FATAL ERROR: Could not create egl dispatch\n");
|
|
exit(-1);
|
|
}
|
|
|
|
//
|
|
// initialize gles
|
|
//
|
|
s_needEncode = isNeedEncode();
|
|
void *gles_encoder = NULL;
|
|
if (s_needEncode) {
|
|
// initialize a connection to the server, and the GLESv1/v2 encoders;
|
|
ServerConnection * connection = ServerConnection::s_getServerConnection();
|
|
if (connection == NULL) {
|
|
ALOGE("couldn't create server connection\n");
|
|
s_needEncode = false;
|
|
}
|
|
}
|
|
|
|
// init dispatch tabels for GLESv1 & GLESv2
|
|
if (s_needEncode) {
|
|
// XXX - we do not check the retrun value because there isn't much we can do here on failure.
|
|
|
|
if (initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLESv1_enc_LIB, &g_gl_dispatch, getGLContext) < 0) {
|
|
// fallback to android on faluire
|
|
s_needEncode = false;
|
|
} else {
|
|
initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLESv2_enc_LIB, &g_gl2_dispatch, getGL2Context);
|
|
}
|
|
}
|
|
|
|
if (!s_needEncode) {
|
|
ALOGD("Initializing native opengl for %s\n", getProcName());
|
|
initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLES_android_LIB, &g_gl_dispatch, getGLContext);
|
|
// try to initialize gl2 from GLES, though its probably going to fail
|
|
initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLES_android_LIB, &g_gl2_dispatch, getGL2Context);
|
|
}
|
|
}
|
|
|
|
static struct egl_dispatch *getDispatch()
|
|
{
|
|
pthread_once(&dispatchTablesInitialized, initDispatchTables);
|
|
return s_dispatch;
|
|
}
|
|
|
|
__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;
|
|
}
|
|
}
|
|
|
|
// we do not support eglGetProcAddress for GLESv1 & GLESv2. The loader
|
|
// should be able to find this function through dynamic loading.
|
|
return NULL;
|
|
}
|
|
|
|
//////////////// Path through functions //////////
|
|
|
|
EGLint eglGetError()
|
|
{
|
|
return getDispatch()->eglGetError();
|
|
}
|
|
|
|
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
|
|
{
|
|
return getDispatch()->eglGetDisplay(display_id);
|
|
}
|
|
|
|
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
|
|
{
|
|
return getDispatch()->eglInitialize(dpy, major, minor);
|
|
}
|
|
|
|
EGLBoolean eglTerminate(EGLDisplay dpy)
|
|
{
|
|
return getDispatch()->eglTerminate(dpy);
|
|
}
|
|
|
|
const char* eglQueryString(EGLDisplay dpy, EGLint name)
|
|
{
|
|
return getDispatch()->eglQueryString(dpy, name);
|
|
}
|
|
|
|
EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
|
|
{
|
|
return getDispatch()->eglGetConfigs(dpy, configs, config_size, num_config);
|
|
}
|
|
|
|
static EGLint * filter_es2_bit(const EGLint *attrib_list, bool *isES2)
|
|
{
|
|
if (attrib_list == NULL) {
|
|
if (isES2 != NULL) *isES2 = false;
|
|
return NULL;
|
|
}
|
|
|
|
EGLint *attribs = NULL;
|
|
int nAttribs = 0;
|
|
while(attrib_list[nAttribs] != EGL_NONE) nAttribs++;
|
|
nAttribs++;
|
|
|
|
attribs = new EGLint[nAttribs];
|
|
memcpy(attribs, attrib_list, nAttribs * sizeof(EGLint));
|
|
if (isES2 != NULL) *isES2 = false;
|
|
|
|
// scan the attribute list for ES2 request and replace with ES1.
|
|
for (int i = 0; i < nAttribs; i++) {
|
|
if (attribs[i] == EGL_RENDERABLE_TYPE) {
|
|
if (attribs[i + 1] & EGL_OPENGL_ES2_BIT) {
|
|
attribs[i + 1] &= ~EGL_OPENGL_ES2_BIT;
|
|
attribs[i + 1] |= EGL_OPENGL_ES_BIT;
|
|
ALOGD("removing ES2 bit 0x%x\n", attribs[i + 1]);
|
|
if (isES2 != NULL) *isES2 = true;
|
|
}
|
|
}
|
|
}
|
|
return attribs;
|
|
}
|
|
|
|
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
|
|
{
|
|
EGLBoolean res;
|
|
if (s_needEncode) {
|
|
EGLint *attribs = filter_es2_bit(attrib_list, NULL);
|
|
res = getDispatch()->eglChooseConfig(dpy,
|
|
attribs,
|
|
configs,
|
|
config_size,
|
|
num_config);
|
|
ALOGD("eglChooseConfig: %d configs found\n", *num_config);
|
|
if (*num_config == 0 && attribs != NULL) {
|
|
ALOGD("requested attributes:\n");
|
|
for (int i = 0; attribs[i] != EGL_NONE; i++) {
|
|
ALOGD("%d: 0x%x\n", i, attribs[i]);
|
|
}
|
|
}
|
|
|
|
delete attribs;
|
|
} else {
|
|
res = getDispatch()->eglChooseConfig(dpy, attrib_list, configs, config_size, num_config);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
|
|
{
|
|
if (s_needEncode && attribute == EGL_RENDERABLE_TYPE) {
|
|
*value = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;
|
|
return EGL_TRUE;
|
|
} else {
|
|
return getDispatch()->eglGetConfigAttrib(dpy, config, attribute, value);
|
|
}
|
|
}
|
|
|
|
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
|
|
{
|
|
EGLSurface surface = getDispatch()->eglCreateWindowSurface(dpy, config, win, attrib_list);
|
|
if (surface != EGL_NO_SURFACE) {
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
|
|
server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
|
|
}
|
|
}
|
|
return surface;
|
|
}
|
|
|
|
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
|
|
{
|
|
EGLSurface surface = getDispatch()->eglCreatePbufferSurface(dpy, config, attrib_list);
|
|
if (surface != EGL_NO_SURFACE) {
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
|
|
server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
|
|
}
|
|
}
|
|
return surface;
|
|
}
|
|
|
|
EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
|
|
{
|
|
EGLSurface surface = getDispatch()->eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
|
|
if (surface != EGL_NO_SURFACE) {
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
|
|
server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
|
|
}
|
|
}
|
|
return surface;
|
|
}
|
|
|
|
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
|
|
{
|
|
EGLBoolean res = getDispatch()->eglDestroySurface(dpy, surface);
|
|
if (res && surface != EGL_NO_SURFACE) {
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
|
|
server->utEnc()->destroySurface(server->utEnc(), getpid(), (uint32_t)surface);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
|
|
{
|
|
EGLBoolean res = getDispatch()->eglQuerySurface(dpy, surface, attribute, value);
|
|
if (res && attribute == EGL_RENDERABLE_TYPE) {
|
|
*value |= EGL_OPENGL_ES2_BIT;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
EGLBoolean eglBindAPI(EGLenum api)
|
|
{
|
|
return getDispatch()->eglBindAPI(api);
|
|
}
|
|
|
|
EGLenum eglQueryAPI()
|
|
{
|
|
return getDispatch()->eglQueryAPI();
|
|
}
|
|
|
|
EGLBoolean eglWaitClient()
|
|
{
|
|
return getDispatch()->eglWaitClient();
|
|
}
|
|
|
|
EGLBoolean eglReleaseThread()
|
|
{
|
|
return getDispatch()->eglReleaseThread();
|
|
}
|
|
|
|
EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
|
|
{
|
|
return getDispatch()->eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
|
|
}
|
|
|
|
EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
|
|
{
|
|
return getDispatch()->eglSurfaceAttrib(dpy, surface, attribute, value);
|
|
}
|
|
|
|
EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
|
|
{
|
|
return getDispatch()->eglBindTexImage(dpy, surface, buffer);
|
|
}
|
|
|
|
EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
|
|
{
|
|
return getDispatch()->eglReleaseTexImage(dpy, surface, buffer);
|
|
}
|
|
|
|
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
|
|
{
|
|
return getDispatch()->eglSwapInterval(dpy, interval);
|
|
}
|
|
|
|
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
|
|
{
|
|
|
|
EGLContext share = share_context;
|
|
if (share) share = ((EGLWrapperContext *)share_context)->aglContext;
|
|
|
|
// check if are ES2, and convert it to ES1.
|
|
int nAttribs = 0;
|
|
if (attrib_list != NULL) {
|
|
while(attrib_list[nAttribs] != EGL_NONE) {
|
|
nAttribs++;
|
|
}
|
|
nAttribs++;
|
|
}
|
|
|
|
EGLint *attrib = NULL;
|
|
if (nAttribs > 0) {
|
|
attrib = new EGLint[nAttribs];
|
|
memcpy(attrib, attrib_list, nAttribs * sizeof(EGLint));
|
|
}
|
|
|
|
int version = 1;
|
|
for (int i = 0; i < nAttribs; i++) {
|
|
if (attrib[i] == EGL_CONTEXT_CLIENT_VERSION &&
|
|
attrib[i + 1] == 2) {
|
|
version = 2;
|
|
attrib[i + 1] = 1; // replace to version 1
|
|
}
|
|
}
|
|
|
|
EGLContext ctx = getDispatch()->eglCreateContext(dpy, config, share, attrib);
|
|
delete[] attrib;
|
|
EGLWrapperContext *wctx = new EGLWrapperContext(ctx, version);
|
|
if (ctx != EGL_NO_CONTEXT) {
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
|
|
wctx->clientState = new GLClientState();
|
|
server->utEnc()->createContext(server->utEnc(), getpid(),
|
|
(uint32_t)wctx,
|
|
(uint32_t)(share_context == EGL_NO_CONTEXT ? 0 : share_context), wctx->version);
|
|
}
|
|
}
|
|
return (EGLContext)wctx;
|
|
}
|
|
|
|
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
|
|
{
|
|
EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
|
|
EGLBoolean res = EGL_FALSE;
|
|
|
|
if (ctx && ctx != EGL_NO_CONTEXT) {
|
|
res = getDispatch()->eglDestroyContext(dpy, wctx->aglContext);
|
|
if (res) {
|
|
EGLThreadInfo *ti = getEGLThreadInfo();
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection())) {
|
|
server->utEnc()->destroyContext(ti->serverConn->utEnc(), getpid(), (uint32_t)ctx);
|
|
}
|
|
if (ti->currentContext == wctx) ti->currentContext = NULL;
|
|
delete wctx;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
|
|
{
|
|
EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
|
|
EGLContext aglContext = (ctx == EGL_NO_CONTEXT ? EGL_NO_CONTEXT : wctx->aglContext);
|
|
EGLThreadInfo *ti = getEGLThreadInfo();
|
|
EGLBoolean res = getDispatch()->eglMakeCurrent(dpy, draw, read, aglContext);
|
|
if (res ) {
|
|
// NOTE - we do get a pointer to the server connection, (rather then using ti->serverConn)
|
|
// for cases that this is the first egl call of the current thread.
|
|
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection())) {
|
|
server->utEnc()->makeCurrentContext(server->utEnc(), getpid(),
|
|
(uint32_t) (draw == EGL_NO_SURFACE ? 0 : draw),
|
|
(uint32_t) (read == EGL_NO_SURFACE ? 0 : read),
|
|
(uint32_t) (ctx == EGL_NO_CONTEXT ? 0 : ctx));
|
|
server->glEncoder()->setClientState( wctx ? wctx->clientState : NULL );
|
|
server->gl2Encoder()->setClientState( wctx ? wctx->clientState : NULL );
|
|
}
|
|
|
|
// set current context in our thread info
|
|
ti->currentContext = wctx;
|
|
}
|
|
return res;
|
|
|
|
}
|
|
|
|
EGLContext eglGetCurrentContext()
|
|
{
|
|
EGLThreadInfo *ti = getEGLThreadInfo();
|
|
return (ti->currentContext ? ti->currentContext : EGL_NO_CONTEXT);
|
|
}
|
|
|
|
EGLSurface eglGetCurrentSurface(EGLint readdraw)
|
|
{
|
|
return getDispatch()->eglGetCurrentSurface(readdraw);
|
|
}
|
|
|
|
EGLDisplay eglGetCurrentDisplay()
|
|
{
|
|
return getDispatch()->eglGetCurrentDisplay();
|
|
}
|
|
|
|
EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
|
|
{
|
|
EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
|
|
if (wctx) {
|
|
if (attribute == EGL_CONTEXT_CLIENT_VERSION) {
|
|
*value = wctx->version;
|
|
return EGL_TRUE;
|
|
} else {
|
|
return getDispatch()->eglQueryContext(dpy, wctx->aglContext, attribute, value);
|
|
}
|
|
}
|
|
else {
|
|
return EGL_BAD_CONTEXT;
|
|
}
|
|
}
|
|
|
|
EGLBoolean eglWaitGL()
|
|
{
|
|
return getDispatch()->eglWaitGL();
|
|
}
|
|
|
|
EGLBoolean eglWaitNative(EGLint engine)
|
|
{
|
|
return getDispatch()->eglWaitNative(engine);
|
|
}
|
|
|
|
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
|
|
{
|
|
ServerConnection *server;
|
|
if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
|
|
server->utEnc()->swapBuffers(server->utEnc(), getpid(), (uint32_t)surface);
|
|
server->glEncoder()->flush();
|
|
server->gl2Encoder()->flush();
|
|
return 1;
|
|
}
|
|
return getDispatch()->eglSwapBuffers(dpy, surface);
|
|
}
|
|
|
|
EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
|
|
{
|
|
return getDispatch()->eglCopyBuffers(dpy, surface, target);
|
|
}
|
|
|
|
EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list)
|
|
{
|
|
return getDispatch()->eglLockSurfaceKHR(display, surface, attrib_list);
|
|
}
|
|
|
|
EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface)
|
|
{
|
|
return getDispatch()->eglUnlockSurfaceKHR(display, surface);
|
|
}
|
|
|
|
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
|
|
{
|
|
EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
|
|
EGLContext aglContext = (wctx ? wctx->aglContext : EGL_NO_CONTEXT);
|
|
return getDispatch()->eglCreateImageKHR(dpy, aglContext, target, buffer, attrib_list);
|
|
}
|
|
|
|
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
|
|
{
|
|
return getDispatch()->eglDestroyImageKHR(dpy, image);
|
|
}
|
|
|
|
EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
|
|
{
|
|
return getDispatch()->eglCreateSyncKHR(dpy, type, attrib_list);
|
|
}
|
|
|
|
EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
|
|
{
|
|
return getDispatch()->eglDestroySyncKHR(dpy, sync);
|
|
}
|
|
|
|
EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
|
|
{
|
|
return getDispatch()->eglClientWaitSyncKHR(dpy, sync, flags, timeout);
|
|
}
|
|
|
|
EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode)
|
|
{
|
|
return getDispatch()->eglSignalSyncKHR(dpy, sync, mode);
|
|
}
|
|
|
|
EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
|
|
{
|
|
return getDispatch()->eglGetSyncAttribKHR(dpy, sync, attribute, value);
|
|
}
|
|
|
|
EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height)
|
|
{
|
|
return getDispatch()->eglSetSwapRectangleANDROID(dpy, draw, left, top, width, height);
|
|
}
|