eglApi.cpp revision 73d2b3c7e5537a6645f20f022b2e60cb9f342cbe
1e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/*
2e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** Copyright 2007, The Android Open Source Project
3e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy **
4e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** Licensed under the Apache License, Version 2.0 (the "License");
5e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** you may not use this file except in compliance with the License.
6e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** You may obtain a copy of the License at
7e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy **
8e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy **     http://www.apache.org/licenses/LICENSE-2.0
9e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy **
10e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** Unless required by applicable law or agreed to in writing, software
11e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** distributed under the License is distributed on an "AS IS" BASIS,
12e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** See the License for the specific language governing permissions and
14e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy ** limitations under the License.
15e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
16e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
17a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy#include <ctype.h>
18a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy#include <stdlib.h>
19e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <string.h>
20e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
21e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <hardware/gralloc.h>
22deba785f122a47915756ffd991f5540d952cf937Romain Guy#include <system/window.h>
23e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
24ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include <EGL/egl.h>
25c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy#include <EGL/eglext.h>
26f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy#include <GLES/gl.h>
27c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy#include <GLES/glext.h>
28079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy
29a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy#include <cutils/log.h>
3085bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include <cutils/atomic.h>
31e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <cutils/properties.h>
3285bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include <cutils/memory.h>
3306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
34db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy#include <utils/KeyedVector.h>
359d5316e3f56d138504565ff311145ac01621dff4Romain Guy#include <utils/SortedVector.h>
369d5316e3f56d138504565ff311145ac01621dff4Romain Guy#include <utils/String8.h>
3785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
38e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy#include "egl_impl.h"
39e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy#include "egl_tls.h"
40e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include "glestrace.h"
41e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include "hooks.h"
429d5316e3f56d138504565ff311145ac01621dff4Romain Guy
439d5316e3f56d138504565ff311145ac01621dff4Romain Guy#include "egl_display.h"
44163935113919a184122b8b3bd672ef08c8df65dcRomain Guy#include "egl_impl.h"
45163935113919a184122b8b3bd672ef08c8df65dcRomain Guy#include "egl_object.h"
46163935113919a184122b8b3bd672ef08c8df65dcRomain Guy#include "egl_tls.h"
47163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
48163935113919a184122b8b3bd672ef08c8df65dcRomain Guyusing namespace android;
49163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
50163935113919a184122b8b3bd672ef08c8df65dcRomain Guy// ----------------------------------------------------------------------------
519d5316e3f56d138504565ff311145ac01621dff4Romain Guy
529d5316e3f56d138504565ff311145ac01621dff4Romain Guy#define EGL_VERSION_HW_ANDROID  0x3143
539d5316e3f56d138504565ff311145ac01621dff4Romain Guy
549d5316e3f56d138504565ff311145ac01621dff4Romain Guystruct extention_map_t {
559d5316e3f56d138504565ff311145ac01621dff4Romain Guy    const char* name;
567ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    __eglMustCastToProperFunctionPointerType address;
577ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy};
589d5316e3f56d138504565ff311145ac01621dff4Romain Guy
599d5316e3f56d138504565ff311145ac01621dff4Romain Guystatic const extention_map_t sExtentionMap[] = {
60e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "eglLockSurfaceKHR",
61e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
62e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "eglUnlockSurfaceKHR",
63e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
64ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    { "eglCreateImageKHR",
6585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
66e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "eglDestroyImageKHR",
67e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
68ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    { "eglGetSystemTimeFrequencyNV",
69f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
70f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "eglGetSystemTimeNV",
71e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
72e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy};
73e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
74e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy// accesses protected by sExtensionMapMutex
75e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guystatic DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
76e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guystatic int sGLExtentionSlot = 0;
77ce0537b80087a6225273040a987414b1dd081aa0Romain Guystatic pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
78f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
79f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guystatic void(*findProcAddress(const char* name,
80e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        const extention_map_t* map, size_t n))() {
81e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    for (uint32_t i=0 ; i<n ; i++) {
82ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        if (!strcmp(name, map[i].name)) {
83f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            return map[i].address;
84f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
85e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
86e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    return NULL;
87e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
88bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
89bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy// ----------------------------------------------------------------------------
90bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
91ce0537b80087a6225273040a987414b1dd081aa0Romain Guytemplate<typename T>
92bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guystatic __attribute__((noinline))
93f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyint binarySearch(T const sortedArray[], int first, int last, T key) {
94f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    while (first <= last) {
95bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        int mid = (first + last) / 2;
96ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        if (sortedArray[mid] < key) {
97f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            first = mid + 1;
98f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        } else if (key < sortedArray[mid]) {
99bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            last = mid - 1;
100bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        } else {
101ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            return mid;
102f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
103f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    }
104bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    return -1;
105bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
106ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
107f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// ----------------------------------------------------------------------------
108f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
109bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guynamespace android {
110bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyextern void setGLHooksThreadSpecific(gl_hooks_t const *value);
111f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyextern EGLBoolean egl_init_drivers();
112bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyextern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
113bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyextern int gEGLDebugLevel;
114bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyextern gl_hooks_t gHooksTrace;
115ce0537b80087a6225273040a987414b1dd081aa0Romain Guy} // namespace android;
116bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
117bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy// ----------------------------------------------------------------------------
118bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
119bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guystatic inline void clearError() { egl_tls_t::clearError(); }
120bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guystatic inline EGLContext getContext() { return egl_tls_t::getContext(); }
121ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
122bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy// ----------------------------------------------------------------------------
123bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
124bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain GuyEGLDisplay eglGetDisplay(EGLNativeDisplayType display)
125bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy{
126bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    clearError();
127bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
128f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    uint32_t index = uint32_t(display);
129f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    if (index >= NUM_DISPLAYS) {
130f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
131ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    }
132c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
133c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    if (egl_init_drivers() == EGL_FALSE) {
134c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
135c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    }
136c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
137ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
138079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    return dpy;
139079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy}
140079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy
141f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// ----------------------------------------------------------------------------
142bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy// Initialization
143ce0537b80087a6225273040a987414b1dd081aa0Romain Guy// ----------------------------------------------------------------------------
144079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy
145079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain GuyEGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
146079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy{
147bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    clearError();
148bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
149ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    egl_display_t * const dp = get_display(dpy);
1509d5316e3f56d138504565ff311145ac01621dff4Romain Guy    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1517ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy
1529d5316e3f56d138504565ff311145ac01621dff4Romain Guy    EGLBoolean res = dp->initialize(major, minor);
1537ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy
1547ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    return res;
1559d5316e3f56d138504565ff311145ac01621dff4Romain Guy}
1567ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy
1579d5316e3f56d138504565ff311145ac01621dff4Romain GuyEGLBoolean eglTerminate(EGLDisplay dpy)
1589d5316e3f56d138504565ff311145ac01621dff4Romain Guy{
159bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    // NOTE: don't unload the drivers b/c some APIs can be called
160f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    // after eglTerminate() has been called. eglTerminate() only
161bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    // terminates an EGLDisplay, not a EGL itself.
162bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
163ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    clearError();
164f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1657ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    egl_display_t* const dp = get_display(dpy);
166f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
167bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
168ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    EGLBoolean res = dp->terminate();
169f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1707ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    return res;
171bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
172bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
173ce0537b80087a6225273040a987414b1dd081aa0Romain Guy// ----------------------------------------------------------------------------
174f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// configuration
1757ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy// ----------------------------------------------------------------------------
176f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
177bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain GuyEGLBoolean eglGetConfigs(   EGLDisplay dpy,
178ce0537b80087a6225273040a987414b1dd081aa0Romain Guy                            EGLConfig *configs,
179f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy                            EGLint config_size, EGLint *num_config)
1807ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy{
181f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    clearError();
182f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
183ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    egl_display_t const * const dp = validate_display(dpy);
184f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    if (!dp) return EGL_FALSE;
1857ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy
186f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    GLint numConfigs = dp->numTotalConfigs;
187f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    if (!configs) {
188ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        *num_config = numConfigs;
189f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        return EGL_TRUE;
1907ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    }
191bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
192bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    GLint n = 0;
193bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
194bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        *configs++ = EGLConfig(i);
19585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        config_size--;
19685bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        n++;
197ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    }
198dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
199dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    *num_config = n;
200ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    return EGL_TRUE;
201ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
202ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
203ce0537b80087a6225273040a987414b1dd081aa0Romain GuyEGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
204ce0537b80087a6225273040a987414b1dd081aa0Romain Guy                            EGLConfig *configs, EGLint config_size,
205dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy                            EGLint *num_config)
206dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy{
207dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    clearError();
208f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
2098ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    egl_display_t const * const dp = validate_display(dpy);
210f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy    if (!dp) return EGL_FALSE;
211dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
212dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    if (num_config==0) {
213ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
214ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    }
215deba785f122a47915756ffd991f5540d952cf937Romain Guy
216deba785f122a47915756ffd991f5540d952cf937Romain Guy    EGLint n;
217dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    EGLBoolean res = EGL_FALSE;
218deba785f122a47915756ffd991f5540d952cf937Romain Guy    *num_config = 0;
219deba785f122a47915756ffd991f5540d952cf937Romain Guy
220deba785f122a47915756ffd991f5540d952cf937Romain Guy
221deba785f122a47915756ffd991f5540d952cf937Romain Guy    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
222dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    // to do this, we have to go through the attrib_list array once
223deba785f122a47915756ffd991f5540d952cf937Romain Guy    // to figure out both its size and if it contains an EGL_CONFIG_ID
224deba785f122a47915756ffd991f5540d952cf937Romain Guy    // key. If so, the full array is copied and patched.
225deba785f122a47915756ffd991f5540d952cf937Romain Guy    // NOTE: we assume that there can be only one occurrence
226deba785f122a47915756ffd991f5540d952cf937Romain Guy    // of EGL_CONFIG_ID.
227ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
228ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    EGLint patch_index = -1;
229ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    GLint attr;
23085bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    size_t size = 0;
23185bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    if (attrib_list) {
232ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        while ((attr=attrib_list[size]) != EGL_NONE) {
233c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            if (attr == EGL_CONFIG_ID)
234c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy                patch_index = size;
235c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            size += 2;
236c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        }
237c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    }
2387fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    if (patch_index >= 0) {
2397fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        size += 2; // we need copy the sentinel as well
2407fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
2417fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        if (new_list == 0)
2427fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy            return setError(EGL_BAD_ALLOC, EGL_FALSE);
24385bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        memcpy(new_list, attrib_list, size*sizeof(EGLint));
244db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
245d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // patch the requested EGL_CONFIG_ID
246d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        bool found = false;
247db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        EGLConfig ourConfig(0);
248d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        EGLint& configId(new_list[patch_index+1]);
249d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
250db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            if (dp->configs[i].configId == configId) {
251d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy                ourConfig = EGLConfig(i);
252d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy                configId = dp->configs[i].implConfigId;
25306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy                found = true;
25406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy                break;
25506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            }
2567fac2e18339f765320d759e8d4c090f92431959eRomain Guy        }
2577fac2e18339f765320d759e8d4c090f92431959eRomain Guy
258db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
259db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (found && cnx->dso) {
260db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            // and switch to the new list
261db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            attrib_list = const_cast<const EGLint *>(new_list);
262db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
263d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy            // At this point, the only configuration that can match is
264a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            // dp->configs[i][index], however, we don't know if it would be
265a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            // rejected because of the other attributes, so we do have to call
266a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            // cnx->egl.eglChooseConfig() -- but we don't have to loop
267e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            // through all the EGLimpl[].
268e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            // We also know we can only get a single config back, and we know
269e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            // which one.
2709226298891119acff6b5e8b65fb7074fb99dc0c0Romain Guy
271e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            res = cnx->egl.eglChooseConfig(
2729226298891119acff6b5e8b65fb7074fb99dc0c0Romain Guy                    dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
273e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    attrib_list, configs, config_size, &n);
2749226298891119acff6b5e8b65fb7074fb99dc0c0Romain Guy            if (res && n>0) {
275e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                // n has to be 0 or 1, by construction, and we already know
276e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                // which config it will return (since there can be only one).
277e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                if (configs) {
278a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy                    configs[0] = ourConfig;
279a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy                }
280a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy                *num_config = 1;
281a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            }
282e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        }
283a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
284a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        free(const_cast<EGLint *>(attrib_list));
285a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        return res;
286a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    }
287a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
288a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
289a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
290e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        egl_connection_t* const cnx = &gEGLImpl[i];
291a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if (cnx->dso) {
292a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            if (cnx->egl.eglChooseConfig(
293a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy                    dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
294163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                if (configs) {
295163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    // now we need to convert these client EGLConfig to our
296163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    // internal EGLConfig format.
297163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    // This is done in O(n Log(n)) time.
298163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    for (int j=0 ; j<n ; j++) {
299163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                        egl_config_t key(i, configs[j]);
300163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                        intptr_t index = binarySearch<egl_config_t>(
301163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                                dp->configs, 0, dp->numTotalConfigs, key);
302163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                        if (index >= 0) {
303163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                            configs[j] = EGLConfig(index);
304163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                        } else {
305163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
306163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                        }
307163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    }
308a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy                    configs += n;
309e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy                    config_size -= n;
310e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy                }
311e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy                *num_config += n;
312e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy                res = EGL_TRUE;
313e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            }
314e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
315163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    }
316163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    return res;
317163935113919a184122b8b3bd672ef08c8df65dcRomain Guy}
318dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
319dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain GuyEGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
320dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        EGLint attribute, EGLint *value)
321dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy{
322dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    clearError();
323dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
324dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    egl_display_t const* dp = 0;
325dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
326dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    if (!cnx) return EGL_FALSE;
327dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
328dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    if (attribute == EGL_CONFIG_ID) {
329dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        *value = dp->configs[intptr_t(config)].configId;
330dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        return EGL_TRUE;
331dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    }
332079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    return cnx->egl.eglGetConfigAttrib(
333079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy            dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
334dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy            dp->configs[intptr_t(config)].config, attribute, value);
335dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy}
336dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
337dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy// ----------------------------------------------------------------------------
338dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy// surfaces
339dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy// ----------------------------------------------------------------------------
340dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
341dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain GuyEGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
342dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy                                    NativeWindowType window,
343dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy                                    const EGLint *attrib_list)
344dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy{
345dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    clearError();
346dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
347dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    egl_display_t const* dp = 0;
348dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
3497fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    if (cnx) {
350f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
351db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        EGLConfig iConfig = dp->configs[intptr_t(config)].config;
35206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        EGLint format;
353db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
354d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
355a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            LOGE("EGLNativeWindowType %p already connected to another API",
356a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy                    window);
357a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
358a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
359c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
360ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        // set the native window's buffers format to match this config
361163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        if (cnx->egl.eglGetConfigAttrib(iDpy,
362e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy                iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
363e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            if (format != 0) {
364163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                int err = native_window_set_buffers_format(window, format);
365163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                if (err != 0) {
366163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    LOGE("error setting native window pixel format: %s (%d)",
367163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                            strerror(-err), err);
368163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
369163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
370163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                }
371163935113919a184122b8b3bd672ef08c8df65dcRomain Guy            }
372163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        }
373163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
374163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        // the EGL spec requires that a new EGLSurface default to swap interval
375163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        // 1, so explicitly set that on the window here.
376163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
3779d5316e3f56d138504565ff311145ac01621dff4Romain Guy        anw->setSwapInterval(anw, 1);
378e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
3797ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
3807ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy                iDpy, iConfig, window, attrib_list);
3819d5316e3f56d138504565ff311145ac01621dff4Romain Guy        if (surface != EGL_NO_SURFACE) {
382e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
383e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy                    dp->configs[intptr_t(config)].impl, cnx);
384e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            return s;
385e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
386
387        // EGLSurface creation failed
388        native_window_set_buffers_format(window, 0);
389        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
390    }
391    return EGL_NO_SURFACE;
392}
393
394EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
395                                    NativePixmapType pixmap,
396                                    const EGLint *attrib_list)
397{
398    clearError();
399
400    egl_display_t const* dp = 0;
401    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
402    if (cnx) {
403        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
404                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
405                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
406        if (surface != EGL_NO_SURFACE) {
407            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
408                    dp->configs[intptr_t(config)].impl, cnx);
409            return s;
410        }
411    }
412    return EGL_NO_SURFACE;
413}
414
415EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
416                                    const EGLint *attrib_list)
417{
418    clearError();
419
420    egl_display_t const* dp = 0;
421    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
422    if (cnx) {
423        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
424                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
425                dp->configs[intptr_t(config)].config, attrib_list);
426        if (surface != EGL_NO_SURFACE) {
427            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
428                    dp->configs[intptr_t(config)].impl, cnx);
429            return s;
430        }
431    }
432    return EGL_NO_SURFACE;
433}
434
435EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
436{
437    clearError();
438
439    egl_display_t const * const dp = validate_display(dpy);
440    if (!dp) return EGL_FALSE;
441
442    SurfaceRef _s(dp, surface);
443    if (!_s.get())
444        return setError(EGL_BAD_SURFACE, EGL_FALSE);
445
446    egl_surface_t * const s = get_surface(surface);
447    EGLBoolean result = s->cnx->egl.eglDestroySurface(
448            dp->disp[s->impl].dpy, s->surface);
449    if (result == EGL_TRUE) {
450        _s.terminate();
451    }
452    return result;
453}
454
455EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
456                            EGLint attribute, EGLint *value)
457{
458    clearError();
459
460    egl_display_t const * const dp = validate_display(dpy);
461    if (!dp) return EGL_FALSE;
462
463    SurfaceRef _s(dp, surface);
464    if (!_s.get())
465        return setError(EGL_BAD_SURFACE, EGL_FALSE);
466
467    egl_surface_t const * const s = get_surface(surface);
468    EGLBoolean result(EGL_TRUE);
469    if (attribute == EGL_CONFIG_ID) {
470        // We need to remap EGL_CONFIG_IDs
471        *value = dp->configs[intptr_t(s->config)].configId;
472    } else {
473        result = s->cnx->egl.eglQuerySurface(
474                dp->disp[s->impl].dpy, s->surface, attribute, value);
475    }
476
477    return result;
478}
479
480// ----------------------------------------------------------------------------
481// Contexts
482// ----------------------------------------------------------------------------
483
484EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
485                            EGLContext share_list, const EGLint *attrib_list)
486{
487    clearError();
488
489    egl_display_t const* dp = 0;
490    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
491    if (cnx) {
492        if (share_list != EGL_NO_CONTEXT) {
493            egl_context_t* const c = get_context(share_list);
494            share_list = c->context;
495        }
496        EGLContext context = cnx->egl.eglCreateContext(
497                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
498                dp->configs[intptr_t(config)].config,
499                share_list, attrib_list);
500        if (context != EGL_NO_CONTEXT) {
501            // figure out if it's a GLESv1 or GLESv2
502            int version = 0;
503            if (attrib_list) {
504                while (*attrib_list != EGL_NONE) {
505                    GLint attr = *attrib_list++;
506                    GLint value = *attrib_list++;
507                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
508                        if (value == 1) {
509                            version = GLESv1_INDEX;
510                        } else if (value == 2) {
511                            version = GLESv2_INDEX;
512                        }
513                    }
514                };
515            }
516            egl_context_t* c = new egl_context_t(dpy, context, config,
517                    dp->configs[intptr_t(config)].impl, cnx, version);
518#if EGL_TRACE
519            if (gEGLDebugLevel > 0)
520                GLTrace_eglCreateContext(version, c);
521#endif
522            return c;
523        }
524    }
525    return EGL_NO_CONTEXT;
526}
527
528EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
529{
530    clearError();
531
532    egl_display_t const * const dp = validate_display(dpy);
533    if (!dp)
534        return EGL_FALSE;
535
536    ContextRef _c(dp, ctx);
537    if (!_c.get())
538        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
539
540    egl_context_t * const c = get_context(ctx);
541    EGLBoolean result = c->cnx->egl.eglDestroyContext(
542            dp->disp[c->impl].dpy, c->context);
543    if (result == EGL_TRUE) {
544        _c.terminate();
545    }
546    return result;
547}
548
549static void loseCurrent(egl_context_t * cur_c)
550{
551    if (cur_c) {
552        egl_surface_t * cur_r = get_surface(cur_c->read);
553        egl_surface_t * cur_d = get_surface(cur_c->draw);
554
555        // by construction, these are either 0 or valid (possibly terminated)
556        // it should be impossible for these to be invalid
557        ContextRef _cur_c(cur_c);
558        SurfaceRef _cur_r(cur_r);
559        SurfaceRef _cur_d(cur_d);
560
561        cur_c->read = NULL;
562        cur_c->draw = NULL;
563
564        _cur_c.release();
565        _cur_r.release();
566        _cur_d.release();
567    }
568}
569
570EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
571                            EGLSurface read, EGLContext ctx)
572{
573    clearError();
574
575    egl_display_t const * const dp = get_display(dpy);
576    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
577
578    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
579    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
580    // a valid but uninitialized display.
581    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
582         (draw != EGL_NO_SURFACE) ) {
583        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
584    }
585
586    // get a reference to the object passed in
587    ContextRef _c(dp, ctx);
588    SurfaceRef _d(dp, draw);
589    SurfaceRef _r(dp, read);
590
591    // validate the context (if not EGL_NO_CONTEXT)
592    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
593        // EGL_NO_CONTEXT is valid
594        return EGL_FALSE;
595    }
596
597    // these are the underlying implementation's object
598    EGLContext impl_ctx  = EGL_NO_CONTEXT;
599    EGLSurface impl_draw = EGL_NO_SURFACE;
600    EGLSurface impl_read = EGL_NO_SURFACE;
601
602    // these are our objects structs passed in
603    egl_context_t       * c = NULL;
604    egl_surface_t const * d = NULL;
605    egl_surface_t const * r = NULL;
606
607    // these are the current objects structs
608    egl_context_t * cur_c = get_context(getContext());
609
610    if (ctx != EGL_NO_CONTEXT) {
611        c = get_context(ctx);
612        impl_ctx = c->context;
613    } else {
614        // no context given, use the implementation of the current context
615        if (cur_c == NULL) {
616            // no current context
617            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
618                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
619                return setError(EGL_BAD_MATCH, EGL_FALSE);
620            }
621            // not an error, there is just no current context.
622            return EGL_TRUE;
623        }
624    }
625
626    // retrieve the underlying implementation's draw EGLSurface
627    if (draw != EGL_NO_SURFACE) {
628        d = get_surface(draw);
629        // make sure the EGLContext and EGLSurface passed in are for
630        // the same driver
631        if (c && d->impl != c->impl)
632            return setError(EGL_BAD_MATCH, EGL_FALSE);
633        impl_draw = d->surface;
634    }
635
636    // retrieve the underlying implementation's read EGLSurface
637    if (read != EGL_NO_SURFACE) {
638        r = get_surface(read);
639        // make sure the EGLContext and EGLSurface passed in are for
640        // the same driver
641        if (c && r->impl != c->impl)
642            return setError(EGL_BAD_MATCH, EGL_FALSE);
643        impl_read = r->surface;
644    }
645
646    EGLBoolean result;
647
648    if (c) {
649        result = c->cnx->egl.eglMakeCurrent(
650                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
651    } else {
652        result = cur_c->cnx->egl.eglMakeCurrent(
653                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
654    }
655
656    if (result == EGL_TRUE) {
657
658        loseCurrent(cur_c);
659
660        if (ctx != EGL_NO_CONTEXT) {
661            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
662            egl_tls_t::setContext(ctx);
663#if EGL_TRACE
664            if (gEGLDebugLevel > 0)
665                GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version]);
666#endif
667            _c.acquire();
668            _r.acquire();
669            _d.acquire();
670            c->read = read;
671            c->draw = draw;
672        } else {
673            setGLHooksThreadSpecific(&gHooksNoContext);
674            egl_tls_t::setContext(EGL_NO_CONTEXT);
675        }
676    } else {
677        // this will LOGE the error
678        result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
679    }
680    return result;
681}
682
683
684EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
685                            EGLint attribute, EGLint *value)
686{
687    clearError();
688
689    egl_display_t const * const dp = validate_display(dpy);
690    if (!dp) return EGL_FALSE;
691
692    ContextRef _c(dp, ctx);
693    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
694
695    egl_context_t * const c = get_context(ctx);
696
697    EGLBoolean result(EGL_TRUE);
698    if (attribute == EGL_CONFIG_ID) {
699        *value = dp->configs[intptr_t(c->config)].configId;
700    } else {
701        // We need to remap EGL_CONFIG_IDs
702        result = c->cnx->egl.eglQueryContext(
703                dp->disp[c->impl].dpy, c->context, attribute, value);
704    }
705
706    return result;
707}
708
709EGLContext eglGetCurrentContext(void)
710{
711    // could be called before eglInitialize(), but we wouldn't have a context
712    // then, and this function would correctly return EGL_NO_CONTEXT.
713
714    clearError();
715
716    EGLContext ctx = getContext();
717    return ctx;
718}
719
720EGLSurface eglGetCurrentSurface(EGLint readdraw)
721{
722    // could be called before eglInitialize(), but we wouldn't have a context
723    // then, and this function would correctly return EGL_NO_SURFACE.
724
725    clearError();
726
727    EGLContext ctx = getContext();
728    if (ctx) {
729        egl_context_t const * const c = get_context(ctx);
730        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
731        switch (readdraw) {
732            case EGL_READ: return c->read;
733            case EGL_DRAW: return c->draw;
734            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
735        }
736    }
737    return EGL_NO_SURFACE;
738}
739
740EGLDisplay eglGetCurrentDisplay(void)
741{
742    // could be called before eglInitialize(), but we wouldn't have a context
743    // then, and this function would correctly return EGL_NO_DISPLAY.
744
745    clearError();
746
747    EGLContext ctx = getContext();
748    if (ctx) {
749        egl_context_t const * const c = get_context(ctx);
750        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
751        return c->dpy;
752    }
753    return EGL_NO_DISPLAY;
754}
755
756EGLBoolean eglWaitGL(void)
757{
758    // could be called before eglInitialize(), but we wouldn't have a context
759    // then, and this function would return GL_TRUE, which isn't wrong.
760
761    clearError();
762
763    EGLBoolean res = EGL_TRUE;
764    EGLContext ctx = getContext();
765    if (ctx) {
766        egl_context_t const * const c = get_context(ctx);
767        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
768        if (uint32_t(c->impl)>=2)
769            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
770        egl_connection_t* const cnx = &gEGLImpl[c->impl];
771        if (!cnx->dso)
772            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
773        res = cnx->egl.eglWaitGL();
774    }
775    return res;
776}
777
778EGLBoolean eglWaitNative(EGLint engine)
779{
780    // could be called before eglInitialize(), but we wouldn't have a context
781    // then, and this function would return GL_TRUE, which isn't wrong.
782
783    clearError();
784
785    EGLBoolean res = EGL_TRUE;
786    EGLContext ctx = getContext();
787    if (ctx) {
788        egl_context_t const * const c = get_context(ctx);
789        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
790        if (uint32_t(c->impl)>=2)
791            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
792        egl_connection_t* const cnx = &gEGLImpl[c->impl];
793        if (!cnx->dso)
794            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
795        res = cnx->egl.eglWaitNative(engine);
796    }
797    return res;
798}
799
800EGLint eglGetError(void)
801{
802    EGLint result = EGL_SUCCESS;
803    EGLint err;
804    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
805        err = EGL_SUCCESS;
806        egl_connection_t* const cnx = &gEGLImpl[i];
807        if (cnx->dso)
808            err = cnx->egl.eglGetError();
809        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
810            result = err;
811    }
812    err = egl_tls_t::getError();
813    if (result == EGL_SUCCESS)
814        result = err;
815    return result;
816}
817
818// Note: Similar implementations of these functions also exist in
819// gl2.cpp and gl.cpp, and are used by applications that call the
820// exported entry points directly.
821typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
822typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
823
824static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
825static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
826
827static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
828{
829    GLeglImageOES implImage =
830        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
831    glEGLImageTargetTexture2DOES_impl(target, implImage);
832}
833
834static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
835{
836    GLeglImageOES implImage =
837        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
838    glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
839}
840
841__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
842{
843    // eglGetProcAddress() could be the very first function called
844    // in which case we must make sure we've initialized ourselves, this
845    // happens the first time egl_get_display() is called.
846
847    clearError();
848
849    if (egl_init_drivers() == EGL_FALSE) {
850        setError(EGL_BAD_PARAMETER, NULL);
851        return  NULL;
852    }
853
854    // The EGL_ANDROID_blob_cache extension should not be exposed to
855    // applications.  It is used internally by the Android EGL layer.
856    if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID")) {
857        return NULL;
858    }
859
860    __eglMustCastToProperFunctionPointerType addr;
861    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
862    if (addr) return addr;
863
864
865    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
866    pthread_mutex_lock(&sExtensionMapMutex);
867
868        /*
869         * Since eglGetProcAddress() is not associated to anything, it needs
870         * to return a function pointer that "works" regardless of what
871         * the current context is.
872         *
873         * For this reason, we return a "forwarder", a small stub that takes
874         * care of calling the function associated with the context
875         * currently bound.
876         *
877         * We first look for extensions we've already resolved, if we're seeing
878         * this extension for the first time, we go through all our
879         * implementations and call eglGetProcAddress() and record the
880         * result in the appropriate implementation hooks and return the
881         * address of the forwarder corresponding to that hook set.
882         *
883         */
884
885        const String8 name(procname);
886        addr = sGLExtentionMap.valueFor(name);
887        const int slot = sGLExtentionSlot;
888
889        LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
890                "no more slots for eglGetProcAddress(\"%s\")",
891                procname);
892
893#if EGL_TRACE
894        gl_hooks_t *debugHooks = GLTrace_getGLHooks();
895#endif
896
897        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
898            bool found = false;
899            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
900                egl_connection_t* const cnx = &gEGLImpl[i];
901                if (cnx->dso && cnx->egl.eglGetProcAddress) {
902                    found = true;
903                    // Extensions are independent of the bound context
904                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
905                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
906#if EGL_TRACE
907                    debugHooks->ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
908#endif
909                            cnx->egl.eglGetProcAddress(procname);
910                }
911            }
912            if (found) {
913                addr = gExtensionForwarders[slot];
914
915                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
916                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
917                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
918                }
919                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
920                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
921                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
922                }
923
924                sGLExtentionMap.add(name, addr);
925                sGLExtentionSlot++;
926            }
927        }
928
929    pthread_mutex_unlock(&sExtensionMapMutex);
930    return addr;
931}
932
933EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
934{
935    clearError();
936
937    egl_display_t const * const dp = validate_display(dpy);
938    if (!dp) return EGL_FALSE;
939
940    SurfaceRef _s(dp, draw);
941    if (!_s.get())
942        return setError(EGL_BAD_SURFACE, EGL_FALSE);
943
944#if EGL_TRACE
945    if (gEGLDebugLevel > 0)
946        GLTrace_eglSwapBuffers(dpy, draw);
947#endif
948
949    egl_surface_t const * const s = get_surface(draw);
950    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
951}
952
953EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
954                            NativePixmapType target)
955{
956    clearError();
957
958    egl_display_t const * const dp = validate_display(dpy);
959    if (!dp) return EGL_FALSE;
960
961    SurfaceRef _s(dp, surface);
962    if (!_s.get())
963        return setError(EGL_BAD_SURFACE, EGL_FALSE);
964
965    egl_surface_t const * const s = get_surface(surface);
966    return s->cnx->egl.eglCopyBuffers(
967            dp->disp[s->impl].dpy, s->surface, target);
968}
969
970const char* eglQueryString(EGLDisplay dpy, EGLint name)
971{
972    clearError();
973
974    egl_display_t const * const dp = validate_display(dpy);
975    if (!dp) return (const char *) NULL;
976
977    switch (name) {
978        case EGL_VENDOR:
979            return dp->getVendorString();
980        case EGL_VERSION:
981            return dp->getVersionString();
982        case EGL_EXTENSIONS:
983            return dp->getExtensionString();
984        case EGL_CLIENT_APIS:
985            return dp->getClientApiString();
986        case EGL_VERSION_HW_ANDROID: {
987            if (gEGLImpl[IMPL_HARDWARE].dso) {
988                return dp->disp[IMPL_HARDWARE].queryString.version;
989            }
990            return dp->disp[IMPL_SOFTWARE].queryString.version;
991        }
992    }
993    return setError(EGL_BAD_PARAMETER, (const char *)0);
994}
995
996
997// ----------------------------------------------------------------------------
998// EGL 1.1
999// ----------------------------------------------------------------------------
1000
1001EGLBoolean eglSurfaceAttrib(
1002        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1003{
1004    clearError();
1005
1006    egl_display_t const * const dp = validate_display(dpy);
1007    if (!dp) return EGL_FALSE;
1008
1009    SurfaceRef _s(dp, surface);
1010    if (!_s.get())
1011        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1012
1013    egl_surface_t const * const s = get_surface(surface);
1014    if (s->cnx->egl.eglSurfaceAttrib) {
1015        return s->cnx->egl.eglSurfaceAttrib(
1016                dp->disp[s->impl].dpy, s->surface, attribute, value);
1017    }
1018    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1019}
1020
1021EGLBoolean eglBindTexImage(
1022        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1023{
1024    clearError();
1025
1026    egl_display_t const * const dp = validate_display(dpy);
1027    if (!dp) return EGL_FALSE;
1028
1029    SurfaceRef _s(dp, surface);
1030    if (!_s.get())
1031        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1032
1033    egl_surface_t const * const s = get_surface(surface);
1034    if (s->cnx->egl.eglBindTexImage) {
1035        return s->cnx->egl.eglBindTexImage(
1036                dp->disp[s->impl].dpy, s->surface, buffer);
1037    }
1038    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1039}
1040
1041EGLBoolean eglReleaseTexImage(
1042        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1043{
1044    clearError();
1045
1046    egl_display_t const * const dp = validate_display(dpy);
1047    if (!dp) return EGL_FALSE;
1048
1049    SurfaceRef _s(dp, surface);
1050    if (!_s.get())
1051        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1052
1053    egl_surface_t const * const s = get_surface(surface);
1054    if (s->cnx->egl.eglReleaseTexImage) {
1055        return s->cnx->egl.eglReleaseTexImage(
1056                dp->disp[s->impl].dpy, s->surface, buffer);
1057    }
1058    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1059}
1060
1061EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1062{
1063    clearError();
1064
1065    egl_display_t const * const dp = validate_display(dpy);
1066    if (!dp) return EGL_FALSE;
1067
1068    EGLBoolean res = EGL_TRUE;
1069    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1070        egl_connection_t* const cnx = &gEGLImpl[i];
1071        if (cnx->dso) {
1072            if (cnx->egl.eglSwapInterval) {
1073                if (cnx->egl.eglSwapInterval(
1074                        dp->disp[i].dpy, interval) == EGL_FALSE) {
1075                    res = EGL_FALSE;
1076                }
1077            }
1078        }
1079    }
1080    return res;
1081}
1082
1083
1084// ----------------------------------------------------------------------------
1085// EGL 1.2
1086// ----------------------------------------------------------------------------
1087
1088EGLBoolean eglWaitClient(void)
1089{
1090    clearError();
1091
1092    // could be called before eglInitialize(), but we wouldn't have a context
1093    // then, and this function would return GL_TRUE, which isn't wrong.
1094    EGLBoolean res = EGL_TRUE;
1095    EGLContext ctx = getContext();
1096    if (ctx) {
1097        egl_context_t const * const c = get_context(ctx);
1098        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1099        if (uint32_t(c->impl)>=2)
1100            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1101        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1102        if (!cnx->dso)
1103            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1104        if (cnx->egl.eglWaitClient) {
1105            res = cnx->egl.eglWaitClient();
1106        } else {
1107            res = cnx->egl.eglWaitGL();
1108        }
1109    }
1110    return res;
1111}
1112
1113EGLBoolean eglBindAPI(EGLenum api)
1114{
1115    clearError();
1116
1117    if (egl_init_drivers() == EGL_FALSE) {
1118        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1119    }
1120
1121    // bind this API on all EGLs
1122    EGLBoolean res = EGL_TRUE;
1123    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1124        egl_connection_t* const cnx = &gEGLImpl[i];
1125        if (cnx->dso) {
1126            if (cnx->egl.eglBindAPI) {
1127                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1128                    res = EGL_FALSE;
1129                }
1130            }
1131        }
1132    }
1133    return res;
1134}
1135
1136EGLenum eglQueryAPI(void)
1137{
1138    clearError();
1139
1140    if (egl_init_drivers() == EGL_FALSE) {
1141        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1142    }
1143
1144    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1145        egl_connection_t* const cnx = &gEGLImpl[i];
1146        if (cnx->dso) {
1147            if (cnx->egl.eglQueryAPI) {
1148                // the first one we find is okay, because they all
1149                // should be the same
1150                return cnx->egl.eglQueryAPI();
1151            }
1152        }
1153    }
1154    // or, it can only be OpenGL ES
1155    return EGL_OPENGL_ES_API;
1156}
1157
1158EGLBoolean eglReleaseThread(void)
1159{
1160    clearError();
1161
1162    // If there is context bound to the thread, release it
1163    loseCurrent(get_context(getContext()));
1164
1165    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1166        egl_connection_t* const cnx = &gEGLImpl[i];
1167        if (cnx->dso) {
1168            if (cnx->egl.eglReleaseThread) {
1169                cnx->egl.eglReleaseThread();
1170            }
1171        }
1172    }
1173    egl_tls_t::clearTLS();
1174#if EGL_TRACE
1175    if (gEGLDebugLevel > 0)
1176        GLTrace_eglReleaseThread();
1177#endif
1178    return EGL_TRUE;
1179}
1180
1181EGLSurface eglCreatePbufferFromClientBuffer(
1182          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1183          EGLConfig config, const EGLint *attrib_list)
1184{
1185    clearError();
1186
1187    egl_display_t const* dp = 0;
1188    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1189    if (!cnx) return EGL_FALSE;
1190    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1191        return cnx->egl.eglCreatePbufferFromClientBuffer(
1192                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1193                buftype, buffer,
1194                dp->configs[intptr_t(config)].config, attrib_list);
1195    }
1196    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1197}
1198
1199// ----------------------------------------------------------------------------
1200// EGL_EGLEXT_VERSION 3
1201// ----------------------------------------------------------------------------
1202
1203EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1204        const EGLint *attrib_list)
1205{
1206    clearError();
1207
1208    egl_display_t const * const dp = validate_display(dpy);
1209    if (!dp) return EGL_FALSE;
1210
1211    SurfaceRef _s(dp, surface);
1212    if (!_s.get())
1213        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1214
1215    egl_surface_t const * const s = get_surface(surface);
1216    if (s->cnx->egl.eglLockSurfaceKHR) {
1217        return s->cnx->egl.eglLockSurfaceKHR(
1218                dp->disp[s->impl].dpy, s->surface, attrib_list);
1219    }
1220    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1221}
1222
1223EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1224{
1225    clearError();
1226
1227    egl_display_t const * const dp = validate_display(dpy);
1228    if (!dp) return EGL_FALSE;
1229
1230    SurfaceRef _s(dp, surface);
1231    if (!_s.get())
1232        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1233
1234    egl_surface_t const * const s = get_surface(surface);
1235    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1236        return s->cnx->egl.eglUnlockSurfaceKHR(
1237                dp->disp[s->impl].dpy, s->surface);
1238    }
1239    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1240}
1241
1242EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1243        EGLClientBuffer buffer, const EGLint *attrib_list)
1244{
1245    clearError();
1246
1247    egl_display_t const * const dp = validate_display(dpy);
1248    if (!dp) return EGL_NO_IMAGE_KHR;
1249
1250    if (ctx != EGL_NO_CONTEXT) {
1251        ContextRef _c(dp, ctx);
1252        if (!_c.get())
1253            return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1254        egl_context_t * const c = get_context(ctx);
1255        // since we have an EGLContext, we know which implementation to use
1256        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1257                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1258        if (image == EGL_NO_IMAGE_KHR)
1259            return image;
1260
1261        egl_image_t* result = new egl_image_t(dpy, ctx);
1262        result->images[c->impl] = image;
1263        return (EGLImageKHR)result;
1264    } else {
1265        // EGL_NO_CONTEXT is a valid parameter
1266
1267        /* Since we don't have a way to know which implementation to call,
1268         * we're calling all of them. If at least one of the implementation
1269         * succeeded, this is a success.
1270         */
1271
1272        EGLint currentError = eglGetError();
1273
1274        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1275        bool success = false;
1276        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1277            egl_connection_t* const cnx = &gEGLImpl[i];
1278            implImages[i] = EGL_NO_IMAGE_KHR;
1279            if (cnx->dso) {
1280                if (cnx->egl.eglCreateImageKHR) {
1281                    implImages[i] = cnx->egl.eglCreateImageKHR(
1282                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1283                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
1284                        success = true;
1285                    }
1286                }
1287            }
1288        }
1289
1290        if (!success) {
1291            // failure, if there was an error when we entered this function,
1292            // the error flag must not be updated.
1293            // Otherwise, the error is whatever happened in the implementation
1294            // that faulted.
1295            if (currentError != EGL_SUCCESS) {
1296                setError(currentError, EGL_NO_IMAGE_KHR);
1297            }
1298            return EGL_NO_IMAGE_KHR;
1299        } else {
1300            // In case of success, we need to clear all error flags
1301            // (especially those caused by the implementation that didn't
1302            // succeed). TODO: we could avoid this if we knew this was
1303            // a "full" success (all implementation succeeded).
1304            eglGetError();
1305        }
1306
1307        egl_image_t* result = new egl_image_t(dpy, ctx);
1308        memcpy(result->images, implImages, sizeof(implImages));
1309        return (EGLImageKHR)result;
1310    }
1311}
1312
1313EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1314{
1315    clearError();
1316
1317    egl_display_t const * const dp = validate_display(dpy);
1318    if (!dp) return EGL_FALSE;
1319
1320    ImageRef _i(dp, img);
1321    if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1322
1323    egl_image_t* image = get_image(img);
1324    bool success = false;
1325    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1326        egl_connection_t* const cnx = &gEGLImpl[i];
1327        if (image->images[i] != EGL_NO_IMAGE_KHR) {
1328            if (cnx->dso) {
1329                if (cnx->egl.eglDestroyImageKHR) {
1330                    if (cnx->egl.eglDestroyImageKHR(
1331                            dp->disp[i].dpy, image->images[i])) {
1332                        success = true;
1333                    }
1334                }
1335            }
1336        }
1337    }
1338    if (!success)
1339        return EGL_FALSE;
1340
1341    _i.terminate();
1342
1343    return EGL_TRUE;
1344}
1345
1346// ----------------------------------------------------------------------------
1347// EGL_EGLEXT_VERSION 5
1348// ----------------------------------------------------------------------------
1349
1350
1351EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1352{
1353    clearError();
1354
1355    egl_display_t const * const dp = validate_display(dpy);
1356    if (!dp) return EGL_NO_SYNC_KHR;
1357
1358    EGLContext ctx = eglGetCurrentContext();
1359    ContextRef _c(dp, ctx);
1360    if (!_c.get())
1361        return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1362
1363    egl_context_t * const c = get_context(ctx);
1364    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1365    if (c->cnx->egl.eglCreateSyncKHR) {
1366        EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1367                dp->disp[c->impl].dpy, type, attrib_list);
1368        if (sync == EGL_NO_SYNC_KHR)
1369            return sync;
1370        result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1371    }
1372    return (EGLSyncKHR)result;
1373}
1374
1375EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1376{
1377    clearError();
1378
1379    egl_display_t const * const dp = validate_display(dpy);
1380    if (!dp) return EGL_FALSE;
1381
1382    SyncRef _s(dp, sync);
1383    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1384    egl_sync_t* syncObject = get_sync(sync);
1385
1386    EGLContext ctx = syncObject->context;
1387    ContextRef _c(dp, ctx);
1388    if (!_c.get())
1389        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1390
1391    EGLBoolean result = EGL_FALSE;
1392    egl_context_t * const c = get_context(ctx);
1393    if (c->cnx->egl.eglDestroySyncKHR) {
1394        result = c->cnx->egl.eglDestroySyncKHR(
1395                dp->disp[c->impl].dpy, syncObject->sync);
1396        if (result)
1397            _s.terminate();
1398    }
1399    return result;
1400}
1401
1402EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1403{
1404    clearError();
1405
1406    egl_display_t const * const dp = validate_display(dpy);
1407    if (!dp) return EGL_FALSE;
1408
1409    SyncRef _s(dp, sync);
1410    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1411    egl_sync_t* syncObject = get_sync(sync);
1412
1413    EGLContext ctx = syncObject->context;
1414    ContextRef _c(dp, ctx);
1415    if (!_c.get())
1416        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1417
1418    egl_context_t * const c = get_context(ctx);
1419    if (c->cnx->egl.eglClientWaitSyncKHR) {
1420        return c->cnx->egl.eglClientWaitSyncKHR(
1421                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1422    }
1423
1424    return EGL_FALSE;
1425}
1426
1427EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1428{
1429    clearError();
1430
1431    egl_display_t const * const dp = validate_display(dpy);
1432    if (!dp) return EGL_FALSE;
1433
1434    SyncRef _s(dp, sync);
1435    if (!_s.get())
1436        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1437
1438    egl_sync_t* syncObject = get_sync(sync);
1439    EGLContext ctx = syncObject->context;
1440    ContextRef _c(dp, ctx);
1441    if (!_c.get())
1442        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1443
1444    egl_context_t * const c = get_context(ctx);
1445    if (c->cnx->egl.eglGetSyncAttribKHR) {
1446        return c->cnx->egl.eglGetSyncAttribKHR(
1447                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1448    }
1449
1450    return EGL_FALSE;
1451}
1452
1453// ----------------------------------------------------------------------------
1454// ANDROID extensions
1455// ----------------------------------------------------------------------------
1456
1457/* ANDROID extensions entry-point go here */
1458
1459// ----------------------------------------------------------------------------
1460// NVIDIA extensions
1461// ----------------------------------------------------------------------------
1462EGLuint64NV eglGetSystemTimeFrequencyNV()
1463{
1464    clearError();
1465
1466    if (egl_init_drivers() == EGL_FALSE) {
1467        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1468    }
1469
1470    EGLuint64NV ret = 0;
1471    egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
1472
1473    if (cnx->dso) {
1474        if (cnx->egl.eglGetSystemTimeFrequencyNV) {
1475            return cnx->egl.eglGetSystemTimeFrequencyNV();
1476        }
1477    }
1478
1479    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1480}
1481
1482EGLuint64NV eglGetSystemTimeNV()
1483{
1484    clearError();
1485
1486    if (egl_init_drivers() == EGL_FALSE) {
1487        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1488    }
1489
1490    EGLuint64NV ret = 0;
1491    egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
1492
1493    if (cnx->dso) {
1494        if (cnx->egl.eglGetSystemTimeNV) {
1495            return cnx->egl.eglGetSystemTimeNV();
1496        }
1497    }
1498
1499    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1500}
1501