egl.cpp revision 43aa2b1cbf7a03e248e10f4d0fec0463257cd52d
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
466static char const * const gVendorString     = "Google Inc.";
467static char const * const gVersionString    = "1.2 Android Driver";
468static char const * const gClientApiString  = "OpenGL ES";
469static char const * const gExtensionsString = "";
470
471// ----------------------------------------------------------------------------
472
473struct extention_map_t {
474    const char * const name;
475    __eglMustCastToProperFunctionPointerType address;
476};
477
478static const extention_map_t gExtentionMap[] = {
479    { "glDrawTexsOES",              (void(*)())&glDrawTexsOES },
480    { "glDrawTexiOES",              (void(*)())&glDrawTexiOES },
481    { "glDrawTexfOES",              (void(*)())&glDrawTexfOES },
482    { "glDrawTexxOES",              (void(*)())&glDrawTexxOES },
483    { "glDrawTexsvOES",             (void(*)())&glDrawTexsvOES },
484    { "glDrawTexivOES",             (void(*)())&glDrawTexivOES },
485    { "glDrawTexfvOES",             (void(*)())&glDrawTexfvOES },
486    { "glDrawTexxvOES",             (void(*)())&glDrawTexxvOES },
487    { "glQueryMatrixxOES",          (void(*)())&glQueryMatrixxOES },
488    { "glClipPlanef",               (void(*)())&glClipPlanef },
489    { "glClipPlanex",               (void(*)())&glClipPlanex },
490    { "glBindBuffer",               (void(*)())&glBindBuffer },
491    { "glBufferData",               (void(*)())&glBufferData },
492    { "glBufferSubData",            (void(*)())&glBufferSubData },
493    { "glDeleteBuffers",            (void(*)())&glDeleteBuffers },
494    { "glGenBuffers",               (void(*)())&glGenBuffers },
495};
496
497/*
498 * In the lists below, attributes names MUST be sorted.
499 * Additionally, all configs must be sorted according to
500 * the EGL specification.
501 */
502
503static config_pair_t const config_base_attribute_list[] = {
504        { EGL_STENCIL_SIZE,               0                                 },
505        { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
506        { EGL_LEVEL,                      0                                 },
507        { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
508        { EGL_MAX_PBUFFER_PIXELS,
509                GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
510        { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
511        { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
512        { EGL_NATIVE_VISUAL_ID,           0                                 },
513        { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGB_565          },
514        { EGL_SAMPLES,                    0                                 },
515        { EGL_SAMPLE_BUFFERS,             0                                 },
516        { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
517        { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
518        { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
519        { EGL_TRANSPARENT_RED_VALUE,      0                                 },
520        { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
521        { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
522        { EGL_MIN_SWAP_INTERVAL,          1                                 },
523        { EGL_MAX_SWAP_INTERVAL,          4                                 },
524};
525
526// These configs can override the base attribute list
527// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
528
529static config_pair_t const config_0_attribute_list[] = {
530        { EGL_BUFFER_SIZE,     16 },
531        { EGL_ALPHA_SIZE,       0 },
532        { EGL_BLUE_SIZE,        5 },
533        { EGL_GREEN_SIZE,       6 },
534        { EGL_RED_SIZE,         5 },
535        { EGL_DEPTH_SIZE,       0 },
536        { EGL_CONFIG_ID,        0 },
537        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
538};
539
540static config_pair_t const config_1_attribute_list[] = {
541        { EGL_BUFFER_SIZE,     16 },
542        { EGL_ALPHA_SIZE,       0 },
543        { EGL_BLUE_SIZE,        5 },
544        { EGL_GREEN_SIZE,       6 },
545        { EGL_RED_SIZE,         5 },
546        { EGL_DEPTH_SIZE,      16 },
547        { EGL_CONFIG_ID,        1 },
548        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
549};
550
551static config_pair_t const config_2_attribute_list[] = {
552        { EGL_BUFFER_SIZE,     32 },
553        { EGL_ALPHA_SIZE,       8 },
554        { EGL_BLUE_SIZE,        8 },
555        { EGL_GREEN_SIZE,       8 },
556        { EGL_RED_SIZE,         8 },
557        { EGL_DEPTH_SIZE,       0 },
558        { EGL_CONFIG_ID,        2 },
559        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
560};
561
562static config_pair_t const config_3_attribute_list[] = {
563        { EGL_BUFFER_SIZE,     32 },
564        { EGL_ALPHA_SIZE,       8 },
565        { EGL_BLUE_SIZE,        8 },
566        { EGL_GREEN_SIZE,       8 },
567        { EGL_RED_SIZE,         8 },
568        { EGL_DEPTH_SIZE,      16 },
569        { EGL_CONFIG_ID,        3 },
570        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
571};
572
573static config_pair_t const config_4_attribute_list[] = {
574        { EGL_BUFFER_SIZE,      8 },
575        { EGL_ALPHA_SIZE,       8 },
576        { EGL_BLUE_SIZE,        0 },
577        { EGL_GREEN_SIZE,       0 },
578        { EGL_RED_SIZE,         0 },
579        { EGL_DEPTH_SIZE,       0 },
580        { EGL_CONFIG_ID,        4 },
581        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
582};
583
584static config_pair_t const config_5_attribute_list[] = {
585        { EGL_BUFFER_SIZE,      8 },
586        { EGL_ALPHA_SIZE,       8 },
587        { EGL_BLUE_SIZE,        0 },
588        { EGL_GREEN_SIZE,       0 },
589        { EGL_RED_SIZE,         0 },
590        { EGL_DEPTH_SIZE,      16 },
591        { EGL_CONFIG_ID,        5 },
592        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
593};
594
595static configs_t const gConfigs[] = {
596        { config_0_attribute_list, NELEM(config_0_attribute_list) },
597        { config_1_attribute_list, NELEM(config_1_attribute_list) },
598        { config_2_attribute_list, NELEM(config_2_attribute_list) },
599        { config_3_attribute_list, NELEM(config_3_attribute_list) },
600        { config_4_attribute_list, NELEM(config_4_attribute_list) },
601        { config_5_attribute_list, NELEM(config_5_attribute_list) },
602};
603
604static config_management_t const gConfigManagement[] = {
605        { EGL_BUFFER_SIZE,                config_management_t::atLeast },
606        { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
607        { EGL_BLUE_SIZE,                  config_management_t::atLeast },
608        { EGL_GREEN_SIZE,                 config_management_t::atLeast },
609        { EGL_RED_SIZE,                   config_management_t::atLeast },
610        { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
611        { EGL_STENCIL_SIZE,               config_management_t::atLeast },
612        { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
613        { EGL_CONFIG_ID,                  config_management_t::exact   },
614        { EGL_LEVEL,                      config_management_t::exact   },
615        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::exact   },
616        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::exact   },
617        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::exact   },
618        { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
619        { EGL_NATIVE_VISUAL_ID,           config_management_t::exact   },
620        { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
621        { EGL_SAMPLES,                    config_management_t::exact   },
622        { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
623        { EGL_SURFACE_TYPE,               config_management_t::mask    },
624        { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
625        { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
626        { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
627        { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
628        { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
629        { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
630        { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
631        { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
632};
633
634static config_pair_t const config_defaults[] = {
635        { EGL_SURFACE_TYPE,        EGL_WINDOW_BIT },
636};
637
638// ----------------------------------------------------------------------------
639
640template<typename T>
641static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
642{
643   while (first <= last) {
644       int mid = (first + last) / 2;
645       if (key > sortedArray[mid].key) {
646           first = mid + 1;
647       } else if (key < sortedArray[mid].key) {
648           last = mid - 1;
649       } else {
650           return mid;
651       }
652   }
653   return -1;
654}
655
656static int isAttributeMatching(int i, EGLint attr, EGLint val)
657{
658    // look for the attribute in all of our configs
659    config_pair_t const* configFound = gConfigs[i].array;
660    int index = binarySearch<config_pair_t>(
661            gConfigs[i].array,
662            0, gConfigs[i].size-1,
663            attr);
664    if (index < 0) {
665        configFound = config_base_attribute_list;
666        index = binarySearch<config_pair_t>(
667                config_base_attribute_list,
668                0, NELEM(config_base_attribute_list)-1,
669                attr);
670    }
671    if (index >= 0) {
672        // attribute found, check if this config could match
673        int cfgMgtIndex = binarySearch<config_management_t>(
674                gConfigManagement,
675                0, NELEM(gConfigManagement)-1,
676                attr);
677        if (index >= 0) {
678            bool match = gConfigManagement[cfgMgtIndex].match(
679                    val, configFound[index].value);
680            if (match) {
681                // this config matches
682                return 1;
683            }
684        } else {
685            // attribute not found. this should NEVER happen.
686        }
687    } else {
688        // error, this attribute doesn't exist
689    }
690    return 0;
691}
692
693static int makeCurrent(ogles_context_t* gl)
694{
695    ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
696    if (gl) {
697        egl_context_t* c = egl_context_t::context(gl);
698        if (c->flags & egl_context_t::IS_CURRENT) {
699            if (current != gl) {
700                // it is an error to set a context current, if it's already
701                // current to another thread
702                return -1;
703            }
704        } else {
705            if (current) {
706                // mark the current context as not current, and flush
707                glFlush();
708                egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
709            }
710        }
711        if (!(c->flags & egl_context_t::IS_CURRENT)) {
712            // The context is not current, make it current!
713            setGlThreadSpecific(gl);
714            c->flags |= egl_context_t::IS_CURRENT;
715        }
716    } else {
717        if (current) {
718            // mark the current context as not current, and flush
719            glFlush();
720            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
721        }
722        // this thread has no context attached to it
723        setGlThreadSpecific(0);
724    }
725    return 0;
726}
727
728static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
729        EGLint attribute, EGLint *value)
730{
731    size_t numConfigs =  NELEM(gConfigs);
732    int index = (int)config;
733    if (uint32_t(index) >= numConfigs)
734        return setError(EGL_BAD_CONFIG, EGL_FALSE);
735
736    int attrIndex;
737    attrIndex = binarySearch<config_pair_t>(
738            gConfigs[index].array,
739            0, gConfigs[index].size-1,
740            attribute);
741    if (attrIndex>=0) {
742        *value = gConfigs[index].array[attrIndex].value;
743        return EGL_TRUE;
744    }
745
746    attrIndex = binarySearch<config_pair_t>(
747            config_base_attribute_list,
748            0, NELEM(config_base_attribute_list)-1,
749            attribute);
750    if (attrIndex>=0) {
751        *value = config_base_attribute_list[attrIndex].value;
752        return EGL_TRUE;
753    }
754    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
755}
756
757static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
758        NativeWindowType window, const EGLint *attrib_list)
759{
760    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
761        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
762    if (window == 0)
763        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
764
765    EGLint surfaceType;
766    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
767        return EGL_FALSE;
768
769    if (!(surfaceType & EGL_WINDOW_BIT))
770        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
771
772    EGLint configID;
773    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
774        return EGL_FALSE;
775
776    int32_t depthFormat;
777    int32_t pixelFormat;
778    switch(configID) {
779    case 0:
780        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
781        depthFormat = 0;
782        break;
783    case 1:
784        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
785        depthFormat = GGL_PIXEL_FORMAT_Z_16;
786        break;
787    case 2:
788        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
789        depthFormat = 0;
790        break;
791    case 3:
792        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
793        depthFormat = GGL_PIXEL_FORMAT_Z_16;
794        break;
795    case 4:
796        pixelFormat = GGL_PIXEL_FORMAT_A_8;
797        depthFormat = 0;
798        break;
799    case 5:
800        pixelFormat = GGL_PIXEL_FORMAT_A_8;
801        depthFormat = GGL_PIXEL_FORMAT_Z_16;
802        break;
803    default:
804        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
805    }
806
807    // FIXME: we don't have access to the pixelFormat here just yet.
808    // (it's possible that the surface is not fully initialized)
809    // maybe this should be done after the page-flip
810    //if (EGLint(info.format) != pixelFormat)
811    //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
812
813    egl_surface_t* surface =
814        new egl_window_surface_t(dpy, config, depthFormat,
815                static_cast<egl_native_window_t*>(window));
816
817    if (!surface->isValid()) {
818        // there was a problem in the ctor, the error
819        // flag has been set.
820        delete surface;
821        surface = 0;
822    }
823    return surface;
824}
825
826static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
827        NativePixmapType pixmap, const EGLint *attrib_list)
828{
829    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
830        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
831    if (pixmap == 0)
832        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
833
834    EGLint surfaceType;
835    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
836        return EGL_FALSE;
837
838    if (!(surfaceType & EGL_PIXMAP_BIT))
839        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
840
841    EGLint configID;
842    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
843        return EGL_FALSE;
844
845    int32_t depthFormat;
846    int32_t pixelFormat;
847    switch(configID) {
848    case 0:
849        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
850        depthFormat = 0;
851        break;
852    case 1:
853        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
854        depthFormat = GGL_PIXEL_FORMAT_Z_16;
855        break;
856    case 2:
857        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
858        depthFormat = 0;
859        break;
860    case 3:
861        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
862        depthFormat = GGL_PIXEL_FORMAT_Z_16;
863        break;
864    case 4:
865        pixelFormat = GGL_PIXEL_FORMAT_A_8;
866        depthFormat = 0;
867        break;
868    case 5:
869        pixelFormat = GGL_PIXEL_FORMAT_A_8;
870        depthFormat = GGL_PIXEL_FORMAT_Z_16;
871        break;
872    default:
873        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
874    }
875
876    if (pixmap->format != pixelFormat)
877        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
878
879    egl_surface_t* surface =
880        new egl_pixmap_surface_t(dpy, config, depthFormat,
881                static_cast<egl_native_pixmap_t*>(pixmap));
882
883    if (!surface->isValid()) {
884        // there was a problem in the ctor, the error
885        // flag has been set.
886        delete surface;
887        surface = 0;
888    }
889    return surface;
890}
891
892static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
893        const EGLint *attrib_list)
894{
895    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
896        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
897
898    EGLint surfaceType;
899    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
900        return EGL_FALSE;
901
902    if (!(surfaceType & EGL_PBUFFER_BIT))
903        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
904
905    EGLint configID;
906    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
907        return EGL_FALSE;
908
909    int32_t depthFormat;
910    int32_t pixelFormat;
911    switch(configID) {
912    case 0:
913        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
914        depthFormat = 0;
915        break;
916    case 1:
917        pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
918        depthFormat = GGL_PIXEL_FORMAT_Z_16;
919        break;
920    case 2:
921        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
922        depthFormat = 0;
923        break;
924    case 3:
925        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
926        depthFormat = GGL_PIXEL_FORMAT_Z_16;
927        break;
928    case 4:
929        pixelFormat = GGL_PIXEL_FORMAT_A_8;
930        depthFormat = 0;
931        break;
932    case 5:
933        pixelFormat = GGL_PIXEL_FORMAT_A_8;
934        depthFormat = GGL_PIXEL_FORMAT_Z_16;
935        break;
936    default:
937        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
938    }
939
940    int32_t w = 0;
941    int32_t h = 0;
942    while (attrib_list[0]) {
943        if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
944        if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
945        attrib_list+=2;
946    }
947
948    egl_surface_t* surface =
949        new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
950
951    if (!surface->isValid()) {
952        // there was a problem in the ctor, the error
953        // flag has been set.
954        delete surface;
955        surface = 0;
956    }
957    return surface;
958}
959
960// ----------------------------------------------------------------------------
961}; // namespace android
962// ----------------------------------------------------------------------------
963
964using namespace android;
965
966// ----------------------------------------------------------------------------
967// Initialization
968// ----------------------------------------------------------------------------
969
970EGLDisplay eglGetDisplay(NativeDisplayType display)
971{
972#ifndef HAVE_ANDROID_OS
973    // this just needs to be done once
974    if (gGLKey == -1) {
975        pthread_mutex_lock(&gInitMutex);
976        if (gGLKey == -1)
977            pthread_key_create(&gGLKey, NULL);
978        pthread_mutex_unlock(&gInitMutex);
979    }
980#endif
981    if (display == EGL_DEFAULT_DISPLAY) {
982        EGLDisplay dpy = (EGLDisplay)1;
983        egl_display_t& d = egl_display_t::get_display(dpy);
984        d.type = display;
985        return dpy;
986    }
987    return EGL_NO_DISPLAY;
988}
989
990EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
991{
992    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
993        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
994
995    EGLBoolean res = EGL_TRUE;
996    egl_display_t& d = egl_display_t::get_display(dpy);
997
998    if (android_atomic_inc(&d.initialized) == 0) {
999        // initialize stuff here if needed
1000        //pthread_mutex_lock(&gInitMutex);
1001        //pthread_mutex_unlock(&gInitMutex);
1002    }
1003
1004    if (res == EGL_TRUE) {
1005        if (major != NULL) *major = 1;
1006        if (minor != NULL) *minor = 2;
1007    }
1008    return res;
1009}
1010
1011EGLBoolean eglTerminate(EGLDisplay dpy)
1012{
1013    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1014        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1015
1016    EGLBoolean res = EGL_TRUE;
1017    egl_display_t& d = egl_display_t::get_display(dpy);
1018    if (android_atomic_dec(&d.initialized) == 1) {
1019        // TODO: destroy all resources (surfaces, contexts, etc...)
1020        //pthread_mutex_lock(&gInitMutex);
1021        //pthread_mutex_unlock(&gInitMutex);
1022    }
1023    return res;
1024}
1025
1026// ----------------------------------------------------------------------------
1027// configuration
1028// ----------------------------------------------------------------------------
1029
1030EGLBoolean eglGetConfigs(   EGLDisplay dpy,
1031                            EGLConfig *configs,
1032                            EGLint config_size, EGLint *num_config)
1033{
1034    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1035        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1036
1037    GLint numConfigs = NELEM(gConfigs);
1038    if (!configs) {
1039        *num_config = numConfigs;
1040        return EGL_TRUE;
1041    }
1042    GLint i;
1043    for (i=0 ; i<numConfigs && i<config_size ; i++) {
1044        *configs++ = (EGLConfig)i;
1045    }
1046    *num_config = i;
1047    return EGL_TRUE;
1048}
1049
1050EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1051                            EGLConfig *configs, EGLint config_size,
1052                            EGLint *num_config)
1053{
1054    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1055        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1056
1057    if (ggl_unlikely(configs==0 || attrib_list==0)) {
1058        *num_config = 0;
1059        return EGL_TRUE;
1060    }
1061
1062    int numAttributes = 0;
1063    int numConfigs =  NELEM(gConfigs);
1064    uint32_t possibleMatch = (1<<numConfigs)-1;
1065    while(possibleMatch && *attrib_list != EGL_NONE) {
1066        numAttributes++;
1067        EGLint attr = *attrib_list++;
1068        EGLint val  = *attrib_list++;
1069        for (int i=0 ; i<numConfigs ; i++) {
1070            if (!(possibleMatch & (1<<i)))
1071                continue;
1072            if (isAttributeMatching(i, attr, val) == 0) {
1073                possibleMatch &= ~(1<<i);
1074            }
1075        }
1076    }
1077
1078    // now, handle the attributes which have a useful default value
1079    for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
1080        // see if this attribute was specified, if not apply its
1081        // default value
1082        if (binarySearch<config_pair_t>(
1083                (config_pair_t const*)attrib_list,
1084                0, numAttributes,
1085                config_defaults[j].key) < 0)
1086        {
1087            for (int i=0 ; i<numConfigs ; i++) {
1088                if (!(possibleMatch & (1<<i)))
1089                    continue;
1090                if (isAttributeMatching(i,
1091                        config_defaults[j].key,
1092                        config_defaults[j].value) == 0)
1093                {
1094                    possibleMatch &= ~(1<<i);
1095                }
1096            }
1097        }
1098    }
1099
1100    // return the configurations found
1101    int n=0;
1102    if (possibleMatch) {
1103        for (int i=0 ; config_size && i<numConfigs ; i++) {
1104            if (possibleMatch & (1<<i)) {
1105               *configs++ = (EGLConfig)i;
1106                config_size--;
1107                n++;
1108            }
1109        }
1110    }
1111    *num_config = n;
1112     return EGL_TRUE;
1113}
1114
1115EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1116        EGLint attribute, EGLint *value)
1117{
1118    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1119        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1120
1121    return getConfigAttrib(dpy, config, attribute, value);
1122}
1123
1124// ----------------------------------------------------------------------------
1125// surfaces
1126// ----------------------------------------------------------------------------
1127
1128EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
1129                                    NativeWindowType window,
1130                                    const EGLint *attrib_list)
1131{
1132    return createWindowSurface(dpy, config, window, attrib_list);
1133}
1134
1135EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
1136                                    NativePixmapType pixmap,
1137                                    const EGLint *attrib_list)
1138{
1139    return createPixmapSurface(dpy, config, pixmap, attrib_list);
1140}
1141
1142EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1143                                    const EGLint *attrib_list)
1144{
1145    return createPbufferSurface(dpy, config, attrib_list);
1146}
1147
1148EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
1149{
1150    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1151        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1152    if (eglSurface != EGL_NO_SURFACE) {
1153        egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
1154        if (surface->magic != egl_surface_t::MAGIC)
1155            return setError(EGL_BAD_SURFACE, EGL_FALSE);
1156        if (surface->dpy != dpy)
1157            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1158        delete surface;
1159    }
1160    return EGL_TRUE;
1161}
1162
1163EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
1164                            EGLint attribute, EGLint *value)
1165{
1166    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1167        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1168    egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
1169    if (surface->dpy != dpy)
1170        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1171
1172    EGLBoolean ret = EGL_TRUE;
1173    switch (attribute) {
1174        case EGL_CONFIG_ID:
1175            ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
1176            break;
1177        case EGL_WIDTH:
1178            *value = surface->getWidth();
1179            break;
1180        case EGL_HEIGHT:
1181            *value = surface->getHeight();
1182            break;
1183        case EGL_LARGEST_PBUFFER:
1184            // not modified for a window or pixmap surface
1185            break;
1186        case EGL_TEXTURE_FORMAT:
1187            *value = EGL_NO_TEXTURE;
1188            break;
1189        case EGL_TEXTURE_TARGET:
1190            *value = EGL_NO_TEXTURE;
1191            break;
1192        case EGL_MIPMAP_TEXTURE:
1193            *value = EGL_FALSE;
1194            break;
1195        case EGL_MIPMAP_LEVEL:
1196            *value = 0;
1197            break;
1198        case EGL_RENDER_BUFFER:
1199            // TODO: return the real RENDER_BUFFER here
1200            *value = EGL_BACK_BUFFER;
1201            break;
1202        case EGL_HORIZONTAL_RESOLUTION:
1203            // pixel/mm * EGL_DISPLAY_SCALING
1204            *value = surface->getHorizontalResolution();
1205            break;
1206        case EGL_VERTICAL_RESOLUTION:
1207            // pixel/mm * EGL_DISPLAY_SCALING
1208            *value = surface->getVerticalResolution();
1209            break;
1210        case EGL_PIXEL_ASPECT_RATIO: {
1211            // w/h * EGL_DISPLAY_SCALING
1212            int wr = surface->getHorizontalResolution();
1213            int hr = surface->getVerticalResolution();
1214            *value = (wr * EGL_DISPLAY_SCALING) / hr;
1215        } break;
1216        case EGL_SWAP_BEHAVIOR:
1217            *value = surface->getSwapBehavior();
1218            break;
1219        default:
1220            ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1221    }
1222    return ret;
1223}
1224
1225EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1226                            EGLContext share_list, const EGLint *attrib_list)
1227{
1228    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1229        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1230
1231    ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
1232    if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1233
1234    egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
1235    c->flags = egl_context_t::NEVER_CURRENT;
1236    c->dpy = dpy;
1237    c->config = config;
1238    c->read = 0;
1239    c->draw = 0;
1240    return (EGLContext)gl;
1241}
1242
1243EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1244{
1245    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1246        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1247    egl_context_t* c = egl_context_t::context(ctx);
1248    if (c->flags & egl_context_t::IS_CURRENT)
1249        setGlThreadSpecific(0);
1250    ogles_uninit((ogles_context_t*)ctx);
1251    return EGL_TRUE;
1252}
1253
1254EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
1255                            EGLSurface read, EGLContext ctx)
1256{
1257    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1258        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1259    if (draw) {
1260        egl_surface_t* s = (egl_surface_t*)draw;
1261        if (s->dpy != dpy)
1262            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1263        // TODO: check that draw and read are compatible with the context
1264    }
1265
1266    EGLContext current_ctx = EGL_NO_CONTEXT;
1267
1268    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1269        return setError(EGL_BAD_MATCH, EGL_FALSE);
1270
1271    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1272        return setError(EGL_BAD_MATCH, EGL_FALSE);
1273
1274    if (ctx == EGL_NO_CONTEXT) {
1275        // if we're detaching, we need the current context
1276        current_ctx = (EGLContext)getGlThreadSpecific();
1277    } else {
1278        egl_context_t* c = egl_context_t::context(ctx);
1279        egl_surface_t* d = (egl_surface_t*)draw;
1280        egl_surface_t* r = (egl_surface_t*)read;
1281        if ((d && d->ctx && d->ctx != ctx) ||
1282            (r && r->ctx && r->ctx != ctx)) {
1283            // once of the surface is bound to a context in another thread
1284            return setError(EGL_BAD_ACCESS, EGL_FALSE);
1285        }
1286    }
1287
1288    ogles_context_t* gl = (ogles_context_t*)ctx;
1289    if (makeCurrent(gl) == 0) {
1290        if (ctx) {
1291            egl_context_t* c = egl_context_t::context(ctx);
1292            egl_surface_t* d = (egl_surface_t*)draw;
1293            egl_surface_t* r = (egl_surface_t*)read;
1294            c->read = read;
1295            c->draw = draw;
1296            if (c->flags & egl_context_t::NEVER_CURRENT) {
1297                c->flags &= ~egl_context_t::NEVER_CURRENT;
1298                GLint w = 0;
1299                GLint h = 0;
1300                if (draw) {
1301                    w = d->getWidth();
1302                    h = d->getHeight();
1303                }
1304                ogles_surfaceport(gl, 0, 0);
1305                ogles_viewport(gl, 0, 0, w, h);
1306                ogles_scissor(gl, 0, 0, w, h);
1307            }
1308            if (d) {
1309                d->ctx = ctx;
1310                d->bindDrawSurface(gl);
1311            }
1312            if (r) {
1313                r->ctx = ctx;
1314                r->bindReadSurface(gl);
1315            }
1316        } else {
1317            // if surfaces were bound to the context bound to this thread
1318            // mark then as unbound.
1319            if (current_ctx) {
1320                egl_context_t* c = egl_context_t::context(current_ctx);
1321                egl_surface_t* d = (egl_surface_t*)c->draw;
1322                egl_surface_t* r = (egl_surface_t*)c->read;
1323                if (d) d->ctx = EGL_NO_CONTEXT;
1324                if (r) r->ctx = EGL_NO_CONTEXT;
1325            }
1326        }
1327        return EGL_TRUE;
1328    }
1329    return setError(EGL_BAD_ACCESS, EGL_FALSE);
1330}
1331
1332EGLContext eglGetCurrentContext(void)
1333{
1334    // eglGetCurrentContext returns the current EGL rendering context,
1335    // as specified by eglMakeCurrent. If no context is current,
1336    // EGL_NO_CONTEXT is returned.
1337    return (EGLContext)getGlThreadSpecific();
1338}
1339
1340EGLSurface eglGetCurrentSurface(EGLint readdraw)
1341{
1342    // eglGetCurrentSurface returns the read or draw surface attached
1343    // to the current EGL rendering context, as specified by eglMakeCurrent.
1344    // If no context is current, EGL_NO_SURFACE is returned.
1345    EGLContext ctx = (EGLContext)getGlThreadSpecific();
1346    if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
1347    egl_context_t* c = egl_context_t::context(ctx);
1348    if (readdraw == EGL_READ) {
1349        return c->read;
1350    } else if (readdraw == EGL_DRAW) {
1351        return c->draw;
1352    }
1353    return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
1354}
1355
1356EGLDisplay eglGetCurrentDisplay(void)
1357{
1358    // eglGetCurrentDisplay returns the current EGL display connection
1359    // for the current EGL rendering context, as specified by eglMakeCurrent.
1360    // If no context is current, EGL_NO_DISPLAY is returned.
1361    EGLContext ctx = (EGLContext)getGlThreadSpecific();
1362    if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
1363    egl_context_t* c = egl_context_t::context(ctx);
1364    return c->dpy;
1365}
1366
1367EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1368                            EGLint attribute, EGLint *value)
1369{
1370    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1371        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1372    egl_context_t* c = egl_context_t::context(ctx);
1373    switch (attribute) {
1374        case EGL_CONFIG_ID:
1375            // Returns the ID of the EGL frame buffer configuration with
1376            // respect to which the context was created
1377            return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
1378    }
1379    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1380}
1381
1382EGLBoolean eglWaitGL(void)
1383{
1384    return EGL_TRUE;
1385}
1386
1387EGLBoolean eglWaitNative(EGLint engine)
1388{
1389    return EGL_TRUE;
1390}
1391
1392EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1393{
1394    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1395        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1396
1397    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1398    if (d->dpy != dpy)
1399        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1400
1401    // post the surface
1402    d->swapBuffers();
1403
1404    // if it's bound to a context, update the buffer
1405    if (d->ctx != EGL_NO_CONTEXT) {
1406        d->bindDrawSurface((ogles_context_t*)d->ctx);
1407        // if this surface is also the read surface of the context
1408        // it is bound to, make sure to update the read buffer as well.
1409        // The EGL spec is a little unclear about this.
1410        egl_context_t* c = egl_context_t::context(d->ctx);
1411        if (c->read == draw) {
1412            d->bindReadSurface((ogles_context_t*)d->ctx);
1413        }
1414    }
1415
1416    return EGL_TRUE;
1417}
1418
1419EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1420                            NativePixmapType target)
1421{
1422    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1423        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1424    // TODO: eglCopyBuffers()
1425    return EGL_FALSE;
1426}
1427
1428EGLint eglGetError(void)
1429{
1430    return getError();
1431}
1432
1433const char* eglQueryString(EGLDisplay dpy, EGLint name)
1434{
1435    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1436        return setError(EGL_BAD_DISPLAY, (const char*)0);
1437
1438    switch (name) {
1439        case EGL_VENDOR:
1440            return gVendorString;
1441        case EGL_VERSION:
1442            return gVersionString;
1443        case EGL_EXTENSIONS:
1444            return gExtensionsString;
1445        case EGL_CLIENT_APIS:
1446            return gClientApiString;
1447    }
1448    return setError(EGL_BAD_PARAMETER, (const char *)0);
1449}
1450
1451// ----------------------------------------------------------------------------
1452// EGL 1.1
1453// ----------------------------------------------------------------------------
1454
1455EGLBoolean eglSurfaceAttrib(
1456        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1457{
1458    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1459        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1460    // TODO: eglSurfaceAttrib()
1461    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1462}
1463
1464EGLBoolean eglBindTexImage(
1465        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1466{
1467    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1468        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1469    // TODO: eglBindTexImage()
1470    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1471}
1472
1473EGLBoolean eglReleaseTexImage(
1474        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1475{
1476    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1477        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1478    // TODO: eglReleaseTexImage()
1479    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1480}
1481
1482EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1483{
1484    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1485        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1486    // TODO: eglSwapInterval()
1487    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1488}
1489
1490// ----------------------------------------------------------------------------
1491// EGL 1.2
1492// ----------------------------------------------------------------------------
1493
1494EGLBoolean eglBindAPI(EGLenum api)
1495{
1496    if (api != EGL_OPENGL_ES_API)
1497        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1498    return EGL_TRUE;
1499}
1500
1501EGLenum eglQueryAPI(void)
1502{
1503    return EGL_OPENGL_ES_API;
1504}
1505
1506EGLBoolean eglWaitClient(void)
1507{
1508    glFinish();
1509    return EGL_TRUE;
1510}
1511
1512EGLBoolean eglReleaseThread(void)
1513{
1514    // TODO: eglReleaseThread()
1515    return EGL_TRUE;
1516}
1517
1518EGLSurface eglCreatePbufferFromClientBuffer(
1519          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1520          EGLConfig config, const EGLint *attrib_list)
1521{
1522    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1523        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1524    // TODO: eglCreatePbufferFromClientBuffer()
1525    return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1526}
1527
1528// ----------------------------------------------------------------------------
1529// Android extensions
1530// ----------------------------------------------------------------------------
1531
1532void (*eglGetProcAddress (const char *procname))()
1533{
1534    extention_map_t const * const map = gExtentionMap;
1535    for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
1536        if (!strcmp(procname, map[i].name)) {
1537            return map[i].address;
1538        }
1539    }
1540    return NULL;
1541}
1542