Edit

kc3-lang/angle/src/libGLESv2/egl_stubs.cpp

Branch :

  • Show log

    Commit

  • Author : Jeff Vigil
    Date : 2021-02-03 15:32:48
    Hash : 22fc9523
    Message : EGL: implement EGL_EXT_buffer_age Add extension flag. Add Validation check to surface query. Enable extension for vulkan. Modify AcquireNextImage to ++frame count and tag images with frame number. Buffer age is the difference between current frame count and the tagged frame number on the buffer. getBuffeAge may need to trigger AcquireNextImage to be current. Pass through egl extension and query. Add EGLBufferAgeTest Test: angle_end2end_test --gtest_filter=EGLBufferAgeTest Test: angle_deqp_egl_tests --deqp-case=dEQP-EGL.functional.buffer_age.* Bug: angleproject:3529 Change-Id: I0cb94be1c3e85d6f33e82a6a1ccdc9731b6a7f23 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2684724 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • src/libGLESv2/egl_stubs.cpp
  • //
    // Copyright 2020 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.
    //
    // egl_stubs.cpp: Stubs for EGL entry points.
    //
    
    #include "libGLESv2/egl_stubs_autogen.h"
    
    #include "common/version.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/Display.h"
    #include "libANGLE/EGLSync.h"
    #include "libANGLE/Surface.h"
    #include "libANGLE/Thread.h"
    #include "libANGLE/queryutils.h"
    #include "libANGLE/validationEGL.h"
    #include "libGLESv2/global_state.h"
    #include "libGLESv2/proc_table_egl.h"
    
    namespace egl
    {
    namespace
    {
    bool CompareProc(const ProcEntry &a, const char *b)
    {
        return strcmp(a.first, b) < 0;
    }
    
    void ClipConfigs(const std::vector<const Config *> &filteredConfigs,
                     EGLConfig *outputConfigs,
                     EGLint configSize,
                     EGLint *numConfigs)
    {
        EGLint resultSize = static_cast<EGLint>(filteredConfigs.size());
        if (outputConfigs)
        {
            resultSize = std::max(std::min(resultSize, configSize), 0);
            for (EGLint i = 0; i < resultSize; i++)
            {
                outputConfigs[i] = const_cast<Config *>(filteredConfigs[i]);
            }
        }
        *numConfigs = resultSize;
    }
    }  // anonymous namespace
    
    EGLBoolean BindAPI(Thread *thread, EGLenum api)
    {
        thread->setAPI(api);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean BindTexImage(Thread *thread, Display *display, Surface *eglSurface, EGLint buffer)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglBindTexImage",
                             GetDisplayIfValid(display), EGL_FALSE);
    
        gl::Context *context = thread->getContext();
        if (context)
        {
            gl::TextureType type =
                egl_gl::EGLTextureTargetToTextureType(eglSurface->getTextureTarget());
            gl::Texture *textureObject = context->getTextureByType(type);
            ANGLE_EGL_TRY_RETURN(thread, eglSurface->bindTexImage(context, textureObject, buffer),
                                 "eglBindTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
        }
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean ChooseConfig(Thread *thread,
                            Display *display,
                            const AttributeMap &attribMap,
                            EGLConfig *configs,
                            EGLint config_size,
                            EGLint *num_config)
    {
        ClipConfigs(display->chooseConfig(attribMap), configs, config_size, num_config);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLint ClientWaitSync(Thread *thread,
                          Display *display,
                          Sync *syncObject,
                          EGLint flags,
                          EGLTime timeout)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglClientWaitSync",
                             GetDisplayIfValid(display), EGL_FALSE);
        gl::Context *currentContext = thread->getContext();
        EGLint syncStatus           = EGL_FALSE;
        ANGLE_EGL_TRY_RETURN(
            thread, syncObject->clientWait(display, currentContext, flags, timeout, &syncStatus),
            "eglClientWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
    
        thread->setSuccess();
        return syncStatus;
    }
    
    EGLBoolean CopyBuffers(Thread *thread,
                           Display *display,
                           Surface *eglSurface,
                           EGLNativePixmapType target)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCopyBuffers",
                             GetDisplayIfValid(display), EGL_FALSE);
        UNIMPLEMENTED();  // FIXME
    
        thread->setSuccess();
        return 0;
    }
    
    EGLContext CreateContext(Thread *thread,
                             Display *display,
                             Config *configuration,
                             gl::Context *sharedGLContext,
                             const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateContext",
                             GetDisplayIfValid(display), EGL_NO_CONTEXT);
        gl::Context *context = nullptr;
        ANGLE_EGL_TRY_RETURN(thread,
                             display->createContext(configuration, sharedGLContext, thread->getAPI(),
                                                    attributes, &context),
                             "eglCreateContext", GetDisplayIfValid(display), EGL_NO_CONTEXT);
    
        thread->setSuccess();
        return static_cast<EGLContext>(context);
    }
    
    EGLImage CreateImage(Thread *thread,
                         Display *display,
                         gl::Context *context,
                         EGLenum target,
                         EGLClientBuffer buffer,
                         const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateImage",
                             GetDisplayIfValid(display), EGL_FALSE);
    
        Image *image = nullptr;
        Error error  = display->createImage(context, target, buffer, attributes, &image);
        if (error.isError())
        {
            thread->setError(error, "eglCreateImage", GetDisplayIfValid(display));
            return EGL_NO_IMAGE;
        }
    
        thread->setSuccess();
        return static_cast<EGLImage>(image);
    }
    
    EGLSurface CreatePbufferFromClientBuffer(Thread *thread,
                                             Display *display,
                                             EGLenum buftype,
                                             EGLClientBuffer buffer,
                                             Config *configuration,
                                             const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePbufferFromClientBuffer",
                             GetDisplayIfValid(display), EGL_NO_SURFACE);
        Surface *surface = nullptr;
        ANGLE_EGL_TRY_RETURN(thread,
                             display->createPbufferFromClientBuffer(configuration, buftype, buffer,
                                                                    attributes, &surface),
                             "eglCreatePbufferFromClientBuffer", GetDisplayIfValid(display),
                             EGL_NO_SURFACE);
    
        return static_cast<EGLSurface>(surface);
    }
    
    EGLSurface CreatePbufferSurface(Thread *thread,
                                    Display *display,
                                    Config *configuration,
                                    const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePbufferSurface",
                             GetDisplayIfValid(display), EGL_NO_SURFACE);
        Surface *surface = nullptr;
        ANGLE_EGL_TRY_RETURN(thread, display->createPbufferSurface(configuration, attributes, &surface),
                             "eglCreatePbufferSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
    
        return static_cast<EGLSurface>(surface);
    }
    
    EGLSurface CreatePixmapSurface(Thread *thread,
                                   Display *display,
                                   Config *configuration,
                                   EGLNativePixmapType pixmap,
                                   const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePixmapSurface",
                             GetDisplayIfValid(display), EGL_NO_SURFACE);
        Surface *surface = nullptr;
        ANGLE_EGL_TRY_RETURN(thread,
                             display->createPixmapSurface(configuration, pixmap, attributes, &surface),
                             "eglCreatePixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
    
        thread->setSuccess();
        return static_cast<EGLSurface>(surface);
    }
    
    EGLSurface CreatePlatformPixmapSurface(Thread *thread,
                                           Display *display,
                                           Config *configuration,
                                           void *pixmap,
                                           const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformPixmapSurface",
                             GetDisplayIfValid(display), EGL_NO_SURFACE);
        Surface *surface                 = nullptr;
        EGLNativePixmapType nativePixmap = reinterpret_cast<EGLNativePixmapType>(pixmap);
        ANGLE_EGL_TRY_RETURN(
            thread, display->createPixmapSurface(configuration, nativePixmap, attributes, &surface),
            "eglCreatePlatformPixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
    
        thread->setSuccess();
        return static_cast<EGLSurface>(surface);
    }
    
    EGLSurface CreatePlatformWindowSurface(Thread *thread,
                                           Display *display,
                                           Config *configuration,
                                           void *win,
                                           const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformWindowSurface",
                             GetDisplayIfValid(display), EGL_NO_SURFACE);
        Surface *surface                 = nullptr;
        EGLNativeWindowType nativeWindow = reinterpret_cast<EGLNativeWindowType>(win);
        ANGLE_EGL_TRY_RETURN(
            thread, display->createWindowSurface(configuration, nativeWindow, attributes, &surface),
            "eglPlatformCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
    
        return static_cast<EGLSurface>(surface);
    }
    
    EGLSync CreateSync(Thread *thread, Display *display, EGLenum type, const AttributeMap &attributes)
    {
        gl::Context *currentContext = thread->getContext();
    
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateSync",
                             GetDisplayIfValid(display), EGL_FALSE);
        Sync *syncObject = nullptr;
        ANGLE_EGL_TRY_RETURN(thread, display->createSync(currentContext, type, attributes, &syncObject),
                             "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC);
    
        thread->setSuccess();
        return static_cast<EGLSync>(syncObject);
    }
    
    EGLSurface CreateWindowSurface(Thread *thread,
                                   Display *display,
                                   Config *configuration,
                                   EGLNativeWindowType win,
                                   const AttributeMap &attributes)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateWindowSurface",
                             GetDisplayIfValid(display), EGL_NO_SURFACE);
    
        Surface *surface = nullptr;
        ANGLE_EGL_TRY_RETURN(thread,
                             display->createWindowSurface(configuration, win, attributes, &surface),
                             "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
    
        return static_cast<EGLSurface>(surface);
    }
    
    EGLBoolean DestroyContext(Thread *thread, Display *display, gl::Context *context)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyContext",
                             GetDisplayIfValid(display), EGL_FALSE);
        bool contextWasCurrent = context == thread->getContext();
    
        ANGLE_EGL_TRY_RETURN(thread, display->destroyContext(thread, context), "eglDestroyContext",
                             GetContextIfValid(display, context), EGL_FALSE);
    
        if (contextWasCurrent)
        {
            ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(context, nullptr, nullptr, nullptr),
                                 "eglDestroyContext", GetContextIfValid(display, context), EGL_FALSE);
            SetContextCurrent(thread, nullptr);
        }
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean DestroyImage(Thread *thread, Display *display, Image *img)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyImage",
                             GetDisplayIfValid(display), EGL_FALSE);
        display->destroyImage(img);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean DestroySurface(Thread *thread, Display *display, Surface *eglSurface)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySurface",
                             GetDisplayIfValid(display), EGL_FALSE);
        ANGLE_EGL_TRY_RETURN(thread, display->destroySurface(eglSurface), "eglDestroySurface",
                             GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean DestroySync(Thread *thread, Display *display, Sync *syncObject)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySync",
                             GetDisplayIfValid(display), EGL_FALSE);
        display->destroySync(syncObject);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean GetConfigAttrib(Thread *thread,
                               Display *display,
                               Config *configuration,
                               EGLint attribute,
                               EGLint *value)
    {
        QueryConfigAttrib(configuration, attribute, value);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean GetConfigs(Thread *thread,
                          Display *display,
                          EGLConfig *configs,
                          EGLint config_size,
                          EGLint *num_config)
    {
        ClipConfigs(display->getConfigs(AttributeMap()), configs, config_size, num_config);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLContext GetCurrentContext(Thread *thread)
    {
        gl::Context *context = thread->getContext();
    
        thread->setSuccess();
        return static_cast<EGLContext>(context);
    }
    
    EGLDisplay GetCurrentDisplay(Thread *thread)
    {
        thread->setSuccess();
        if (thread->getContext() != nullptr)
        {
            return thread->getContext()->getDisplay();
        }
        return EGL_NO_DISPLAY;
    }
    
    EGLSurface GetCurrentSurface(Thread *thread, EGLint readdraw)
    {
        if (readdraw == EGL_READ)
        {
            thread->setSuccess();
            return thread->getCurrentReadSurface();
        }
        else if (readdraw == EGL_DRAW)
        {
            thread->setSuccess();
            return thread->getCurrentDrawSurface();
        }
        else
        {
            thread->setError(EglBadParameter(), "eglGetCurrentSurface", nullptr);
            return EGL_NO_SURFACE;
        }
    }
    
    EGLDisplay GetDisplay(Thread *thread, EGLNativeDisplayType display_id)
    {
        return Display::GetDisplayFromNativeDisplay(display_id, AttributeMap());
    }
    
    EGLint GetError(Thread *thread)
    {
        EGLint error = thread->getError();
        thread->setSuccess();
        return error;
    }
    
    EGLDisplay GetPlatformDisplay(Thread *thread,
                                  EGLenum platform,
                                  void *native_display,
                                  const AttributeMap &attribMap)
    {
        if (platform == EGL_PLATFORM_ANGLE_ANGLE)
        {
            return Display::GetDisplayFromNativeDisplay(
                gl::bitCast<EGLNativeDisplayType>(native_display), attribMap);
        }
        else if (platform == EGL_PLATFORM_DEVICE_EXT)
        {
            Device *eglDevice = static_cast<Device *>(native_display);
            return Display::GetDisplayFromDevice(eglDevice, attribMap);
        }
        else
        {
            UNREACHABLE();
            return EGL_NO_DISPLAY;
        }
    }
    
    __eglMustCastToProperFunctionPointerType GetProcAddress(Thread *thread, const char *procname)
    {
        const ProcEntry *entry =
            std::lower_bound(&g_procTable[0], &g_procTable[g_numProcs], procname, CompareProc);
    
        thread->setSuccess();
    
        if (entry == &g_procTable[g_numProcs] || strcmp(entry->first, procname) != 0)
        {
            return nullptr;
        }
    
        return entry->second;
    }
    
    EGLBoolean GetSyncAttrib(Thread *thread,
                             Display *display,
                             Sync *syncObject,
                             EGLint attribute,
                             EGLAttrib *value)
    {
        EGLint valueExt;
        ANGLE_EGL_TRY_RETURN(thread, GetSyncAttrib(display, syncObject, attribute, &valueExt),
                             "eglGetSyncAttrib", GetSyncIfValid(display, syncObject), EGL_FALSE);
        *value = valueExt;
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean Initialize(Thread *thread, Display *display, EGLint *major, EGLint *minor)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->initialize(), "eglInitialize", GetDisplayIfValid(display),
                             EGL_FALSE);
    
        if (major)
            *major = 1;
        if (minor)
            *minor = 5;
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean MakeCurrent(Thread *thread,
                           Display *display,
                           Surface *drawSurface,
                           Surface *readSurface,
                           gl::Context *context)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglMakeCurrent",
                             GetDisplayIfValid(display), EGL_FALSE);
        Surface *previousDraw        = thread->getCurrentDrawSurface();
        Surface *previousRead        = thread->getCurrentReadSurface();
        gl::Context *previousContext = thread->getContext();
    
        // Only call makeCurrent if the context or surfaces have changed.
        if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context)
        {
            ANGLE_EGL_TRY_RETURN(
                thread, display->makeCurrent(previousContext, drawSurface, readSurface, context),
                "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
            SetContextCurrent(thread, context);
        }
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLenum QueryAPI(Thread *thread)
    {
        EGLenum API = thread->getAPI();
    
        thread->setSuccess();
        return API;
    }
    
    EGLBoolean QueryContext(Thread *thread,
                            Display *display,
                            gl::Context *context,
                            EGLint attribute,
                            EGLint *value)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryContext",
                             GetDisplayIfValid(display), EGL_FALSE);
        QueryContextAttrib(context, attribute, value);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    const char *QueryString(Thread *thread, Display *display, EGLint name)
    {
        if (display)
        {
            ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryString",
                                 GetDisplayIfValid(display), nullptr);
        }
    
        const char *result = nullptr;
        switch (name)
        {
            case EGL_CLIENT_APIS:
                result = "OpenGL_ES";
                break;
            case EGL_EXTENSIONS:
                if (display == EGL_NO_DISPLAY)
                {
                    result = Display::GetClientExtensionString().c_str();
                }
                else
                {
                    result = display->getExtensionString().c_str();
                }
                break;
            case EGL_VENDOR:
                result = display->getVendorString().c_str();
                break;
            case EGL_VERSION:
                result = "1.5 (ANGLE " ANGLE_VERSION_STRING ")";
                break;
            default:
                UNREACHABLE();
                break;
        }
    
        thread->setSuccess();
        return result;
    }
    
    EGLBoolean QuerySurface(Thread *thread,
                            Display *display,
                            Surface *eglSurface,
                            EGLint attribute,
                            EGLint *value)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface",
                             GetDisplayIfValid(display), EGL_FALSE);
        ANGLE_EGL_TRY_RETURN(
            thread, QuerySurfaceAttrib(display, thread->getContext(), eglSurface, attribute, value),
            "eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean ReleaseTexImage(Thread *thread, Display *display, Surface *eglSurface, EGLint buffer)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglReleaseTexImage",
                             GetDisplayIfValid(display), EGL_FALSE);
        gl::Texture *texture = eglSurface->getBoundTexture();
    
        if (texture)
        {
            ANGLE_EGL_TRY_RETURN(thread, eglSurface->releaseTexImage(thread->getContext(), buffer),
                                 "eglReleaseTexImage", GetSurfaceIfValid(display, eglSurface),
                                 EGL_FALSE);
        }
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean ReleaseThread(Thread *thread)
    {
        Surface *previousDraw        = thread->getCurrentDrawSurface();
        Surface *previousRead        = thread->getCurrentReadSurface();
        gl::Context *previousContext = thread->getContext();
        Display *previousDisplay     = thread->getDisplay();
    
        if (previousDisplay != EGL_NO_DISPLAY)
        {
            ANGLE_EGL_TRY_RETURN(thread, previousDisplay->prepareForCall(), "eglReleaseThread",
                                 GetDisplayIfValid(previousDisplay), EGL_FALSE);
            // Only call makeCurrent if the context or surfaces have changed.
            if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
                previousContext != EGL_NO_CONTEXT)
            {
                ANGLE_EGL_TRY_RETURN(
                    thread, previousDisplay->makeCurrent(previousContext, nullptr, nullptr, nullptr),
                    "eglReleaseThread", nullptr, EGL_FALSE);
            }
            ANGLE_EGL_TRY_RETURN(thread, previousDisplay->releaseThread(), "eglReleaseThread",
                                 GetDisplayIfValid(previousDisplay), EGL_FALSE);
            SetContextCurrent(thread, nullptr);
        }
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean SurfaceAttrib(Thread *thread,
                             Display *display,
                             Surface *eglSurface,
                             EGLint attribute,
                             EGLint value)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSurfaceAttrib",
                             GetDisplayIfValid(display), EGL_FALSE);
        SetSurfaceAttrib(eglSurface, attribute, value);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean SwapBuffers(Thread *thread, Display *display, Surface *eglSurface)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffers",
                             GetDisplayIfValid(display), EGL_FALSE);
    
        ANGLE_EGL_TRY_RETURN(thread, eglSurface->swap(thread->getContext()), "eglSwapBuffers",
                             GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean SwapInterval(Thread *thread, Display *display, EGLint interval)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapInterval",
                             GetDisplayIfValid(display), EGL_FALSE);
    
        Surface *drawSurface        = static_cast<Surface *>(thread->getCurrentDrawSurface());
        const Config *surfaceConfig = drawSurface->getConfig();
        EGLint clampedInterval      = std::min(std::max(interval, surfaceConfig->minSwapInterval),
                                          surfaceConfig->maxSwapInterval);
    
        drawSurface->setSwapInterval(clampedInterval);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean Terminate(Thread *thread, Display *display)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglTerminate",
                             GetDisplayIfValid(display), EGL_FALSE);
        ANGLE_EGL_TRY_RETURN(thread,
                             display->makeCurrent(thread->getContext(), nullptr, nullptr, nullptr),
                             "eglTerminate", GetDisplayIfValid(display), EGL_FALSE);
        SetContextCurrent(thread, nullptr);
        ANGLE_EGL_TRY_RETURN(thread, display->terminate(thread), "eglTerminate",
                             GetDisplayIfValid(display), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean WaitClient(Thread *thread)
    {
        Display *display     = thread->getDisplay();
        gl::Context *context = thread->getContext();
    
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitClient",
                             GetDisplayIfValid(display), EGL_FALSE);
        ANGLE_EGL_TRY_RETURN(thread, display->waitClient(context), "eglWaitClient",
                             GetContextIfValid(display, context), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean WaitGL(Thread *thread)
    {
        Display *display = thread->getDisplay();
    
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitGL", GetDisplayIfValid(display),
                             EGL_FALSE);
    
        // eglWaitGL like calling eglWaitClient with the OpenGL ES API bound. Since we only implement
        // OpenGL ES we can do the call directly.
        ANGLE_EGL_TRY_RETURN(thread, display->waitClient(thread->getContext()), "eglWaitGL",
                             GetDisplayIfValid(display), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean WaitNative(Thread *thread, EGLint engine)
    {
        Display *display = thread->getDisplay();
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitNative",
                             GetDisplayIfValid(display), EGL_FALSE);
        ANGLE_EGL_TRY_RETURN(thread, display->waitNative(thread->getContext(), engine), "eglWaitNative",
                             GetThreadIfValid(thread), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    
    EGLBoolean WaitSync(Thread *thread, Display *display, Sync *syncObject, EGLint flags)
    {
        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitSync",
                             GetDisplayIfValid(display), EGL_FALSE);
        gl::Context *currentContext = thread->getContext();
        ANGLE_EGL_TRY_RETURN(thread, syncObject->serverWait(display, currentContext, flags),
                             "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
    
        thread->setSuccess();
        return EGL_TRUE;
    }
    }  // namespace egl