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