egl.cpp revision e09fd9e819c23dc90bca68375645e15544861330
1/*
2**
3** Copyright 2007 The Android Open Source Project
4**
5** Licensed under the Apache License Version 2.0(the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing software
12** distributed under the License is distributed on an "AS IS" BASIS
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "EGL"
19
20#include <assert.h>
21#include <errno.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/ioctl.h>
28#include <sys/types.h>
29#include <sys/mman.h>
30
31#include <cutils/log.h>
32#include <cutils/atomic.h>
33
34#include <utils/threads.h>
35
36#include <GLES/egl.h>
37
38#include <pixelflinger/format.h>
39#include <pixelflinger/pixelflinger.h>
40
41#include "context.h"
42#include "state.h"
43#include "texture.h"
44#include "matrix.h"
45
46#undef NELEM
47#define NELEM(x) (sizeof(x)/sizeof(*(x)))
48
49// ----------------------------------------------------------------------------
50namespace android {
51// ----------------------------------------------------------------------------
52
53const unsigned int NUM_DISPLAYS = 1;
54
55static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
56static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
57static pthread_key_t gEGLErrorKey = -1;
58#ifndef HAVE_ANDROID_OS
59namespace gl {
60pthread_key_t gGLKey = -1;
61}; // namespace gl
62#endif
63
64template<typename T>
65static T setError(GLint error, T returnValue) {
66    if (ggl_unlikely(gEGLErrorKey == -1)) {
67        pthread_mutex_lock(&gErrorKeyMutex);
68        if (gEGLErrorKey == -1)
69            pthread_key_create(&gEGLErrorKey, NULL);
70        pthread_mutex_unlock(&gErrorKeyMutex);
71    }
72    pthread_setspecific(gEGLErrorKey, (void*)error);
73    return returnValue;
74}
75
76static GLint getError() {
77    if (ggl_unlikely(gEGLErrorKey == -1))
78        return EGL_SUCCESS;
79    GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
80    pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
81    return error;
82}
83
84// ----------------------------------------------------------------------------
85
86struct egl_display_t
87{
88    egl_display_t() : type(0), initialized(0) { }
89
90    static egl_display_t& get_display(EGLDisplay dpy);
91
92    static EGLBoolean is_valid(EGLDisplay dpy) {
93        return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
94    }
95
96    NativeDisplayType   type;
97    volatile int32_t    initialized;
98};
99
100static egl_display_t gDisplays[NUM_DISPLAYS];
101
102egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
103    return gDisplays[uintptr_t(dpy)-1U];
104}
105
106struct egl_context_t {
107    enum {
108        IS_CURRENT      =   0x00010000,
109        NEVER_CURRENT   =   0x00020000
110    };
111    uint32_t            flags;
112    EGLDisplay          dpy;
113    EGLConfig           config;
114    EGLSurface          read;
115    EGLSurface          draw;
116
117    static inline egl_context_t* context(EGLContext ctx) {
118        ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
119        return static_cast<egl_context_t*>(gl->rasterizer.base);
120    }
121};
122
123// ----------------------------------------------------------------------------
124
125struct egl_surface_t
126{
127    enum {
128        PAGE_FLIP = 0x00000001,
129        MAGIC     = 0x31415265
130    };
131
132    uint32_t            magic;
133    EGLDisplay          dpy;
134    EGLConfig           config;
135    EGLContext          ctx;
136
137                egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
138    virtual     ~egl_surface_t();
139    virtual     bool    isValid() const = 0;
140
141    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl) = 0;
142    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl) = 0;
143    virtual     EGLint      getWidth() const = 0;
144    virtual     EGLint      getHeight() const = 0;
145    virtual     void*       getBits() const = 0;
146
147    virtual     EGLint      getHorizontalResolution() const;
148    virtual     EGLint      getVerticalResolution() const;
149    virtual     EGLint      getRefreshRate() const;
150    virtual     EGLint      getSwapBehavior() const;
151    virtual     EGLBoolean  swapBuffers();
152    virtual     EGLBoolean  swapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
153protected:
154    GGLSurface              depth;
155};
156
157egl_surface_t::egl_surface_t(EGLDisplay dpy,
158        EGLConfig config,
159        int32_t depthFormat)
160    : magic(MAGIC), dpy(dpy), config(config), ctx(0)
161{
162    depth.version = sizeof(GGLSurface);
163    depth.data = 0;
164    depth.format = depthFormat;
165}
166egl_surface_t::~egl_surface_t()
167{
168    magic = 0;
169    free(depth.data);
170}
171EGLBoolean egl_surface_t::swapBuffers() {
172    return EGL_FALSE;
173}
174EGLBoolean egl_surface_t::swapRectangle(
175        EGLint l, EGLint t, EGLint w, EGLint h) {
176    return EGL_FALSE;
177}
178EGLint egl_surface_t::getHorizontalResolution() const {
179    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
180}
181EGLint egl_surface_t::getVerticalResolution() const {
182    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
183}
184EGLint egl_surface_t::getRefreshRate() const {
185    return (60 * EGL_DISPLAY_SCALING);
186}
187EGLint egl_surface_t::getSwapBehavior() const {
188    return EGL_BUFFER_PRESERVED;
189}
190
191// ----------------------------------------------------------------------------
192
193struct egl_window_surface_t : public egl_surface_t
194{
195    egl_window_surface_t(
196            EGLDisplay dpy, EGLConfig config,
197            int32_t depthFormat,
198            egl_native_window_t* window);
199
200     ~egl_window_surface_t();
201
202    virtual     bool        isValid() const { return nativeWindow->magic == 0x600913; }
203    virtual     EGLBoolean  swapBuffers();
204    virtual     EGLBoolean  swapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
205    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
206    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
207    virtual     EGLint      getWidth() const    { return nativeWindow->width;  }
208    virtual     EGLint      getHeight() const   { return nativeWindow->height; }
209    virtual     void*       getBits() const;
210    virtual     EGLint      getHorizontalResolution() const;
211    virtual     EGLint      getVerticalResolution() const;
212    virtual     EGLint      getRefreshRate() const;
213    virtual     EGLint      getSwapBehavior() const;
214private:
215    egl_native_window_t*    nativeWindow;
216};
217
218egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
219        EGLConfig config,
220        int32_t depthFormat,
221        egl_native_window_t* window)
222    : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
223{
224    if (depthFormat) {
225        depth.width   = window->width;
226        depth.height  = window->height;
227        depth.stride  = depth.width; // use the width here
228        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
229        if (depth.data == 0) {
230            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
231            return;
232        }
233    }
234    nativeWindow->incRef(nativeWindow);
235}
236egl_window_surface_t::~egl_window_surface_t() {
237    nativeWindow->decRef(nativeWindow);
238}
239
240EGLBoolean egl_window_surface_t::swapBuffers()
241{
242    uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
243    if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
244        // TODO: we probably should reset the swap rect here
245        // if the window size has changed
246        //    window->setSwapRectangle(Rect(info.w, info.h));
247        if (depth.data) {
248            free(depth.data);
249            depth.width   = nativeWindow->width;
250            depth.height  = nativeWindow->height;
251            depth.stride  = nativeWindow->stride;
252            depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
253            if (depth.data == 0) {
254                setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
255                return EGL_FALSE;
256            }
257        }
258    }
259    return EGL_TRUE;
260}
261
262EGLBoolean egl_window_surface_t::swapRectangle(
263        EGLint l, EGLint t, EGLint w, EGLint h)
264{
265    nativeWindow->setSwapRectangle(nativeWindow, l, t, w, h);
266    return EGL_TRUE;
267}
268EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
269{
270    GGLSurface buffer;
271    buffer.version = sizeof(GGLSurface);
272    buffer.width   = nativeWindow->width;
273    buffer.height  = nativeWindow->height;
274    buffer.stride  = nativeWindow->stride;
275    buffer.data    = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
276    buffer.format  = nativeWindow->format;
277    gl->rasterizer.procs.colorBuffer(gl, &buffer);
278    if (depth.data != gl->rasterizer.state.buffers.depth.data)
279        gl->rasterizer.procs.depthBuffer(gl, &depth);
280    return EGL_TRUE;
281}
282EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
283{
284    GGLSurface buffer;
285    buffer.version = sizeof(GGLSurface);
286    buffer.width   = nativeWindow->width;
287    buffer.height  = nativeWindow->height;
288    buffer.stride  = nativeWindow->stride;
289    buffer.data    = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
290    buffer.format  = nativeWindow->format;
291    gl->rasterizer.procs.readBuffer(gl, &buffer);
292    return EGL_TRUE;
293}
294void* egl_window_surface_t::getBits() const {
295    return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
296}
297EGLint egl_window_surface_t::getHorizontalResolution() const {
298    return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
299}
300EGLint egl_window_surface_t::getVerticalResolution() const {
301    return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
302}
303EGLint egl_window_surface_t::getRefreshRate() const {
304    return (nativeWindow->fps * EGL_DISPLAY_SCALING);
305}
306EGLint egl_window_surface_t::getSwapBehavior() const {
307    uint32_t flags = nativeWindow->flags;
308    if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
309        return EGL_BUFFER_DESTROYED;
310    return EGL_BUFFER_PRESERVED;
311}
312
313// ----------------------------------------------------------------------------
314
315struct egl_pixmap_surface_t : public egl_surface_t
316{
317    egl_pixmap_surface_t(
318            EGLDisplay dpy, EGLConfig config,
319            int32_t depthFormat,
320            egl_native_pixmap_t const * pixmap);
321
322    virtual ~egl_pixmap_surface_t() { }
323
324    virtual     bool        isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
325    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
326    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
327    virtual     EGLint      getWidth() const    { return nativePixmap.width;  }
328    virtual     EGLint      getHeight() const   { return nativePixmap.height; }
329    virtual     void*       getBits() const     { return nativePixmap.data; }
330private:
331    egl_native_pixmap_t     nativePixmap;
332};
333
334egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
335        EGLConfig config,
336        int32_t depthFormat,
337        egl_native_pixmap_t const * pixmap)
338    : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
339{
340    if (depthFormat) {
341        depth.width   = pixmap->width;
342        depth.height  = pixmap->height;
343        depth.stride  = depth.width; // use the width here
344        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
345        if (depth.data == 0) {
346            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
347            return;
348        }
349    }
350}
351EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
352{
353    GGLSurface buffer;
354    buffer.version = sizeof(GGLSurface);
355    buffer.width   = nativePixmap.width;
356    buffer.height  = nativePixmap.height;
357    buffer.stride  = nativePixmap.stride;
358    buffer.data    = nativePixmap.data;
359    buffer.format  = nativePixmap.format;
360
361    gl->rasterizer.procs.colorBuffer(gl, &buffer);
362    if (depth.data != gl->rasterizer.state.buffers.depth.data)
363        gl->rasterizer.procs.depthBuffer(gl, &depth);
364    return EGL_TRUE;
365}
366EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
367{
368    GGLSurface buffer;
369    buffer.version = sizeof(GGLSurface);
370    buffer.width   = nativePixmap.width;
371    buffer.height  = nativePixmap.height;
372    buffer.stride  = nativePixmap.stride;
373    buffer.data    = nativePixmap.data;
374    buffer.format  = nativePixmap.format;
375    gl->rasterizer.procs.readBuffer(gl, &buffer);
376    return EGL_TRUE;
377}
378
379// ----------------------------------------------------------------------------
380
381struct egl_pbuffer_surface_t : public egl_surface_t
382{
383    egl_pbuffer_surface_t(
384            EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
385            int32_t w, int32_t h, int32_t f);
386
387    virtual ~egl_pbuffer_surface_t();
388
389    virtual     bool        isValid() const { return pbuffer.data != 0; }
390    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
391    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
392    virtual     EGLint      getWidth() const    { return pbuffer.width;  }
393    virtual     EGLint      getHeight() const   { return pbuffer.height; }
394    virtual     void*       getBits() const     { return pbuffer.data; }
395private:
396    GGLSurface  pbuffer;
397};
398
399egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
400        EGLConfig config, int32_t depthFormat,
401        int32_t w, int32_t h, int32_t f)
402    : egl_surface_t(dpy, config, depthFormat)
403{
404    size_t size = w*h;
405    switch (f) {
406        case GGL_PIXEL_FORMAT_A_8:          size *= 1; break;
407        case GGL_PIXEL_FORMAT_RGB_565:      size *= 2; break;
408        case GGL_PIXEL_FORMAT_RGBA_8888:    size *= 4; break;
409        default:
410            LOGE("incompatible pixel format for pbuffer (format=%d)", f);
411            pbuffer.data = 0;
412            break;
413    }
414    pbuffer.version = sizeof(GGLSurface);
415    pbuffer.width   = w;
416    pbuffer.height  = h;
417    pbuffer.stride  = w;
418    pbuffer.data    = (GGLubyte*)malloc(size);
419    pbuffer.format  = f;
420
421    if (depthFormat) {
422        depth.width   = pbuffer.width;
423        depth.height  = pbuffer.height;
424        depth.stride  = depth.width; // use the width here
425        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
426        if (depth.data == 0) {
427            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
428            return;
429        }
430    }
431}
432egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
433    free(pbuffer.data);
434}
435EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
436{
437    gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
438    if (depth.data != gl->rasterizer.state.buffers.depth.data)
439        gl->rasterizer.procs.depthBuffer(gl, &depth);
440    return EGL_TRUE;
441}
442EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
443{
444    gl->rasterizer.procs.readBuffer(gl, &pbuffer);
445    return EGL_TRUE;
446}
447
448// ----------------------------------------------------------------------------
449
450struct config_pair_t {
451    GLint key;
452    GLint value;
453};
454
455struct configs_t {
456    const config_pair_t* array;
457    int                  size;
458};
459
460struct config_management_t {
461    GLint key;
462    bool (*match)(GLint reqValue, GLint confValue);
463    static bool atLeast(GLint reqValue, GLint confValue) {
464        return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
465    }
466    static bool exact(GLint reqValue, GLint confValue) {
467        return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
468    }
469    static bool mask(GLint reqValue, GLint confValue) {
470        return (confValue & reqValue) == reqValue;
471    }
472};
473
474// ----------------------------------------------------------------------------
475
476static char const * const gVendorString     = "Google Inc.";
477static char const * const gVersionString    = "1.2 Android Driver";
478static char const * const gClientApiString  = "OpenGL ES";
479static char const * const gExtensionsString =
480    "EGL_ANDROID_swap_rectangle"                " "
481    "EGL_ANDROID_copy_front_to_back"            " "
482    "EGL_ANDROID_get_render_buffer_address"
483    ;
484
485// ----------------------------------------------------------------------------
486
487struct extention_map_t {
488    const char * const name;
489    void (*address)(void);
490};
491
492static const extention_map_t gExtentionMap[] = {
493    { "eglSwapRectangleANDROID",    (void(*)())&eglSwapRectangleANDROID },
494    { "glDrawTexsOES",              (void(*)())&glDrawTexsOES },
495    { "glDrawTexiOES",              (void(*)())&glDrawTexiOES },
496    { "glDrawTexfOES",              (void(*)())&glDrawTexfOES },
497    { "glDrawTexxOES",              (void(*)())&glDrawTexxOES },
498    { "glDrawTexsvOES",             (void(*)())&glDrawTexsvOES },
499    { "glDrawTexivOES",             (void(*)())&glDrawTexivOES },
500    { "glDrawTexfvOES",             (void(*)())&glDrawTexfvOES },
501    { "glDrawTexxvOES",             (void(*)())&glDrawTexxvOES },
502    { "glQueryMatrixxOES",          (void(*)())&glQueryMatrixxOES },
503    { "glClipPlanef",               (void(*)())&glClipPlanef },
504    { "glClipPlanex",               (void(*)())&glClipPlanex },
505    { "glBindBuffer",               (void(*)())&glBindBuffer },
506    { "glBufferData",               (void(*)())&glBufferData },
507    { "glBufferSubData",            (void(*)())&glBufferSubData },
508    { "glDeleteBuffers",            (void(*)())&glDeleteBuffers },
509    { "glGenBuffers",               (void(*)())&glGenBuffers },
510};
511
512/*
513 * In the lists below, attributes names MUST be sorted.
514 * Additionally, all configs must be sorted according to
515 * the EGL specification.
516 */
517
518static config_pair_t const config_base_attribute_list[] = {
519        { EGL_STENCIL_SIZE,               0                                 },
520        { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
521        { EGL_LEVEL,                      0                                 },
522        { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
523        { EGL_MAX_PBUFFER_PIXELS,
524                GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
525        { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
526        { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
527        { EGL_NATIVE_VISUAL_ID,           0                                 },
528        { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGB_565          },
529        { EGL_SAMPLES,                    0                                 },
530        { EGL_SAMPLE_BUFFERS,             0                                 },
531        { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
532        { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
533        { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
534        { EGL_TRANSPARENT_RED_VALUE,      0                                 },
535        { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
536        { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
537        { EGL_MIN_SWAP_INTERVAL,          1                                 },
538        { EGL_MAX_SWAP_INTERVAL,          4                                 },
539};
540
541// These configs can override the base attribute list
542// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
543
544static config_pair_t const config_0_attribute_list[] = {
545        { EGL_BUFFER_SIZE,     16 },
546        { EGL_ALPHA_SIZE,       0 },
547        { EGL_BLUE_SIZE,        5 },
548        { EGL_GREEN_SIZE,       6 },
549        { EGL_RED_SIZE,         5 },
550        { EGL_DEPTH_SIZE,       0 },
551        { EGL_CONFIG_ID,        0 },
552        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
553};
554
555static config_pair_t const config_1_attribute_list[] = {
556        { EGL_BUFFER_SIZE,     16 },
557        { EGL_ALPHA_SIZE,       0 },
558        { EGL_BLUE_SIZE,        5 },
559        { EGL_GREEN_SIZE,       6 },
560        { EGL_RED_SIZE,         5 },
561        { EGL_DEPTH_SIZE,      16 },
562        { EGL_CONFIG_ID,        1 },
563        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
564};
565
566static config_pair_t const config_2_attribute_list[] = {
567        { EGL_BUFFER_SIZE,     32 },
568        { EGL_ALPHA_SIZE,       8 },
569        { EGL_BLUE_SIZE,        8 },
570        { EGL_GREEN_SIZE,       8 },
571        { EGL_RED_SIZE,         8 },
572        { EGL_DEPTH_SIZE,       0 },
573        { EGL_CONFIG_ID,        2 },
574        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
575};
576
577static config_pair_t const config_3_attribute_list[] = {
578        { EGL_BUFFER_SIZE,     32 },
579        { EGL_ALPHA_SIZE,       8 },
580        { EGL_BLUE_SIZE,        8 },
581        { EGL_GREEN_SIZE,       8 },
582        { EGL_RED_SIZE,         8 },
583        { EGL_DEPTH_SIZE,      16 },
584        { EGL_CONFIG_ID,        3 },
585        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
586};
587
588static config_pair_t const config_4_attribute_list[] = {
589        { EGL_BUFFER_SIZE,      8 },
590        { EGL_ALPHA_SIZE,       8 },
591        { EGL_BLUE_SIZE,        0 },
592        { EGL_GREEN_SIZE,       0 },
593        { EGL_RED_SIZE,         0 },
594        { EGL_DEPTH_SIZE,       0 },
595        { EGL_CONFIG_ID,        4 },
596        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
597};
598
599static config_pair_t const config_5_attribute_list[] = {
600        { EGL_BUFFER_SIZE,      8 },
601        { EGL_ALPHA_SIZE,       8 },
602        { EGL_BLUE_SIZE,        0 },
603        { EGL_GREEN_SIZE,       0 },
604        { EGL_RED_SIZE,         0 },
605        { EGL_DEPTH_SIZE,      16 },
606        { EGL_CONFIG_ID,        5 },
607        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
608};
609
610static configs_t const gConfigs[] = {
611        { config_0_attribute_list, NELEM(config_0_attribute_list) },
612        { config_1_attribute_list, NELEM(config_1_attribute_list) },
613        { config_2_attribute_list, NELEM(config_2_attribute_list) },
614        { config_3_attribute_list, NELEM(config_3_attribute_list) },
615        { config_4_attribute_list, NELEM(config_4_attribute_list) },
616        { config_5_attribute_list, NELEM(config_5_attribute_list) },
617};
618
619static config_management_t const gConfigManagement[] = {
620        { EGL_BUFFER_SIZE,                config_management_t::atLeast },
621        { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
622        { EGL_BLUE_SIZE,                  config_management_t::atLeast },
623        { EGL_GREEN_SIZE,                 config_management_t::atLeast },
624        { EGL_RED_SIZE,                   config_management_t::atLeast },
625        { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
626        { EGL_STENCIL_SIZE,               config_management_t::atLeast },
627        { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
628        { EGL_CONFIG_ID,                  config_management_t::exact   },
629        { EGL_LEVEL,                      config_management_t::exact   },
630        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::exact   },
631        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::exact   },
632        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::exact   },
633        { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
634        { EGL_NATIVE_VISUAL_ID,           config_management_t::exact   },
635        { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
636        { EGL_SAMPLES,                    config_management_t::exact   },
637        { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
638        { EGL_SURFACE_TYPE,               config_management_t::mask    },
639        { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
640        { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
641        { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
642        { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
643        { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
644        { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
645        { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
646        { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
647};
648
649static config_pair_t const config_defaults[] = {
650        { EGL_SURFACE_TYPE,        EGL_WINDOW_BIT },
651};
652
653// ----------------------------------------------------------------------------
654
655template<typename T>
656static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
657{
658   while (first <= last) {
659       int mid = (first + last) / 2;
660       if (key > sortedArray[mid].key) {
661           first = mid + 1;
662       } else if (key < sortedArray[mid].key) {
663           last = mid - 1;
664       } else {
665           return mid;
666       }
667   }
668   return -1;
669}
670
671static int isAttributeMatching(int i, EGLint attr, EGLint val)
672{
673    // look for the attribute in all of our configs
674    config_pair_t const* configFound = gConfigs[i].array;
675    int index = binarySearch<config_pair_t>(
676            gConfigs[i].array,
677            0, gConfigs[i].size-1,
678            attr);
679    if (index < 0) {
680        configFound = config_base_attribute_list;
681        index = binarySearch<config_pair_t>(
682                config_base_attribute_list,
683                0, NELEM(config_base_attribute_list)-1,
684                attr);
685    }
686    if (index >= 0) {
687        // attribute found, check if this config could match
688        int cfgMgtIndex = binarySearch<config_management_t>(
689                gConfigManagement,
690                0, NELEM(gConfigManagement)-1,
691                attr);
692        if (index >= 0) {
693            bool match = gConfigManagement[cfgMgtIndex].match(
694                    val, configFound[index].value);
695            if (match) {
696                // this config matches
697                return 1;
698            }
699        } else {
700            // attribute not found. this should NEVER happen.
701        }
702    } else {
703        // error, this attribute doesn't exist
704    }
705    return 0;
706}
707
708static int makeCurrent(ogles_context_t* gl)
709{
710    ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
711    if (gl) {
712        egl_context_t* c = egl_context_t::context(gl);
713        if (c->flags & egl_context_t::IS_CURRENT) {
714            if (current != gl) {
715                // it is an error to set a context current, if it's already
716                // current to another thread
717                return -1;
718            }
719        } else {
720            if (current) {
721                // mark the current context as not current, and flush
722                glFlush();
723                egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
724            }
725        }
726        if (!(c->flags & egl_context_t::IS_CURRENT)) {
727            // The context is not current, make it current!
728            setGlThreadSpecific(gl);
729            c->flags |= egl_context_t::IS_CURRENT;
730        }
731    } else {
732        if (current) {
733            // mark the current context as not current, and flush
734            glFlush();
735            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
736        }
737        // this thread has no context attached to it
738        setGlThreadSpecific(0);
739    }
740    return 0;
741}
742
743static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
744        EGLint attribute, EGLint *value)
745{
746    size_t numConfigs =  NELEM(gConfigs);
747    int index = (int)config;
748    if (uint32_t(index) >= numConfigs)
749        return setError(EGL_BAD_CONFIG, EGL_FALSE);
750
751    int attrIndex;
752    attrIndex = binarySearch<config_pair_t>(
753            gConfigs[index].array,
754            0, gConfigs[index].size-1,
755            attribute);
756    if (attrIndex>=0) {
757        *value = gConfigs[index].array[attrIndex].value;
758        return EGL_TRUE;
759    }
760
761    attrIndex = binarySearch<config_pair_t>(
762            config_base_attribute_list,
763            0, NELEM(config_base_attribute_list)-1,
764            attribute);
765    if (attrIndex>=0) {
766        *value = config_base_attribute_list[attrIndex].value;
767        return EGL_TRUE;
768    }
769    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
770}
771
772static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
773        NativeWindowType window, const EGLint *attrib_list)
774{
775    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
776        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
777    if (window == 0)
778        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
779
780    EGLint surfaceType;
781    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
782        return EGL_FALSE;
783
784    if (!(surfaceType & EGL_WINDOW_BIT))
785        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
786
787    EGLint configID;
788    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
789        return EGL_FALSE;
790
791    int32_t depthFormat;
792    int32_t pixelFormat;
793    switch(configID) {
794    case 0:
795        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
796        depthFormat = 0;
797        break;
798    case 1:
799        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
800        depthFormat = GGL_PIXEL_FORMAT_Z_16;
801        break;
802    case 2:
803        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
804        depthFormat = 0;
805        break;
806    case 3:
807        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
808        depthFormat = GGL_PIXEL_FORMAT_Z_16;
809        break;
810    case 4:
811        pixelFormat = GGL_PIXEL_FORMAT_A_8;
812        depthFormat = 0;
813        break;
814    case 5:
815        pixelFormat = GGL_PIXEL_FORMAT_A_8;
816        depthFormat = GGL_PIXEL_FORMAT_Z_16;
817        break;
818    default:
819        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
820    }
821
822    // FIXME: we don't have access to the pixelFormat here just yet.
823    // (it's possible that the surface is not fully initialized)
824    // maybe this should be done after the page-flip
825    //if (EGLint(info.format) != pixelFormat)
826    //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
827
828    egl_surface_t* surface =
829        new egl_window_surface_t(dpy, config, depthFormat,
830                static_cast<egl_native_window_t*>(window));
831
832    if (!surface->isValid()) {
833        // there was a problem in the ctor, the error
834        // flag has been set.
835        delete surface;
836        surface = 0;
837    }
838    return surface;
839}
840
841static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
842        NativePixmapType pixmap, const EGLint *attrib_list)
843{
844    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
845        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
846    if (pixmap == 0)
847        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
848
849    EGLint surfaceType;
850    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
851        return EGL_FALSE;
852
853    if (!(surfaceType & EGL_PIXMAP_BIT))
854        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
855
856    EGLint configID;
857    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
858        return EGL_FALSE;
859
860    int32_t depthFormat;
861    int32_t pixelFormat;
862    switch(configID) {
863    case 0:
864        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
865        depthFormat = 0;
866        break;
867    case 1:
868        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
869        depthFormat = GGL_PIXEL_FORMAT_Z_16;
870        break;
871    case 2:
872        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
873        depthFormat = 0;
874        break;
875    case 3:
876        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
877        depthFormat = GGL_PIXEL_FORMAT_Z_16;
878        break;
879    case 4:
880        pixelFormat = GGL_PIXEL_FORMAT_A_8;
881        depthFormat = 0;
882        break;
883    case 5:
884        pixelFormat = GGL_PIXEL_FORMAT_A_8;
885        depthFormat = GGL_PIXEL_FORMAT_Z_16;
886        break;
887    default:
888        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
889    }
890
891    if (pixmap->format != pixelFormat)
892        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
893
894    egl_surface_t* surface =
895        new egl_pixmap_surface_t(dpy, config, depthFormat,
896                static_cast<egl_native_pixmap_t*>(pixmap));
897
898    if (!surface->isValid()) {
899        // there was a problem in the ctor, the error
900        // flag has been set.
901        delete surface;
902        surface = 0;
903    }
904    return surface;
905}
906
907static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
908        const EGLint *attrib_list)
909{
910    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
911        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
912
913    EGLint surfaceType;
914    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
915        return EGL_FALSE;
916
917    if (!(surfaceType & EGL_PBUFFER_BIT))
918        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
919
920    EGLint configID;
921    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
922        return EGL_FALSE;
923
924    int32_t depthFormat;
925    int32_t pixelFormat;
926    switch(configID) {
927    case 0:
928        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
929        depthFormat = 0;
930        break;
931    case 1:
932        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
933        depthFormat = GGL_PIXEL_FORMAT_Z_16;
934        break;
935    case 2:
936        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
937        depthFormat = 0;
938        break;
939    case 3:
940        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
941        depthFormat = GGL_PIXEL_FORMAT_Z_16;
942        break;
943    case 4:
944        pixelFormat = GGL_PIXEL_FORMAT_A_8;
945        depthFormat = 0;
946        break;
947    case 5:
948        pixelFormat = GGL_PIXEL_FORMAT_A_8;
949        depthFormat = GGL_PIXEL_FORMAT_Z_16;
950        break;
951    default:
952        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
953    }
954
955    int32_t w = 0;
956    int32_t h = 0;
957    while (attrib_list[0]) {
958        if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
959        if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
960        attrib_list+=2;
961    }
962
963    egl_surface_t* surface =
964        new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
965
966    if (!surface->isValid()) {
967        // there was a problem in the ctor, the error
968        // flag has been set.
969        delete surface;
970        surface = 0;
971    }
972    return surface;
973}
974
975// ----------------------------------------------------------------------------
976}; // namespace android
977// ----------------------------------------------------------------------------
978
979using namespace android;
980
981// ----------------------------------------------------------------------------
982// Initialization
983// ----------------------------------------------------------------------------
984
985EGLDisplay eglGetDisplay(NativeDisplayType display)
986{
987#ifndef HAVE_ANDROID_OS
988    // this just needs to be done once
989    if (gGLKey == -1) {
990        pthread_mutex_lock(&gInitMutex);
991        if (gGLKey == -1)
992            pthread_key_create(&gGLKey, NULL);
993        pthread_mutex_unlock(&gInitMutex);
994    }
995#endif
996    if (display == EGL_DEFAULT_DISPLAY) {
997        EGLDisplay dpy = (EGLDisplay)1;
998        egl_display_t& d = egl_display_t::get_display(dpy);
999        d.type = display;
1000        return dpy;
1001    }
1002    return EGL_NO_DISPLAY;
1003}
1004
1005EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
1006{
1007    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1008        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1009
1010    EGLBoolean res = EGL_TRUE;
1011    egl_display_t& d = egl_display_t::get_display(dpy);
1012
1013    if (android_atomic_inc(&d.initialized) == 0) {
1014        // initialize stuff here if needed
1015        //pthread_mutex_lock(&gInitMutex);
1016        //pthread_mutex_unlock(&gInitMutex);
1017    }
1018
1019    if (res == EGL_TRUE) {
1020        if (major != NULL) *major = 1;
1021        if (minor != NULL) *minor = 2;
1022    }
1023    return res;
1024}
1025
1026EGLBoolean eglTerminate(EGLDisplay dpy)
1027{
1028    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1029        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1030
1031    EGLBoolean res = EGL_TRUE;
1032    egl_display_t& d = egl_display_t::get_display(dpy);
1033    if (android_atomic_dec(&d.initialized) == 1) {
1034        // TODO: destroy all resources (surfaces, contexts, etc...)
1035        //pthread_mutex_lock(&gInitMutex);
1036        //pthread_mutex_unlock(&gInitMutex);
1037    }
1038    return res;
1039}
1040
1041// ----------------------------------------------------------------------------
1042// configuration
1043// ----------------------------------------------------------------------------
1044
1045EGLBoolean eglGetConfigs(   EGLDisplay dpy,
1046                            EGLConfig *configs,
1047                            EGLint config_size, EGLint *num_config)
1048{
1049    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1050        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1051
1052    GLint numConfigs = NELEM(gConfigs);
1053    if (!configs) {
1054        *num_config = numConfigs;
1055        return EGL_TRUE;
1056    }
1057    GLint i;
1058    for (i=0 ; i<numConfigs && i<config_size ; i++) {
1059        *configs++ = (EGLConfig)i;
1060    }
1061    *num_config = i;
1062    return EGL_TRUE;
1063}
1064
1065EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1066                            EGLConfig *configs, EGLint config_size,
1067                            EGLint *num_config)
1068{
1069    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1070        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1071
1072    if (ggl_unlikely(configs==0 || attrib_list==0)) {
1073        *num_config = 0;
1074        return EGL_TRUE;
1075    }
1076
1077    int numAttributes = 0;
1078    int numConfigs =  NELEM(gConfigs);
1079    uint32_t possibleMatch = (1<<numConfigs)-1;
1080    while(possibleMatch && *attrib_list != EGL_NONE) {
1081        numAttributes++;
1082        EGLint attr = *attrib_list++;
1083        EGLint val  = *attrib_list++;
1084        for (int i=0 ; i<numConfigs ; i++) {
1085            if (!(possibleMatch & (1<<i)))
1086                continue;
1087            if (isAttributeMatching(i, attr, val) == 0) {
1088                possibleMatch &= ~(1<<i);
1089            }
1090        }
1091    }
1092
1093    // now, handle the attributes which have a useful default value
1094    for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
1095        // see if this attribute was specified, if not apply its
1096        // default value
1097        if (binarySearch<config_pair_t>(
1098                (config_pair_t const*)attrib_list,
1099                0, numAttributes,
1100                config_defaults[j].key) < 0)
1101        {
1102            for (int i=0 ; i<numConfigs ; i++) {
1103                if (!(possibleMatch & (1<<i)))
1104                    continue;
1105                if (isAttributeMatching(i,
1106                        config_defaults[j].key,
1107                        config_defaults[j].value) == 0)
1108                {
1109                    possibleMatch &= ~(1<<i);
1110                }
1111            }
1112        }
1113    }
1114
1115    // return the configurations found
1116    int n=0;
1117    if (possibleMatch) {
1118        for (int i=0 ; config_size && i<numConfigs ; i++) {
1119            if (possibleMatch & (1<<i)) {
1120               *configs++ = (EGLConfig)i;
1121                config_size--;
1122                n++;
1123            }
1124        }
1125    }
1126    *num_config = n;
1127     return EGL_TRUE;
1128}
1129
1130EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1131        EGLint attribute, EGLint *value)
1132{
1133    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1134        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1135
1136    return getConfigAttrib(dpy, config, attribute, value);
1137}
1138
1139// ----------------------------------------------------------------------------
1140// surfaces
1141// ----------------------------------------------------------------------------
1142
1143EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
1144                                    NativeWindowType window,
1145                                    const EGLint *attrib_list)
1146{
1147    return createWindowSurface(dpy, config, window, attrib_list);
1148}
1149
1150EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
1151                                    NativePixmapType pixmap,
1152                                    const EGLint *attrib_list)
1153{
1154    return createPixmapSurface(dpy, config, pixmap, attrib_list);
1155}
1156
1157EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1158                                    const EGLint *attrib_list)
1159{
1160    return createPbufferSurface(dpy, config, attrib_list);
1161}
1162
1163EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
1164{
1165    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1166        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1167    if (eglSurface != EGL_NO_SURFACE) {
1168        egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
1169        if (surface->magic != egl_surface_t::MAGIC)
1170            return setError(EGL_BAD_SURFACE, EGL_FALSE);
1171        if (surface->dpy != dpy)
1172            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1173        delete surface;
1174    }
1175    return EGL_TRUE;
1176}
1177
1178EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
1179                            EGLint attribute, EGLint *value)
1180{
1181    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1182        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1183    egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
1184    if (surface->dpy != dpy)
1185        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1186
1187    EGLBoolean ret = EGL_TRUE;
1188    switch (attribute) {
1189        case EGL_CONFIG_ID:
1190            ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
1191            break;
1192        case EGL_WIDTH:
1193            *value = surface->getWidth();
1194            break;
1195        case EGL_HEIGHT:
1196            *value = surface->getHeight();
1197            break;
1198        case EGL_LARGEST_PBUFFER:
1199            // not modified for a window or pixmap surface
1200            break;
1201        case EGL_TEXTURE_FORMAT:
1202            *value = EGL_NO_TEXTURE;
1203            break;
1204        case EGL_TEXTURE_TARGET:
1205            *value = EGL_NO_TEXTURE;
1206            break;
1207        case EGL_MIPMAP_TEXTURE:
1208            *value = EGL_FALSE;
1209            break;
1210        case EGL_MIPMAP_LEVEL:
1211            *value = 0;
1212            break;
1213        case EGL_RENDER_BUFFER:
1214            // TODO: return the real RENDER_BUFFER here
1215            *value = EGL_BACK_BUFFER;
1216            break;
1217        case EGL_HORIZONTAL_RESOLUTION:
1218            // pixel/mm * EGL_DISPLAY_SCALING
1219            *value = surface->getHorizontalResolution();
1220            break;
1221        case EGL_VERTICAL_RESOLUTION:
1222            // pixel/mm * EGL_DISPLAY_SCALING
1223            *value = surface->getVerticalResolution();
1224            break;
1225        case EGL_PIXEL_ASPECT_RATIO: {
1226            // w/h * EGL_DISPLAY_SCALING
1227            int wr = surface->getHorizontalResolution();
1228            int hr = surface->getVerticalResolution();
1229            *value = (wr * EGL_DISPLAY_SCALING) / hr;
1230        } break;
1231        case EGL_SWAP_BEHAVIOR:
1232            *value = surface->getSwapBehavior();
1233            break;
1234        default:
1235            ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1236    }
1237    return ret;
1238}
1239
1240EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1241                            EGLContext share_list, const EGLint *attrib_list)
1242{
1243    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1244        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1245
1246    ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
1247    if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1248
1249    egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
1250    c->flags = egl_context_t::NEVER_CURRENT;
1251    c->dpy = dpy;
1252    c->config = config;
1253    c->read = 0;
1254    c->draw = 0;
1255    return (EGLContext)gl;
1256}
1257
1258EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1259{
1260    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1261        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1262    egl_context_t* c = egl_context_t::context(ctx);
1263    if (c->flags & egl_context_t::IS_CURRENT)
1264        setGlThreadSpecific(0);
1265    ogles_uninit((ogles_context_t*)ctx);
1266    return EGL_TRUE;
1267}
1268
1269EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
1270                            EGLSurface read, EGLContext ctx)
1271{
1272    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1273        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1274    if (draw) {
1275        egl_surface_t* s = (egl_surface_t*)draw;
1276        if (s->dpy != dpy)
1277            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1278        // TODO: check that draw and read are compatible with the context
1279    }
1280
1281    EGLContext current_ctx = EGL_NO_CONTEXT;
1282
1283    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1284        return setError(EGL_BAD_MATCH, EGL_FALSE);
1285
1286    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1287        return setError(EGL_BAD_MATCH, EGL_FALSE);
1288
1289    if (ctx == EGL_NO_CONTEXT) {
1290        // if we're detaching, we need the current context
1291        current_ctx = (EGLContext)getGlThreadSpecific();
1292    } else {
1293        egl_context_t* c = egl_context_t::context(ctx);
1294        egl_surface_t* d = (egl_surface_t*)draw;
1295        egl_surface_t* r = (egl_surface_t*)read;
1296        if ((d && d->ctx && d->ctx != ctx) ||
1297            (r && r->ctx && r->ctx != ctx)) {
1298            // once of the surface is bound to a context in another thread
1299            return setError(EGL_BAD_ACCESS, EGL_FALSE);
1300        }
1301    }
1302
1303    ogles_context_t* gl = (ogles_context_t*)ctx;
1304    if (makeCurrent(gl) == 0) {
1305        if (ctx) {
1306            egl_context_t* c = egl_context_t::context(ctx);
1307            egl_surface_t* d = (egl_surface_t*)draw;
1308            egl_surface_t* r = (egl_surface_t*)read;
1309            c->read = read;
1310            c->draw = draw;
1311            if (c->flags & egl_context_t::NEVER_CURRENT) {
1312                c->flags &= ~egl_context_t::NEVER_CURRENT;
1313                GLint w = 0;
1314                GLint h = 0;
1315                if (draw) {
1316                    w = d->getWidth();
1317                    h = d->getHeight();
1318                }
1319                ogles_surfaceport(gl, 0, 0);
1320                ogles_viewport(gl, 0, 0, w, h);
1321                ogles_scissor(gl, 0, 0, w, h);
1322            }
1323            if (d) {
1324                d->ctx = ctx;
1325                d->bindDrawSurface(gl);
1326            }
1327            if (r) {
1328                r->ctx = ctx;
1329                r->bindReadSurface(gl);
1330            }
1331        } else {
1332            // if surfaces were bound to the context bound to this thread
1333            // mark then as unbound.
1334            if (current_ctx) {
1335                egl_context_t* c = egl_context_t::context(current_ctx);
1336                egl_surface_t* d = (egl_surface_t*)c->draw;
1337                egl_surface_t* r = (egl_surface_t*)c->read;
1338                if (d) d->ctx = EGL_NO_CONTEXT;
1339                if (r) r->ctx = EGL_NO_CONTEXT;
1340            }
1341        }
1342        return EGL_TRUE;
1343    }
1344    return setError(EGL_BAD_ACCESS, EGL_FALSE);
1345}
1346
1347EGLContext eglGetCurrentContext(void)
1348{
1349    // eglGetCurrentContext returns the current EGL rendering context,
1350    // as specified by eglMakeCurrent. If no context is current,
1351    // EGL_NO_CONTEXT is returned.
1352    return (EGLContext)getGlThreadSpecific();
1353}
1354
1355EGLSurface eglGetCurrentSurface(EGLint readdraw)
1356{
1357    // eglGetCurrentSurface returns the read or draw surface attached
1358    // to the current EGL rendering context, as specified by eglMakeCurrent.
1359    // If no context is current, EGL_NO_SURFACE is returned.
1360    EGLContext ctx = (EGLContext)getGlThreadSpecific();
1361    if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
1362    egl_context_t* c = egl_context_t::context(ctx);
1363    if (readdraw == EGL_READ) {
1364        return c->read;
1365    } else if (readdraw == EGL_DRAW) {
1366        return c->draw;
1367    }
1368    return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
1369}
1370
1371EGLDisplay eglGetCurrentDisplay(void)
1372{
1373    // eglGetCurrentDisplay returns the current EGL display connection
1374    // for the current EGL rendering context, as specified by eglMakeCurrent.
1375    // If no context is current, EGL_NO_DISPLAY is returned.
1376    EGLContext ctx = (EGLContext)getGlThreadSpecific();
1377    if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
1378    egl_context_t* c = egl_context_t::context(ctx);
1379    return c->dpy;
1380}
1381
1382EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1383                            EGLint attribute, EGLint *value)
1384{
1385    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1386        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1387    egl_context_t* c = egl_context_t::context(ctx);
1388    switch (attribute) {
1389        case EGL_CONFIG_ID:
1390            // Returns the ID of the EGL frame buffer configuration with
1391            // respect to which the context was created
1392            return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
1393    }
1394    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1395}
1396
1397EGLBoolean eglWaitGL(void)
1398{
1399    return EGL_TRUE;
1400}
1401
1402EGLBoolean eglWaitNative(EGLint engine)
1403{
1404    return EGL_TRUE;
1405}
1406
1407EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1408{
1409    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1410        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1411
1412    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1413    if (d->dpy != dpy)
1414        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1415
1416    // post the surface
1417    d->swapBuffers();
1418
1419    // if it's bound to a context, update the buffer
1420    if (d->ctx != EGL_NO_CONTEXT) {
1421        d->bindDrawSurface((ogles_context_t*)d->ctx);
1422        // if this surface is also the read surface of the context
1423        // it is bound to, make sure to update the read buffer as well.
1424        // The EGL spec is a little unclear about this.
1425        egl_context_t* c = egl_context_t::context(d->ctx);
1426        if (c->read == draw) {
1427            d->bindReadSurface((ogles_context_t*)d->ctx);
1428        }
1429    }
1430
1431    return EGL_TRUE;
1432}
1433
1434EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1435                            NativePixmapType target)
1436{
1437    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1438        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1439    // TODO: eglCopyBuffers()
1440    return EGL_FALSE;
1441}
1442
1443EGLint eglGetError(void)
1444{
1445    return getError();
1446}
1447
1448const char* eglQueryString(EGLDisplay dpy, EGLint name)
1449{
1450    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1451        return setError(EGL_BAD_DISPLAY, (const char*)0);
1452
1453    switch (name) {
1454        case EGL_VENDOR:
1455            return gVendorString;
1456        case EGL_VERSION:
1457            return gVersionString;
1458        case EGL_EXTENSIONS:
1459            return gExtensionsString;
1460        case EGL_CLIENT_APIS:
1461            return gClientApiString;
1462    }
1463    return setError(EGL_BAD_PARAMETER, (const char *)0);
1464}
1465
1466// ----------------------------------------------------------------------------
1467// EGL 1.1
1468// ----------------------------------------------------------------------------
1469
1470EGLBoolean eglSurfaceAttrib(
1471        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1472{
1473    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1474        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1475    // TODO: eglSurfaceAttrib()
1476    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1477}
1478
1479EGLBoolean eglBindTexImage(
1480        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1481{
1482    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1483        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1484    // TODO: eglBindTexImage()
1485    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1486}
1487
1488EGLBoolean eglReleaseTexImage(
1489        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1490{
1491    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1492        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1493    // TODO: eglReleaseTexImage()
1494    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1495}
1496
1497EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1498{
1499    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1500        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1501    // TODO: eglSwapInterval()
1502    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1503}
1504
1505// ----------------------------------------------------------------------------
1506// EGL 1.2
1507// ----------------------------------------------------------------------------
1508
1509EGLBoolean eglBindAPI(EGLenum api)
1510{
1511    if (api != EGL_OPENGL_ES_API)
1512        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1513    return EGL_TRUE;
1514}
1515
1516EGLenum eglQueryAPI(void)
1517{
1518    return EGL_OPENGL_ES_API;
1519}
1520
1521EGLBoolean eglWaitClient(void)
1522{
1523    glFinish();
1524    return EGL_TRUE;
1525}
1526
1527EGLBoolean eglReleaseThread(void)
1528{
1529    // TODO: eglReleaseThread()
1530    return EGL_TRUE;
1531}
1532
1533EGLSurface eglCreatePbufferFromClientBuffer(
1534          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1535          EGLConfig config, const EGLint *attrib_list)
1536{
1537    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1538        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1539    // TODO: eglCreatePbufferFromClientBuffer()
1540    return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1541}
1542
1543// ----------------------------------------------------------------------------
1544// Android extensions
1545// ----------------------------------------------------------------------------
1546
1547void (*eglGetProcAddress (const char *procname))()
1548{
1549    extention_map_t const * const map = gExtentionMap;
1550    for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
1551        if (!strcmp(procname, map[i].name)) {
1552            return map[i].address;
1553        }
1554    }
1555    return NULL;
1556}
1557
1558EGLBoolean eglSwapRectangleANDROID(
1559        EGLDisplay dpy, EGLSurface draw,
1560        EGLint l, EGLint t, EGLint w, EGLint h)
1561{
1562    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1563        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1564    egl_surface_t* surface = (egl_surface_t*)draw;
1565    if (surface->dpy != dpy)
1566        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1567    return surface->swapRectangle(l, t, w, h);
1568}
1569