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