18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#if RENDER_HAS_GLES_BACKEND
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include "egl_state.h"
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ci#include <EGL/egl.h>
218bf80f4bSopenharmony_ci#include <EGL/eglext.h>
228bf80f4bSopenharmony_ci
238bf80f4bSopenharmony_ci#ifndef EGL_VERSION_1_5
248bf80f4bSopenharmony_ci// If egl 1.5 headers not available, just define the values here.
258bf80f4bSopenharmony_ci// (copied from khronos specifications)
268bf80f4bSopenharmony_ci#define EGL_CONTEXT_MAJOR_VERSION 0x3098
278bf80f4bSopenharmony_ci#define EGL_CONTEXT_MINOR_VERSION 0x30FB
288bf80f4bSopenharmony_ci#define EGL_OPENGL_ES3_BIT 0x00000040
298bf80f4bSopenharmony_ci#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
308bf80f4bSopenharmony_ci#define EGL_GL_COLORSPACE 0x309D
318bf80f4bSopenharmony_ci#define EGL_GL_COLORSPACE_SRGB 0x3089
328bf80f4bSopenharmony_ci#define EGL_GL_COLORSPACE_LINEAR 0x308A
338bf80f4bSopenharmony_citypedef intptr_t EGLAttrib;
348bf80f4bSopenharmony_ci#endif
358bf80f4bSopenharmony_ci
368bf80f4bSopenharmony_ci#ifndef EGL_KHR_create_context
378bf80f4bSopenharmony_ci// If EGL_KHR_create_context extension not defined in headers, so just define the values here.
388bf80f4bSopenharmony_ci// (copied from khronos specifications)
398bf80f4bSopenharmony_ci#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
408bf80f4bSopenharmony_ci#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
418bf80f4bSopenharmony_ci#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
428bf80f4bSopenharmony_ci#define EGL_CONTEXT_FLAGS_KHR 0x30FC
438bf80f4bSopenharmony_ci#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
448bf80f4bSopenharmony_ci#endif
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_ci#ifndef EGL_KHR_gl_colorspace
478bf80f4bSopenharmony_ci// If EGL_KHR_gl_colorspace extension not defined in headers, so just define the values here.
488bf80f4bSopenharmony_ci// (copied from khronos specifications)
498bf80f4bSopenharmony_ci#define EGL_GL_COLORSPACE_KHR 0x309D
508bf80f4bSopenharmony_ci#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
518bf80f4bSopenharmony_ci#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
528bf80f4bSopenharmony_ci#endif /* EGL_KHR_gl_colorspace */
538bf80f4bSopenharmony_ci
548bf80f4bSopenharmony_ci#ifndef EGL_KHR_no_config_context
558bf80f4bSopenharmony_ci// If #ifndef EGL_KHR_no_config_context extension not defined in headers, so just define the values here.
568bf80f4bSopenharmony_ci// (copied from khronos specifications)
578bf80f4bSopenharmony_ci#define EGL_NO_CONFIG_KHR ((EGLConfig)0)
588bf80f4bSopenharmony_ci#endif
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_ci#include <securec.h>
618bf80f4bSopenharmony_ci
628bf80f4bSopenharmony_ci#include <render/namespace.h>
638bf80f4bSopenharmony_ci
648bf80f4bSopenharmony_ci#include "gles/gl_functions.h"
658bf80f4bSopenharmony_ci#include "util/log.h"
668bf80f4bSopenharmony_ci#define declare(a, b) a b = nullptr;
678bf80f4bSopenharmony_ci#include "gles/gl_functions.h"
688bf80f4bSopenharmony_ci#define declare(a, b) a b = nullptr;
698bf80f4bSopenharmony_ci#include "gles/egl_functions.h"
708bf80f4bSopenharmony_ci#include "gles/surface_information.h"
718bf80f4bSopenharmony_ci#include "gles/swapchain_gles.h"
728bf80f4bSopenharmony_ci
738bf80f4bSopenharmony_ci#if RENDER_GL_DEBUG
748bf80f4bSopenharmony_ci#define CHECK_EGL_ERROR() EGLHelpers::CheckEGLError(PLUGIN_FILE_INFO)
758bf80f4bSopenharmony_ci#define CHECK_EGL_ERROR2() EGLHelpers::CheckEGLError2(PLUGIN_FILE_INFO)
768bf80f4bSopenharmony_ci#else
778bf80f4bSopenharmony_ci#define CHECK_EGL_ERROR()
788bf80f4bSopenharmony_ci#define CHECK_EGL_ERROR2() EGLHelpers::CheckEGLError2(PLUGIN_FILE_INFO)
798bf80f4bSopenharmony_ci#endif
808bf80f4bSopenharmony_ci
818bf80f4bSopenharmony_ciRENDER_BEGIN_NAMESPACE()
828bf80f4bSopenharmony_ciusing BASE_NS::string;
838bf80f4bSopenharmony_ciusing BASE_NS::string_view;
848bf80f4bSopenharmony_ciusing BASE_NS::vector;
858bf80f4bSopenharmony_ci
868bf80f4bSopenharmony_cinamespace EGLHelpers {
878bf80f4bSopenharmony_cinamespace {
888bf80f4bSopenharmony_cistatic bool FilterError(
898bf80f4bSopenharmony_ci    GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei, const string_view, const void*) noexcept
908bf80f4bSopenharmony_ci{
918bf80f4bSopenharmony_ci    if (source == GL_DEBUG_SOURCE_OTHER) {
928bf80f4bSopenharmony_ci        if (type == GL_DEBUG_TYPE_PERFORMANCE) {
938bf80f4bSopenharmony_ci            if ((id == 2147483647) && (severity == GL_DEBUG_SEVERITY_HIGH)) { // 2147483647:big data
948bf80f4bSopenharmony_ci                /*  Ignore the following warning that Adreno drivers seem to spam.
958bf80f4bSopenharmony_ci                source: GL_DEBUG_SOURCE_OTHER
968bf80f4bSopenharmony_ci                type: GL_DEBUG_TYPE_PERFORMANCE
978bf80f4bSopenharmony_ci                id: 2147483647
988bf80f4bSopenharmony_ci                severity: GL_DEBUG_SEVERITY_HIGH
998bf80f4bSopenharmony_ci                message: FreeAllocationOnTimestamp - WaitForTimestamp
1008bf80f4bSopenharmony_ci                */
1018bf80f4bSopenharmony_ci                return true;
1028bf80f4bSopenharmony_ci            }
1038bf80f4bSopenharmony_ci        }
1048bf80f4bSopenharmony_ci    }
1058bf80f4bSopenharmony_ci    return false;
1068bf80f4bSopenharmony_ci}
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ciconst char* EglErrorStr(EGLint aError)
1098bf80f4bSopenharmony_ci{
1108bf80f4bSopenharmony_ci    switch (aError) {
1118bf80f4bSopenharmony_ci        case EGL_SUCCESS:
1128bf80f4bSopenharmony_ci            return "The last function succeeded without error.";
1138bf80f4bSopenharmony_ci        case EGL_NOT_INITIALIZED:
1148bf80f4bSopenharmony_ci            return "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
1158bf80f4bSopenharmony_ci        case EGL_BAD_ACCESS:
1168bf80f4bSopenharmony_ci            return "EGL cannot access a requested resource(for example a context is bound in another thread).";
1178bf80f4bSopenharmony_ci        case EGL_BAD_ALLOC:
1188bf80f4bSopenharmony_ci            return "EGL failed to allocate resources for the requested operation.";
1198bf80f4bSopenharmony_ci        case EGL_BAD_ATTRIBUTE:
1208bf80f4bSopenharmony_ci            return "An unrecognized attribute or attribute value was passed in the attribute list.";
1218bf80f4bSopenharmony_ci        case EGL_BAD_CONTEXT:
1228bf80f4bSopenharmony_ci            return "An EGLContext argument does not name a valid EGL rendering context.";
1238bf80f4bSopenharmony_ci        case EGL_BAD_CONFIG:
1248bf80f4bSopenharmony_ci            return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
1258bf80f4bSopenharmony_ci        case EGL_BAD_CURRENT_SURFACE:
1268bf80f4bSopenharmony_ci            return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer "
1278bf80f4bSopenharmony_ci                   "valid.";
1288bf80f4bSopenharmony_ci        case EGL_BAD_DISPLAY:
1298bf80f4bSopenharmony_ci            return "An EGLDisplay argument does not name a valid EGL display connection.";
1308bf80f4bSopenharmony_ci        case EGL_BAD_SURFACE:
1318bf80f4bSopenharmony_ci            return "An EGLSurface argument does not name a valid surface(window, pixel buffer or pixmap) configured "
1328bf80f4bSopenharmony_ci                   "for GL rendering.";
1338bf80f4bSopenharmony_ci        case EGL_BAD_MATCH:
1348bf80f4bSopenharmony_ci            return "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid "
1358bf80f4bSopenharmony_ci                   "surface).";
1368bf80f4bSopenharmony_ci        case EGL_BAD_PARAMETER:
1378bf80f4bSopenharmony_ci            return "One or more argument values are invalid.";
1388bf80f4bSopenharmony_ci        case EGL_BAD_NATIVE_PIXMAP:
1398bf80f4bSopenharmony_ci            return "A NativePixmapType argument does not refer to a valid native pixmap.";
1408bf80f4bSopenharmony_ci        case EGL_BAD_NATIVE_WINDOW:
1418bf80f4bSopenharmony_ci            return "A NativeWindowType argument does not refer to a valid native window.";
1428bf80f4bSopenharmony_ci        case EGL_CONTEXT_LOST:
1438bf80f4bSopenharmony_ci            return "A power management event has occurred.The application must destroy all contexts and reinitialise "
1448bf80f4bSopenharmony_ci                   "OpenGL ES state and objects to continue rendering.";
1458bf80f4bSopenharmony_ci        default:
1468bf80f4bSopenharmony_ci            break;
1478bf80f4bSopenharmony_ci    }
1488bf80f4bSopenharmony_ci
1498bf80f4bSopenharmony_ci    static char error[64];
1508bf80f4bSopenharmony_ci    if (sprintf_s(error, sizeof(error), "Unknown error %x", aError) < 0) {
1518bf80f4bSopenharmony_ci        PLUGIN_LOG_E("EglErrorStr: sprintf_s failed");
1528bf80f4bSopenharmony_ci    }
1538bf80f4bSopenharmony_ci    return error;
1548bf80f4bSopenharmony_ci}
1558bf80f4bSopenharmony_ci
1568bf80f4bSopenharmony_civoid CheckEGLError(const char* const file, int line)
1578bf80f4bSopenharmony_ci{
1588bf80f4bSopenharmony_ci    EGLint error = eglGetError();
1598bf80f4bSopenharmony_ci    if (error != EGL_SUCCESS) {
1608bf80f4bSopenharmony_ci        PLUGIN_LOG_E("eglGetError failed : %s (%s %d)", EglErrorStr(error), file, line);
1618bf80f4bSopenharmony_ci        PLUGIN_ASSERT(false);
1628bf80f4bSopenharmony_ci    }
1638bf80f4bSopenharmony_ci}
1648bf80f4bSopenharmony_ci
1658bf80f4bSopenharmony_civoid CheckEGLError2(const char* const file, int line)
1668bf80f4bSopenharmony_ci{
1678bf80f4bSopenharmony_ci    EGLint error = eglGetError();
1688bf80f4bSopenharmony_ci    if (error != EGL_SUCCESS) {
1698bf80f4bSopenharmony_ci        PLUGIN_LOG_E("eglGetError failed : %s (%s %d)", EglErrorStr(error), file, line);
1708bf80f4bSopenharmony_ci    }
1718bf80f4bSopenharmony_ci}
1728bf80f4bSopenharmony_ci
1738bf80f4bSopenharmony_ci#define ATTRIBUTE(_attr) \
1748bf80f4bSopenharmony_ci    {                    \
1758bf80f4bSopenharmony_ci        _attr, #_attr    \
1768bf80f4bSopenharmony_ci    }
1778bf80f4bSopenharmony_ci
1788bf80f4bSopenharmony_cistruct Attribute {
1798bf80f4bSopenharmony_ci    EGLint attribute;
1808bf80f4bSopenharmony_ci    char const* const Name;
1818bf80f4bSopenharmony_ci};
1828bf80f4bSopenharmony_ci
1838bf80f4bSopenharmony_civoid DumpEGLStrings(EGLDisplay dpy)
1848bf80f4bSopenharmony_ci{
1858bf80f4bSopenharmony_ci    // extensions dumped later.
1868bf80f4bSopenharmony_ci    static constexpr Attribute strings[] = { ATTRIBUTE(EGL_CLIENT_APIS), ATTRIBUTE(EGL_VENDOR),
1878bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_VERSION) };
1888bf80f4bSopenharmony_ci    for (size_t attr = 0; attr < sizeof(strings) / sizeof(Attribute); attr++) {
1898bf80f4bSopenharmony_ci        const char* const value = eglQueryString(dpy, strings[attr].attribute);
1908bf80f4bSopenharmony_ci        if (value) {
1918bf80f4bSopenharmony_ci            PLUGIN_LOG_D("\t%-32s: %s", strings[attr].Name, value);
1928bf80f4bSopenharmony_ci        } else {
1938bf80f4bSopenharmony_ci            PLUGIN_LOG_D("\t%-32s:", strings[attr].Name);
1948bf80f4bSopenharmony_ci        }
1958bf80f4bSopenharmony_ci    }
1968bf80f4bSopenharmony_ci}
1978bf80f4bSopenharmony_ci
1988bf80f4bSopenharmony_ci#ifdef PLUGIN_UNUSED_EGL_HELPERS
1998bf80f4bSopenharmony_civoid DumpEGLConfigs(EGLDisplay dpy)
2008bf80f4bSopenharmony_ci{
2018bf80f4bSopenharmony_ci    EGLConfig* configs = nullptr;
2028bf80f4bSopenharmony_ci    EGLint n = 0;
2038bf80f4bSopenharmony_ci
2048bf80f4bSopenharmony_ci    eglGetConfigs(dpy, NULL, 0, &n);
2058bf80f4bSopenharmony_ci    configs = new EGLConfig[(size_t)n];
2068bf80f4bSopenharmony_ci    eglGetConfigs(dpy, configs, n, &n);
2078bf80f4bSopenharmony_ci    for (EGLint i = 0; i < n; i++) {
2088bf80f4bSopenharmony_ci        PLUGIN_LOG_V("EGLConfig[%d]", i);
2098bf80f4bSopenharmony_ci        DumpEGLConfig(dpy, configs[i]);
2108bf80f4bSopenharmony_ci    }
2118bf80f4bSopenharmony_ci    delete[] configs;
2128bf80f4bSopenharmony_ci}
2138bf80f4bSopenharmony_ci#endif
2148bf80f4bSopenharmony_ci
2158bf80f4bSopenharmony_cibool stringToUInt(string_view string, EGLint& value)
2168bf80f4bSopenharmony_ci{
2178bf80f4bSopenharmony_ci    value = 0;
2188bf80f4bSopenharmony_ci    for (auto digit : string) {
2198bf80f4bSopenharmony_ci        value *= 10;
2208bf80f4bSopenharmony_ci        if ((digit >= '0') && (digit <= '9')) {
2218bf80f4bSopenharmony_ci            value += digit - '0';
2228bf80f4bSopenharmony_ci        } else {
2238bf80f4bSopenharmony_ci            return false;
2248bf80f4bSopenharmony_ci        }
2258bf80f4bSopenharmony_ci    }
2268bf80f4bSopenharmony_ci    return true;
2278bf80f4bSopenharmony_ci}
2288bf80f4bSopenharmony_ci
2298bf80f4bSopenharmony_civoid DumpEGLSurface(EGLDisplay dpy, EGLSurface surf)
2308bf80f4bSopenharmony_ci{
2318bf80f4bSopenharmony_ci    static constexpr Attribute attribs[] = {
2328bf80f4bSopenharmony_ci        // Returns the ID of the EGL frame buffer configuration with respect to which the surface was created.
2338bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_CONFIG_ID),
2348bf80f4bSopenharmony_ci        // Returns the color space used by OpenGL and OpenGL ES when rendering to the surface, either
2358bf80f4bSopenharmony_ci        // EGL_GL_COLORSPACE_SRGB or EGL_GL_COLORSPACE_LINEAR.
2368bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_GL_COLORSPACE),
2378bf80f4bSopenharmony_ci        // Returns the height of the surface in pixels
2388bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_HEIGHT),
2398bf80f4bSopenharmony_ci        // Returns the horizontal dot pitch of the display on which a window surface is  visible.The value returned is
2408bf80f4bSopenharmony_ci        // equal to the actual dot pitch, in pixels meter, multiplied by the constant value EGL_DISPLAY_SCALING.
2418bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_HORIZONTAL_RESOLUTION),
2428bf80f4bSopenharmony_ci        // Returns the same attribute value specified when the surface was created with  eglCreatePbufferSurface.For a
2438bf80f4bSopenharmony_ci        // window or pixmap surface, value is not modified.
2448bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_LARGEST_PBUFFER),
2458bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MIPMAP_LEVEL),   // Returns which level of the mipmap to render to, if texture has mipmaps.
2468bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MIPMAP_TEXTURE), // Returns EGL_TRUE if texture has mipmaps, EGL_FALSE otherwise.
2478bf80f4bSopenharmony_ci        // Returns the filter used when resolving the multisample buffer.The filter may be either
2488bf80f4bSopenharmony_ci        // EGL_MULTISAMPLE_RESOLVE_DEFAULT or EGL_MULTISAMPLE_RESOLVE_BOX, as described for eglSurfaceAttrib.
2498bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MULTISAMPLE_RESOLVE),
2508bf80f4bSopenharmony_ci        // Returns the aspect ratio of an individual pixel(the ratio of a pixel's width to its height). The value
2518bf80f4bSopenharmony_ci        // returned is equal to the actual aspect ratio multiplied by the constant value EGL_DISPLAY_SCALING.
2528bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_PIXEL_ASPECT_RATIO),
2538bf80f4bSopenharmony_ci        // Returns the buffer which client API rendering is requested to use.For a window surface, this is the same
2548bf80f4bSopenharmony_ci        // attribute value specified when the surface was created.For a pbuffer surface, it is always
2558bf80f4bSopenharmony_ci        // EGL_BACK_BUFFER.For a pixmap surface, it is always EGL_SINGLE_BUFFER.To determine the actual buffer being
2568bf80f4bSopenharmony_ci        // rendered to by a context, call eglQueryContext.
2578bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_RENDER_BUFFER),
2588bf80f4bSopenharmony_ci        // Returns the effect on the color buffer when posting a surface with eglSwapBuffers.Swap behavior may be either
2598bf80f4bSopenharmony_ci        // EGL_BUFFER_PRESERVED or EGL_BUFFER_DESTROYED, as described for eglSurfaceAttrib.
2608bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_SWAP_BEHAVIOR),
2618bf80f4bSopenharmony_ci        // Returns format of texture.Possible values are EGL_NO_TEXTURE, EGL_TEXTURE_RGB, and EGL_TEXTURE_RGBA.
2628bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_TEXTURE_FORMAT),
2638bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_TEXTURE_TARGET), // Returns type of texture.Possible values are EGL_NO_TEXTURE, or EGL_TEXTURE_2D.
2648bf80f4bSopenharmony_ci        // Returns the vertical dot pitch of the display on which a window surface is visible.The value returned is
2658bf80f4bSopenharmony_ci        // equal to the actual dot pitch, in pixels  / meter, multiplied by the constant value EGL_DISPLAY_SCALING.
2668bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_VERTICAL_RESOLUTION),
2678bf80f4bSopenharmony_ci        // Returns the interpretation of alpha values used by OpenVG when rendering to the surface, either
2688bf80f4bSopenharmony_ci        // EGL_VG_ALPHA_FORMAT_NONPRE or EGL_VG_ALPHA_FORMAT_PRE.
2698bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_VG_ALPHA_FORMAT),
2708bf80f4bSopenharmony_ci        // Returns the color space used by OpenVG when rendering to the surface, either EGL_VG_COLORSPACE_sRGB or
2718bf80f4bSopenharmony_ci        // EGL_VG_COLORSPACE_LINEAR.
2728bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_VG_COLORSPACE),
2738bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_WIDTH), // Returns the width of the surface in pixels.
2748bf80f4bSopenharmony_ci    };
2758bf80f4bSopenharmony_ci    for (size_t attr = 0; attr < sizeof(attribs) / sizeof(Attribute); attr++) {
2768bf80f4bSopenharmony_ci        EGLint value;
2778bf80f4bSopenharmony_ci        if (EGL_TRUE == eglQuerySurface(dpy, surf, attribs[attr].attribute, &value)) {
2788bf80f4bSopenharmony_ci            PLUGIN_LOG_V("\t%-32s: %10d (0x%08x)", attribs[attr].Name, value, value);
2798bf80f4bSopenharmony_ci        }
2808bf80f4bSopenharmony_ci    }
2818bf80f4bSopenharmony_ci}
2828bf80f4bSopenharmony_ci
2838bf80f4bSopenharmony_civoid DumpEGLConfig(EGLDisplay dpy, const EGLConfig& config)
2848bf80f4bSopenharmony_ci{
2858bf80f4bSopenharmony_ci    static constexpr Attribute attributes[] = {
2868bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_ALPHA_SIZE),      // Returns the number of bits of alpha stored in the color buffer.
2878bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_ALPHA_MASK_SIZE), // Returns the number of bits in the alpha mask buffer.
2888bf80f4bSopenharmony_ci        // Returns EGL_TRUE if color buffers can be bound to an RGB texture,  EGL_FALSE otherwise.
2898bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_BIND_TO_TEXTURE_RGB),
2908bf80f4bSopenharmony_ci        // Returns EGL_TRUE if color buffers can be bound to an RGBA texture, EGL_FALSE otherwise.
2918bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_BIND_TO_TEXTURE_RGBA),
2928bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_BLUE_SIZE), // Returns the number of bits of blue stored in the color buffer.
2938bf80f4bSopenharmony_ci        // Returns the depth of the color buffer.It is the sum of EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, and
2948bf80f4bSopenharmony_ci        // EGL_ALPHA_SIZE.
2958bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_BUFFER_SIZE),
2968bf80f4bSopenharmony_ci        // Returns the color buffer type.Possible types are EGL_RGB_BUFFER and  EGL_LUMINANCE_BUFFER.
2978bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_COLOR_BUFFER_TYPE),
2988bf80f4bSopenharmony_ci        // Returns the caveats for the frame buffer configuration.Possible caveat values  are EGL_NONE, EGL_SLOW_CONFIG,
2998bf80f4bSopenharmony_ci        // and EGL_NON_CONFORMANT.
3008bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_CONFIG_CAVEAT),
3018bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_CONFIG_ID), // Returns the ID of the frame buffer configuration.
3028bf80f4bSopenharmony_ci        // Returns a bitmask indicating which client API contexts created with respect to this
3038bf80f4bSopenharmony_ci        // config are conformant.
3048bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_CONFORMANT),
3058bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_DEPTH_SIZE), // Returns the number of bits in the depth buffer.
3068bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_GREEN_SIZE), // Returns the number of bits of green stored in the color buffer.
3078bf80f4bSopenharmony_ci        // Returns the frame buffer level.Level zero is the default frame buffer.Positive levels correspond to frame
3088bf80f4bSopenharmony_ci        // buffers that overlay the default buffer and negative levels correspond to frame buffers that underlay the
3098bf80f4bSopenharmony_ci        // default buffer.
3108bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_LEVEL),
3118bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_LUMINANCE_SIZE),     // Returns the number of bits of luminance stored in the luminance buffer.
3128bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MAX_PBUFFER_WIDTH),  // Returns the maximum width of a pixel buffer surface in pixels.
3138bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MAX_PBUFFER_HEIGHT), // Returns the maximum height of a pixel buffer surface in pixels.
3148bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MAX_PBUFFER_PIXELS), // Returns the maximum size of a pixel buffer surface in pixels.
3158bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MAX_SWAP_INTERVAL),  // Returns the maximum value that can be passed to eglSwapInterval.
3168bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_MIN_SWAP_INTERVAL),  // Returns the minimum value that can be passed to eglSwapInterval.
3178bf80f4bSopenharmony_ci        // Returns EGL_TRUE if native rendering APIs can render into the surface, EGL_FALSE otherwise.
3188bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_NATIVE_RENDERABLE),
3198bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_NATIVE_VISUAL_ID),   // Returns the ID of the associated native visual.
3208bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_NATIVE_VISUAL_TYPE), // Returns the type of the associated native visual.
3218bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_RED_SIZE),           // Returns the number of bits of red stored in the color buffer.
3228bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_RENDERABLE_TYPE),    // Returns a bitmask indicating the types of supported client API contexts.
3238bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_SAMPLE_BUFFERS),     // Returns the number of multisample buffers.
3248bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_SAMPLES),            // Returns the number of samples per pixel.
3258bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_STENCIL_SIZE),       // Returns the number of bits in the stencil buffer.
3268bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_SURFACE_TYPE),       // Returns a bitmask indicating the types of supported EGL surfaces.
3278bf80f4bSopenharmony_ci        // Returns the type of supported transparency.Possible transparency values are  EGL_NONE, and
3288bf80f4bSopenharmony_ci        // EGL_TRANSPARENT_RGB.
3298bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_TRANSPARENT_TYPE),
3308bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_TRANSPARENT_RED_VALUE),   // Returns the transparent red value.
3318bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_TRANSPARENT_GREEN_VALUE), // Returns the transparent green value.
3328bf80f4bSopenharmony_ci        ATTRIBUTE(EGL_TRANSPARENT_BLUE_VALUE),  // Returns the transparent blue value.
3338bf80f4bSopenharmony_ci        // ATTRIBUTE(EGL_MATCH_NATIVE_PIXMAP),  While EGL_MATCH_NATIVE_PIXMAP can be specified in the attribute list
3348bf80f4bSopenharmony_ci        // passed to eglChooseConfig, it is not an attribute of the resulting config and cannot be queried using
3358bf80f4bSopenharmony_ci        // eglGetConfigAttrib.
3368bf80f4bSopenharmony_ci    };
3378bf80f4bSopenharmony_ci    for (size_t attr = 0; attr < sizeof(attributes) / sizeof(Attribute); attr++) {
3388bf80f4bSopenharmony_ci        EGLint value;
3398bf80f4bSopenharmony_ci        if (EGL_TRUE == eglGetConfigAttrib(dpy, config, attributes[attr].attribute, &value)) {
3408bf80f4bSopenharmony_ci            PLUGIN_LOG_V("\t%-32s: %10d (0x%08x)", attributes[attr].Name, value, value);
3418bf80f4bSopenharmony_ci        }
3428bf80f4bSopenharmony_ci    }
3438bf80f4bSopenharmony_ci}
3448bf80f4bSopenharmony_ci
3458bf80f4bSopenharmony_civoid ParseExtensions(const string& extensions, vector<string_view>& extensionList)
3468bf80f4bSopenharmony_ci{
3478bf80f4bSopenharmony_ci    size_t start = 0;
3488bf80f4bSopenharmony_ci    for (auto end = extensions.find(' '); end != string::npos; end = extensions.find(' ', start)) {
3498bf80f4bSopenharmony_ci        extensionList.emplace_back(extensions.data() + start, end - start);
3508bf80f4bSopenharmony_ci        start = end + 1;
3518bf80f4bSopenharmony_ci    }
3528bf80f4bSopenharmony_ci    if (start < extensions.size()) {
3538bf80f4bSopenharmony_ci        extensionList.emplace_back(extensions.data() + start);
3548bf80f4bSopenharmony_ci    }
3558bf80f4bSopenharmony_ci}
3568bf80f4bSopenharmony_ci
3578bf80f4bSopenharmony_civoid FillProperties(DevicePropertiesGLES& properties)
3588bf80f4bSopenharmony_ci{
3598bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &properties.maxCombinedTextureImageUnits);
3608bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &properties.maxCubeMapTextureSize);
3618bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &properties.maxFragmentUniformVectors);
3628bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &properties.maxRenderbufferSize);
3638bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &properties.maxTextureImageUnits);
3648bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &properties.maxTextureSize);
3658bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VARYING_VECTORS, &properties.maxVaryingVectors);
3668bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &properties.maxVertexAttribs);
3678bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &properties.maxVertexTextureImageUnits);
3688bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &properties.maxVertexUniformVectors);
3698bf80f4bSopenharmony_ci    glGetFloatv(GL_MAX_VIEWPORT_DIMS, properties.maxViewportDims);
3708bf80f4bSopenharmony_ci    glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &properties.numCompressedTextureFormats);
3718bf80f4bSopenharmony_ci    glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &properties.numShaderBinaryFormats);
3728bf80f4bSopenharmony_ci    glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &properties.numProgramBinaryFormats);
3738bf80f4bSopenharmony_ci
3748bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &properties.max3DTextureSize);
3758bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &properties.maxArrayTextureLayers);
3768bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &properties.maxColorAttachments);
3778bf80f4bSopenharmony_ci    glGetInteger64v(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxCombinedFragmentUniformComponents);
3788bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &properties.maxCombinedUniformBlocks);
3798bf80f4bSopenharmony_ci    glGetInteger64v(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, &properties.maxCombinedVertexUniformComponents);
3808bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_DRAW_BUFFERS, &properties.maxDrawBuffers);
3818bf80f4bSopenharmony_ci    glGetInteger64v(GL_MAX_ELEMENT_INDEX, &properties.maxElementIndex);
3828bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &properties.maxElementsIndices);
3838bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &properties.maxElementsVertices);
3848bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &properties.maxFragmentInputComponents);
3858bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &properties.maxFragmentUniformBlocks);
3868bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxFragmentUniformComponents);
3878bf80f4bSopenharmony_ci    glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &properties.minProgramTexelOffset);
3888bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &properties.maxProgramTexelOffset);
3898bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_SAMPLES, &properties.maxSamples);
3908bf80f4bSopenharmony_ci    glGetInteger64v(GL_MAX_SERVER_WAIT_TIMEOUT, &properties.maxServerWaitTimeout);
3918bf80f4bSopenharmony_ci    glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &properties.maxTextureLodBias);
3928bf80f4bSopenharmony_ci    glGetIntegerv(
3938bf80f4bSopenharmony_ci        GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &properties.maxTransformFeedbackInterleavedComponents);
3948bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &properties.maxTransformFeedbackSeparateAttribs);
3958bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &properties.maxTransformFeedbackSeparateComponents);
3968bf80f4bSopenharmony_ci    glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &properties.maxUniformBlockSize);
3978bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &properties.maxUniformBufferBindings);
3988bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &properties.maxVaryingComponents);
3998bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &properties.maxVertexOutputComponents);
4008bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &properties.maxVertexUniformBlocks);
4018bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &properties.maxVertexUniformComponents);
4028bf80f4bSopenharmony_ci
4038bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &properties.maxAtomicCounterBufferBindings);
4048bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &properties.maxAtomicCounterBufferSize);
4058bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &properties.maxColorTextureSamples);
4068bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &properties.maxCombinedAtomicCounters);
4078bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, &properties.maxCombinedAtomicCounterBuffers);
4088bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, &properties.maxCombinedComputeUniformComponents);
4098bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &properties.maxCombinedImageUniforms);
4108bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &properties.maxCombinedShaderOutputResources);
4118bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &properties.maxCombinedShaderStorageBlocks);
4128bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &properties.maxComputeAtomicCounters);
4138bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &properties.maxComputeAtomicCounterBuffers);
4148bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &properties.maxComputeImageUniforms);
4158bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &properties.maxComputeShaderStorageBlocks);
4168bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &properties.maxComputeSharedMemorySize);
4178bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &properties.maxComputeTextureImageUnits);
4188bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &properties.maxComputeUniformBlocks);
4198bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, &properties.maxComputeUniformComponents);
4208bf80f4bSopenharmony_ci    glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, properties.maxComputeWorkGroupCount);
4218bf80f4bSopenharmony_ci    glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, properties.maxComputeWorkGroupCount + 1);
4228bf80f4bSopenharmony_ci    glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, properties.maxComputeWorkGroupCount + 2); // 2 : param
4238bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &properties.maxComputeWorkGroupInvocations);
4248bf80f4bSopenharmony_ci    glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, properties.maxComputeWorkGroupSize);
4258bf80f4bSopenharmony_ci    glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, properties.maxComputeWorkGroupSize + 1);
4268bf80f4bSopenharmony_ci    glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, properties.maxComputeWorkGroupSize + 2); // 2 : param
4278bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &properties.maxDepthTextureSamples);
4288bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &properties.maxFragmentAtomicCounters);
4298bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &properties.maxFragmentAtomicCounterBuffers);
4308bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &properties.maxFragmentImageUniforms);
4318bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &properties.maxFragmentShaderStorageBlocks);
4328bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &properties.maxFramebufferHeight);
4338bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &properties.maxFramebufferSamples);
4348bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &properties.maxFramebufferWidth);
4358bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_IMAGE_UNITS, &properties.maxImageUnits);
4368bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &properties.maxIntegerSamples);
4378bf80f4bSopenharmony_ci    glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.minProgramTextureGatherOffset);
4388bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.maxProgramTextureGatherOffset);
4398bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &properties.maxSampleMaskWords);
4408bf80f4bSopenharmony_ci    glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &properties.maxShaderStorageBlockSize);
4418bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &properties.maxShaderStorageBufferBindings);
4428bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &properties.maxUniformLocations);
4438bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &properties.maxVertexAtomicCounters);
4448bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &properties.maxVertexAtomicCounterBuffers);
4458bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &properties.maxVertexAttribBindings);
4468bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &properties.maxVertexAttribRelativeOffset);
4478bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &properties.maxVertexAttribStride);
4488bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &properties.maxVertexImageUniforms);
4498bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &properties.maxVertexShaderStorageBlocks);
4508bf80f4bSopenharmony_ci    glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &properties.uniformBufferOffsetAlignment);
4518bf80f4bSopenharmony_ci    glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &properties.shaderStorageBufferOffsetAlignment);
4528bf80f4bSopenharmony_ci
4538bf80f4bSopenharmony_ci    glGetIntegerv(GL_MIN_SAMPLE_SHADING_VALUE, &properties.minSampleShadingValue);
4548bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_DEBUG_GROUP_STACK_DEPTH, &properties.maxDebugGroupStackDepth);
4558bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES, &properties.maxDebugLoggedMessages);
4568bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &properties.maxDebugMessageLength);
4578bf80f4bSopenharmony_ci    glGetFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, &properties.minFragmentInterpolationOffset);
4588bf80f4bSopenharmony_ci    glGetFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, &properties.maxFragmentInterpolationOffset);
4598bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS, &properties.maxFramebufferLayers);
4608bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_LABEL_LENGTH, &properties.maxLabelLength);
4618bf80f4bSopenharmony_ci    glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &properties.maxTextureBufferSize);
4628bf80f4bSopenharmony_ci}
4638bf80f4bSopenharmony_ci
4648bf80f4bSopenharmony_cibool IsSrgbSurfaceSupported(const DevicePlatformDataGLES& plat)
4658bf80f4bSopenharmony_ci{
4668bf80f4bSopenharmony_ci    // Check if EGL supports sRGB color space (either EGL is > 1.5 or EGL_KHR_gl_colorspace extension is supported).
4678bf80f4bSopenharmony_ci    if (plat.majorVersion > 1u || (plat.majorVersion == 1u && plat.minorVersion >= 5u)) {
4688bf80f4bSopenharmony_ci        // EGL 1.5 or newer -> no need to check the extension.
4698bf80f4bSopenharmony_ci        return true;
4708bf80f4bSopenharmony_ci    }
4718bf80f4bSopenharmony_ci    // Check if the sRGB color space extension is supported.
4728bf80f4bSopenharmony_ci    return plat.hasColorSpaceExt;
4738bf80f4bSopenharmony_ci}
4748bf80f4bSopenharmony_ci
4758bf80f4bSopenharmony_ci} // namespace
4768bf80f4bSopenharmony_ci
4778bf80f4bSopenharmony_ci#undef ATTRIBUTE
4788bf80f4bSopenharmony_civoid EGLState::HandleExtensions()
4798bf80f4bSopenharmony_ci{
4808bf80f4bSopenharmony_ci    if (plat_.minorVersion > 4) {
4818bf80f4bSopenharmony_ci        cextensions_ = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
4828bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
4838bf80f4bSopenharmony_ci        PLUGIN_LOG_D("\t%-32s: %s", "EGL_EXTENSIONS (CLIENT)", cextensions_.c_str());
4848bf80f4bSopenharmony_ci        ParseExtensions(cextensions_, cextensionList_);
4858bf80f4bSopenharmony_ci    }
4868bf80f4bSopenharmony_ci
4878bf80f4bSopenharmony_ci    dextensions_ = eglQueryString(plat_.display, EGL_EXTENSIONS);
4888bf80f4bSopenharmony_ci    CHECK_EGL_ERROR();
4898bf80f4bSopenharmony_ci    ParseExtensions(dextensions_, dextensionList_);
4908bf80f4bSopenharmony_ci    PLUGIN_LOG_D("\t%-32s: %s", "EGL_EXTENSIONS (DISPLAY)", dextensions_.c_str());
4918bf80f4bSopenharmony_ci}
4928bf80f4bSopenharmony_ci
4938bf80f4bSopenharmony_ciuint32_t EGLState::MajorVersion() const
4948bf80f4bSopenharmony_ci{
4958bf80f4bSopenharmony_ci    return plat_.majorVersion;
4968bf80f4bSopenharmony_ci}
4978bf80f4bSopenharmony_ci
4988bf80f4bSopenharmony_ciuint32_t EGLState::MinorVersion() const
4998bf80f4bSopenharmony_ci{
5008bf80f4bSopenharmony_ci    return plat_.minorVersion;
5018bf80f4bSopenharmony_ci}
5028bf80f4bSopenharmony_ci
5038bf80f4bSopenharmony_civoid EGLState::ChooseConfiguration(const BackendExtraGLES* backendConfig)
5048bf80f4bSopenharmony_ci{
5058bf80f4bSopenharmony_ci    EGLint num_configs;
5068bf80f4bSopenharmony_ci    // construct attribute list dynamically
5078bf80f4bSopenharmony_ci    vector<EGLint> attributes;
5088bf80f4bSopenharmony_ci    const size_t ATTRIBUTE_RESERVE = 16;       // reserve 16 attributes
5098bf80f4bSopenharmony_ci    attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
5108bf80f4bSopenharmony_ci    auto addAttribute = [&attributes](EGLint a, EGLint b) {
5118bf80f4bSopenharmony_ci        attributes.push_back(a);
5128bf80f4bSopenharmony_ci        attributes.push_back(b);
5138bf80f4bSopenharmony_ci    };
5148bf80f4bSopenharmony_ci    // Request OpenGL ES 3.x configs
5158bf80f4bSopenharmony_ci    if (IsVersionGreaterOrEqual(1, 5)) {
5168bf80f4bSopenharmony_ci        // EGL 1.5+
5178bf80f4bSopenharmony_ci        addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT);
5188bf80f4bSopenharmony_ci        addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES3_BIT);
5198bf80f4bSopenharmony_ci    } else if (HasExtension("EGL_KHR_create_context")) {
5208bf80f4bSopenharmony_ci        // "EGL_KHR_create_context"
5218bf80f4bSopenharmony_ci        addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR);
5228bf80f4bSopenharmony_ci        addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES3_BIT_KHR);
5238bf80f4bSopenharmony_ci    } else {
5248bf80f4bSopenharmony_ci        // We might be in trouble now.
5258bf80f4bSopenharmony_ci        addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
5268bf80f4bSopenharmony_ci        addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES2_BIT);
5278bf80f4bSopenharmony_ci    }
5288bf80f4bSopenharmony_ci    addAttribute(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
5298bf80f4bSopenharmony_ci    addAttribute(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
5308bf80f4bSopenharmony_ci    addAttribute(EGL_RED_SIZE, 8);
5318bf80f4bSopenharmony_ci    addAttribute(EGL_GREEN_SIZE, 8);
5328bf80f4bSopenharmony_ci    addAttribute(EGL_BLUE_SIZE, 8);
5338bf80f4bSopenharmony_ci    addAttribute(EGL_CONFIG_CAVEAT, EGL_NONE);
5348bf80f4bSopenharmony_ci    if (backendConfig) {
5358bf80f4bSopenharmony_ci        if (backendConfig->MSAASamples > 1) {
5368bf80f4bSopenharmony_ci            addAttribute(EGL_SAMPLES, (EGLint)backendConfig->MSAASamples);
5378bf80f4bSopenharmony_ci            addAttribute(EGL_SAMPLE_BUFFERS, 1);
5388bf80f4bSopenharmony_ci        }
5398bf80f4bSopenharmony_ci        addAttribute(EGL_ALPHA_SIZE, (EGLint)backendConfig->alphaBits);
5408bf80f4bSopenharmony_ci        addAttribute(EGL_DEPTH_SIZE, (EGLint)backendConfig->depthBits);
5418bf80f4bSopenharmony_ci        addAttribute(EGL_STENCIL_SIZE, (EGLint)backendConfig->stencilBits);
5428bf80f4bSopenharmony_ci        PLUGIN_LOG_I("Samples:%d Alpha:%d Depth:%d Stencil:%d", backendConfig->MSAASamples, backendConfig->alphaBits,
5438bf80f4bSopenharmony_ci            backendConfig->depthBits, backendConfig->stencilBits);
5448bf80f4bSopenharmony_ci    }
5458bf80f4bSopenharmony_ci    addAttribute(EGL_NONE, EGL_NONE); // terminate list
5468bf80f4bSopenharmony_ci    eglChooseConfig(plat_.display, attributes.data(), &plat_.config, 1, &num_configs);
5478bf80f4bSopenharmony_ci    CHECK_EGL_ERROR();
5488bf80f4bSopenharmony_ci#if RENDER_GL_DEBUG
5498bf80f4bSopenharmony_ci    PLUGIN_LOG_I("eglChooseConfig returned:");
5508bf80f4bSopenharmony_ci    DumpEGLConfig(plat_.display, plat_.config);
5518bf80f4bSopenharmony_ci#endif
5528bf80f4bSopenharmony_ci}
5538bf80f4bSopenharmony_ci
5548bf80f4bSopenharmony_civoid EGLState::CreateContext(const BackendExtraGLES* backendConfig)
5558bf80f4bSopenharmony_ci{
5568bf80f4bSopenharmony_ci    vector<EGLint> context_attributes;
5578bf80f4bSopenharmony_ci    const size_t ATTRIBUTE_RESERVE = 16;               // reserve 16 attributes
5588bf80f4bSopenharmony_ci    context_attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
5598bf80f4bSopenharmony_ci    auto addAttribute = [&context_attributes](EGLint a, EGLint b) {
5608bf80f4bSopenharmony_ci        context_attributes.push_back(a);
5618bf80f4bSopenharmony_ci        context_attributes.push_back(b);
5628bf80f4bSopenharmony_ci    };
5638bf80f4bSopenharmony_ci    if (IsVersionGreaterOrEqual(1, 5)) {
5648bf80f4bSopenharmony_ci        // egl 1.5 or greater.
5658bf80f4bSopenharmony_ci        addAttribute(EGL_CONTEXT_MAJOR_VERSION, 3); // Select an OpenGL ES 3.x context
5668bf80f4bSopenharmony_ci        addAttribute(EGL_CONTEXT_MINOR_VERSION, 2); // Select an OpenGL ES x.2 context
5678bf80f4bSopenharmony_ci#if RENDER_GL_DEBUG
5688bf80f4bSopenharmony_ci        // should use EGL_CONTEXT_OPENGL_DEBUG , but at least PowerVR simulator fails with this
5698bf80f4bSopenharmony_ci        if (HasExtension("EGL_KHR_create_context")) {
5708bf80f4bSopenharmony_ci            // Setting up debug context with the extension seems to work.
5718bf80f4bSopenharmony_ci            addAttribute(EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
5728bf80f4bSopenharmony_ci        }
5738bf80f4bSopenharmony_ci#endif
5748bf80f4bSopenharmony_ci    } else if (HasExtension("EGL_KHR_create_context")) {
5758bf80f4bSopenharmony_ci        // egl 1.4 with EGL_KHR_create_context
5768bf80f4bSopenharmony_ci        addAttribute(EGL_CONTEXT_MAJOR_VERSION_KHR, 3); // Select an OpenGL ES 3.x context
5778bf80f4bSopenharmony_ci        addAttribute(EGL_CONTEXT_MINOR_VERSION_KHR, 2); // Select an OpenGL ES x.2 context
5788bf80f4bSopenharmony_ci#if RENDER_GL_DEBUG
5798bf80f4bSopenharmony_ci        addAttribute(EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
5808bf80f4bSopenharmony_ci#endif
5818bf80f4bSopenharmony_ci    } else {
5828bf80f4bSopenharmony_ci        // fallback to non-extended or pre 1.5 EGL, we expect 3.2 OpenGL context, this is now checked later.
5838bf80f4bSopenharmony_ci        addAttribute(EGL_CONTEXT_CLIENT_VERSION, 3); // Select an OpenGL ES 3.x context
5848bf80f4bSopenharmony_ci    }
5858bf80f4bSopenharmony_ci    addAttribute(EGL_NONE, EGL_NONE);
5868bf80f4bSopenharmony_ci
5878bf80f4bSopenharmony_ci    EGLContext sharedContext = EGL_NO_CONTEXT;
5888bf80f4bSopenharmony_ci    if (backendConfig) {
5898bf80f4bSopenharmony_ci        sharedContext = backendConfig->sharedContext;
5908bf80f4bSopenharmony_ci    }
5918bf80f4bSopenharmony_ci    plat_.context = eglCreateContext(plat_.display, plat_.config, sharedContext, context_attributes.data());
5928bf80f4bSopenharmony_ci    CHECK_EGL_ERROR();
5938bf80f4bSopenharmony_ci
5948bf80f4bSopenharmony_ci    if (plat_.context == EGL_NO_CONTEXT) {
5958bf80f4bSopenharmony_ci        PLUGIN_LOG_E("eglCreateContext failed : %s", EglErrorStr(eglGetError()));
5968bf80f4bSopenharmony_ci        PLUGIN_ASSERT(false);
5978bf80f4bSopenharmony_ci        return;
5988bf80f4bSopenharmony_ci    }
5998bf80f4bSopenharmony_ci}
6008bf80f4bSopenharmony_ci
6018bf80f4bSopenharmony_cibool EGLState::IsVersionGreaterOrEqual(uint32_t major, uint32_t minor) const
6028bf80f4bSopenharmony_ci{
6038bf80f4bSopenharmony_ci    if (plat_.majorVersion < major) {
6048bf80f4bSopenharmony_ci        return false;
6058bf80f4bSopenharmony_ci    }
6068bf80f4bSopenharmony_ci    if (plat_.majorVersion > major) {
6078bf80f4bSopenharmony_ci        return true;
6088bf80f4bSopenharmony_ci    }
6098bf80f4bSopenharmony_ci    if (plat_.minorVersion >= minor) {
6108bf80f4bSopenharmony_ci        return true;
6118bf80f4bSopenharmony_ci    }
6128bf80f4bSopenharmony_ci    return false;
6138bf80f4bSopenharmony_ci}
6148bf80f4bSopenharmony_ci
6158bf80f4bSopenharmony_cibool EGLState::VerifyVersion()
6168bf80f4bSopenharmony_ci{
6178bf80f4bSopenharmony_ci    // Verify that we have at least 3.2 context.
6188bf80f4bSopenharmony_ci    EGLint glMajor = 0;
6198bf80f4bSopenharmony_ci    EGLint glMinor = 0;
6208bf80f4bSopenharmony_ci    SaveContext();
6218bf80f4bSopenharmony_ci    SetContext(nullptr); // activate the context with the dummy PBuffer.
6228bf80f4bSopenharmony_ci    string_view string((char*)glGetString(GL_VERSION));
6238bf80f4bSopenharmony_ci    // the format according to spec pdf is "OpenGL ES N.M vendor-specific information"
6248bf80f4bSopenharmony_ci    bool fail = false;
6258bf80f4bSopenharmony_ci    if (string.starts_with("OpenGL ES ")) {
6268bf80f4bSopenharmony_ci        // Must be OpenGL ES FULL. Trust this information. (even if it might mismatch with the eglQueryContext results)
6278bf80f4bSopenharmony_ci        string_view version = string.substr(10);
6288bf80f4bSopenharmony_ci        version = version.substr(0, version.find_first_of(' '));
6298bf80f4bSopenharmony_ci        auto dot = version.find_first_of('.');
6308bf80f4bSopenharmony_ci        auto majorS = version.substr(0, dot);
6318bf80f4bSopenharmony_ci        if (dot != string_view::npos) {
6328bf80f4bSopenharmony_ci            auto minorS = version.substr(dot + 1);
6338bf80f4bSopenharmony_ci            fail = (stringToUInt(minorS, glMinor)) ? fail : false;
6348bf80f4bSopenharmony_ci        }
6358bf80f4bSopenharmony_ci        fail = (stringToUInt(majorS, glMajor)) ? fail : false;
6368bf80f4bSopenharmony_ci    }
6378bf80f4bSopenharmony_ci    if (fail) {
6388bf80f4bSopenharmony_ci        // Try these then, if parsing the GL_VERSION string failed
6398bf80f4bSopenharmony_ci        glMajor = glMinor = 0;
6408bf80f4bSopenharmony_ci        eglQueryContext(plat_.display, plat_.context, EGL_CONTEXT_MAJOR_VERSION, &glMajor);
6418bf80f4bSopenharmony_ci        eglQueryContext(plat_.display, plat_.context, EGL_CONTEXT_MINOR_VERSION_KHR, &glMinor);
6428bf80f4bSopenharmony_ci    }
6438bf80f4bSopenharmony_ci
6448bf80f4bSopenharmony_ci    if (glMajor < 3) {
6458bf80f4bSopenharmony_ci        fail = true;
6468bf80f4bSopenharmony_ci    } else if (glMajor == 3) {
6478bf80f4bSopenharmony_ci        if (glMinor < 2) {
6488bf80f4bSopenharmony_ci            // We do NOT support 3.0 or 3.1
6498bf80f4bSopenharmony_ci            fail = true;
6508bf80f4bSopenharmony_ci        }
6518bf80f4bSopenharmony_ci    }
6528bf80f4bSopenharmony_ci
6538bf80f4bSopenharmony_ci    if (fail) {
6548bf80f4bSopenharmony_ci        // restore contexts and cleanup.
6558bf80f4bSopenharmony_ci        PLUGIN_LOG_E(
6568bf80f4bSopenharmony_ci            "Could not to Initialize required OpenGL ES version [%d.%d] [%s]", glMajor, glMinor, string.data());
6578bf80f4bSopenharmony_ci        RestoreContext();
6588bf80f4bSopenharmony_ci        // destroy the dummy surface also.
6598bf80f4bSopenharmony_ci        eglDestroySurface(plat_.display, dummySurface_);
6608bf80f4bSopenharmony_ci        dummyContext_.context = EGL_NO_CONTEXT;
6618bf80f4bSopenharmony_ci        dummyContext_.drawSurface = dummyContext_.readSurface = EGL_NO_SURFACE;
6628bf80f4bSopenharmony_ci        dummyContext_.display = EGL_NO_DISPLAY;
6638bf80f4bSopenharmony_ci    }
6648bf80f4bSopenharmony_ci    return !fail;
6658bf80f4bSopenharmony_ci}
6668bf80f4bSopenharmony_ci
6678bf80f4bSopenharmony_cibool EGLState::CreateContext(DeviceCreateInfo const& createInfo)
6688bf80f4bSopenharmony_ci{
6698bf80f4bSopenharmony_ci    auto backendConfig = static_cast<const BackendExtraGLES*>(createInfo.backendConfiguration);
6708bf80f4bSopenharmony_ci    EGLint major, minor;
6718bf80f4bSopenharmony_ci
6728bf80f4bSopenharmony_ci    plat_.display = eglGetDisplay(backendConfig ? backendConfig->display : EGL_DEFAULT_DISPLAY);
6738bf80f4bSopenharmony_ci    const EGLContext appContext = backendConfig ? backendConfig->applicationContext : EGL_NO_CONTEXT;
6748bf80f4bSopenharmony_ci    const EGLContext sharedContext = backendConfig ? backendConfig->sharedContext : EGL_NO_CONTEXT;
6758bf80f4bSopenharmony_ci    if (appContext == EGL_NO_CONTEXT && sharedContext == EGL_NO_CONTEXT) {
6768bf80f4bSopenharmony_ci        if (!eglInitialize(plat_.display, &major, &minor)) {
6778bf80f4bSopenharmony_ci            PLUGIN_LOG_E("EGL initialization failed");
6788bf80f4bSopenharmony_ci            CHECK_EGL_ERROR();
6798bf80f4bSopenharmony_ci            PLUGIN_ASSERT(false);
6808bf80f4bSopenharmony_ci            return false;
6818bf80f4bSopenharmony_ci        }
6828bf80f4bSopenharmony_ci        plat_.eglInitialized = true;
6838bf80f4bSopenharmony_ci    } else {
6848bf80f4bSopenharmony_ci        major = 0;
6858bf80f4bSopenharmony_ci        minor = 0;
6868bf80f4bSopenharmony_ci
6878bf80f4bSopenharmony_ci        // Check version from display as we don't call eglInitialize ourselves
6888bf80f4bSopenharmony_ci        const string_view version = eglQueryString(plat_.display, EGL_VERSION);
6898bf80f4bSopenharmony_ci        if (!version.empty()) {
6908bf80f4bSopenharmony_ci            const auto dot = version.find_first_of('.');
6918bf80f4bSopenharmony_ci            if (dot != string_view::npos) {
6928bf80f4bSopenharmony_ci                const auto majorS = version.substr(0, dot);
6938bf80f4bSopenharmony_ci                if (!stringToUInt(majorS, major)) {
6948bf80f4bSopenharmony_ci                    major = 0;
6958bf80f4bSopenharmony_ci                }
6968bf80f4bSopenharmony_ci                const auto space = version.find_first_of(' ', dot + 1);
6978bf80f4bSopenharmony_ci                if (space != string_view::npos) {
6988bf80f4bSopenharmony_ci                    auto minorS = version.substr(dot + 1, space - (dot + 1));
6998bf80f4bSopenharmony_ci                    if (!stringToUInt(minorS, minor)) {
7008bf80f4bSopenharmony_ci                        minor = 0;
7018bf80f4bSopenharmony_ci                    }
7028bf80f4bSopenharmony_ci                }
7038bf80f4bSopenharmony_ci            }
7048bf80f4bSopenharmony_ci        } else {
7058bf80f4bSopenharmony_ci            CHECK_EGL_ERROR();
7068bf80f4bSopenharmony_ci        }
7078bf80f4bSopenharmony_ci    }
7088bf80f4bSopenharmony_ci    plat_.majorVersion = static_cast<uint32_t>(major);
7098bf80f4bSopenharmony_ci    plat_.minorVersion = static_cast<uint32_t>(minor);
7108bf80f4bSopenharmony_ci    PLUGIN_LOG_I("EGL %d.%d Initialized", major, minor);
7118bf80f4bSopenharmony_ci
7128bf80f4bSopenharmony_ci    if (!IsVersionGreaterOrEqual(1, 4)) {
7138bf80f4bSopenharmony_ci        // we need atleast egl 1.4
7148bf80f4bSopenharmony_ci        PLUGIN_LOG_F("EGL version too old. 1.4 or later requried.");
7158bf80f4bSopenharmony_ci        if (plat_.eglInitialized) {
7168bf80f4bSopenharmony_ci            eglTerminate(plat_.display);
7178bf80f4bSopenharmony_ci        }
7188bf80f4bSopenharmony_ci        return false;
7198bf80f4bSopenharmony_ci    }
7208bf80f4bSopenharmony_ci
7218bf80f4bSopenharmony_ci    eglBindAPI(EGL_OPENGL_ES_API);
7228bf80f4bSopenharmony_ci    CHECK_EGL_ERROR();
7238bf80f4bSopenharmony_ci
7248bf80f4bSopenharmony_ci    DumpEGLStrings(plat_.display);
7258bf80f4bSopenharmony_ci
7268bf80f4bSopenharmony_ci    HandleExtensions();
7278bf80f4bSopenharmony_ci
7288bf80f4bSopenharmony_ci    plat_.hasColorSpaceExt = hasColorSpaceExt_ = HasExtension("EGL_KHR_gl_colorspace");
7298bf80f4bSopenharmony_ci    // NOTE: "EGL_KHR_no_config_context" and "EGL_KHR_surfaceless_context" is technically working, but disabled for now.
7308bf80f4bSopenharmony_ci    hasConfiglessExt_ = false;
7318bf80f4bSopenharmony_ci    hasSurfacelessExt_ = false;
7328bf80f4bSopenharmony_ci    plat_.config = EGL_NO_CONFIG_KHR;
7338bf80f4bSopenharmony_ci    if (!hasConfiglessExt_) {
7348bf80f4bSopenharmony_ci        // we need a config for the context..
7358bf80f4bSopenharmony_ci        ChooseConfiguration(backendConfig);
7368bf80f4bSopenharmony_ci    }
7378bf80f4bSopenharmony_ci
7388bf80f4bSopenharmony_ci    if (appContext) {
7398bf80f4bSopenharmony_ci        // use applications context
7408bf80f4bSopenharmony_ci        PLUGIN_LOG_I("Using application context in DeviceGLES");
7418bf80f4bSopenharmony_ci        plat_.context = appContext;
7428bf80f4bSopenharmony_ci    } else {
7438bf80f4bSopenharmony_ci        // Create a new context
7448bf80f4bSopenharmony_ci        CreateContext(backendConfig);
7458bf80f4bSopenharmony_ci        plat_.contextCreated = true;
7468bf80f4bSopenharmony_ci    }
7478bf80f4bSopenharmony_ci    if (plat_.context == EGL_NO_CONTEXT) {
7488bf80f4bSopenharmony_ci        // we have failed then.
7498bf80f4bSopenharmony_ci        if (plat_.eglInitialized) {
7508bf80f4bSopenharmony_ci            eglTerminate(plat_.display);
7518bf80f4bSopenharmony_ci        }
7528bf80f4bSopenharmony_ci        return false;
7538bf80f4bSopenharmony_ci    }
7548bf80f4bSopenharmony_ci
7558bf80f4bSopenharmony_ci    if (!hasSurfacelessExt_) {
7568bf80f4bSopenharmony_ci        // Create a placeholder pbuffer, since we do NOT have a surface yet.
7578bf80f4bSopenharmony_ci        if (plat_.config == EGL_NO_CONFIG_KHR) {
7588bf80f4bSopenharmony_ci            // we need to choose a config for the surface..
7598bf80f4bSopenharmony_ci            ChooseConfiguration(backendConfig);
7608bf80f4bSopenharmony_ci        }
7618bf80f4bSopenharmony_ci        GLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
7628bf80f4bSopenharmony_ci        dummySurface_ = eglCreatePbufferSurface(plat_.display, plat_.config, surface_attribs);
7638bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
7648bf80f4bSopenharmony_ci#if RENDER_GL_DEBUG
7658bf80f4bSopenharmony_ci        DumpEGLSurface(plat_.display, dummySurface_);
7668bf80f4bSopenharmony_ci#endif
7678bf80f4bSopenharmony_ci    }
7688bf80f4bSopenharmony_ci
7698bf80f4bSopenharmony_ci    dummyContext_.context = plat_.context;
7708bf80f4bSopenharmony_ci    dummyContext_.drawSurface = dummyContext_.readSurface = dummySurface_;
7718bf80f4bSopenharmony_ci    dummyContext_.display = plat_.display;
7728bf80f4bSopenharmony_ci
7738bf80f4bSopenharmony_ci    if (!VerifyVersion()) {
7748bf80f4bSopenharmony_ci        if (plat_.contextCreated) {
7758bf80f4bSopenharmony_ci            eglDestroyContext(plat_.display, plat_.context);
7768bf80f4bSopenharmony_ci            plat_.context = EGL_NO_CONTEXT;
7778bf80f4bSopenharmony_ci        }
7788bf80f4bSopenharmony_ci        if (plat_.eglInitialized) {
7798bf80f4bSopenharmony_ci            eglTerminate(plat_.display);
7808bf80f4bSopenharmony_ci        }
7818bf80f4bSopenharmony_ci        return false;
7828bf80f4bSopenharmony_ci    }
7838bf80f4bSopenharmony_ci    return true;
7848bf80f4bSopenharmony_ci}
7858bf80f4bSopenharmony_ci
7868bf80f4bSopenharmony_civoid EGLState::GlInitialize()
7878bf80f4bSopenharmony_ci{
7888bf80f4bSopenharmony_ci#define declare(a, b)                                                                     \
7898bf80f4bSopenharmony_ci    if (b == nullptr) {                                                                   \
7908bf80f4bSopenharmony_ci        *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(eglGetProcAddress(#b)); \
7918bf80f4bSopenharmony_ci    }                                                                                     \
7928bf80f4bSopenharmony_ci    if (b == nullptr) {                                                                   \
7938bf80f4bSopenharmony_ci        PLUGIN_LOG_E("Missing %s\n", #b);                                                 \
7948bf80f4bSopenharmony_ci    }
7958bf80f4bSopenharmony_ci#include "gles/gl_functions.h"
7968bf80f4bSopenharmony_ci
7978bf80f4bSopenharmony_ci#define declare(a, b)                                                                     \
7988bf80f4bSopenharmony_ci    if (b == nullptr) {                                                                   \
7998bf80f4bSopenharmony_ci        *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(eglGetProcAddress(#b)); \
8008bf80f4bSopenharmony_ci    }                                                                                     \
8018bf80f4bSopenharmony_ci    if (b == nullptr) {                                                                   \
8028bf80f4bSopenharmony_ci        PLUGIN_LOG_E("Missing %s\n", #b);                                                 \
8038bf80f4bSopenharmony_ci    }
8048bf80f4bSopenharmony_ci#include "gles/egl_functions.h"
8058bf80f4bSopenharmony_ci    if (!HasExtension("EGL_ANDROID_get_native_client_buffer")) {
8068bf80f4bSopenharmony_ci        eglGetNativeClientBufferANDROID = nullptr;
8078bf80f4bSopenharmony_ci    }
8088bf80f4bSopenharmony_ci    if (!HasExtension("EGL_KHR_image_base")) {
8098bf80f4bSopenharmony_ci        eglCreateImageKHR = nullptr;
8108bf80f4bSopenharmony_ci        eglDestroyImageKHR = nullptr;
8118bf80f4bSopenharmony_ci    }
8128bf80f4bSopenharmony_ci
8138bf80f4bSopenharmony_ci    plat_.deviceName = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
8148bf80f4bSopenharmony_ci    plat_.driverVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
8158bf80f4bSopenharmony_ci    BASE_NS::ClearToValue(
8168bf80f4bSopenharmony_ci        &plat_.deviceProperties, sizeof(plat_.deviceProperties), 0x00, sizeof(plat_.deviceProperties));
8178bf80f4bSopenharmony_ci    FillProperties(plat_.deviceProperties);
8188bf80f4bSopenharmony_ci
8198bf80f4bSopenharmony_ci    SetSwapInterval(1); // default to vsync enabled.
8208bf80f4bSopenharmony_ci}
8218bf80f4bSopenharmony_ci
8228bf80f4bSopenharmony_cibool EGLState::IsValid()
8238bf80f4bSopenharmony_ci{
8248bf80f4bSopenharmony_ci    return (plat_.context != EGL_NO_CONTEXT);
8258bf80f4bSopenharmony_ci}
8268bf80f4bSopenharmony_ci
8278bf80f4bSopenharmony_civoid EGLState::SaveContext()
8288bf80f4bSopenharmony_ci{
8298bf80f4bSopenharmony_ci    PLUGIN_ASSERT(!oldIsSet_);
8308bf80f4bSopenharmony_ci    oldIsSet_ = true;
8318bf80f4bSopenharmony_ci    GetContext(oldContext_);
8328bf80f4bSopenharmony_ci}
8338bf80f4bSopenharmony_ci
8348bf80f4bSopenharmony_civoid EGLState::SetContext(const SwapchainGLES* swapchain)
8358bf80f4bSopenharmony_ci{
8368bf80f4bSopenharmony_ci    if (swapchain == nullptr) {
8378bf80f4bSopenharmony_ci        SetContext(dummyContext_, true);
8388bf80f4bSopenharmony_ci    } else {
8398bf80f4bSopenharmony_ci        ContextState newContext;
8408bf80f4bSopenharmony_ci        const auto& plat = swapchain->GetPlatformData();
8418bf80f4bSopenharmony_ci        newContext.display = plat_.display;
8428bf80f4bSopenharmony_ci        newContext.context = plat_.context;
8438bf80f4bSopenharmony_ci        newContext.drawSurface = (EGLSurface)plat.surface;
8448bf80f4bSopenharmony_ci        newContext.readSurface = (EGLSurface)plat.surface;
8458bf80f4bSopenharmony_ci        SetContext(newContext, false);
8468bf80f4bSopenharmony_ci
8478bf80f4bSopenharmony_ci        if (vSync_ != plat.vsync) {
8488bf80f4bSopenharmony_ci            vSync_ = plat.vsync;
8498bf80f4bSopenharmony_ci            SetSwapInterval(plat.vsync ? 1u : 0u);
8508bf80f4bSopenharmony_ci        }
8518bf80f4bSopenharmony_ci    }
8528bf80f4bSopenharmony_ci}
8538bf80f4bSopenharmony_ci
8548bf80f4bSopenharmony_civoid EGLState::RestoreContext()
8558bf80f4bSopenharmony_ci{
8568bf80f4bSopenharmony_ci    PLUGIN_ASSERT(oldIsSet_);
8578bf80f4bSopenharmony_ci    SetContext(oldContext_, true);
8588bf80f4bSopenharmony_ci    oldIsSet_ = false;
8598bf80f4bSopenharmony_ci}
8608bf80f4bSopenharmony_ci
8618bf80f4bSopenharmony_civoid EGLState::GetContext(ContextState& state)
8628bf80f4bSopenharmony_ci{
8638bf80f4bSopenharmony_ci    state.display = eglGetCurrentDisplay();
8648bf80f4bSopenharmony_ci    CHECK_EGL_ERROR();
8658bf80f4bSopenharmony_ci    if (state.display != EGL_NO_DISPLAY) {
8668bf80f4bSopenharmony_ci        state.context = eglGetCurrentContext();
8678bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
8688bf80f4bSopenharmony_ci        state.readSurface = eglGetCurrentSurface(EGL_READ);
8698bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
8708bf80f4bSopenharmony_ci        state.drawSurface = eglGetCurrentSurface(EGL_DRAW);
8718bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
8728bf80f4bSopenharmony_ci    } else {
8738bf80f4bSopenharmony_ci        state.context = EGL_NO_CONTEXT;
8748bf80f4bSopenharmony_ci        state.readSurface = EGL_NO_SURFACE;
8758bf80f4bSopenharmony_ci        state.drawSurface = EGL_NO_SURFACE;
8768bf80f4bSopenharmony_ci    }
8778bf80f4bSopenharmony_ci}
8788bf80f4bSopenharmony_ci
8798bf80f4bSopenharmony_civoid EGLState::SetContext(const ContextState& state, bool force)
8808bf80f4bSopenharmony_ci{
8818bf80f4bSopenharmony_ci    PLUGIN_ASSERT(oldIsSet_);
8828bf80f4bSopenharmony_ci    if (state.display != EGL_NO_DISPLAY) {
8838bf80f4bSopenharmony_ci        if ((force) || (oldContext_.display != state.display) || (oldContext_.drawSurface != state.drawSurface) ||
8848bf80f4bSopenharmony_ci            (oldContext_.readSurface != state.readSurface) || (oldContext_.context != state.context)) {
8858bf80f4bSopenharmony_ci            if (eglMakeCurrent(state.display, state.drawSurface, state.readSurface, state.context) == EGL_FALSE) {
8868bf80f4bSopenharmony_ci                CHECK_EGL_ERROR2();
8878bf80f4bSopenharmony_ci                if (eglMakeCurrent(state.display, dummySurface_, dummySurface_, state.context) == EGL_FALSE) {
8888bf80f4bSopenharmony_ci                    CHECK_EGL_ERROR2();
8898bf80f4bSopenharmony_ci                }
8908bf80f4bSopenharmony_ci            }
8918bf80f4bSopenharmony_ci        }
8928bf80f4bSopenharmony_ci    } else {
8938bf80f4bSopenharmony_ci        // Okay, do nothing.
8948bf80f4bSopenharmony_ci        // no display was active, so there can be no surface and no context.
8958bf80f4bSopenharmony_ci        // We need a display to deactivate context. (EGL_NO_DISPLAY is not a valid argument to eglMakeCurrent)
8968bf80f4bSopenharmony_ci        // so what to do, leak context?
8978bf80f4bSopenharmony_ci        // Or just disconnect context/surface from plat_.display (which currently is EGL_DEFAULT_DISPLAY...)
8988bf80f4bSopenharmony_ci        if (eglMakeCurrent(plat_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) {
8998bf80f4bSopenharmony_ci            CHECK_EGL_ERROR2();
9008bf80f4bSopenharmony_ci        }
9018bf80f4bSopenharmony_ci    }
9028bf80f4bSopenharmony_ci}
9038bf80f4bSopenharmony_ci
9048bf80f4bSopenharmony_civoid EGLState::DestroyContext()
9058bf80f4bSopenharmony_ci{
9068bf80f4bSopenharmony_ci    if (plat_.display != EGL_NO_DISPLAY) {
9078bf80f4bSopenharmony_ci        eglMakeCurrent(plat_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
9088bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
9098bf80f4bSopenharmony_ci        if (dummySurface_ != EGL_NO_SURFACE) {
9108bf80f4bSopenharmony_ci            eglDestroySurface(plat_.display, dummySurface_);
9118bf80f4bSopenharmony_ci        }
9128bf80f4bSopenharmony_ci        CHECK_EGL_ERROR();
9138bf80f4bSopenharmony_ci        if (plat_.contextCreated) {
9148bf80f4bSopenharmony_ci            if (plat_.context != EGL_NO_CONTEXT) {
9158bf80f4bSopenharmony_ci                eglDestroyContext(plat_.display, plat_.context);
9168bf80f4bSopenharmony_ci                CHECK_EGL_ERROR();
9178bf80f4bSopenharmony_ci            }
9188bf80f4bSopenharmony_ci        }
9198bf80f4bSopenharmony_ci        if (plat_.eglInitialized) {
9208bf80f4bSopenharmony_ci            eglTerminate(plat_.display);
9218bf80f4bSopenharmony_ci            CHECK_EGL_ERROR();
9228bf80f4bSopenharmony_ci        }
9238bf80f4bSopenharmony_ci    }
9248bf80f4bSopenharmony_ci}
9258bf80f4bSopenharmony_ci
9268bf80f4bSopenharmony_cibool EGLState::HasExtension(const string_view extension) const
9278bf80f4bSopenharmony_ci{
9288bf80f4bSopenharmony_ci    for (const auto& e : dextensionList_) {
9298bf80f4bSopenharmony_ci        if (extension == e)
9308bf80f4bSopenharmony_ci            return true;
9318bf80f4bSopenharmony_ci    }
9328bf80f4bSopenharmony_ci    for (const auto& e : cextensionList_) {
9338bf80f4bSopenharmony_ci        if (extension == e)
9348bf80f4bSopenharmony_ci            return true;
9358bf80f4bSopenharmony_ci    }
9368bf80f4bSopenharmony_ci    return false;
9378bf80f4bSopenharmony_ci}
9388bf80f4bSopenharmony_ci
9398bf80f4bSopenharmony_civoid EGLState::SetSwapInterval(uint32_t interval)
9408bf80f4bSopenharmony_ci{
9418bf80f4bSopenharmony_ci    eglSwapInterval(plat_.display, (EGLint)interval);
9428bf80f4bSopenharmony_ci}
9438bf80f4bSopenharmony_ci
9448bf80f4bSopenharmony_ciconst DevicePlatformData& EGLState::GetPlatformData() const
9458bf80f4bSopenharmony_ci{
9468bf80f4bSopenharmony_ci    return plat_;
9478bf80f4bSopenharmony_ci}
9488bf80f4bSopenharmony_ci
9498bf80f4bSopenharmony_civoid* EGLState::ErrorFilter() const
9508bf80f4bSopenharmony_ci{
9518bf80f4bSopenharmony_ci    return reinterpret_cast<void*>(FilterError);
9528bf80f4bSopenharmony_ci}
9538bf80f4bSopenharmony_ci
9548bf80f4bSopenharmony_ciuintptr_t EGLState::CreateSurface(uintptr_t window, uintptr_t instance) const noexcept
9558bf80f4bSopenharmony_ci{
9568bf80f4bSopenharmony_ci    // Check if sRGB colorspace is supported by EGL.
9578bf80f4bSopenharmony_ci    const bool isSrgbSurfaceSupported = IsSrgbSurfaceSupported(plat_);
9588bf80f4bSopenharmony_ci
9598bf80f4bSopenharmony_ci    EGLint attribsSrgb[] = { EGL_NONE, EGL_NONE, EGL_NONE };
9608bf80f4bSopenharmony_ci    if (isSrgbSurfaceSupported) {
9618bf80f4bSopenharmony_ci        if (IsVersionGreaterOrEqual(1, 5)) { // 5 : param
9628bf80f4bSopenharmony_ci            attribsSrgb[0] = EGL_GL_COLORSPACE;
9638bf80f4bSopenharmony_ci            attribsSrgb[1] = EGL_GL_COLORSPACE_SRGB;
9648bf80f4bSopenharmony_ci        } else if (hasColorSpaceExt_) {
9658bf80f4bSopenharmony_ci            attribsSrgb[0] = EGL_GL_COLORSPACE_KHR;
9668bf80f4bSopenharmony_ci            attribsSrgb[1] = EGL_GL_COLORSPACE_SRGB_KHR;
9678bf80f4bSopenharmony_ci        }
9688bf80f4bSopenharmony_ci    }
9698bf80f4bSopenharmony_ci    EGLSurface eglSurface = eglCreateWindowSurface(plat_.display, plat_.config,
9708bf80f4bSopenharmony_ci        reinterpret_cast<EGLNativeWindowType>(window), isSrgbSurfaceSupported ? attribsSrgb : nullptr);
9718bf80f4bSopenharmony_ci    if (eglSurface == EGL_NO_SURFACE) {
9728bf80f4bSopenharmony_ci        EGLint error = eglGetError();
9738bf80f4bSopenharmony_ci        PLUGIN_LOG_E("eglCreateWindowSurface failed (with null attributes): %d", error);
9748bf80f4bSopenharmony_ci    }
9758bf80f4bSopenharmony_ci    return reinterpret_cast<uintptr_t>(eglSurface);
9768bf80f4bSopenharmony_ci}
9778bf80f4bSopenharmony_ci
9788bf80f4bSopenharmony_civoid EGLState::DestroySurface(uintptr_t surface) const noexcept
9798bf80f4bSopenharmony_ci{
9808bf80f4bSopenharmony_ci    if (reinterpret_cast<EGLSurface>(surface) != EGL_NO_SURFACE) {
9818bf80f4bSopenharmony_ci        eglDestroySurface(plat_.display, reinterpret_cast<EGLSurface>(surface));
9828bf80f4bSopenharmony_ci    }
9838bf80f4bSopenharmony_ci}
9848bf80f4bSopenharmony_ci
9858bf80f4bSopenharmony_cibool EGLState::GetSurfaceInformation(
9868bf80f4bSopenharmony_ci    const DevicePlatformDataGLES& plat, EGLSurface surface, GlesImplementation::SurfaceInfo& res) const
9878bf80f4bSopenharmony_ci{
9888bf80f4bSopenharmony_ci    EGLDisplay display = plat.display;
9898bf80f4bSopenharmony_ci
9908bf80f4bSopenharmony_ci#ifndef NDEBUG
9918bf80f4bSopenharmony_ci    PLUGIN_LOG_V("EGLState::GetSurfaceInformation: input surface information:");
9928bf80f4bSopenharmony_ci    DumpEGLSurface(display, surface);
9938bf80f4bSopenharmony_ci#endif
9948bf80f4bSopenharmony_ci    EGLint configId;
9958bf80f4bSopenharmony_ci    // Get configId from surface
9968bf80f4bSopenharmony_ci    if (eglQuerySurface(display, surface, EGL_CONFIG_ID, &configId) == false) {
9978bf80f4bSopenharmony_ci        PLUGIN_LOG_E("EGLState::GetSurfaceInformation: Could not fetch surface config_id.");
9988bf80f4bSopenharmony_ci        return false;
9998bf80f4bSopenharmony_ci    }
10008bf80f4bSopenharmony_ci
10018bf80f4bSopenharmony_ci    EGLConfig config = EGL_NO_CONFIG_KHR;
10028bf80f4bSopenharmony_ci    EGLint numconfigs = 0;
10038bf80f4bSopenharmony_ci    EGLint attrs[] = { EGL_CONFIG_ID, configId, EGL_NONE };
10048bf80f4bSopenharmony_ci    if (eglChooseConfig(display, attrs, &config, 1, &numconfigs) == false) {
10058bf80f4bSopenharmony_ci        PLUGIN_LOG_E("EGLState::GetSurfaceInformation: Could not fetch surface config.");
10068bf80f4bSopenharmony_ci        return false;
10078bf80f4bSopenharmony_ci    }
10088bf80f4bSopenharmony_ci
10098bf80f4bSopenharmony_ci    PLUGIN_LOG_V("EGLState::GetSurfaceInformation: input surface configuration:");
10108bf80f4bSopenharmony_ci    DumpEGLConfig(display, config);
10118bf80f4bSopenharmony_ci
10128bf80f4bSopenharmony_ci#ifndef NDEBUG
10138bf80f4bSopenharmony_ci    if (!hasConfiglessExt_) {
10148bf80f4bSopenharmony_ci        // Check that it matches the config id from "system config"
10158bf80f4bSopenharmony_ci        EGLConfig plat_config = plat.config;
10168bf80f4bSopenharmony_ci        if ((plat_config != EGL_NO_CONFIG_KHR) && (plat_config != config)) {
10178bf80f4bSopenharmony_ci            PLUGIN_ASSERT_MSG(plat_config == config, "display config and surface config should match!");
10188bf80f4bSopenharmony_ci            PLUGIN_LOG_V("EGLState::GetSurfaceInformation: plat surface configuration:");
10198bf80f4bSopenharmony_ci            EGLHelpers::DumpEGLConfig(display, plat_config);
10208bf80f4bSopenharmony_ci        }
10218bf80f4bSopenharmony_ci    }
10228bf80f4bSopenharmony_ci#endif
10238bf80f4bSopenharmony_ci
10248bf80f4bSopenharmony_ci    // Fetch surface parameters
10258bf80f4bSopenharmony_ci    EGLint width = 0;
10268bf80f4bSopenharmony_ci    EGLint height = 0;
10278bf80f4bSopenharmony_ci    EGLint red_size = 0;
10288bf80f4bSopenharmony_ci    EGLint green_size = 0;
10298bf80f4bSopenharmony_ci    EGLint blue_size = 0;
10308bf80f4bSopenharmony_ci    EGLint alpha_size = 0;
10318bf80f4bSopenharmony_ci    EGLint samples = 0;
10328bf80f4bSopenharmony_ci    EGLint depth_size = 0;
10338bf80f4bSopenharmony_ci    EGLint stencil_size = 0;
10348bf80f4bSopenharmony_ci    eglQuerySurface(display, surface, EGL_WIDTH, &width);
10358bf80f4bSopenharmony_ci    eglQuerySurface(display, surface, EGL_HEIGHT, &height);
10368bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red_size);
10378bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green_size);
10388bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue_size);
10398bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha_size);
10408bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
10418bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth_size);
10428bf80f4bSopenharmony_ci    eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil_size);
10438bf80f4bSopenharmony_ci
10448bf80f4bSopenharmony_ci    res.configId = (uint32_t)configId;
10458bf80f4bSopenharmony_ci    res.alpha_size = (uint32_t)alpha_size;
10468bf80f4bSopenharmony_ci    res.blue_size = (uint32_t)blue_size;
10478bf80f4bSopenharmony_ci    res.depth_size = (uint32_t)depth_size;
10488bf80f4bSopenharmony_ci    res.green_size = (uint32_t)green_size;
10498bf80f4bSopenharmony_ci    res.height = (uint32_t)height;
10508bf80f4bSopenharmony_ci    res.red_size = (uint32_t)red_size;
10518bf80f4bSopenharmony_ci    res.samples = (uint32_t)samples;
10528bf80f4bSopenharmony_ci    res.stencil_size = (uint32_t)stencil_size;
10538bf80f4bSopenharmony_ci    res.width = (uint32_t)width;
10548bf80f4bSopenharmony_ci
10558bf80f4bSopenharmony_ci    EGLint colorspace = 0;
10568bf80f4bSopenharmony_ci    EGLint COLOR_SPACE = 0;
10578bf80f4bSopenharmony_ci    EGLint COLOR_SPACE_SRGB = 0;
10588bf80f4bSopenharmony_ci    if (IsVersionGreaterOrEqual(1, 5)) {
10598bf80f4bSopenharmony_ci        COLOR_SPACE = EGL_GL_COLORSPACE;
10608bf80f4bSopenharmony_ci        COLOR_SPACE_SRGB = EGL_GL_COLORSPACE_SRGB;
10618bf80f4bSopenharmony_ci    } else if (hasColorSpaceExt_) {
10628bf80f4bSopenharmony_ci        COLOR_SPACE = EGL_GL_COLORSPACE_KHR;
10638bf80f4bSopenharmony_ci        COLOR_SPACE_SRGB = EGL_GL_COLORSPACE_SRGB_KHR;
10648bf80f4bSopenharmony_ci    }
10658bf80f4bSopenharmony_ci
10668bf80f4bSopenharmony_ci    if (COLOR_SPACE > 0) {
10678bf80f4bSopenharmony_ci        if (eglQuerySurface(display, surface, COLOR_SPACE, &colorspace)) {
10688bf80f4bSopenharmony_ci            // EGL_GL_COLORSPACE_SRGB or EGL_GL_COLORSPACE_LINEAR.
10698bf80f4bSopenharmony_ci            res.srgb = (colorspace == COLOR_SPACE_SRGB);
10708bf80f4bSopenharmony_ci        }
10718bf80f4bSopenharmony_ci    }
10728bf80f4bSopenharmony_ci
10738bf80f4bSopenharmony_ci    if (colorspace == 0) {
10748bf80f4bSopenharmony_ci        // surface is linear (no conversion made during read/write)
10758bf80f4bSopenharmony_ci        // data should be srgb though.
10768bf80f4bSopenharmony_ci        PLUGIN_LOG_E("EGL_GL_COLORSPACE query failed (or not available). Defaulting to linear buffer with srgb data");
10778bf80f4bSopenharmony_ci        res.srgb = false;
10788bf80f4bSopenharmony_ci    }
10798bf80f4bSopenharmony_ci
10808bf80f4bSopenharmony_ci    return true;
10818bf80f4bSopenharmony_ci}
10828bf80f4bSopenharmony_ci
10838bf80f4bSopenharmony_civoid EGLState::SwapBuffers(const SwapchainGLES& swapchain)
10848bf80f4bSopenharmony_ci{
10858bf80f4bSopenharmony_ci    SetContext(&swapchain);
10868bf80f4bSopenharmony_ci    const auto& platSwapchain = static_cast<const SwapchainPlatformDataGL&>(swapchain.GetPlatformData());
10878bf80f4bSopenharmony_ci    eglSwapBuffers(plat_.display, (EGLSurface)platSwapchain.surface);
10888bf80f4bSopenharmony_ci}
10898bf80f4bSopenharmony_ci} // namespace EGLHelpers
10908bf80f4bSopenharmony_ciRENDER_END_NAMESPACE()
10918bf80f4bSopenharmony_ci#endif
1092