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