Edit

kc3-lang/angle/src/libEGL/libEGL.cpp

Branch :

  • Show log

    Commit

  • Author : apatrick@chromium.org
    Date : 2011-05-05 00:00:30
    Hash : 192a1810
    Message : Implemented semantics for eglDestroySurface when surface is current on thread. The spec has this to say. " All resources associated with surface which were allocated by EGL are marked for deletion as soon as possible. If surface is current to any thread (see section 3.7.3), resources are not actually released while the surface remains current. Future references to surface remain valid only so long as it is current; it will be destroyed, and all future references to it will become invalid, as soon as any otherwise valid eglMakeCurrent call is made from the thread it is bound to." Review URL: http://codereview.appspot.com/4449064 git-svn-id: https://angleproject.googlecode.com/svn/trunk@632 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/libEGL/libEGL.cpp
  • //
    // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // libEGL.cpp: Implements the exported EGL functions.
    
    #include <exception>
    
    #include "common/debug.h"
    #include "common/version.h"
    #include "libGLESv2/Context.h"
    #include "libGLESv2/Texture.h"
    
    #include "libEGL/main.h"
    #include "libEGL/Display.h"
    
    
    bool validateDisplay(egl::Display *display)
    {
        if (display == EGL_NO_DISPLAY)
        {
            return error(EGL_BAD_DISPLAY, false);
        }
    
        if (!display->isInitialized())
        {
            return error(EGL_NOT_INITIALIZED, false);
        }
    
        return true;
    }
    
    bool validateConfig(egl::Display *display, EGLConfig config)
    {
        if (!validateDisplay(display))
        {
            return false;
        }
    
        if (!display->isValidConfig(config))
        {
            return error(EGL_BAD_CONFIG, false);
        }
    
        return true;
    }
    
    bool validateContext(egl::Display *display, gl::Context *context)
    {
        if (!validateDisplay(display))
        {
            return false;
        }
    
        if (!display->isValidContext(context))
        {
            return error(EGL_BAD_CONTEXT, false);
        }
    
        return true;
    }
    
    bool validateSurface(egl::Display *display, egl::Surface *surface)
    {
        if (!validateDisplay(display))
        {
            return false;
        }
    
        if (!display->isValidSurface(surface))
        {
            return error(EGL_BAD_SURFACE, false);
        }
    
        return true;
    }
    
    extern "C"
    {
    EGLint __stdcall eglGetError(void)
    {
        EVENT("()");
    
        EGLint error = egl::getCurrentError();
    
        if (error != EGL_SUCCESS)
        {
            egl::setCurrentError(EGL_SUCCESS);
        }
    
        return error;
    }
    
    EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id)
    {
        EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
    
        try
        {
            // FIXME: Return the same EGLDisplay handle when display_id already created a display
    
            if (display_id == EGL_DEFAULT_DISPLAY)
            {
                return new egl::Display((HDC)NULL);
            }
            else
            {
                // FIXME: Check if display_id is a valid display device context
    
                return new egl::Display((HDC)display_id);
            }
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY);
        }
    
        return EGL_NO_DISPLAY;
    }
    
    EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)",
              dpy, major, minor);
    
        try
        {
            if (dpy == EGL_NO_DISPLAY)
            {
                return error(EGL_BAD_DISPLAY, EGL_FALSE);
            }
    
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!display->initialize())
            {
                return error(EGL_NOT_INITIALIZED, EGL_FALSE);
            }
    
            if (major) *major = 1;
            if (minor) *minor = 4;
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglTerminate(EGLDisplay dpy)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy);
    
        try
        {
            if (dpy == EGL_NO_DISPLAY)
            {
                return error(EGL_BAD_DISPLAY, EGL_FALSE);
            }
    
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            display->terminate();
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateDisplay(display))
            {
                return NULL;
            }
    
            switch (name)
            {
              case EGL_CLIENT_APIS:
                return success("OpenGL_ES");
              case EGL_EXTENSIONS:
                return display->getExtensionString();
              case EGL_VENDOR:
                return success("Google Inc.");
              case EGL_VERSION:
                return success("1.4 (ANGLE "VERSION_STRING")");
            }
    
            return error(EGL_BAD_PARAMETER, (const char*)NULL);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, (const char*)NULL);
        }
    
        return NULL;
    }
    
    EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, "
              "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
              dpy, configs, config_size, num_config);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateDisplay(display))
            {
                return EGL_FALSE;
            }
    
            if (!num_config)
            {
                return error(EGL_BAD_PARAMETER, EGL_FALSE);
            }
    
            const EGLint attribList[] =    {EGL_NONE};
    
            if (!display->getConfigs(configs, attribList, config_size, num_config))
            {
                return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
            }
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, "
              "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
              dpy, attrib_list, configs, config_size, num_config);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateDisplay(display))
            {
                return EGL_FALSE;
            }
    
            if (!num_config)
            {
                return error(EGL_BAD_PARAMETER, EGL_FALSE);
            }
    
            const EGLint attribList[] =    {EGL_NONE};
    
            if (!attrib_list)
            {
                attrib_list = attribList;
            }
    
            display->getConfigs(configs, attrib_list, config_size, num_config);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
              dpy, config, attribute, value);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateConfig(display, config))
            {
                return EGL_FALSE;
            }
    
            if (!display->getConfigAttrib(config, attribute, value))
            {
                return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
            }
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, "
              "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateConfig(display, config))
            {
                return EGL_NO_SURFACE;
            }
    
            HWND window = (HWND)win;
    
            if (!IsWindow(window))
            {
                return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
            }
    
            return display->createWindowSurface(window, config, attrib_list);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
        }
    
        return EGL_NO_SURFACE;
    }
    
    EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
              dpy, config, attrib_list);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateConfig(display, config))
            {
                return EGL_NO_SURFACE;
            }
    
            return display->createOffscreenSurface(config, attrib_list);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
        }
    
        return EGL_NO_SURFACE;
    }
    
    EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, "
              "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateConfig(display, config))
            {
                return EGL_NO_SURFACE;
            }
    
            UNIMPLEMENTED();   // FIXME
    
            return success(EGL_NO_SURFACE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
        }
    
        return EGL_NO_SURFACE;
    }
    
    EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            if (surface == EGL_NO_SURFACE)
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
    
            display->destroySurface((egl::Surface*)surface);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
              dpy, surface, attribute, value);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = (egl::Surface*)surface;
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            if (surface == EGL_NO_SURFACE)
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
    
            switch (attribute)
            {
              case EGL_VG_ALPHA_FORMAT:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_VG_COLORSPACE:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_CONFIG_ID:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_HEIGHT:
                *value = eglSurface->getHeight();
                break;
              case EGL_HORIZONTAL_RESOLUTION:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_LARGEST_PBUFFER:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_MIPMAP_TEXTURE:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_MIPMAP_LEVEL:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_MULTISAMPLE_RESOLVE:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_PIXEL_ASPECT_RATIO:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_RENDER_BUFFER:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_SWAP_BEHAVIOR:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_TEXTURE_FORMAT:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_TEXTURE_TARGET:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_VERTICAL_RESOLUTION:
                UNIMPLEMENTED();   // FIXME
                break;
              case EGL_WIDTH:
                *value = eglSurface->getWidth();
                break;
              default:
                return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
            }
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value)
    {
        TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)",
              dpy, surface, attribute, value);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = (egl::Surface*)surface;
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            if (surface == EGL_NO_SURFACE)
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
    
            switch (attribute)
            {
              case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
                *value = (void*) eglSurface->getShareHandle();
                break;
              default:
                return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
            }
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglBindAPI(EGLenum api)
    {
        EVENT("(EGLenum api = 0x%X)", api);
    
        try
        {
            switch (api)
            {
              case EGL_OPENGL_API:
              case EGL_OPENVG_API:
                return error(EGL_BAD_PARAMETER, EGL_FALSE);   // Not supported by this implementation
              case EGL_OPENGL_ES_API:
                break;
              default:
                return error(EGL_BAD_PARAMETER, EGL_FALSE);
            }
    
            egl::setCurrentAPI(api);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLenum __stdcall eglQueryAPI(void)
    {
        EVENT("()");
    
        try
        {
            EGLenum API = egl::getCurrentAPI();
    
            return success(API);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglWaitClient(void)
    {
        EVENT("()");
    
        try
        {
            UNIMPLEMENTED();   // FIXME
    
            return success(0);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglReleaseThread(void)
    {
        EVENT("()");
    
        try
        {
            eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, "
              "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
              dpy, buftype, buffer, config, attrib_list);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateConfig(display, config))
            {
                return EGL_NO_SURFACE;
            }
    
            UNIMPLEMENTED();   // FIXME
    
            return success(EGL_NO_SURFACE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
        }
    
        return EGL_NO_SURFACE;
    }
    
    EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)",
              dpy, surface, attribute, value);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            UNIMPLEMENTED();   // FIXME
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            if (buffer != EGL_BACK_BUFFER)
            {
                return error(EGL_BAD_PARAMETER, EGL_FALSE);
            }
    
            if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
    
            if (eglSurface->getBoundTexture())
            {
                return error(EGL_BAD_ACCESS, EGL_FALSE);
            }
    
            if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
            {
                return error(EGL_BAD_MATCH, EGL_FALSE);
            }
    
            glBindTexImage(eglSurface);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            if (buffer != EGL_BACK_BUFFER)
            {
                return error(EGL_BAD_PARAMETER, EGL_FALSE);
            }
    
            if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
    
            if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
            {
                return error(EGL_BAD_MATCH, EGL_FALSE);
            }
    
            gl::Texture2D *texture = eglSurface->getBoundTexture();
    
            if (texture)
            {
                texture->releaseTexImage();
            }
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateDisplay(display))
            {
                return EGL_FALSE;
            }
    
            egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
    
            if (draw_surface == NULL)
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
            
            draw_surface->setSwapInterval(interval);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, "
              "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list);
    
        try
        {
            // Get the requested client version (default is 1) and check it is two.
            EGLint client_version = 1;
            if (attrib_list)
            {
                for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
                {
                    if (attribute[0] == EGL_CONTEXT_CLIENT_VERSION)
                    {
                        client_version = attribute[1];
                    }
                    else
                    {
                        return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
                    }
                }
            }
    
            if (client_version != 2)
            {
                return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
            }
    
            egl::Display *display = static_cast<egl::Display*>(dpy);
    
            if (!validateConfig(display, config))
            {
                return EGL_NO_CONTEXT;
            }
    
            EGLContext context = display->createContext(config, static_cast<gl::Context*>(share_context));
    
            return success(context);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
        }
    
        return EGL_NO_CONTEXT;
    }
    
    EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            gl::Context *context = static_cast<gl::Context*>(ctx);
    
            if (!validateContext(display, context))
            {
                return EGL_FALSE;
            }
    
            if (ctx == EGL_NO_CONTEXT)
            {
                return error(EGL_BAD_CONTEXT, EGL_FALSE);
            }
    
            display->destroyContext(context);
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)",
              dpy, draw, read, ctx);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            gl::Context *context = static_cast<gl::Context*>(ctx);
            IDirect3DDevice9 *device = display->getDevice();
    
            if (!device || display->isDeviceLost())
            {
                return error(EGL_CONTEXT_LOST, EGL_FALSE);
            }
    
            if (ctx != EGL_NO_CONTEXT && !validateContext(display, context))
            {
                return EGL_FALSE;
            }
    
            if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(draw))) ||
                (read != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(read))))
            {
                return EGL_FALSE;
            }
    
            if (draw != read)
            {
                UNIMPLEMENTED();   // FIXME
            }
    
            egl::Surface* previousDraw = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
            egl::Surface* previousRead = static_cast<egl::Surface*>(egl::getCurrentReadSurface());
    
            egl::setCurrentDisplay(dpy);
            egl::setCurrentDrawSurface(draw);
            egl::setCurrentReadSurface(read);
    
            glMakeCurrent(context, display, static_cast<egl::Surface*>(draw));
    
            // If the previous surfaces are still current, this might just flag
            // them as pending destruction again, deferring destruction to a future
            // eglMakeCurrent or eglTerminate call.
            if (previousDraw && previousDraw->isPendingDestroy())
            {
                eglDestroySurface(dpy, previousDraw);
            }
            if (previousRead && previousRead != previousDraw && previousRead->isPendingDestroy())
            {
                eglDestroySurface(dpy, previousRead);
            }
    
            return success(EGL_TRUE);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLContext __stdcall eglGetCurrentContext(void)
    {
        EVENT("()");
    
        try
        {
            EGLContext context = glGetCurrentContext();
    
            return success(context);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
        }
    
        return EGL_NO_CONTEXT;
    }
    
    EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw)
    {
        EVENT("(EGLint readdraw = %d)", readdraw);
    
        try
        {
            if (readdraw == EGL_READ)
            {
                EGLSurface read = egl::getCurrentReadSurface();
                return success(read);
            }
            else if (readdraw == EGL_DRAW)
            {
                EGLSurface draw = egl::getCurrentDrawSurface();
                return success(draw);
            }
            else
            {
                return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
            }
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
        }
    
        return EGL_NO_SURFACE;
    }
    
    EGLDisplay __stdcall eglGetCurrentDisplay(void)
    {
        EVENT("()");
    
        try
        {
            EGLDisplay dpy = egl::getCurrentDisplay();
    
            return success(dpy);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY);
        }
    
        return EGL_NO_DISPLAY;
    }
    
    EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
              dpy, ctx, attribute, value);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            gl::Context *context = static_cast<gl::Context*>(ctx);
    
            if (!validateContext(display, context))
            {
                return EGL_FALSE;
            }
    
            UNIMPLEMENTED();   // FIXME
    
            return success(0);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglWaitGL(void)
    {
        EVENT("()");
    
        try
        {
            UNIMPLEMENTED();   // FIXME
    
            return success(0);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglWaitNative(EGLint engine)
    {
        EVENT("(EGLint engine = %d)", engine);
    
        try
        {
            UNIMPLEMENTED();   // FIXME
    
            return success(0);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = (egl::Surface*)surface;
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            if (surface == EGL_NO_SURFACE)
            {
                return error(EGL_BAD_SURFACE, EGL_FALSE);
            }
    
            if (eglSurface->swap())
            {
                return success(EGL_TRUE);
            }
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
    {
        EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target);
    
        try
        {
            egl::Display *display = static_cast<egl::Display*>(dpy);
            egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
    
            if (!validateSurface(display, eglSurface))
            {
                return EGL_FALSE;
            }
    
            UNIMPLEMENTED();   // FIXME
    
            return success(0);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_FALSE;
    }
    
    __eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname)
    {
        EVENT("(const char *procname = \"%s\")", procname);
    
        try
        {
            struct Extension
            {
                const char *name;
                __eglMustCastToProperFunctionPointerType address;
            };
    
            static const Extension eglExtensions[] =
            {
                {"eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE},
                {"", NULL},
            };
    
            for (int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++)
            {
                if (strcmp(procname, eglExtensions[ext].name) == 0)
                {
                    return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address;
                }
            }
    
            return glGetProcAddress(procname);
        }
        catch(std::bad_alloc&)
        {
            return error(EGL_BAD_ALLOC, (__eglMustCastToProperFunctionPointerType)NULL);
        }
    
        return NULL;
    }
    }