Home | History | Annotate | Download | only in libagl
      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 <atomic>
     20 #include <errno.h>
     21 #include <stdlib.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <fcntl.h>
     26 #include <sys/ioctl.h>
     27 #include <sys/types.h>
     28 #include <sys/mman.h>
     29 
     30 #include <cutils/log.h>
     31 
     32 #include <utils/threads.h>
     33 #include <ui/ANativeObjectBase.h>
     34 #include <ui/Fence.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 // ----------------------------------------------------------------------------
     53 
     54 EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
     55         EGLint left, EGLint top, EGLint width, EGLint height);
     56 
     57 // ----------------------------------------------------------------------------
     58 namespace android {
     59 
     60 // ----------------------------------------------------------------------------
     61 
     62 const unsigned int NUM_DISPLAYS = 1;
     63 
     64 static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
     65 static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
     66 static pthread_key_t gEGLErrorKey = -1;
     67 #ifndef __ANDROID__
     68 namespace gl {
     69 pthread_key_t gGLKey = -1;
     70 }; // namespace gl
     71 #endif
     72 
     73 template<typename T>
     74 static T setError(GLint error, T returnValue) {
     75     if (ggl_unlikely(gEGLErrorKey == -1)) {
     76         pthread_mutex_lock(&gErrorKeyMutex);
     77         if (gEGLErrorKey == -1)
     78             pthread_key_create(&gEGLErrorKey, NULL);
     79         pthread_mutex_unlock(&gErrorKeyMutex);
     80     }
     81     pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)error);
     82     return returnValue;
     83 }
     84 
     85 static GLint getError() {
     86     if (ggl_unlikely(gEGLErrorKey == -1))
     87         return EGL_SUCCESS;
     88     GLint error = (GLint)(uintptr_t)pthread_getspecific(gEGLErrorKey);
     89     if (error == 0) {
     90         // The TLS key has been created by another thread, but the value for
     91         // this thread has not been initialized.
     92         return EGL_SUCCESS;
     93     }
     94     pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)EGL_SUCCESS);
     95     return error;
     96 }
     97 
     98 // ----------------------------------------------------------------------------
     99 
    100 struct egl_display_t
    101 {
    102     egl_display_t() : type(0), initialized(0) { }
    103 
    104     static egl_display_t& get_display(EGLDisplay dpy);
    105 
    106     static EGLBoolean is_valid(EGLDisplay dpy) {
    107         return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
    108     }
    109 
    110     NativeDisplayType  type;
    111     std::atomic_size_t initialized;
    112 };
    113 
    114 static egl_display_t gDisplays[NUM_DISPLAYS];
    115 
    116 egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
    117     return gDisplays[uintptr_t(dpy)-1U];
    118 }
    119 
    120 struct egl_context_t {
    121     enum {
    122         IS_CURRENT      =   0x00010000,
    123         NEVER_CURRENT   =   0x00020000
    124     };
    125     uint32_t            flags;
    126     EGLDisplay          dpy;
    127     EGLConfig           config;
    128     EGLSurface          read;
    129     EGLSurface          draw;
    130 
    131     static inline egl_context_t* context(EGLContext ctx) {
    132         ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
    133         return static_cast<egl_context_t*>(gl->rasterizer.base);
    134     }
    135 };
    136 
    137 // ----------------------------------------------------------------------------
    138 
    139 struct egl_surface_t
    140 {
    141     enum {
    142         PAGE_FLIP = 0x00000001,
    143         MAGIC     = 0x31415265
    144     };
    145 
    146     uint32_t            magic;
    147     EGLDisplay          dpy;
    148     EGLConfig           config;
    149     EGLContext          ctx;
    150     bool                zombie;
    151 
    152                 egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
    153     virtual     ~egl_surface_t();
    154                 bool    isValid() const;
    155     virtual     bool    initCheck() const = 0;
    156 
    157     virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl) = 0;
    158     virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl) = 0;
    159     virtual     EGLBoolean  connect() { return EGL_TRUE; }
    160     virtual     void        disconnect() {}
    161     virtual     EGLint      getWidth() const = 0;
    162     virtual     EGLint      getHeight() const = 0;
    163 
    164     virtual     EGLint      getHorizontalResolution() const;
    165     virtual     EGLint      getVerticalResolution() const;
    166     virtual     EGLint      getRefreshRate() const;
    167     virtual     EGLint      getSwapBehavior() const;
    168     virtual     EGLBoolean  swapBuffers();
    169     virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
    170 protected:
    171     GGLSurface              depth;
    172 };
    173 
    174 egl_surface_t::egl_surface_t(EGLDisplay dpy,
    175         EGLConfig config,
    176         int32_t depthFormat)
    177     : magic(MAGIC), dpy(dpy), config(config), ctx(0), zombie(false)
    178 {
    179     depth.version = sizeof(GGLSurface);
    180     depth.data = 0;
    181     depth.format = depthFormat;
    182 }
    183 egl_surface_t::~egl_surface_t()
    184 {
    185     magic = 0;
    186     free(depth.data);
    187 }
    188 bool egl_surface_t::isValid() const {
    189     ALOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
    190     return magic == MAGIC;
    191 }
    192 
    193 EGLBoolean egl_surface_t::swapBuffers() {
    194     return EGL_FALSE;
    195 }
    196 EGLint egl_surface_t::getHorizontalResolution() const {
    197     return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
    198 }
    199 EGLint egl_surface_t::getVerticalResolution() const {
    200     return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
    201 }
    202 EGLint egl_surface_t::getRefreshRate() const {
    203     return (60 * EGL_DISPLAY_SCALING);
    204 }
    205 EGLint egl_surface_t::getSwapBehavior() const {
    206     return EGL_BUFFER_PRESERVED;
    207 }
    208 EGLBoolean egl_surface_t::setSwapRectangle(
    209         EGLint /*l*/, EGLint /*t*/, EGLint /*w*/, EGLint /*h*/)
    210 {
    211     return EGL_FALSE;
    212 }
    213 
    214 // ----------------------------------------------------------------------------
    215 
    216 struct egl_window_surface_v2_t : public egl_surface_t
    217 {
    218     egl_window_surface_v2_t(
    219             EGLDisplay dpy, EGLConfig config,
    220             int32_t depthFormat,
    221             ANativeWindow* window);
    222 
    223     ~egl_window_surface_v2_t();
    224 
    225     virtual     bool        initCheck() const { return true; } // TODO: report failure if ctor fails
    226     virtual     EGLBoolean  swapBuffers();
    227     virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
    228     virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
    229     virtual     EGLBoolean  connect();
    230     virtual     void        disconnect();
    231     virtual     EGLint      getWidth() const    { return width;  }
    232     virtual     EGLint      getHeight() const   { return height; }
    233     virtual     EGLint      getHorizontalResolution() const;
    234     virtual     EGLint      getVerticalResolution() const;
    235     virtual     EGLint      getRefreshRate() const;
    236     virtual     EGLint      getSwapBehavior() const;
    237     virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
    238 
    239 private:
    240     status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
    241     status_t unlock(ANativeWindowBuffer* buf);
    242     ANativeWindow*   nativeWindow;
    243     ANativeWindowBuffer*   buffer;
    244     ANativeWindowBuffer*   previousBuffer;
    245     gralloc_module_t const*    module;
    246     int width;
    247     int height;
    248     void* bits;
    249     GGLFormat const* pixelFormatTable;
    250 
    251     struct Rect {
    252         inline Rect() { };
    253         inline Rect(int32_t w, int32_t h)
    254             : left(0), top(0), right(w), bottom(h) { }
    255         inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
    256             : left(l), top(t), right(r), bottom(b) { }
    257         Rect& andSelf(const Rect& r) {
    258             left   = max(left, r.left);
    259             top    = max(top, r.top);
    260             right  = min(right, r.right);
    261             bottom = min(bottom, r.bottom);
    262             return *this;
    263         }
    264         bool isEmpty() const {
    265             return (left>=right || top>=bottom);
    266         }
    267         void dump(char const* what) {
    268             ALOGD("%s { %5d, %5d, w=%5d, h=%5d }",
    269                     what, left, top, right-left, bottom-top);
    270         }
    271 
    272         int32_t left;
    273         int32_t top;
    274         int32_t right;
    275         int32_t bottom;
    276     };
    277 
    278     struct Region {
    279         inline Region() : count(0) { }
    280         typedef Rect const* const_iterator;
    281         const_iterator begin() const { return storage; }
    282         const_iterator end() const { return storage+count; }
    283         static Region subtract(const Rect& lhs, const Rect& rhs) {
    284             Region reg;
    285             Rect* storage = reg.storage;
    286             if (!lhs.isEmpty()) {
    287                 if (lhs.top < rhs.top) { // top rect
    288                     storage->left   = lhs.left;
    289                     storage->top    = lhs.top;
    290                     storage->right  = lhs.right;
    291                     storage->bottom = rhs.top;
    292                     storage++;
    293                 }
    294                 const int32_t top = max(lhs.top, rhs.top);
    295                 const int32_t bot = min(lhs.bottom, rhs.bottom);
    296                 if (top < bot) {
    297                     if (lhs.left < rhs.left) { // left-side rect
    298                         storage->left   = lhs.left;
    299                         storage->top    = top;
    300                         storage->right  = rhs.left;
    301                         storage->bottom = bot;
    302                         storage++;
    303                     }
    304                     if (lhs.right > rhs.right) { // right-side rect
    305                         storage->left   = rhs.right;
    306                         storage->top    = top;
    307                         storage->right  = lhs.right;
    308                         storage->bottom = bot;
    309                         storage++;
    310                     }
    311                 }
    312                 if (lhs.bottom > rhs.bottom) { // bottom rect
    313                     storage->left   = lhs.left;
    314                     storage->top    = rhs.bottom;
    315                     storage->right  = lhs.right;
    316                     storage->bottom = lhs.bottom;
    317                     storage++;
    318                 }
    319                 reg.count = storage - reg.storage;
    320             }
    321             return reg;
    322         }
    323         bool isEmpty() const {
    324             return count<=0;
    325         }
    326     private:
    327         Rect storage[4];
    328         ssize_t count;
    329     };
    330 
    331     void copyBlt(
    332             ANativeWindowBuffer* dst, void* dst_vaddr,
    333             ANativeWindowBuffer* src, void const* src_vaddr,
    334             const Region& clip);
    335 
    336     Rect dirtyRegion;
    337     Rect oldDirtyRegion;
    338 };
    339 
    340 egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
    341         EGLConfig config,
    342         int32_t depthFormat,
    343         ANativeWindow* window)
    344     : egl_surface_t(dpy, config, depthFormat),
    345     nativeWindow(window), buffer(0), previousBuffer(0), module(0),
    346     bits(NULL)
    347 {
    348     hw_module_t const* pModule;
    349     hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
    350     module = reinterpret_cast<gralloc_module_t const*>(pModule);
    351 
    352     pixelFormatTable = gglGetPixelFormatTable();
    353 
    354     // keep a reference on the window
    355     nativeWindow->common.incRef(&nativeWindow->common);
    356     nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
    357     nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
    358 }
    359 
    360 egl_window_surface_v2_t::~egl_window_surface_v2_t() {
    361     if (buffer) {
    362         buffer->common.decRef(&buffer->common);
    363     }
    364     if (previousBuffer) {
    365         previousBuffer->common.decRef(&previousBuffer->common);
    366     }
    367     nativeWindow->common.decRef(&nativeWindow->common);
    368 }
    369 
    370 EGLBoolean egl_window_surface_v2_t::connect()
    371 {
    372     // we're intending to do software rendering
    373     native_window_set_usage(nativeWindow,
    374             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
    375 
    376     // dequeue a buffer
    377     int fenceFd = -1;
    378     if (nativeWindow->dequeueBuffer(nativeWindow, &buffer,
    379             &fenceFd) != NO_ERROR) {
    380         return setError(EGL_BAD_ALLOC, EGL_FALSE);
    381     }
    382 
    383     // wait for the buffer
    384     sp<Fence> fence(new Fence(fenceFd));
    385     if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) {
    386         nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
    387         return setError(EGL_BAD_ALLOC, EGL_FALSE);
    388     }
    389 
    390     // allocate a corresponding depth-buffer
    391     width = buffer->width;
    392     height = buffer->height;
    393     if (depth.format) {
    394         depth.width   = width;
    395         depth.height  = height;
    396         depth.stride  = depth.width; // use the width here
    397         uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
    398                 static_cast<uint64_t>(depth.height) * 2;
    399         if (depth.stride < 0 || depth.height > INT_MAX ||
    400                 allocSize > UINT32_MAX) {
    401             return setError(EGL_BAD_ALLOC, EGL_FALSE);
    402         }
    403         depth.data    = (GGLubyte*)malloc(allocSize);
    404         if (depth.data == 0) {
    405             return setError(EGL_BAD_ALLOC, EGL_FALSE);
    406         }
    407     }
    408 
    409     // keep a reference on the buffer
    410     buffer->common.incRef(&buffer->common);
    411 
    412     // pin the buffer down
    413     if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
    414             GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
    415         ALOGE("connect() failed to lock buffer %p (%ux%u)",
    416                 buffer, buffer->width, buffer->height);
    417         return setError(EGL_BAD_ACCESS, EGL_FALSE);
    418         // FIXME: we should make sure we're not accessing the buffer anymore
    419     }
    420     return EGL_TRUE;
    421 }
    422 
    423 void egl_window_surface_v2_t::disconnect()
    424 {
    425     if (buffer && bits) {
    426         bits = NULL;
    427         unlock(buffer);
    428     }
    429     if (buffer) {
    430         nativeWindow->cancelBuffer(nativeWindow, buffer, -1);
    431         buffer->common.decRef(&buffer->common);
    432         buffer = 0;
    433     }
    434     if (previousBuffer) {
    435         previousBuffer->common.decRef(&previousBuffer->common);
    436         previousBuffer = 0;
    437     }
    438 }
    439 
    440 status_t egl_window_surface_v2_t::lock(
    441         ANativeWindowBuffer* buf, int usage, void** vaddr)
    442 {
    443     int err;
    444 
    445     err = module->lock(module, buf->handle,
    446             usage, 0, 0, buf->width, buf->height, vaddr);
    447 
    448     return err;
    449 }
    450 
    451 status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
    452 {
    453     if (!buf) return BAD_VALUE;
    454     int err = NO_ERROR;
    455 
    456     err = module->unlock(module, buf->handle);
    457 
    458     return err;
    459 }
    460 
    461 void egl_window_surface_v2_t::copyBlt(
    462         ANativeWindowBuffer* dst, void* dst_vaddr,
    463         ANativeWindowBuffer* src, void const* src_vaddr,
    464         const Region& clip)
    465 {
    466     // NOTE: dst and src must be the same format
    467 
    468     Region::const_iterator cur = clip.begin();
    469     Region::const_iterator end = clip.end();
    470 
    471     const size_t bpp = pixelFormatTable[src->format].size;
    472     const size_t dbpr = dst->stride * bpp;
    473     const size_t sbpr = src->stride * bpp;
    474 
    475     uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
    476     uint8_t       * const dst_bits = (uint8_t       *)dst_vaddr;
    477 
    478     while (cur != end) {
    479         const Rect& r(*cur++);
    480         ssize_t w = r.right - r.left;
    481         ssize_t h = r.bottom - r.top;
    482         if (w <= 0 || h<=0) continue;
    483         size_t size = w * bpp;
    484         uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
    485         uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
    486         if (dbpr==sbpr && size==sbpr) {
    487             size *= h;
    488             h = 1;
    489         }
    490         do {
    491             memcpy(d, s, size);
    492             d += dbpr;
    493             s += sbpr;
    494         } while (--h > 0);
    495     }
    496 }
    497 
    498 EGLBoolean egl_window_surface_v2_t::swapBuffers()
    499 {
    500     if (!buffer) {
    501         return setError(EGL_BAD_ACCESS, EGL_FALSE);
    502     }
    503 
    504     /*
    505      * Handle eglSetSwapRectangleANDROID()
    506      * We copyback from the front buffer
    507      */
    508     if (!dirtyRegion.isEmpty()) {
    509         dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
    510         if (previousBuffer) {
    511             // This was const Region copyBack, but that causes an
    512             // internal compile error on simulator builds
    513             /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
    514             if (!copyBack.isEmpty()) {
    515                 void* prevBits;
    516                 if (lock(previousBuffer,
    517                         GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
    518                     // copy from previousBuffer to buffer
    519                     copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
    520                     unlock(previousBuffer);
    521                 }
    522             }
    523         }
    524         oldDirtyRegion = dirtyRegion;
    525     }
    526 
    527     if (previousBuffer) {
    528         previousBuffer->common.decRef(&previousBuffer->common);
    529         previousBuffer = 0;
    530     }
    531 
    532     unlock(buffer);
    533     previousBuffer = buffer;
    534     nativeWindow->queueBuffer(nativeWindow, buffer, -1);
    535     buffer = 0;
    536 
    537     // dequeue a new buffer
    538     int fenceFd = -1;
    539     if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) {
    540         sp<Fence> fence(new Fence(fenceFd));
    541         if (fence->wait(Fence::TIMEOUT_NEVER)) {
    542             nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
    543             return setError(EGL_BAD_ALLOC, EGL_FALSE);
    544         }
    545 
    546         // reallocate the depth-buffer if needed
    547         if ((width != buffer->width) || (height != buffer->height)) {
    548             // TODO: we probably should reset the swap rect here
    549             // if the window size has changed
    550             width = buffer->width;
    551             height = buffer->height;
    552             if (depth.data) {
    553                 free(depth.data);
    554                 depth.width   = width;
    555                 depth.height  = height;
    556                 depth.stride  = buffer->stride;
    557                 uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
    558                         static_cast<uint64_t>(depth.height) * 2;
    559                 if (depth.stride < 0 || depth.height > INT_MAX ||
    560                         allocSize > UINT32_MAX) {
    561                     setError(EGL_BAD_ALLOC, EGL_FALSE);
    562                     return EGL_FALSE;
    563                 }
    564                 depth.data    = (GGLubyte*)malloc(allocSize);
    565                 if (depth.data == 0) {
    566                     setError(EGL_BAD_ALLOC, EGL_FALSE);
    567                     return EGL_FALSE;
    568                 }
    569             }
    570         }
    571 
    572         // keep a reference on the buffer
    573         buffer->common.incRef(&buffer->common);
    574 
    575         // finally pin the buffer down
    576         if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
    577                 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
    578             ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
    579                     buffer, buffer->width, buffer->height);
    580             return setError(EGL_BAD_ACCESS, EGL_FALSE);
    581             // FIXME: we should make sure we're not accessing the buffer anymore
    582         }
    583     } else {
    584         return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
    585     }
    586 
    587     return EGL_TRUE;
    588 }
    589 
    590 EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
    591         EGLint l, EGLint t, EGLint w, EGLint h)
    592 {
    593     dirtyRegion = Rect(l, t, l+w, t+h);
    594     return EGL_TRUE;
    595 }
    596 
    597 EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
    598 {
    599     GGLSurface buffer;
    600     buffer.version = sizeof(GGLSurface);
    601     buffer.width   = this->buffer->width;
    602     buffer.height  = this->buffer->height;
    603     buffer.stride  = this->buffer->stride;
    604     buffer.data    = (GGLubyte*)bits;
    605     buffer.format  = this->buffer->format;
    606     gl->rasterizer.procs.colorBuffer(gl, &buffer);
    607     if (depth.data != gl->rasterizer.state.buffers.depth.data)
    608         gl->rasterizer.procs.depthBuffer(gl, &depth);
    609 
    610     return EGL_TRUE;
    611 }
    612 EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
    613 {
    614     GGLSurface buffer;
    615     buffer.version = sizeof(GGLSurface);
    616     buffer.width   = this->buffer->width;
    617     buffer.height  = this->buffer->height;
    618     buffer.stride  = this->buffer->stride;
    619     buffer.data    = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
    620     buffer.format  = this->buffer->format;
    621     gl->rasterizer.procs.readBuffer(gl, &buffer);
    622     return EGL_TRUE;
    623 }
    624 EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
    625     return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
    626 }
    627 EGLint egl_window_surface_v2_t::getVerticalResolution() const {
    628     return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
    629 }
    630 EGLint egl_window_surface_v2_t::getRefreshRate() const {
    631     return (60 * EGL_DISPLAY_SCALING); // FIXME
    632 }
    633 EGLint egl_window_surface_v2_t::getSwapBehavior() const
    634 {
    635     /*
    636      * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
    637      * the content of the swapped buffer.
    638      *
    639      * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
    640      *
    641      * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
    642      * only applies to the area specified by eglSetSwapRectangleANDROID(), that
    643      * is, everything outside of this area is preserved.
    644      *
    645      * This implementation of EGL assumes the later case.
    646      *
    647      */
    648 
    649     return EGL_BUFFER_DESTROYED;
    650 }
    651 
    652 // ----------------------------------------------------------------------------
    653 
    654 struct egl_pixmap_surface_t : public egl_surface_t
    655 {
    656     egl_pixmap_surface_t(
    657             EGLDisplay dpy, EGLConfig config,
    658             int32_t depthFormat,
    659             egl_native_pixmap_t const * pixmap);
    660 
    661     virtual ~egl_pixmap_surface_t() { }
    662 
    663     virtual     bool        initCheck() const { return !depth.format || depth.data!=0; }
    664     virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
    665     virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
    666     virtual     EGLint      getWidth() const    { return nativePixmap.width;  }
    667     virtual     EGLint      getHeight() const   { return nativePixmap.height; }
    668 private:
    669     egl_native_pixmap_t     nativePixmap;
    670 };
    671 
    672 egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
    673         EGLConfig config,
    674         int32_t depthFormat,
    675         egl_native_pixmap_t const * pixmap)
    676     : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
    677 {
    678     if (depthFormat) {
    679         depth.width   = pixmap->width;
    680         depth.height  = pixmap->height;
    681         depth.stride  = depth.width; // use the width here
    682         uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
    683                 static_cast<uint64_t>(depth.height) * 2;
    684         if (depth.stride < 0 || depth.height > INT_MAX ||
    685                 allocSize > UINT32_MAX) {
    686             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
    687             return;
    688         }
    689         depth.data    = (GGLubyte*)malloc(allocSize);
    690         if (depth.data == 0) {
    691             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
    692         }
    693     }
    694 }
    695 EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
    696 {
    697     GGLSurface buffer;
    698     buffer.version = sizeof(GGLSurface);
    699     buffer.width   = nativePixmap.width;
    700     buffer.height  = nativePixmap.height;
    701     buffer.stride  = nativePixmap.stride;
    702     buffer.data    = nativePixmap.data;
    703     buffer.format  = nativePixmap.format;
    704 
    705     gl->rasterizer.procs.colorBuffer(gl, &buffer);
    706     if (depth.data != gl->rasterizer.state.buffers.depth.data)
    707         gl->rasterizer.procs.depthBuffer(gl, &depth);
    708     return EGL_TRUE;
    709 }
    710 EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
    711 {
    712     GGLSurface buffer;
    713     buffer.version = sizeof(GGLSurface);
    714     buffer.width   = nativePixmap.width;
    715     buffer.height  = nativePixmap.height;
    716     buffer.stride  = nativePixmap.stride;
    717     buffer.data    = nativePixmap.data;
    718     buffer.format  = nativePixmap.format;
    719     gl->rasterizer.procs.readBuffer(gl, &buffer);
    720     return EGL_TRUE;
    721 }
    722 
    723 // ----------------------------------------------------------------------------
    724 
    725 struct egl_pbuffer_surface_t : public egl_surface_t
    726 {
    727     egl_pbuffer_surface_t(
    728             EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
    729             int32_t w, int32_t h, int32_t f);
    730 
    731     virtual ~egl_pbuffer_surface_t();
    732 
    733     virtual     bool        initCheck() const   { return pbuffer.data != 0; }
    734     virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
    735     virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
    736     virtual     EGLint      getWidth() const    { return pbuffer.width;  }
    737     virtual     EGLint      getHeight() const   { return pbuffer.height; }
    738 private:
    739     GGLSurface  pbuffer;
    740 };
    741 
    742 egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
    743         EGLConfig config, int32_t depthFormat,
    744         int32_t w, int32_t h, int32_t f)
    745     : egl_surface_t(dpy, config, depthFormat)
    746 {
    747     size_t size = w*h;
    748     switch (f) {
    749         case GGL_PIXEL_FORMAT_A_8:          size *= 1; break;
    750         case GGL_PIXEL_FORMAT_RGB_565:      size *= 2; break;
    751         case GGL_PIXEL_FORMAT_RGBA_8888:    size *= 4; break;
    752         case GGL_PIXEL_FORMAT_RGBX_8888:    size *= 4; break;
    753         default:
    754             ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
    755             pbuffer.data = 0;
    756             break;
    757     }
    758     pbuffer.version = sizeof(GGLSurface);
    759     pbuffer.width   = w;
    760     pbuffer.height  = h;
    761     pbuffer.stride  = w;
    762     pbuffer.data    = (GGLubyte*)malloc(size);
    763     pbuffer.format  = f;
    764 
    765     if (depthFormat) {
    766         depth.width   = pbuffer.width;
    767         depth.height  = pbuffer.height;
    768         depth.stride  = depth.width; // use the width here
    769         uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
    770                 static_cast<uint64_t>(depth.height) * 2;
    771         if (depth.stride < 0 || depth.height > INT_MAX ||
    772                 allocSize > UINT32_MAX) {
    773             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
    774             return;
    775         }
    776         depth.data    = (GGLubyte*)malloc(allocSize);
    777         if (depth.data == 0) {
    778             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
    779             return;
    780         }
    781     }
    782 }
    783 egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
    784     free(pbuffer.data);
    785 }
    786 EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
    787 {
    788     gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
    789     if (depth.data != gl->rasterizer.state.buffers.depth.data)
    790         gl->rasterizer.procs.depthBuffer(gl, &depth);
    791     return EGL_TRUE;
    792 }
    793 EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
    794 {
    795     gl->rasterizer.procs.readBuffer(gl, &pbuffer);
    796     return EGL_TRUE;
    797 }
    798 
    799 // ----------------------------------------------------------------------------
    800 
    801 struct config_pair_t {
    802     GLint key;
    803     GLint value;
    804 };
    805 
    806 struct configs_t {
    807     const config_pair_t* array;
    808     int                  size;
    809 };
    810 
    811 struct config_management_t {
    812     GLint key;
    813     bool (*match)(GLint reqValue, GLint confValue);
    814     static bool atLeast(GLint reqValue, GLint confValue) {
    815         return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
    816     }
    817     static bool exact(GLint reqValue, GLint confValue) {
    818         return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
    819     }
    820     static bool mask(GLint reqValue, GLint confValue) {
    821         return (confValue & reqValue) == reqValue;
    822     }
    823     static bool ignore(GLint /*reqValue*/, GLint /*confValue*/) {
    824         return true;
    825     }
    826 };
    827 
    828 // ----------------------------------------------------------------------------
    829 
    830 #define VERSION_MAJOR 1
    831 #define VERSION_MINOR 2
    832 static char const * const gVendorString     = "Google Inc.";
    833 static char const * const gVersionString    = "1.2 Android Driver 1.2.0";
    834 static char const * const gClientApiString  = "OpenGL_ES";
    835 static char const * const gExtensionsString =
    836         "EGL_KHR_fence_sync "
    837         "EGL_KHR_image_base "
    838         // "KHR_image_pixmap "
    839         "EGL_ANDROID_image_native_buffer "
    840         "EGL_ANDROID_swap_rectangle "
    841         ;
    842 
    843 // ----------------------------------------------------------------------------
    844 
    845 struct extention_map_t {
    846     const char * const name;
    847     __eglMustCastToProperFunctionPointerType address;
    848 };
    849 
    850 static const extention_map_t gExtentionMap[] = {
    851     { "glDrawTexsOES",
    852             (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
    853     { "glDrawTexiOES",
    854             (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
    855     { "glDrawTexfOES",
    856             (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
    857     { "glDrawTexxOES",
    858             (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
    859     { "glDrawTexsvOES",
    860             (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
    861     { "glDrawTexivOES",
    862             (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
    863     { "glDrawTexfvOES",
    864             (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
    865     { "glDrawTexxvOES",
    866             (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
    867     { "glQueryMatrixxOES",
    868             (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
    869     { "glEGLImageTargetTexture2DOES",
    870             (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
    871     { "glEGLImageTargetRenderbufferStorageOES",
    872             (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
    873     { "glClipPlanef",
    874             (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
    875     { "glClipPlanex",
    876             (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
    877     { "glBindBuffer",
    878             (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
    879     { "glBufferData",
    880             (__eglMustCastToProperFunctionPointerType)&glBufferData },
    881     { "glBufferSubData",
    882             (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
    883     { "glDeleteBuffers",
    884             (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
    885     { "glGenBuffers",
    886             (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
    887     { "eglCreateImageKHR",
    888             (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
    889     { "eglDestroyImageKHR",
    890             (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
    891     { "eglCreateSyncKHR",
    892             (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR },
    893     { "eglDestroySyncKHR",
    894             (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR },
    895     { "eglClientWaitSyncKHR",
    896             (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR },
    897     { "eglGetSyncAttribKHR",
    898             (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR },
    899     { "eglSetSwapRectangleANDROID",
    900             (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
    901 };
    902 
    903 /*
    904  * In the lists below, attributes names MUST be sorted.
    905  * Additionally, all configs must be sorted according to
    906  * the EGL specification.
    907  */
    908 
    909 static config_pair_t const config_base_attribute_list[] = {
    910         { EGL_STENCIL_SIZE,               0                                 },
    911         { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
    912         { EGL_LEVEL,                      0                                 },
    913         { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
    914         { EGL_MAX_PBUFFER_PIXELS,
    915                 GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
    916         { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
    917         { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
    918         { EGL_NATIVE_VISUAL_ID,           0                                 },
    919         { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGB_565          },
    920         { EGL_SAMPLES,                    0                                 },
    921         { EGL_SAMPLE_BUFFERS,             0                                 },
    922         { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
    923         { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
    924         { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
    925         { EGL_TRANSPARENT_RED_VALUE,      0                                 },
    926         { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
    927         { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
    928         { EGL_MIN_SWAP_INTERVAL,          1                                 },
    929         { EGL_MAX_SWAP_INTERVAL,          1                                 },
    930         { EGL_LUMINANCE_SIZE,             0                                 },
    931         { EGL_ALPHA_MASK_SIZE,            0                                 },
    932         { EGL_COLOR_BUFFER_TYPE,          EGL_RGB_BUFFER                    },
    933         { EGL_RENDERABLE_TYPE,            EGL_OPENGL_ES_BIT                 },
    934         { EGL_CONFORMANT,                 0                                 }
    935 };
    936 
    937 // These configs can override the base attribute list
    938 // NOTE: when adding a config here, don't forget to update eglCreate*Surface()
    939 
    940 // 565 configs
    941 static config_pair_t const config_0_attribute_list[] = {
    942         { EGL_BUFFER_SIZE,     16 },
    943         { EGL_ALPHA_SIZE,       0 },
    944         { EGL_BLUE_SIZE,        5 },
    945         { EGL_GREEN_SIZE,       6 },
    946         { EGL_RED_SIZE,         5 },
    947         { EGL_DEPTH_SIZE,       0 },
    948         { EGL_CONFIG_ID,        0 },
    949         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
    950         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
    951 };
    952 
    953 static config_pair_t const config_1_attribute_list[] = {
    954         { EGL_BUFFER_SIZE,     16 },
    955         { EGL_ALPHA_SIZE,       0 },
    956         { EGL_BLUE_SIZE,        5 },
    957         { EGL_GREEN_SIZE,       6 },
    958         { EGL_RED_SIZE,         5 },
    959         { EGL_DEPTH_SIZE,      16 },
    960         { EGL_CONFIG_ID,        1 },
    961         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
    962         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
    963 };
    964 
    965 // RGB 888 configs
    966 static config_pair_t const config_2_attribute_list[] = {
    967         { EGL_BUFFER_SIZE,     32 },
    968         { EGL_ALPHA_SIZE,       0 },
    969         { EGL_BLUE_SIZE,        8 },
    970         { EGL_GREEN_SIZE,       8 },
    971         { EGL_RED_SIZE,         8 },
    972         { EGL_DEPTH_SIZE,       0 },
    973         { EGL_CONFIG_ID,        6 },
    974         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
    975         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
    976 };
    977 
    978 static config_pair_t const config_3_attribute_list[] = {
    979         { EGL_BUFFER_SIZE,     32 },
    980         { EGL_ALPHA_SIZE,       0 },
    981         { EGL_BLUE_SIZE,        8 },
    982         { EGL_GREEN_SIZE,       8 },
    983         { EGL_RED_SIZE,         8 },
    984         { EGL_DEPTH_SIZE,      16 },
    985         { EGL_CONFIG_ID,        7 },
    986         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
    987         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
    988 };
    989 
    990 // 8888 configs
    991 static config_pair_t const config_4_attribute_list[] = {
    992         { EGL_BUFFER_SIZE,     32 },
    993         { EGL_ALPHA_SIZE,       8 },
    994         { EGL_BLUE_SIZE,        8 },
    995         { EGL_GREEN_SIZE,       8 },
    996         { EGL_RED_SIZE,         8 },
    997         { EGL_DEPTH_SIZE,       0 },
    998         { EGL_CONFIG_ID,        2 },
    999         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
   1000         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
   1001 };
   1002 
   1003 static config_pair_t const config_5_attribute_list[] = {
   1004         { EGL_BUFFER_SIZE,     32 },
   1005         { EGL_ALPHA_SIZE,       8 },
   1006         { EGL_BLUE_SIZE,        8 },
   1007         { EGL_GREEN_SIZE,       8 },
   1008         { EGL_RED_SIZE,         8 },
   1009         { EGL_DEPTH_SIZE,      16 },
   1010         { EGL_CONFIG_ID,        3 },
   1011         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
   1012         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
   1013 };
   1014 
   1015 // A8 configs
   1016 static config_pair_t const config_6_attribute_list[] = {
   1017         { EGL_BUFFER_SIZE,      8 },
   1018         { EGL_ALPHA_SIZE,       8 },
   1019         { EGL_BLUE_SIZE,        0 },
   1020         { EGL_GREEN_SIZE,       0 },
   1021         { EGL_RED_SIZE,         0 },
   1022         { EGL_DEPTH_SIZE,       0 },
   1023         { EGL_CONFIG_ID,        4 },
   1024         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
   1025         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
   1026 };
   1027 
   1028 static config_pair_t const config_7_attribute_list[] = {
   1029         { EGL_BUFFER_SIZE,      8 },
   1030         { EGL_ALPHA_SIZE,       8 },
   1031         { EGL_BLUE_SIZE,        0 },
   1032         { EGL_GREEN_SIZE,       0 },
   1033         { EGL_RED_SIZE,         0 },
   1034         { EGL_DEPTH_SIZE,      16 },
   1035         { EGL_CONFIG_ID,        5 },
   1036         { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
   1037         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
   1038 };
   1039 
   1040 static configs_t const gConfigs[] = {
   1041         { config_0_attribute_list, NELEM(config_0_attribute_list) },
   1042         { config_1_attribute_list, NELEM(config_1_attribute_list) },
   1043         { config_2_attribute_list, NELEM(config_2_attribute_list) },
   1044         { config_3_attribute_list, NELEM(config_3_attribute_list) },
   1045         { config_4_attribute_list, NELEM(config_4_attribute_list) },
   1046         { config_5_attribute_list, NELEM(config_5_attribute_list) },
   1047         { config_6_attribute_list, NELEM(config_6_attribute_list) },
   1048         { config_7_attribute_list, NELEM(config_7_attribute_list) },
   1049 };
   1050 
   1051 static config_management_t const gConfigManagement[] = {
   1052         { EGL_BUFFER_SIZE,                config_management_t::atLeast },
   1053         { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
   1054         { EGL_BLUE_SIZE,                  config_management_t::atLeast },
   1055         { EGL_GREEN_SIZE,                 config_management_t::atLeast },
   1056         { EGL_RED_SIZE,                   config_management_t::atLeast },
   1057         { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
   1058         { EGL_STENCIL_SIZE,               config_management_t::atLeast },
   1059         { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
   1060         { EGL_CONFIG_ID,                  config_management_t::exact   },
   1061         { EGL_LEVEL,                      config_management_t::exact   },
   1062         { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::ignore   },
   1063         { EGL_MAX_PBUFFER_PIXELS,         config_management_t::ignore   },
   1064         { EGL_MAX_PBUFFER_WIDTH,          config_management_t::ignore   },
   1065         { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
   1066         { EGL_NATIVE_VISUAL_ID,           config_management_t::ignore   },
   1067         { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
   1068         { EGL_SAMPLES,                    config_management_t::exact   },
   1069         { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
   1070         { EGL_SURFACE_TYPE,               config_management_t::mask    },
   1071         { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
   1072         { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
   1073         { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
   1074         { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
   1075         { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
   1076         { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
   1077         { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
   1078         { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
   1079         { EGL_LUMINANCE_SIZE,             config_management_t::atLeast },
   1080         { EGL_ALPHA_MASK_SIZE,            config_management_t::atLeast },
   1081         { EGL_COLOR_BUFFER_TYPE,          config_management_t::exact   },
   1082         { EGL_RENDERABLE_TYPE,            config_management_t::mask    },
   1083         { EGL_CONFORMANT,                 config_management_t::mask    }
   1084 };
   1085 
   1086 
   1087 static config_pair_t const config_defaults[] = {
   1088     // attributes that are not specified are simply ignored, if a particular
   1089     // one needs not be ignored, it must be specified here, eg:
   1090     // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
   1091 };
   1092 
   1093 // ----------------------------------------------------------------------------
   1094 
   1095 static status_t getConfigFormatInfo(EGLint configID,
   1096         int32_t& pixelFormat, int32_t& depthFormat)
   1097 {
   1098     switch(configID) {
   1099     case 0:
   1100         pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
   1101         depthFormat = 0;
   1102         break;
   1103     case 1:
   1104         pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
   1105         depthFormat = GGL_PIXEL_FORMAT_Z_16;
   1106         break;
   1107     case 2:
   1108         pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
   1109         depthFormat = 0;
   1110         break;
   1111     case 3:
   1112         pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
   1113         depthFormat = GGL_PIXEL_FORMAT_Z_16;
   1114         break;
   1115     case 4:
   1116         pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
   1117         depthFormat = 0;
   1118         break;
   1119     case 5:
   1120         pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
   1121         depthFormat = GGL_PIXEL_FORMAT_Z_16;
   1122         break;
   1123     case 6:
   1124         pixelFormat = GGL_PIXEL_FORMAT_A_8;
   1125         depthFormat = 0;
   1126         break;
   1127     case 7:
   1128         pixelFormat = GGL_PIXEL_FORMAT_A_8;
   1129         depthFormat = GGL_PIXEL_FORMAT_Z_16;
   1130         break;
   1131     default:
   1132         return NAME_NOT_FOUND;
   1133     }
   1134     return NO_ERROR;
   1135 }
   1136 
   1137 // ----------------------------------------------------------------------------
   1138 
   1139 template<typename T>
   1140 static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
   1141 {
   1142    while (first <= last) {
   1143        int mid = (first + last) / 2;
   1144        if (key > sortedArray[mid].key) {
   1145            first = mid + 1;
   1146        } else if (key < sortedArray[mid].key) {
   1147            last = mid - 1;
   1148        } else {
   1149            return mid;
   1150        }
   1151    }
   1152    return -1;
   1153 }
   1154 
   1155 static int isAttributeMatching(int i, EGLint attr, EGLint val)
   1156 {
   1157     // look for the attribute in all of our configs
   1158     config_pair_t const* configFound = gConfigs[i].array;
   1159     int index = binarySearch<config_pair_t>(
   1160             gConfigs[i].array,
   1161             0, gConfigs[i].size-1,
   1162             attr);
   1163     if (index < 0) {
   1164         configFound = config_base_attribute_list;
   1165         index = binarySearch<config_pair_t>(
   1166                 config_base_attribute_list,
   1167                 0, NELEM(config_base_attribute_list)-1,
   1168                 attr);
   1169     }
   1170     if (index >= 0) {
   1171         // attribute found, check if this config could match
   1172         int cfgMgtIndex = binarySearch<config_management_t>(
   1173                 gConfigManagement,
   1174                 0, NELEM(gConfigManagement)-1,
   1175                 attr);
   1176         if (cfgMgtIndex >= 0) {
   1177             bool match = gConfigManagement[cfgMgtIndex].match(
   1178                     val, configFound[index].value);
   1179             if (match) {
   1180                 // this config matches
   1181                 return 1;
   1182             }
   1183         } else {
   1184             // attribute not found. this should NEVER happen.
   1185         }
   1186     } else {
   1187         // error, this attribute doesn't exist
   1188     }
   1189     return 0;
   1190 }
   1191 
   1192 static int makeCurrent(ogles_context_t* gl)
   1193 {
   1194     ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
   1195     if (gl) {
   1196         egl_context_t* c = egl_context_t::context(gl);
   1197         if (c->flags & egl_context_t::IS_CURRENT) {
   1198             if (current != gl) {
   1199                 // it is an error to set a context current, if it's already
   1200                 // current to another thread
   1201                 return -1;
   1202             }
   1203         } else {
   1204             if (current) {
   1205                 // mark the current context as not current, and flush
   1206                 glFlush();
   1207                 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
   1208             }
   1209         }
   1210         if (!(c->flags & egl_context_t::IS_CURRENT)) {
   1211             // The context is not current, make it current!
   1212             setGlThreadSpecific(gl);
   1213             c->flags |= egl_context_t::IS_CURRENT;
   1214         }
   1215     } else {
   1216         if (current) {
   1217             // mark the current context as not current, and flush
   1218             glFlush();
   1219             egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
   1220         }
   1221         // this thread has no context attached to it
   1222         setGlThreadSpecific(0);
   1223     }
   1224     return 0;
   1225 }
   1226 
   1227 static EGLBoolean getConfigAttrib(EGLDisplay /*dpy*/, EGLConfig config,
   1228         EGLint attribute, EGLint *value)
   1229 {
   1230     size_t numConfigs =  NELEM(gConfigs);
   1231     int index = (int)(uintptr_t)config;
   1232     if (uint32_t(index) >= numConfigs)
   1233         return setError(EGL_BAD_CONFIG, EGL_FALSE);
   1234 
   1235     int attrIndex;
   1236     attrIndex = binarySearch<config_pair_t>(
   1237             gConfigs[index].array,
   1238             0, gConfigs[index].size-1,
   1239             attribute);
   1240     if (attrIndex>=0) {
   1241         *value = gConfigs[index].array[attrIndex].value;
   1242         return EGL_TRUE;
   1243     }
   1244 
   1245     attrIndex = binarySearch<config_pair_t>(
   1246             config_base_attribute_list,
   1247             0, NELEM(config_base_attribute_list)-1,
   1248             attribute);
   1249     if (attrIndex>=0) {
   1250         *value = config_base_attribute_list[attrIndex].value;
   1251         return EGL_TRUE;
   1252     }
   1253     return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
   1254 }
   1255 
   1256 static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
   1257         NativeWindowType window, const EGLint* /*attrib_list*/)
   1258 {
   1259     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1260         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
   1261     if (window == 0)
   1262         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1263 
   1264     EGLint surfaceType;
   1265     if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
   1266         return EGL_FALSE;
   1267 
   1268     if (!(surfaceType & EGL_WINDOW_BIT))
   1269         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1270 
   1271     if (static_cast<ANativeWindow*>(window)->common.magic !=
   1272             ANDROID_NATIVE_WINDOW_MAGIC) {
   1273         return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
   1274     }
   1275 
   1276     EGLint configID;
   1277     if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
   1278         return EGL_FALSE;
   1279 
   1280     int32_t depthFormat;
   1281     int32_t pixelFormat;
   1282     if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
   1283         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1284     }
   1285 
   1286     // FIXME: we don't have access to the pixelFormat here just yet.
   1287     // (it's possible that the surface is not fully initialized)
   1288     // maybe this should be done after the page-flip
   1289     //if (EGLint(info.format) != pixelFormat)
   1290     //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1291 
   1292     egl_surface_t* surface;
   1293     surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
   1294             static_cast<ANativeWindow*>(window));
   1295 
   1296     if (!surface->initCheck()) {
   1297         // there was a problem in the ctor, the error
   1298         // flag has been set.
   1299         delete surface;
   1300         surface = 0;
   1301     }
   1302     return surface;
   1303 }
   1304 
   1305 static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
   1306         NativePixmapType pixmap, const EGLint* /*attrib_list*/)
   1307 {
   1308     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1309         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
   1310     if (pixmap == 0)
   1311         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1312 
   1313     EGLint surfaceType;
   1314     if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
   1315         return EGL_FALSE;
   1316 
   1317     if (!(surfaceType & EGL_PIXMAP_BIT))
   1318         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1319 
   1320     if (static_cast<egl_native_pixmap_t*>(pixmap)->version !=
   1321             sizeof(egl_native_pixmap_t)) {
   1322         return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
   1323     }
   1324 
   1325     EGLint configID;
   1326     if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
   1327         return EGL_FALSE;
   1328 
   1329     int32_t depthFormat;
   1330     int32_t pixelFormat;
   1331     if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
   1332         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1333     }
   1334 
   1335     if (pixmap->format != pixelFormat)
   1336         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1337 
   1338     egl_surface_t* surface =
   1339         new egl_pixmap_surface_t(dpy, config, depthFormat,
   1340                 static_cast<egl_native_pixmap_t*>(pixmap));
   1341 
   1342     if (!surface->initCheck()) {
   1343         // there was a problem in the ctor, the error
   1344         // flag has been set.
   1345         delete surface;
   1346         surface = 0;
   1347     }
   1348     return surface;
   1349 }
   1350 
   1351 static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
   1352         const EGLint *attrib_list)
   1353 {
   1354     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1355         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
   1356 
   1357     EGLint surfaceType;
   1358     if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
   1359         return EGL_FALSE;
   1360 
   1361     if (!(surfaceType & EGL_PBUFFER_BIT))
   1362         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1363 
   1364     EGLint configID;
   1365     if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
   1366         return EGL_FALSE;
   1367 
   1368     int32_t depthFormat;
   1369     int32_t pixelFormat;
   1370     if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
   1371         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
   1372     }
   1373 
   1374     int32_t w = 0;
   1375     int32_t h = 0;
   1376     while (attrib_list[0] != EGL_NONE) {
   1377         if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
   1378         if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
   1379         attrib_list+=2;
   1380     }
   1381 
   1382     egl_surface_t* surface =
   1383         new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
   1384 
   1385     if (!surface->initCheck()) {
   1386         // there was a problem in the ctor, the error
   1387         // flag has been set.
   1388         delete surface;
   1389         surface = 0;
   1390     }
   1391     return surface;
   1392 }
   1393 
   1394 // ----------------------------------------------------------------------------
   1395 }; // namespace android
   1396 // ----------------------------------------------------------------------------
   1397 
   1398 using namespace android;
   1399 
   1400 // ----------------------------------------------------------------------------
   1401 // Initialization
   1402 // ----------------------------------------------------------------------------
   1403 
   1404 EGLDisplay eglGetDisplay(NativeDisplayType display)
   1405 {
   1406 #ifndef __ANDROID__
   1407     // this just needs to be done once
   1408     if (gGLKey == -1) {
   1409         pthread_mutex_lock(&gInitMutex);
   1410         if (gGLKey == -1)
   1411             pthread_key_create(&gGLKey, NULL);
   1412         pthread_mutex_unlock(&gInitMutex);
   1413     }
   1414 #endif
   1415     if (display == EGL_DEFAULT_DISPLAY) {
   1416         EGLDisplay dpy = (EGLDisplay)1;
   1417         egl_display_t& d = egl_display_t::get_display(dpy);
   1418         d.type = display;
   1419         return dpy;
   1420     }
   1421     return EGL_NO_DISPLAY;
   1422 }
   1423 
   1424 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
   1425 {
   1426     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1427         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1428 
   1429     EGLBoolean res = EGL_TRUE;
   1430     egl_display_t& d = egl_display_t::get_display(dpy);
   1431 
   1432     if (d.initialized.fetch_add(1, std::memory_order_acquire) == 0) {
   1433         // initialize stuff here if needed
   1434         //pthread_mutex_lock(&gInitMutex);
   1435         //pthread_mutex_unlock(&gInitMutex);
   1436     }
   1437 
   1438     if (res == EGL_TRUE) {
   1439         if (major != NULL) *major = VERSION_MAJOR;
   1440         if (minor != NULL) *minor = VERSION_MINOR;
   1441     }
   1442     return res;
   1443 }
   1444 
   1445 EGLBoolean eglTerminate(EGLDisplay dpy)
   1446 {
   1447     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1448         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1449 
   1450     EGLBoolean res = EGL_TRUE;
   1451     egl_display_t& d = egl_display_t::get_display(dpy);
   1452     if (d.initialized.fetch_sub(1, std::memory_order_release) == 1) {
   1453         std::atomic_thread_fence(std::memory_order_acquire);
   1454         // TODO: destroy all resources (surfaces, contexts, etc...)
   1455         //pthread_mutex_lock(&gInitMutex);
   1456         //pthread_mutex_unlock(&gInitMutex);
   1457     }
   1458     return res;
   1459 }
   1460 
   1461 // ----------------------------------------------------------------------------
   1462 // configuration
   1463 // ----------------------------------------------------------------------------
   1464 
   1465 EGLBoolean eglGetConfigs(   EGLDisplay dpy,
   1466                             EGLConfig *configs,
   1467                             EGLint config_size, EGLint *num_config)
   1468 {
   1469     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1470         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1471 
   1472     GLint numConfigs = NELEM(gConfigs);
   1473     if (!configs) {
   1474         *num_config = numConfigs;
   1475         return EGL_TRUE;
   1476     }
   1477     GLint i;
   1478     for (i=0 ; i<numConfigs && i<config_size ; i++) {
   1479         *configs++ = (EGLConfig)(uintptr_t)i;
   1480     }
   1481     *num_config = i;
   1482     return EGL_TRUE;
   1483 }
   1484 
   1485 EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
   1486                             EGLConfig *configs, EGLint config_size,
   1487                             EGLint *num_config)
   1488 {
   1489     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1490         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1491 
   1492     if (ggl_unlikely(num_config==0)) {
   1493         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   1494     }
   1495 
   1496     if (ggl_unlikely(attrib_list==0)) {
   1497         /*
   1498          * A NULL attrib_list should be treated as though it was an empty
   1499          * one (terminated with EGL_NONE) as defined in
   1500          * section 3.4.1 "Querying Configurations" in the EGL specification.
   1501          */
   1502         static const EGLint dummy = EGL_NONE;
   1503         attrib_list = &dummy;
   1504     }
   1505 
   1506     int numAttributes = 0;
   1507     int numConfigs =  NELEM(gConfigs);
   1508     uint32_t possibleMatch = (1<<numConfigs)-1;
   1509     while(possibleMatch && *attrib_list != EGL_NONE) {
   1510         numAttributes++;
   1511         EGLint attr = *attrib_list++;
   1512         EGLint val  = *attrib_list++;
   1513         for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
   1514             if (!(possibleMatch & (1<<i)))
   1515                 continue;
   1516             if (isAttributeMatching(i, attr, val) == 0) {
   1517                 possibleMatch &= ~(1<<i);
   1518             }
   1519         }
   1520     }
   1521 
   1522     // now, handle the attributes which have a useful default value
   1523     for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
   1524         // see if this attribute was specified, if not, apply its
   1525         // default value
   1526         if (binarySearch<config_pair_t>(
   1527                 (config_pair_t const*)attrib_list,
   1528                 0, numAttributes-1,
   1529                 config_defaults[j].key) < 0)
   1530         {
   1531             for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
   1532                 if (!(possibleMatch & (1<<i)))
   1533                     continue;
   1534                 if (isAttributeMatching(i,
   1535                         config_defaults[j].key,
   1536                         config_defaults[j].value) == 0)
   1537                 {
   1538                     possibleMatch &= ~(1<<i);
   1539                 }
   1540             }
   1541         }
   1542     }
   1543 
   1544     // return the configurations found
   1545     int n=0;
   1546     if (possibleMatch) {
   1547         if (configs) {
   1548             for (int i=0 ; config_size && i<numConfigs ; i++) {
   1549                 if (possibleMatch & (1<<i)) {
   1550                     *configs++ = (EGLConfig)(uintptr_t)i;
   1551                     config_size--;
   1552                     n++;
   1553                 }
   1554             }
   1555         } else {
   1556             for (int i=0 ; i<numConfigs ; i++) {
   1557                 if (possibleMatch & (1<<i)) {
   1558                     n++;
   1559                 }
   1560             }
   1561         }
   1562     }
   1563     *num_config = n;
   1564      return EGL_TRUE;
   1565 }
   1566 
   1567 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
   1568         EGLint attribute, EGLint *value)
   1569 {
   1570     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1571         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1572 
   1573     return getConfigAttrib(dpy, config, attribute, value);
   1574 }
   1575 
   1576 // ----------------------------------------------------------------------------
   1577 // surfaces
   1578 // ----------------------------------------------------------------------------
   1579 
   1580 EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
   1581                                     NativeWindowType window,
   1582                                     const EGLint *attrib_list)
   1583 {
   1584     return createWindowSurface(dpy, config, window, attrib_list);
   1585 }
   1586 
   1587 EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
   1588                                     NativePixmapType pixmap,
   1589                                     const EGLint *attrib_list)
   1590 {
   1591     return createPixmapSurface(dpy, config, pixmap, attrib_list);
   1592 }
   1593 
   1594 EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
   1595                                     const EGLint *attrib_list)
   1596 {
   1597     return createPbufferSurface(dpy, config, attrib_list);
   1598 }
   1599 
   1600 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
   1601 {
   1602     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1603         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1604     if (eglSurface != EGL_NO_SURFACE) {
   1605         egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
   1606         if (!surface->isValid())
   1607             return setError(EGL_BAD_SURFACE, EGL_FALSE);
   1608         if (surface->dpy != dpy)
   1609             return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1610         if (surface->ctx) {
   1611             // defer disconnect/delete until no longer current
   1612             surface->zombie = true;
   1613         } else {
   1614             surface->disconnect();
   1615             delete surface;
   1616         }
   1617     }
   1618     return EGL_TRUE;
   1619 }
   1620 
   1621 EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
   1622                             EGLint attribute, EGLint *value)
   1623 {
   1624     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1625         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1626     egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
   1627     if (!surface->isValid())
   1628         return setError(EGL_BAD_SURFACE, EGL_FALSE);
   1629     if (surface->dpy != dpy)
   1630         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1631 
   1632     EGLBoolean ret = EGL_TRUE;
   1633     switch (attribute) {
   1634         case EGL_CONFIG_ID:
   1635             ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
   1636             break;
   1637         case EGL_WIDTH:
   1638             *value = surface->getWidth();
   1639             break;
   1640         case EGL_HEIGHT:
   1641             *value = surface->getHeight();
   1642             break;
   1643         case EGL_LARGEST_PBUFFER:
   1644             // not modified for a window or pixmap surface
   1645             break;
   1646         case EGL_TEXTURE_FORMAT:
   1647             *value = EGL_NO_TEXTURE;
   1648             break;
   1649         case EGL_TEXTURE_TARGET:
   1650             *value = EGL_NO_TEXTURE;
   1651             break;
   1652         case EGL_MIPMAP_TEXTURE:
   1653             *value = EGL_FALSE;
   1654             break;
   1655         case EGL_MIPMAP_LEVEL:
   1656             *value = 0;
   1657             break;
   1658         case EGL_RENDER_BUFFER:
   1659             // TODO: return the real RENDER_BUFFER here
   1660             *value = EGL_BACK_BUFFER;
   1661             break;
   1662         case EGL_HORIZONTAL_RESOLUTION:
   1663             // pixel/mm * EGL_DISPLAY_SCALING
   1664             *value = surface->getHorizontalResolution();
   1665             break;
   1666         case EGL_VERTICAL_RESOLUTION:
   1667             // pixel/mm * EGL_DISPLAY_SCALING
   1668             *value = surface->getVerticalResolution();
   1669             break;
   1670         case EGL_PIXEL_ASPECT_RATIO: {
   1671             // w/h * EGL_DISPLAY_SCALING
   1672             int wr = surface->getHorizontalResolution();
   1673             int hr = surface->getVerticalResolution();
   1674             *value = (wr * EGL_DISPLAY_SCALING) / hr;
   1675         } break;
   1676         case EGL_SWAP_BEHAVIOR:
   1677             *value = surface->getSwapBehavior();
   1678             break;
   1679         default:
   1680             ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
   1681     }
   1682     return ret;
   1683 }
   1684 
   1685 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
   1686                             EGLContext /*share_list*/, const EGLint* /*attrib_list*/)
   1687 {
   1688     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1689         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
   1690 
   1691     ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
   1692     if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
   1693 
   1694     egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
   1695     c->flags = egl_context_t::NEVER_CURRENT;
   1696     c->dpy = dpy;
   1697     c->config = config;
   1698     c->read = 0;
   1699     c->draw = 0;
   1700     return (EGLContext)gl;
   1701 }
   1702 
   1703 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
   1704 {
   1705     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1706         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1707     egl_context_t* c = egl_context_t::context(ctx);
   1708     if (c->flags & egl_context_t::IS_CURRENT)
   1709         setGlThreadSpecific(0);
   1710     ogles_uninit((ogles_context_t*)ctx);
   1711     return EGL_TRUE;
   1712 }
   1713 
   1714 EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
   1715                             EGLSurface read, EGLContext ctx)
   1716 {
   1717     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1718         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1719     if (draw) {
   1720         egl_surface_t* s = (egl_surface_t*)draw;
   1721         if (!s->isValid())
   1722             return setError(EGL_BAD_SURFACE, EGL_FALSE);
   1723         if (s->dpy != dpy)
   1724             return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1725         // TODO: check that draw is compatible with the context
   1726     }
   1727     if (read && read!=draw) {
   1728         egl_surface_t* s = (egl_surface_t*)read;
   1729         if (!s->isValid())
   1730             return setError(EGL_BAD_SURFACE, EGL_FALSE);
   1731         if (s->dpy != dpy)
   1732             return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1733         // TODO: check that read is compatible with the context
   1734     }
   1735 
   1736     EGLContext current_ctx = EGL_NO_CONTEXT;
   1737 
   1738     if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
   1739         return setError(EGL_BAD_MATCH, EGL_FALSE);
   1740 
   1741     if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
   1742         return setError(EGL_BAD_MATCH, EGL_FALSE);
   1743 
   1744     if (ctx == EGL_NO_CONTEXT) {
   1745         // if we're detaching, we need the current context
   1746         current_ctx = (EGLContext)getGlThreadSpecific();
   1747     } else {
   1748         egl_context_t* c = egl_context_t::context(ctx);
   1749         egl_surface_t* d = (egl_surface_t*)draw;
   1750         egl_surface_t* r = (egl_surface_t*)read;
   1751         if ((d && d->ctx && d->ctx != ctx) ||
   1752             (r && r->ctx && r->ctx != ctx)) {
   1753             // one of the surface is bound to a context in another thread
   1754             return setError(EGL_BAD_ACCESS, EGL_FALSE);
   1755         }
   1756     }
   1757 
   1758     ogles_context_t* gl = (ogles_context_t*)ctx;
   1759     if (makeCurrent(gl) == 0) {
   1760         if (ctx) {
   1761             egl_context_t* c = egl_context_t::context(ctx);
   1762             egl_surface_t* d = (egl_surface_t*)draw;
   1763             egl_surface_t* r = (egl_surface_t*)read;
   1764 
   1765             if (c->draw) {
   1766                 egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
   1767                 s->disconnect();
   1768                 s->ctx = EGL_NO_CONTEXT;
   1769                 if (s->zombie)
   1770                     delete s;
   1771             }
   1772             if (c->read) {
   1773                 // FIXME: unlock/disconnect the read surface too
   1774             }
   1775 
   1776             c->draw = draw;
   1777             c->read = read;
   1778 
   1779             if (c->flags & egl_context_t::NEVER_CURRENT) {
   1780                 c->flags &= ~egl_context_t::NEVER_CURRENT;
   1781                 GLint w = 0;
   1782                 GLint h = 0;
   1783                 if (draw) {
   1784                     w = d->getWidth();
   1785                     h = d->getHeight();
   1786                 }
   1787                 ogles_surfaceport(gl, 0, 0);
   1788                 ogles_viewport(gl, 0, 0, w, h);
   1789                 ogles_scissor(gl, 0, 0, w, h);
   1790             }
   1791             if (d) {
   1792                 if (d->connect() == EGL_FALSE) {
   1793                     return EGL_FALSE;
   1794                 }
   1795                 d->ctx = ctx;
   1796                 d->bindDrawSurface(gl);
   1797             }
   1798             if (r) {
   1799                 // FIXME: lock/connect the read surface too
   1800                 r->ctx = ctx;
   1801                 r->bindReadSurface(gl);
   1802             }
   1803         } else {
   1804             // if surfaces were bound to the context bound to this thread
   1805             // mark then as unbound.
   1806             if (current_ctx) {
   1807                 egl_context_t* c = egl_context_t::context(current_ctx);
   1808                 egl_surface_t* d = (egl_surface_t*)c->draw;
   1809                 egl_surface_t* r = (egl_surface_t*)c->read;
   1810                 if (d) {
   1811                     c->draw = 0;
   1812                     d->disconnect();
   1813                     d->ctx = EGL_NO_CONTEXT;
   1814                     if (d->zombie)
   1815                         delete d;
   1816                 }
   1817                 if (r) {
   1818                     c->read = 0;
   1819                     r->ctx = EGL_NO_CONTEXT;
   1820                     // FIXME: unlock/disconnect the read surface too
   1821                 }
   1822             }
   1823         }
   1824         return EGL_TRUE;
   1825     }
   1826     return setError(EGL_BAD_ACCESS, EGL_FALSE);
   1827 }
   1828 
   1829 EGLContext eglGetCurrentContext(void)
   1830 {
   1831     // eglGetCurrentContext returns the current EGL rendering context,
   1832     // as specified by eglMakeCurrent. If no context is current,
   1833     // EGL_NO_CONTEXT is returned.
   1834     return (EGLContext)getGlThreadSpecific();
   1835 }
   1836 
   1837 EGLSurface eglGetCurrentSurface(EGLint readdraw)
   1838 {
   1839     // eglGetCurrentSurface returns the read or draw surface attached
   1840     // to the current EGL rendering context, as specified by eglMakeCurrent.
   1841     // If no context is current, EGL_NO_SURFACE is returned.
   1842     EGLContext ctx = (EGLContext)getGlThreadSpecific();
   1843     if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
   1844     egl_context_t* c = egl_context_t::context(ctx);
   1845     if (readdraw == EGL_READ) {
   1846         return c->read;
   1847     } else if (readdraw == EGL_DRAW) {
   1848         return c->draw;
   1849     }
   1850     return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
   1851 }
   1852 
   1853 EGLDisplay eglGetCurrentDisplay(void)
   1854 {
   1855     // eglGetCurrentDisplay returns the current EGL display connection
   1856     // for the current EGL rendering context, as specified by eglMakeCurrent.
   1857     // If no context is current, EGL_NO_DISPLAY is returned.
   1858     EGLContext ctx = (EGLContext)getGlThreadSpecific();
   1859     if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
   1860     egl_context_t* c = egl_context_t::context(ctx);
   1861     return c->dpy;
   1862 }
   1863 
   1864 EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
   1865                             EGLint attribute, EGLint *value)
   1866 {
   1867     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1868         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1869     egl_context_t* c = egl_context_t::context(ctx);
   1870     switch (attribute) {
   1871         case EGL_CONFIG_ID:
   1872             // Returns the ID of the EGL frame buffer configuration with
   1873             // respect to which the context was created
   1874             return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
   1875     }
   1876     return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
   1877 }
   1878 
   1879 EGLBoolean eglWaitGL(void)
   1880 {
   1881     return EGL_TRUE;
   1882 }
   1883 
   1884 EGLBoolean eglWaitNative(EGLint /*engine*/)
   1885 {
   1886     return EGL_TRUE;
   1887 }
   1888 
   1889 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
   1890 {
   1891     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1892         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1893 
   1894     egl_surface_t* d = static_cast<egl_surface_t*>(draw);
   1895     if (!d->isValid())
   1896         return setError(EGL_BAD_SURFACE, EGL_FALSE);
   1897     if (d->dpy != dpy)
   1898         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1899 
   1900     // post the surface
   1901     d->swapBuffers();
   1902 
   1903     // if it's bound to a context, update the buffer
   1904     if (d->ctx != EGL_NO_CONTEXT) {
   1905         d->bindDrawSurface((ogles_context_t*)d->ctx);
   1906         // if this surface is also the read surface of the context
   1907         // it is bound to, make sure to update the read buffer as well.
   1908         // The EGL spec is a little unclear about this.
   1909         egl_context_t* c = egl_context_t::context(d->ctx);
   1910         if (c->read == draw) {
   1911             d->bindReadSurface((ogles_context_t*)d->ctx);
   1912         }
   1913     }
   1914 
   1915     return EGL_TRUE;
   1916 }
   1917 
   1918 EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface /*surface*/,
   1919                             NativePixmapType /*target*/)
   1920 {
   1921     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1922         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1923     // TODO: eglCopyBuffers()
   1924     return EGL_FALSE;
   1925 }
   1926 
   1927 EGLint eglGetError(void)
   1928 {
   1929     return getError();
   1930 }
   1931 
   1932 const char* eglQueryString(EGLDisplay dpy, EGLint name)
   1933 {
   1934     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1935         return setError(EGL_BAD_DISPLAY, (const char*)0);
   1936 
   1937     switch (name) {
   1938         case EGL_VENDOR:
   1939             return gVendorString;
   1940         case EGL_VERSION:
   1941             return gVersionString;
   1942         case EGL_EXTENSIONS:
   1943             return gExtensionsString;
   1944         case EGL_CLIENT_APIS:
   1945             return gClientApiString;
   1946     }
   1947     return setError(EGL_BAD_PARAMETER, (const char *)0);
   1948 }
   1949 
   1950 // ----------------------------------------------------------------------------
   1951 // EGL 1.1
   1952 // ----------------------------------------------------------------------------
   1953 
   1954 EGLBoolean eglSurfaceAttrib(
   1955         EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*attribute*/, EGLint /*value*/)
   1956 {
   1957     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1958         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1959     // TODO: eglSurfaceAttrib()
   1960     return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   1961 }
   1962 
   1963 EGLBoolean eglBindTexImage(
   1964         EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/)
   1965 {
   1966     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1967         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1968     // TODO: eglBindTexImage()
   1969     return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   1970 }
   1971 
   1972 EGLBoolean eglReleaseTexImage(
   1973         EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/)
   1974 {
   1975     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1976         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1977     // TODO: eglReleaseTexImage()
   1978     return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   1979 }
   1980 
   1981 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint /*interval*/)
   1982 {
   1983     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   1984         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   1985     // TODO: eglSwapInterval()
   1986     return EGL_TRUE;
   1987 }
   1988 
   1989 // ----------------------------------------------------------------------------
   1990 // EGL 1.2
   1991 // ----------------------------------------------------------------------------
   1992 
   1993 EGLBoolean eglBindAPI(EGLenum api)
   1994 {
   1995     if (api != EGL_OPENGL_ES_API)
   1996         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   1997     return EGL_TRUE;
   1998 }
   1999 
   2000 EGLenum eglQueryAPI(void)
   2001 {
   2002     return EGL_OPENGL_ES_API;
   2003 }
   2004 
   2005 EGLBoolean eglWaitClient(void)
   2006 {
   2007     glFinish();
   2008     return EGL_TRUE;
   2009 }
   2010 
   2011 EGLBoolean eglReleaseThread(void)
   2012 {
   2013     // TODO: eglReleaseThread()
   2014     return EGL_TRUE;
   2015 }
   2016 
   2017 EGLSurface eglCreatePbufferFromClientBuffer(
   2018           EGLDisplay dpy, EGLenum /*buftype*/, EGLClientBuffer /*buffer*/,
   2019           EGLConfig /*config*/, const EGLint* /*attrib_list*/)
   2020 {
   2021     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   2022         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
   2023     // TODO: eglCreatePbufferFromClientBuffer()
   2024     return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
   2025 }
   2026 
   2027 // ----------------------------------------------------------------------------
   2028 // EGL_EGLEXT_VERSION 3
   2029 // ----------------------------------------------------------------------------
   2030 
   2031 void (*eglGetProcAddress (const char *procname))()
   2032 {
   2033     extention_map_t const * const map = gExtentionMap;
   2034     for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
   2035         if (!strcmp(procname, map[i].name)) {
   2036             return map[i].address;
   2037         }
   2038     }
   2039     return NULL;
   2040 }
   2041 
   2042 EGLBoolean eglLockSurfaceKHR(EGLDisplay /*dpy*/, EGLSurface /*surface*/,
   2043         const EGLint* /*attrib_list*/)
   2044 {
   2045     EGLBoolean result = EGL_FALSE;
   2046     return result;
   2047 }
   2048 
   2049 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay /*dpy*/, EGLSurface /*surface*/)
   2050 {
   2051     EGLBoolean result = EGL_FALSE;
   2052     return result;
   2053 }
   2054 
   2055 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
   2056         EGLClientBuffer buffer, const EGLint* /*attrib_list*/)
   2057 {
   2058     if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
   2059         return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
   2060     }
   2061     if (ctx != EGL_NO_CONTEXT) {
   2062         return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
   2063     }
   2064     if (target != EGL_NATIVE_BUFFER_ANDROID) {
   2065         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
   2066     }
   2067 
   2068     ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
   2069 
   2070     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
   2071         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
   2072 
   2073     if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
   2074         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
   2075 
   2076     switch (native_buffer->format) {
   2077         case HAL_PIXEL_FORMAT_RGBA_8888:
   2078         case HAL_PIXEL_FORMAT_RGBX_8888:
   2079         case HAL_PIXEL_FORMAT_RGB_888:
   2080         case HAL_PIXEL_FORMAT_RGB_565:
   2081         case HAL_PIXEL_FORMAT_BGRA_8888:
   2082             break;
   2083         default:
   2084             return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
   2085     }
   2086 
   2087     native_buffer->common.incRef(&native_buffer->common);
   2088     return (EGLImageKHR)native_buffer;
   2089 }
   2090 
   2091 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
   2092 {
   2093     if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
   2094         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   2095     }
   2096 
   2097     ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
   2098 
   2099     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
   2100         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   2101 
   2102     if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
   2103         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   2104 
   2105     native_buffer->common.decRef(&native_buffer->common);
   2106 
   2107     return EGL_TRUE;
   2108 }
   2109 
   2110 // ----------------------------------------------------------------------------
   2111 // EGL_KHR_fence_sync
   2112 // ----------------------------------------------------------------------------
   2113 
   2114 #define FENCE_SYNC_HANDLE ((EGLSyncKHR)0xFE4CE)
   2115 
   2116 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
   2117         const EGLint *attrib_list)
   2118 {
   2119     if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
   2120         return setError(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR);
   2121     }
   2122 
   2123     if (type != EGL_SYNC_FENCE_KHR ||
   2124             (attrib_list != NULL && attrib_list[0] != EGL_NONE)) {
   2125         return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
   2126     }
   2127 
   2128     if (eglGetCurrentContext() == EGL_NO_CONTEXT) {
   2129         return setError(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
   2130     }
   2131 
   2132     // AGL is synchronous; nothing to do here.
   2133 
   2134     return FENCE_SYNC_HANDLE;
   2135 }
   2136 
   2137 EGLBoolean eglDestroySyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync)
   2138 {
   2139     if (sync != FENCE_SYNC_HANDLE) {
   2140         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   2141     }
   2142 
   2143     return EGL_TRUE;
   2144 }
   2145 
   2146 EGLint eglClientWaitSyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, EGLint /*flags*/,
   2147         EGLTimeKHR /*timeout*/)
   2148 {
   2149     if (sync != FENCE_SYNC_HANDLE) {
   2150         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   2151     }
   2152 
   2153     return EGL_CONDITION_SATISFIED_KHR;
   2154 }
   2155 
   2156 EGLBoolean eglGetSyncAttribKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync,
   2157         EGLint attribute, EGLint *value)
   2158 {
   2159     if (sync != FENCE_SYNC_HANDLE) {
   2160         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
   2161     }
   2162 
   2163     switch (attribute) {
   2164     case EGL_SYNC_TYPE_KHR:
   2165         *value = EGL_SYNC_FENCE_KHR;
   2166         return EGL_TRUE;
   2167     case EGL_SYNC_STATUS_KHR:
   2168         *value = EGL_SIGNALED_KHR;
   2169         return EGL_TRUE;
   2170     case EGL_SYNC_CONDITION_KHR:
   2171         *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
   2172         return EGL_TRUE;
   2173     default:
   2174         return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
   2175     }
   2176 }
   2177 
   2178 // ----------------------------------------------------------------------------
   2179 // ANDROID extensions
   2180 // ----------------------------------------------------------------------------
   2181 
   2182 EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
   2183         EGLint left, EGLint top, EGLint width, EGLint height)
   2184 {
   2185     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
   2186         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   2187 
   2188     egl_surface_t* d = static_cast<egl_surface_t*>(draw);
   2189     if (!d->isValid())
   2190         return setError(EGL_BAD_SURFACE, EGL_FALSE);
   2191     if (d->dpy != dpy)
   2192         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
   2193 
   2194     // post the surface
   2195     d->setSwapRectangle(left, top, width, height);
   2196 
   2197     return EGL_TRUE;
   2198 }
   2199