// GENERATED FILE - DO NOT EDIT.
// Generated by generate_entry_points.py using data from egl.xml and egl_angle_ext.xml.
//
// 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.
//
// entry_points_egl_ext_autogen.cpp:
//   Defines the EGL Extension entry points.

#include "libGLESv2/entry_points_egl_ext_autogen.h"

#include "libANGLE/capture/capture_egl_autogen.h"
#include "libANGLE/entry_points_utils.h"
#include "libANGLE/validationEGL_autogen.h"
#include "libGLESv2/egl_context_lock_impl.h"
#include "libGLESv2/egl_ext_stubs_autogen.h"
#include "libGLESv2/global_state.h"

using namespace egl;

extern "C" {

// EGL_ANDROID_blob_cache
void EGLAPIENTRY EGL_SetBlobCacheFuncsANDROID(EGLDisplay dpy,
                                              EGLSetBlobFuncANDROID set,
                                              EGLGetBlobFuncANDROID get)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(SetBlobCacheFuncsANDROID,
                  "dpy = 0x%016" PRIxPTR ", set = 0x%016" PRIxPTR ", get = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)set, (uintptr_t)get);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(SetBlobCacheFuncsANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, SetBlobCacheFuncsANDROID, GetDisplayIfValid(dpyPacked),
                                    dpyPacked, set, get);

            SetBlobCacheFuncsANDROID(thread, dpyPacked, set, get);
        }

        ANGLE_CAPTURE_EGL(SetBlobCacheFuncsANDROID, true, thread, dpyPacked, set, get);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

// EGL_ANDROID_create_native_client_buffer
EGLClientBuffer EGLAPIENTRY EGL_CreateNativeClientBufferANDROID(const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLClientBuffer returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreateNativeClientBufferANDROID, "attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)attrib_list);

        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateNativeClientBufferANDROID, thread);
            ANGLE_EGL_VALIDATE(thread, CreateNativeClientBufferANDROID, nullptr, EGLClientBuffer,
                               attrib_listPacked);

            returnValue = CreateNativeClientBufferANDROID(thread, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreateNativeClientBufferANDROID, true, thread, attrib_listPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANDROID_get_frame_timestamps
EGLBoolean EGLAPIENTRY EGL_GetCompositorTimingSupportedANDROID(EGLDisplay dpy,
                                                               EGLSurface surface,
                                                               EGLint name)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetCompositorTimingSupportedANDROID,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", name = %d", (uintptr_t)dpy,
                  (uintptr_t)surface, name);

        egl::Display *dpyPacked     = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked     = PackParam<SurfaceID>(surface);
        CompositorTiming namePacked = PackParam<CompositorTiming>(name);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetCompositorTimingSupportedANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetCompositorTimingSupportedANDROID,
                               GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, surfacePacked,
                               namePacked);

            returnValue =
                GetCompositorTimingSupportedANDROID(thread, dpyPacked, surfacePacked, namePacked);
        }

        ANGLE_CAPTURE_EGL(GetCompositorTimingSupportedANDROID, true, thread, dpyPacked,
                          surfacePacked, namePacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_GetCompositorTimingANDROID(EGLDisplay dpy,
                                                      EGLSurface surface,
                                                      EGLint numTimestamps,
                                                      const EGLint *names,
                                                      EGLnsecsANDROID *values)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetCompositorTimingANDROID,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
                  ", numTimestamps = %d, names = 0x%016" PRIxPTR ", values = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, numTimestamps, (uintptr_t)names,
                  (uintptr_t)values);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetCompositorTimingANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetCompositorTimingANDROID, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, numTimestamps, names, values);

            returnValue = GetCompositorTimingANDROID(thread, dpyPacked, surfacePacked,
                                                     numTimestamps, names, values);
        }

        ANGLE_CAPTURE_EGL(GetCompositorTimingANDROID, true, thread, dpyPacked, surfacePacked,
                          numTimestamps, names, values, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_GetNextFrameIdANDROID(EGLDisplay dpy,
                                                 EGLSurface surface,
                                                 EGLuint64KHR *frameId)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetNextFrameIdANDROID,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", frameId = 0x%016" PRIxPTR
                  "",
                  (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)frameId);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetNextFrameIdANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetNextFrameIdANDROID, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, frameId);

            returnValue = GetNextFrameIdANDROID(thread, dpyPacked, surfacePacked, frameId);
        }

        ANGLE_CAPTURE_EGL(GetNextFrameIdANDROID, true, thread, dpyPacked, surfacePacked, frameId,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_GetFrameTimestampSupportedANDROID(EGLDisplay dpy,
                                                             EGLSurface surface,
                                                             EGLint timestamp)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetFrameTimestampSupportedANDROID,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", timestamp = %d",
                  (uintptr_t)dpy, (uintptr_t)surface, timestamp);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked   = PackParam<SurfaceID>(surface);
        Timestamp timestampPacked = PackParam<Timestamp>(timestamp);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetFrameTimestampSupportedANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetFrameTimestampSupportedANDROID,
                               GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, surfacePacked,
                               timestampPacked);

            returnValue = GetFrameTimestampSupportedANDROID(thread, dpyPacked, surfacePacked,
                                                            timestampPacked);
        }

        ANGLE_CAPTURE_EGL(GetFrameTimestampSupportedANDROID, true, thread, dpyPacked, surfacePacked,
                          timestampPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_GetFrameTimestampsANDROID(EGLDisplay dpy,
                                                     EGLSurface surface,
                                                     EGLuint64KHR frameId,
                                                     EGLint numTimestamps,
                                                     const EGLint *timestamps,
                                                     EGLnsecsANDROID *values)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetFrameTimestampsANDROID,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
                  ", frameId = %llu, numTimestamps = %d, timestamps = 0x%016" PRIxPTR
                  ", values = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, static_cast<unsigned long long>(frameId),
                  numTimestamps, (uintptr_t)timestamps, (uintptr_t)values);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetFrameTimestampsANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetFrameTimestampsANDROID, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, frameId, numTimestamps,
                               timestamps, values);

            returnValue = GetFrameTimestampsANDROID(thread, dpyPacked, surfacePacked, frameId,
                                                    numTimestamps, timestamps, values);
        }

        ANGLE_CAPTURE_EGL(GetFrameTimestampsANDROID, true, thread, dpyPacked, surfacePacked,
                          frameId, numTimestamps, timestamps, values, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANDROID_get_native_client_buffer
EGLClientBuffer EGLAPIENTRY EGL_GetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer)
{

    Thread *thread = egl::GetCurrentThread();
    EGLClientBuffer returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetNativeClientBufferANDROID, "buffer = 0x%016" PRIxPTR "", (uintptr_t)buffer);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetNativeClientBufferANDROID, thread);
            ANGLE_EGL_VALIDATE(thread, GetNativeClientBufferANDROID, nullptr, EGLClientBuffer,
                               buffer);

            returnValue = GetNativeClientBufferANDROID(thread, buffer);
        }

        ANGLE_CAPTURE_EGL(GetNativeClientBufferANDROID, true, thread, buffer, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANDROID_native_fence_sync
EGLint EGLAPIENTRY EGL_DupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(DupNativeFenceFDANDROID, "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)sync);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(DupNativeFenceFDANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, DupNativeFenceFDANDROID, GetDisplayIfValid(dpyPacked),
                               EGLint, dpyPacked, syncPacked);

            returnValue = DupNativeFenceFDANDROID(thread, dpyPacked, syncPacked);
        }

        ANGLE_CAPTURE_EGL(DupNativeFenceFDANDROID, true, thread, dpyPacked, syncPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANDROID_presentation_time
EGLBoolean EGLAPIENTRY EGL_PresentationTimeANDROID(EGLDisplay dpy,
                                                   EGLSurface surface,
                                                   EGLnsecsANDROID time)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(PresentationTimeANDROID,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", time = %llu",
                  (uintptr_t)dpy, (uintptr_t)surface, static_cast<unsigned long long>(time));

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(PresentationTimeANDROID, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, PresentationTimeANDROID, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, time);

            returnValue = PresentationTimeANDROID(thread, dpyPacked, surfacePacked, time);
        }

        ANGLE_CAPTURE_EGL(PresentationTimeANDROID, true, thread, dpyPacked, surfacePacked, time,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_device_creation
EGLDeviceEXT EGLAPIENTRY EGL_CreateDeviceANGLE(EGLint device_type,
                                               void *native_device,
                                               const EGLAttrib *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLDeviceEXT returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreateDeviceANGLE,
                  "device_type = %d, native_device = 0x%016" PRIxPTR
                  ", attrib_list = 0x%016" PRIxPTR "",
                  device_type, (uintptr_t)native_device, (uintptr_t)attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateDeviceANGLE, thread);
            ANGLE_EGL_VALIDATE(thread, CreateDeviceANGLE, nullptr, EGLDeviceEXT, device_type,
                               native_device, attrib_list);

            returnValue = CreateDeviceANGLE(thread, device_type, native_device, attrib_list);
        }

        ANGLE_CAPTURE_EGL(CreateDeviceANGLE, true, thread, device_type, native_device, attrib_list,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_ReleaseDeviceANGLE(EGLDeviceEXT device)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ReleaseDeviceANGLE, "device = 0x%016" PRIxPTR "", (uintptr_t)device);

        egl::Device *devicePacked = PackParam<egl::Device *>(device);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ReleaseDeviceANGLE, thread);
            ANGLE_EGL_VALIDATE(thread, ReleaseDeviceANGLE, nullptr, EGLBoolean, devicePacked);

            returnValue = ReleaseDeviceANGLE(thread, devicePacked);
        }

        ANGLE_CAPTURE_EGL(ReleaseDeviceANGLE, true, thread, devicePacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_feature_control
const char *EGLAPIENTRY EGL_QueryStringiANGLE(EGLDisplay dpy, EGLint name, EGLint index)
{

    Thread *thread = egl::GetCurrentThread();
    const char *returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryStringiANGLE, "dpy = 0x%016" PRIxPTR ", name = %d, index = %d",
                  (uintptr_t)dpy, name, index);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryStringiANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, QueryStringiANGLE, GetDisplayIfValid(dpyPacked),
                               const char *, dpyPacked, name, index);

            returnValue = QueryStringiANGLE(thread, dpyPacked, name, index);
        }

        ANGLE_CAPTURE_EGL(QueryStringiANGLE, true, thread, dpyPacked, name, index, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QueryDisplayAttribANGLE(EGLDisplay dpy,
                                                   EGLint attribute,
                                                   EGLAttrib *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDisplayAttribANGLE,
                  "dpy = 0x%016" PRIxPTR ", attribute = %d, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, attribute, (uintptr_t)value);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDisplayAttribANGLE, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, QueryDisplayAttribANGLE, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, attribute, value);

            returnValue = QueryDisplayAttribANGLE(thread, dpyPacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QueryDisplayAttribANGLE, true, thread, dpyPacked, attribute, value,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_metal_shared_event_sync
void *EGLAPIENTRY EGL_CopyMetalSharedEventANGLE(EGLDisplay dpy, EGLSyncKHR sync)
{

    Thread *thread = egl::GetCurrentThread();
    void *returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CopyMetalSharedEventANGLE, "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)sync);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CopyMetalSharedEventANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, CopyMetalSharedEventANGLE, GetDisplayIfValid(dpyPacked),
                               void *, dpyPacked, syncPacked);

            returnValue = CopyMetalSharedEventANGLE(thread, dpyPacked, syncPacked);
        }

        ANGLE_CAPTURE_EGL(CopyMetalSharedEventANGLE, true, thread, dpyPacked, syncPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_power_preference
void EGLAPIENTRY EGL_ReleaseHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ReleaseHighPowerGPUANGLE, "dpy = 0x%016" PRIxPTR ", ctx = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)ctx);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ReleaseHighPowerGPUANGLE, thread, dpyPacked, ctxPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, ReleaseHighPowerGPUANGLE, GetDisplayIfValid(dpyPacked),
                                    dpyPacked, ctxPacked);

            ReleaseHighPowerGPUANGLE(thread, dpyPacked, ctxPacked);
        }

        ANGLE_CAPTURE_EGL(ReleaseHighPowerGPUANGLE, true, thread, dpyPacked, ctxPacked);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

void EGLAPIENTRY EGL_ReacquireHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ReacquireHighPowerGPUANGLE, "dpy = 0x%016" PRIxPTR ", ctx = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)ctx);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ReacquireHighPowerGPUANGLE, thread, dpyPacked, ctxPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, ReacquireHighPowerGPUANGLE,
                                    GetDisplayIfValid(dpyPacked), dpyPacked, ctxPacked);

            ReacquireHighPowerGPUANGLE(thread, dpyPacked, ctxPacked);
        }

        ANGLE_CAPTURE_EGL(ReacquireHighPowerGPUANGLE, true, thread, dpyPacked, ctxPacked);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

void EGLAPIENTRY EGL_HandleGPUSwitchANGLE(EGLDisplay dpy)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(HandleGPUSwitchANGLE, "dpy = 0x%016" PRIxPTR "", (uintptr_t)dpy);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(HandleGPUSwitchANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, HandleGPUSwitchANGLE, GetDisplayIfValid(dpyPacked),
                                    dpyPacked);

            HandleGPUSwitchANGLE(thread, dpyPacked);
        }

        ANGLE_CAPTURE_EGL(HandleGPUSwitchANGLE, true, thread, dpyPacked);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

void EGLAPIENTRY EGL_ForceGPUSwitchANGLE(EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ForceGPUSwitchANGLE, "dpy = 0x%016" PRIxPTR ", gpuIDHigh = %d, gpuIDLow = %d",
                  (uintptr_t)dpy, gpuIDHigh, gpuIDLow);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ForceGPUSwitchANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, ForceGPUSwitchANGLE, GetDisplayIfValid(dpyPacked),
                                    dpyPacked, gpuIDHigh, gpuIDLow);

            ForceGPUSwitchANGLE(thread, dpyPacked, gpuIDHigh, gpuIDLow);
        }

        ANGLE_CAPTURE_EGL(ForceGPUSwitchANGLE, true, thread, dpyPacked, gpuIDHigh, gpuIDLow);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

// EGL_ANGLE_prepare_swap_buffers
EGLBoolean EGLAPIENTRY EGL_PrepareSwapBuffersANGLE(EGLDisplay dpy, EGLSurface surface)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(PrepareSwapBuffersANGLE, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(PrepareSwapBuffersANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, PrepareSwapBuffersANGLE, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked);

            returnValue = PrepareSwapBuffersANGLE(thread, dpyPacked, surfacePacked);
        }

        ANGLE_CAPTURE_EGL(PrepareSwapBuffersANGLE, true, thread, dpyPacked, surfacePacked,
                          returnValue);
    }
    egl::Display::GetCurrentThreadUnlockedTailCall()->run();
    return returnValue;
}

// EGL_ANGLE_program_cache_control
EGLint EGLAPIENTRY EGL_ProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ProgramCacheGetAttribANGLE, "dpy = 0x%016" PRIxPTR ", attrib = 0x%X",
                  (uintptr_t)dpy, attrib);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ProgramCacheGetAttribANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, ProgramCacheGetAttribANGLE, GetDisplayIfValid(dpyPacked),
                               EGLint, dpyPacked, attrib);

            returnValue = ProgramCacheGetAttribANGLE(thread, dpyPacked, attrib);
        }

        ANGLE_CAPTURE_EGL(ProgramCacheGetAttribANGLE, true, thread, dpyPacked, attrib, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

void EGLAPIENTRY EGL_ProgramCacheQueryANGLE(EGLDisplay dpy,
                                            EGLint index,
                                            void *key,
                                            EGLint *keysize,
                                            void *binary,
                                            EGLint *binarysize)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ProgramCacheQueryANGLE,
                  "dpy = 0x%016" PRIxPTR ", index = %d, key = 0x%016" PRIxPTR
                  ", keysize = 0x%016" PRIxPTR ", binary = 0x%016" PRIxPTR
                  ", binarysize = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, index, (uintptr_t)key, (uintptr_t)keysize, (uintptr_t)binary,
                  (uintptr_t)binarysize);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ProgramCacheQueryANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, ProgramCacheQueryANGLE, GetDisplayIfValid(dpyPacked),
                                    dpyPacked, index, key, keysize, binary, binarysize);

            ProgramCacheQueryANGLE(thread, dpyPacked, index, key, keysize, binary, binarysize);
        }

        ANGLE_CAPTURE_EGL(ProgramCacheQueryANGLE, true, thread, dpyPacked, index, key, keysize,
                          binary, binarysize);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

void EGLAPIENTRY EGL_ProgramCachePopulateANGLE(EGLDisplay dpy,
                                               const void *key,
                                               EGLint keysize,
                                               const void *binary,
                                               EGLint binarysize)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ProgramCachePopulateANGLE,
                  "dpy = 0x%016" PRIxPTR ", key = 0x%016" PRIxPTR
                  ", keysize = %d, binary = 0x%016" PRIxPTR ", binarysize = %d",
                  (uintptr_t)dpy, (uintptr_t)key, keysize, (uintptr_t)binary, binarysize);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ProgramCachePopulateANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, ProgramCachePopulateANGLE, GetDisplayIfValid(dpyPacked),
                                    dpyPacked, key, keysize, binary, binarysize);

            ProgramCachePopulateANGLE(thread, dpyPacked, key, keysize, binary, binarysize);
        }

        ANGLE_CAPTURE_EGL(ProgramCachePopulateANGLE, true, thread, dpyPacked, key, keysize, binary,
                          binarysize);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

EGLint EGLAPIENTRY EGL_ProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLint mode)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ProgramCacheResizeANGLE, "dpy = 0x%016" PRIxPTR ", limit = %d, mode = %d",
                  (uintptr_t)dpy, limit, mode);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ProgramCacheResizeANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, ProgramCacheResizeANGLE, GetDisplayIfValid(dpyPacked),
                               EGLint, dpyPacked, limit, mode);

            returnValue = ProgramCacheResizeANGLE(thread, dpyPacked, limit, mode);
        }

        ANGLE_CAPTURE_EGL(ProgramCacheResizeANGLE, true, thread, dpyPacked, limit, mode,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_query_surface_pointer
EGLBoolean EGLAPIENTRY EGL_QuerySurfacePointerANGLE(EGLDisplay dpy,
                                                    EGLSurface surface,
                                                    EGLint attribute,
                                                    void **value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QuerySurfacePointerANGLE,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
                  ", attribute = %d, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, attribute, (uintptr_t)value);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QuerySurfacePointerANGLE, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, QuerySurfacePointerANGLE, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, attribute, value);

            returnValue =
                QuerySurfacePointerANGLE(thread, dpyPacked, surfacePacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QuerySurfacePointerANGLE, true, thread, dpyPacked, surfacePacked,
                          attribute, value, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_stream_producer_d3d_texture
EGLBoolean EGLAPIENTRY EGL_CreateStreamProducerD3DTextureANGLE(EGLDisplay dpy,
                                                               EGLStreamKHR stream,
                                                               const EGLAttrib *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreateStreamProducerD3DTextureANGLE,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR
                  ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream, (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked             = PackParam<egl::Stream *>(stream);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateStreamProducerD3DTextureANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, CreateStreamProducerD3DTextureANGLE,
                               GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, streamPacked,
                               attrib_listPacked);

            returnValue = CreateStreamProducerD3DTextureANGLE(thread, dpyPacked, streamPacked,
                                                              attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreateStreamProducerD3DTextureANGLE, true, thread, dpyPacked,
                          streamPacked, attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_StreamPostD3DTextureANGLE(EGLDisplay dpy,
                                                     EGLStreamKHR stream,
                                                     void *texture,
                                                     const EGLAttrib *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(StreamPostD3DTextureANGLE,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR ", texture = 0x%016" PRIxPTR
                  ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream, (uintptr_t)texture, (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked             = PackParam<egl::Stream *>(stream);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(StreamPostD3DTextureANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, StreamPostD3DTextureANGLE, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, streamPacked, texture, attrib_listPacked);

            returnValue = StreamPostD3DTextureANGLE(thread, dpyPacked, streamPacked, texture,
                                                    attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(StreamPostD3DTextureANGLE, true, thread, dpyPacked, streamPacked, texture,
                          attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_swap_with_frame_token
EGLBoolean EGLAPIENTRY EGL_SwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
                                                          EGLSurface surface,
                                                          EGLFrameTokenANGLE frametoken)
{
    ANGLE_EGLBOOLEAN_TRY(EGL_PrepareSwapBuffersANGLE(dpy, surface));
    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(SwapBuffersWithFrameTokenANGLE,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", frametoken = 0x%llX",
                  (uintptr_t)dpy, (uintptr_t)surface, static_cast<unsigned long long>(frametoken));

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(SwapBuffersWithFrameTokenANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, SwapBuffersWithFrameTokenANGLE, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, frametoken);

            returnValue =
                SwapBuffersWithFrameTokenANGLE(thread, dpyPacked, surfacePacked, frametoken);
        }

        ANGLE_CAPTURE_EGL(SwapBuffersWithFrameTokenANGLE, true, thread, dpyPacked, surfacePacked,
                          frametoken, returnValue);
    }
    egl::Display::GetCurrentThreadUnlockedTailCall()->run();
    return returnValue;
}

// EGL_ANGLE_sync_control_rate
EGLBoolean EGLAPIENTRY EGL_GetMscRateANGLE(EGLDisplay dpy,
                                           EGLSurface surface,
                                           EGLint *numerator,
                                           EGLint *denominator)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetMscRateANGLE,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", numerator = 0x%016" PRIxPTR
                  ", denominator = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)numerator, (uintptr_t)denominator);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetMscRateANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetMscRateANGLE, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, surfacePacked, numerator, denominator);

            returnValue = GetMscRateANGLE(thread, dpyPacked, surfacePacked, numerator, denominator);
        }

        ANGLE_CAPTURE_EGL(GetMscRateANGLE, true, thread, dpyPacked, surfacePacked, numerator,
                          denominator, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_vulkan_image
EGLBoolean EGLAPIENTRY EGL_ExportVkImageANGLE(EGLDisplay dpy,
                                              EGLImage image,
                                              void *vk_image,
                                              void *vk_image_create_info)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ExportVkImageANGLE,
                  "dpy = 0x%016" PRIxPTR ", image = 0x%016" PRIxPTR ", vk_image = 0x%016" PRIxPTR
                  ", vk_image_create_info = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)image, (uintptr_t)vk_image,
                  (uintptr_t)vk_image_create_info);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        ImageID imagePacked     = PackParam<ImageID>(image);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ExportVkImageANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, ExportVkImageANGLE, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, imagePacked, vk_image, vk_image_create_info);

            returnValue =
                ExportVkImageANGLE(thread, dpyPacked, imagePacked, vk_image, vk_image_create_info);
        }

        ANGLE_CAPTURE_EGL(ExportVkImageANGLE, true, thread, dpyPacked, imagePacked, vk_image,
                          vk_image_create_info, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_ANGLE_wait_until_work_scheduled
void EGLAPIENTRY EGL_WaitUntilWorkScheduledANGLE(EGLDisplay dpy)
{

    Thread *thread = egl::GetCurrentThread();
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(WaitUntilWorkScheduledANGLE, "dpy = 0x%016" PRIxPTR "", (uintptr_t)dpy);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(WaitUntilWorkScheduledANGLE, thread, dpyPacked);
            ANGLE_EGL_VALIDATE_VOID(thread, WaitUntilWorkScheduledANGLE,
                                    GetDisplayIfValid(dpyPacked), dpyPacked);

            WaitUntilWorkScheduledANGLE(thread, dpyPacked);
        }

        ANGLE_CAPTURE_EGL(WaitUntilWorkScheduledANGLE, true, thread, dpyPacked);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
}

// EGL_CHROMIUM_sync_control
EGLBoolean EGLAPIENTRY EGL_GetSyncValuesCHROMIUM(EGLDisplay dpy,
                                                 EGLSurface surface,
                                                 EGLuint64KHR *ust,
                                                 EGLuint64KHR *msc,
                                                 EGLuint64KHR *sbc)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetSyncValuesCHROMIUM,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", ust = 0x%016" PRIxPTR
                  ", msc = 0x%016" PRIxPTR ", sbc = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)ust, (uintptr_t)msc,
                  (uintptr_t)sbc);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetSyncValuesCHROMIUM, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, GetSyncValuesCHROMIUM, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, ust, msc, sbc);

            returnValue = GetSyncValuesCHROMIUM(thread, dpyPacked, surfacePacked, ust, msc, sbc);
        }

        ANGLE_CAPTURE_EGL(GetSyncValuesCHROMIUM, true, thread, dpyPacked, surfacePacked, ust, msc,
                          sbc, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_EXT_device_query
EGLBoolean EGLAPIENTRY EGL_QueryDeviceAttribEXT(EGLDeviceEXT device,
                                                EGLint attribute,
                                                EGLAttrib *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDeviceAttribEXT,
                  "device = 0x%016" PRIxPTR ", attribute = %d, value = 0x%016" PRIxPTR "",
                  (uintptr_t)device, attribute, (uintptr_t)value);

        egl::Device *devicePacked = PackParam<egl::Device *>(device);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDeviceAttribEXT, thread, attribute);
            ANGLE_EGL_VALIDATE(thread, QueryDeviceAttribEXT, nullptr, EGLBoolean, devicePacked,
                               attribute, value);

            returnValue = QueryDeviceAttribEXT(thread, devicePacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QueryDeviceAttribEXT, true, thread, devicePacked, attribute, value,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

const char *EGLAPIENTRY EGL_QueryDeviceStringEXT(EGLDeviceEXT device, EGLint name)
{

    Thread *thread = egl::GetCurrentThread();
    const char *returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDeviceStringEXT, "device = 0x%016" PRIxPTR ", name = %d", (uintptr_t)device,
                  name);

        egl::Device *devicePacked = PackParam<egl::Device *>(device);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDeviceStringEXT, thread);
            ANGLE_EGL_VALIDATE(thread, QueryDeviceStringEXT, nullptr, const char *, devicePacked,
                               name);

            returnValue = QueryDeviceStringEXT(thread, devicePacked, name);
        }

        ANGLE_CAPTURE_EGL(QueryDeviceStringEXT, true, thread, devicePacked, name, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDisplayAttribEXT,
                  "dpy = 0x%016" PRIxPTR ", attribute = %d, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, attribute, (uintptr_t)value);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDisplayAttribEXT, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, QueryDisplayAttribEXT, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, attribute, value);

            returnValue = QueryDisplayAttribEXT(thread, dpyPacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QueryDisplayAttribEXT, true, thread, dpyPacked, attribute, value,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_EXT_image_dma_buf_import_modifiers
EGLBoolean EGLAPIENTRY EGL_QueryDmaBufFormatsEXT(EGLDisplay dpy,
                                                 EGLint max_formats,
                                                 EGLint *formats,
                                                 EGLint *num_formats)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDmaBufFormatsEXT,
                  "dpy = 0x%016" PRIxPTR ", max_formats = %d, formats = 0x%016" PRIxPTR
                  ", num_formats = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, max_formats, (uintptr_t)formats, (uintptr_t)num_formats);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDmaBufFormatsEXT, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, QueryDmaBufFormatsEXT, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, max_formats, formats, num_formats);

            returnValue =
                QueryDmaBufFormatsEXT(thread, dpyPacked, max_formats, formats, num_formats);
        }

        ANGLE_CAPTURE_EGL(QueryDmaBufFormatsEXT, true, thread, dpyPacked, max_formats, formats,
                          num_formats, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QueryDmaBufModifiersEXT(EGLDisplay dpy,
                                                   EGLint format,
                                                   EGLint max_modifiers,
                                                   EGLuint64KHR *modifiers,
                                                   EGLBoolean *external_only,
                                                   EGLint *num_modifiers)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDmaBufModifiersEXT,
                  "dpy = 0x%016" PRIxPTR
                  ", format = %d, max_modifiers = %d, modifiers = 0x%016" PRIxPTR
                  ", external_only = 0x%016" PRIxPTR ", num_modifiers = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, format, max_modifiers, (uintptr_t)modifiers,
                  (uintptr_t)external_only, (uintptr_t)num_modifiers);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDmaBufModifiersEXT, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, QueryDmaBufModifiersEXT, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, format, max_modifiers, modifiers,
                               external_only, num_modifiers);

            returnValue = QueryDmaBufModifiersEXT(thread, dpyPacked, format, max_modifiers,
                                                  modifiers, external_only, num_modifiers);
        }

        ANGLE_CAPTURE_EGL(QueryDmaBufModifiersEXT, true, thread, dpyPacked, format, max_modifiers,
                          modifiers, external_only, num_modifiers, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_EXT_platform_base
EGLSurface EGLAPIENTRY EGL_CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy,
                                                          EGLConfig config,
                                                          void *native_pixmap,
                                                          const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLSurface returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreatePlatformPixmapSurfaceEXT,
                  "dpy = 0x%016" PRIxPTR ", config = 0x%016" PRIxPTR
                  ", native_pixmap = 0x%016" PRIxPTR ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)native_pixmap,
                  (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        egl::Config *configPacked             = PackParam<egl::Config *>(config);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePlatformPixmapSurfaceEXT, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, CreatePlatformPixmapSurfaceEXT, GetDisplayIfValid(dpyPacked),
                               EGLSurface, dpyPacked, configPacked, native_pixmap,
                               attrib_listPacked);

            returnValue = CreatePlatformPixmapSurfaceEXT(thread, dpyPacked, configPacked,
                                                         native_pixmap, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreatePlatformPixmapSurfaceEXT, true, thread, dpyPacked, configPacked,
                          native_pixmap, attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLSurface EGLAPIENTRY EGL_CreatePlatformWindowSurfaceEXT(EGLDisplay dpy,
                                                          EGLConfig config,
                                                          void *native_window,
                                                          const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLSurface returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreatePlatformWindowSurfaceEXT,
                  "dpy = 0x%016" PRIxPTR ", config = 0x%016" PRIxPTR
                  ", native_window = 0x%016" PRIxPTR ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)native_window,
                  (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        egl::Config *configPacked             = PackParam<egl::Config *>(config);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePlatformWindowSurfaceEXT, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, CreatePlatformWindowSurfaceEXT, GetDisplayIfValid(dpyPacked),
                               EGLSurface, dpyPacked, configPacked, native_window,
                               attrib_listPacked);

            returnValue = CreatePlatformWindowSurfaceEXT(thread, dpyPacked, configPacked,
                                                         native_window, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreatePlatformWindowSurfaceEXT, true, thread, dpyPacked, configPacked,
                          native_window, attrib_listPacked, returnValue);
    }
    egl::Display::GetCurrentThreadUnlockedTailCall()->run();
    return returnValue;
}

EGLDisplay EGLAPIENTRY EGL_GetPlatformDisplayEXT(EGLenum platform,
                                                 void *native_display,
                                                 const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLDisplay returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetPlatformDisplayEXT,
                  "platform = 0x%X, native_display = 0x%016" PRIxPTR
                  ", attrib_list = 0x%016" PRIxPTR "",
                  platform, (uintptr_t)native_display, (uintptr_t)attrib_list);

        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetPlatformDisplayEXT, thread);
            ANGLE_EGL_VALIDATE(thread, GetPlatformDisplayEXT, nullptr, EGLDisplay, platform,
                               native_display, attrib_listPacked);

            returnValue =
                GetPlatformDisplayEXT(thread, platform, native_display, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(GetPlatformDisplayEXT, true, thread, platform, native_display,
                          attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_debug
EGLint EGLAPIENTRY EGL_DebugMessageControlKHR(EGLDEBUGPROCKHR callback,
                                              const EGLAttrib *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(DebugMessageControlKHR,
                  "callback = 0x%016" PRIxPTR ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)callback, (uintptr_t)attrib_list);

        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(DebugMessageControlKHR, thread);
            ANGLE_EGL_VALIDATE(thread, DebugMessageControlKHR, nullptr, EGLint, callback,
                               attrib_listPacked);

            returnValue = DebugMessageControlKHR(thread, callback, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(DebugMessageControlKHR, true, thread, callback, attrib_listPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLint EGLAPIENTRY EGL_LabelObjectKHR(EGLDisplay display,
                                      EGLenum objectType,
                                      EGLObjectKHR object,
                                      EGLLabelKHR label)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(LabelObjectKHR,
                  "display = 0x%016" PRIxPTR ", objectType = 0x%X, object = 0x%016" PRIxPTR
                  ", label = 0x%016" PRIxPTR "",
                  (uintptr_t)display, objectType, (uintptr_t)object, (uintptr_t)label);

        egl::Display *displayPacked = PackParam<egl::Display *>(display);
        ObjectType objectTypePacked = PackParam<ObjectType>(objectType);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(LabelObjectKHR, thread, displayPacked);
            ANGLE_EGL_VALIDATE(thread, LabelObjectKHR, GetDisplayIfValid(displayPacked), EGLint,
                               displayPacked, objectTypePacked, object, label);

            returnValue = LabelObjectKHR(thread, displayPacked, objectTypePacked, object, label);
        }

        ANGLE_CAPTURE_EGL(LabelObjectKHR, true, thread, displayPacked, objectTypePacked, object,
                          label, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QueryDebugKHR(EGLint attribute, EGLAttrib *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryDebugKHR, "attribute = %d, value = 0x%016" PRIxPTR "", attribute,
                  (uintptr_t)value);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryDebugKHR, thread, attribute);
            ANGLE_EGL_VALIDATE(thread, QueryDebugKHR, nullptr, EGLBoolean, attribute, value);

            returnValue = QueryDebugKHR(thread, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QueryDebugKHR, true, thread, attribute, value, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_fence_sync
EGLint EGLAPIENTRY EGL_ClientWaitSyncKHR(EGLDisplay dpy,
                                         EGLSyncKHR sync,
                                         EGLint flags,
                                         EGLTimeKHR timeout)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(ClientWaitSyncKHR,
                  "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR ", flags = %d, timeout = %llu",
                  (uintptr_t)dpy, (uintptr_t)sync, flags, static_cast<unsigned long long>(timeout));

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(ClientWaitSyncKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, ClientWaitSyncKHR, GetDisplayIfValid(dpyPacked), EGLint,
                               dpyPacked, syncPacked, flags, timeout);

            returnValue = ClientWaitSyncKHR(thread, dpyPacked, syncPacked, flags, timeout);
        }

        ANGLE_CAPTURE_EGL(ClientWaitSyncKHR, true, thread, dpyPacked, syncPacked, flags, timeout,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLSyncKHR EGLAPIENTRY EGL_CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLSyncKHR returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreateSyncKHR,
                  "dpy = 0x%016" PRIxPTR ", type = 0x%X, attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, type, (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateSyncKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, CreateSyncKHR, GetDisplayIfValid(dpyPacked), EGLSyncKHR,
                               dpyPacked, type, attrib_listPacked);

            returnValue = CreateSyncKHR(thread, dpyPacked, type, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreateSyncKHR, true, thread, dpyPacked, type, attrib_listPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_DestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(DestroySyncKHR, "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)sync);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroySyncKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, DestroySyncKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, syncPacked);

            returnValue = DestroySyncKHR(thread, dpyPacked, syncPacked);
        }

        ANGLE_CAPTURE_EGL(DestroySyncKHR, true, thread, dpyPacked, syncPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_GetSyncAttribKHR(EGLDisplay dpy,
                                            EGLSyncKHR sync,
                                            EGLint attribute,
                                            EGLint *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(GetSyncAttribKHR,
                  "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR
                  ", attribute = %d, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)sync, attribute, (uintptr_t)value);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetSyncAttribKHR, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, GetSyncAttribKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, syncPacked, attribute, value);

            returnValue = GetSyncAttribKHR(thread, dpyPacked, syncPacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(GetSyncAttribKHR, true, thread, dpyPacked, syncPacked, attribute, value,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_image
EGLImageKHR EGLAPIENTRY EGL_CreateImageKHR(EGLDisplay dpy,
                                           EGLContext ctx,
                                           EGLenum target,
                                           EGLClientBuffer buffer,
                                           const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLImageKHR returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreateImageKHR,
                  "dpy = 0x%016" PRIxPTR ", ctx = 0x%016" PRIxPTR
                  ", target = 0x%X, buffer = 0x%016" PRIxPTR ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)ctx, target, (uintptr_t)buffer,
                  (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        gl::ContextID ctxPacked               = PackParam<gl::ContextID>(ctx);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateImageKHR, thread, dpyPacked, ctxPacked);
            ANGLE_EGL_VALIDATE(thread, CreateImageKHR, GetDisplayIfValid(dpyPacked), EGLImageKHR,
                               dpyPacked, ctxPacked, target, buffer, attrib_listPacked);

            returnValue =
                CreateImageKHR(thread, dpyPacked, ctxPacked, target, buffer, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreateImageKHR, true, thread, dpyPacked, ctxPacked, target, buffer,
                          attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(DestroyImageKHR, "dpy = 0x%016" PRIxPTR ", image = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)image);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        ImageID imagePacked     = PackParam<ImageID>(image);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroyImageKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, DestroyImageKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, imagePacked);

            returnValue = DestroyImageKHR(thread, dpyPacked, imagePacked);
        }

        ANGLE_CAPTURE_EGL(DestroyImageKHR, true, thread, dpyPacked, imagePacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_lock_surface3
EGLBoolean EGLAPIENTRY EGL_LockSurfaceKHR(EGLDisplay dpy,
                                          EGLSurface surface,
                                          const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(LockSurfaceKHR,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
                  ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked               = PackParam<SurfaceID>(surface);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(LockSurfaceKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, LockSurfaceKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, surfacePacked, attrib_listPacked);

            returnValue = LockSurfaceKHR(thread, dpyPacked, surfacePacked, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(LockSurfaceKHR, true, thread, dpyPacked, surfacePacked, attrib_listPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QuerySurface64KHR(EGLDisplay dpy,
                                             EGLSurface surface,
                                             EGLint attribute,
                                             EGLAttribKHR *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QuerySurface64KHR,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
                  ", attribute = %d, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface, attribute, (uintptr_t)value);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QuerySurface64KHR, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, QuerySurface64KHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, surfacePacked, attribute, value);

            returnValue = QuerySurface64KHR(thread, dpyPacked, surfacePacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QuerySurface64KHR, true, thread, dpyPacked, surfacePacked, attribute,
                          value, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_UnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(UnlockSurfaceKHR, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)surface);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(UnlockSurfaceKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, UnlockSurfaceKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, surfacePacked);

            returnValue = UnlockSurfaceKHR(thread, dpyPacked, surfacePacked);
        }

        ANGLE_CAPTURE_EGL(UnlockSurfaceKHR, true, thread, dpyPacked, surfacePacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_partial_update
EGLBoolean EGLAPIENTRY EGL_SetDamageRegionKHR(EGLDisplay dpy,
                                              EGLSurface surface,
                                              EGLint *rects,
                                              EGLint n_rects)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(SetDamageRegionKHR,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", rects = 0x%016" PRIxPTR
                  ", n_rects = %d",
                  (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)rects, n_rects);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(SetDamageRegionKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, SetDamageRegionKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, surfacePacked, rects, n_rects);

            returnValue = SetDamageRegionKHR(thread, dpyPacked, surfacePacked, rects, n_rects);
        }

        ANGLE_CAPTURE_EGL(SetDamageRegionKHR, true, thread, dpyPacked, surfacePacked, rects,
                          n_rects, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_reusable_sync
EGLBoolean EGLAPIENTRY EGL_SignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(SignalSyncKHR, "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR ", mode = 0x%X",
                  (uintptr_t)dpy, (uintptr_t)sync, mode);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(SignalSyncKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, SignalSyncKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, syncPacked, mode);

            returnValue = SignalSyncKHR(thread, dpyPacked, syncPacked, mode);
        }

        ANGLE_CAPTURE_EGL(SignalSyncKHR, true, thread, dpyPacked, syncPacked, mode, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// ClientWaitSyncKHR is already defined.

// CreateSyncKHR is already defined.

// DestroySyncKHR is already defined.

// GetSyncAttribKHR is already defined.

// EGL_KHR_stream
EGLStreamKHR EGLAPIENTRY EGL_CreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLStreamKHR returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(CreateStreamKHR, "dpy = 0x%016" PRIxPTR ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateStreamKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, CreateStreamKHR, GetDisplayIfValid(dpyPacked), EGLStreamKHR,
                               dpyPacked, attrib_listPacked);

            returnValue = CreateStreamKHR(thread, dpyPacked, attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(CreateStreamKHR, true, thread, dpyPacked, attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_DestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(DestroyStreamKHR, "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroyStreamKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, DestroyStreamKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, streamPacked);

            returnValue = DestroyStreamKHR(thread, dpyPacked, streamPacked);
        }

        ANGLE_CAPTURE_EGL(DestroyStreamKHR, true, thread, dpyPacked, streamPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QueryStreamKHR(EGLDisplay dpy,
                                          EGLStreamKHR stream,
                                          EGLenum attribute,
                                          EGLint *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryStreamKHR,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR
                  ", attribute = 0x%X, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream, attribute, (uintptr_t)value);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryStreamKHR, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, QueryStreamKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, streamPacked, attribute, value);

            returnValue = QueryStreamKHR(thread, dpyPacked, streamPacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QueryStreamKHR, true, thread, dpyPacked, streamPacked, attribute, value,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_QueryStreamu64KHR(EGLDisplay dpy,
                                             EGLStreamKHR stream,
                                             EGLenum attribute,
                                             EGLuint64KHR *value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(QueryStreamu64KHR,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR
                  ", attribute = 0x%X, value = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream, attribute, (uintptr_t)value);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryStreamu64KHR, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, QueryStreamu64KHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, streamPacked, attribute, value);

            returnValue = QueryStreamu64KHR(thread, dpyPacked, streamPacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(QueryStreamu64KHR, true, thread, dpyPacked, streamPacked, attribute,
                          value, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_StreamAttribKHR(EGLDisplay dpy,
                                           EGLStreamKHR stream,
                                           EGLenum attribute,
                                           EGLint value)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(StreamAttribKHR,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR
                  ", attribute = 0x%X, value = %d",
                  (uintptr_t)dpy, (uintptr_t)stream, attribute, value);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(StreamAttribKHR, thread, dpyPacked, attribute);
            ANGLE_EGL_VALIDATE(thread, StreamAttribKHR, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, streamPacked, attribute, value);

            returnValue = StreamAttribKHR(thread, dpyPacked, streamPacked, attribute, value);
        }

        ANGLE_CAPTURE_EGL(StreamAttribKHR, true, thread, dpyPacked, streamPacked, attribute, value,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_stream_consumer_gltexture
EGLBoolean EGLAPIENTRY EGL_StreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(StreamConsumerAcquireKHR, "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(StreamConsumerAcquireKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, StreamConsumerAcquireKHR, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, streamPacked);

            returnValue = StreamConsumerAcquireKHR(thread, dpyPacked, streamPacked);
        }

        ANGLE_CAPTURE_EGL(StreamConsumerAcquireKHR, true, thread, dpyPacked, streamPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_StreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(StreamConsumerGLTextureExternalKHR,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR "", (uintptr_t)dpy,
                  (uintptr_t)stream);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(StreamConsumerGLTextureExternalKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, StreamConsumerGLTextureExternalKHR,
                               GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, streamPacked);

            returnValue = StreamConsumerGLTextureExternalKHR(thread, dpyPacked, streamPacked);
        }

        ANGLE_CAPTURE_EGL(StreamConsumerGLTextureExternalKHR, true, thread, dpyPacked, streamPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

EGLBoolean EGLAPIENTRY EGL_StreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(StreamConsumerReleaseKHR, "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream);

        egl::Display *dpyPacked   = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked = PackParam<egl::Stream *>(stream);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(StreamConsumerReleaseKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, StreamConsumerReleaseKHR, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, streamPacked);

            returnValue = StreamConsumerReleaseKHR(thread, dpyPacked, streamPacked);
        }

        ANGLE_CAPTURE_EGL(StreamConsumerReleaseKHR, true, thread, dpyPacked, streamPacked,
                          returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_KHR_swap_buffers_with_damage
EGLBoolean EGLAPIENTRY EGL_SwapBuffersWithDamageKHR(EGLDisplay dpy,
                                                    EGLSurface surface,
                                                    const EGLint *rects,
                                                    EGLint n_rects)
{
    ANGLE_EGLBOOLEAN_TRY(EGL_PrepareSwapBuffersANGLE(dpy, surface));
    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(SwapBuffersWithDamageKHR,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", rects = 0x%016" PRIxPTR
                  ", n_rects = %d",
                  (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)rects, n_rects);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(SwapBuffersWithDamageKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, SwapBuffersWithDamageKHR, GetDisplayIfValid(dpyPacked),
                               EGLBoolean, dpyPacked, surfacePacked, rects, n_rects);

            returnValue =
                SwapBuffersWithDamageKHR(thread, dpyPacked, surfacePacked, rects, n_rects);
        }

        ANGLE_CAPTURE_EGL(SwapBuffersWithDamageKHR, true, thread, dpyPacked, surfacePacked, rects,
                          n_rects, returnValue);
    }
    egl::Display::GetCurrentThreadUnlockedTailCall()->run();
    return returnValue;
}

// EGL_KHR_wait_sync
EGLint EGLAPIENTRY EGL_WaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags)
{

    Thread *thread = egl::GetCurrentThread();
    EGLint returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(WaitSyncKHR, "dpy = 0x%016" PRIxPTR ", sync = 0x%016" PRIxPTR ", flags = %d",
                  (uintptr_t)dpy, (uintptr_t)sync, flags);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        egl::SyncID syncPacked  = PackParam<egl::SyncID>(sync);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(WaitSyncKHR, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, WaitSyncKHR, GetDisplayIfValid(dpyPacked), EGLint, dpyPacked,
                               syncPacked, flags);

            returnValue = WaitSyncKHR(thread, dpyPacked, syncPacked, flags);
        }

        ANGLE_CAPTURE_EGL(WaitSyncKHR, true, thread, dpyPacked, syncPacked, flags, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_NV_post_sub_buffer
EGLBoolean EGLAPIENTRY EGL_PostSubBufferNV(EGLDisplay dpy,
                                           EGLSurface surface,
                                           EGLint x,
                                           EGLint y,
                                           EGLint width,
                                           EGLint height)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(PostSubBufferNV,
                  "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
                  ", x = %d, y = %d, width = %d, height = %d",
                  (uintptr_t)dpy, (uintptr_t)surface, x, y, width, height);

        egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
        SurfaceID surfacePacked = PackParam<SurfaceID>(surface);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(PostSubBufferNV, thread, dpyPacked);
            ANGLE_EGL_VALIDATE(thread, PostSubBufferNV, GetDisplayIfValid(dpyPacked), EGLBoolean,
                               dpyPacked, surfacePacked, x, y, width, height);

            returnValue = PostSubBufferNV(thread, dpyPacked, surfacePacked, x, y, width, height);
        }

        ANGLE_CAPTURE_EGL(PostSubBufferNV, true, thread, dpyPacked, surfacePacked, x, y, width,
                          height, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

// EGL_NV_stream_consumer_gltexture_yuv
EGLBoolean EGLAPIENTRY EGL_StreamConsumerGLTextureExternalAttribsNV(EGLDisplay dpy,
                                                                    EGLStreamKHR stream,
                                                                    const EGLAttrib *attrib_list)
{

    Thread *thread = egl::GetCurrentThread();
    EGLBoolean returnValue;
    {
        ANGLE_SCOPED_GLOBAL_LOCK();
        EGL_EVENT(StreamConsumerGLTextureExternalAttribsNV,
                  "dpy = 0x%016" PRIxPTR ", stream = 0x%016" PRIxPTR
                  ", attrib_list = 0x%016" PRIxPTR "",
                  (uintptr_t)dpy, (uintptr_t)stream, (uintptr_t)attrib_list);

        egl::Display *dpyPacked               = PackParam<egl::Display *>(dpy);
        egl::Stream *streamPacked             = PackParam<egl::Stream *>(stream);
        const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);

        {
            ANGLE_EGL_SCOPED_CONTEXT_LOCK(StreamConsumerGLTextureExternalAttribsNV, thread,
                                          dpyPacked);
            ANGLE_EGL_VALIDATE(thread, StreamConsumerGLTextureExternalAttribsNV,
                               GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, streamPacked,
                               attrib_listPacked);

            returnValue = StreamConsumerGLTextureExternalAttribsNV(thread, dpyPacked, streamPacked,
                                                                   attrib_listPacked);
        }

        ANGLE_CAPTURE_EGL(StreamConsumerGLTextureExternalAttribsNV, true, thread, dpyPacked,
                          streamPacked, attrib_listPacked, returnValue);
    }
    ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
    return returnValue;
}

}  // extern "C"
