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