1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #if RENDER_HAS_GLES_BACKEND
17 
18 #include "egl_state.h"
19 
20 #include <EGL/egl.h>
21 #include <EGL/eglext.h>
22 
23 #ifndef EGL_VERSION_1_5
24 // If egl 1.5 headers not available, just define the values here.
25 // (copied from khronos specifications)
26 #define EGL_CONTEXT_MAJOR_VERSION 0x3098
27 #define EGL_CONTEXT_MINOR_VERSION 0x30FB
28 #define EGL_OPENGL_ES3_BIT 0x00000040
29 #define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
30 #define EGL_GL_COLORSPACE 0x309D
31 #define EGL_GL_COLORSPACE_SRGB 0x3089
32 #define EGL_GL_COLORSPACE_LINEAR 0x308A
33 typedef intptr_t EGLAttrib;
34 #endif
35 
36 #ifndef EGL_KHR_create_context
37 // If EGL_KHR_create_context extension not defined in headers, so just define the values here.
38 // (copied from khronos specifications)
39 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
40 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
41 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
42 #define EGL_CONTEXT_FLAGS_KHR 0x30FC
43 #define EGL_OPENGL_ES3_BIT_KHR 0x00000040
44 #endif
45 
46 #ifndef EGL_KHR_gl_colorspace
47 // If EGL_KHR_gl_colorspace extension not defined in headers, so just define the values here.
48 // (copied from khronos specifications)
49 #define EGL_GL_COLORSPACE_KHR 0x309D
50 #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
51 #define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
52 #endif /* EGL_KHR_gl_colorspace */
53 
54 #ifndef EGL_KHR_no_config_context
55 // If #ifndef EGL_KHR_no_config_context extension not defined in headers, so just define the values here.
56 // (copied from khronos specifications)
57 #define EGL_NO_CONFIG_KHR ((EGLConfig)0)
58 #endif
59 
60 #include <securec.h>
61 
62 #include <render/namespace.h>
63 
64 #include "gles/gl_functions.h"
65 #include "util/log.h"
66 #define declare(a, b) a b = nullptr;
67 #include "gles/gl_functions.h"
68 #define declare(a, b) a b = nullptr;
69 #include "gles/egl_functions.h"
70 #include "gles/surface_information.h"
71 #include "gles/swapchain_gles.h"
72 
73 #if RENDER_GL_DEBUG
74 #define CHECK_EGL_ERROR() EGLHelpers::CheckEGLError(PLUGIN_FILE_INFO)
75 #define CHECK_EGL_ERROR2() EGLHelpers::CheckEGLError2(PLUGIN_FILE_INFO)
76 #else
77 #define CHECK_EGL_ERROR()
78 #define CHECK_EGL_ERROR2() EGLHelpers::CheckEGLError2(PLUGIN_FILE_INFO)
79 #endif
80 
81 RENDER_BEGIN_NAMESPACE()
82 using BASE_NS::string;
83 using BASE_NS::string_view;
84 using BASE_NS::vector;
85 
86 namespace EGLHelpers {
87 namespace {
FilterError(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei,const string_view,const void *)88 static bool FilterError(
89     GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei, const string_view, const void*) noexcept
90 {
91     if (source == GL_DEBUG_SOURCE_OTHER) {
92         if (type == GL_DEBUG_TYPE_PERFORMANCE) {
93             if ((id == 2147483647) && (severity == GL_DEBUG_SEVERITY_HIGH)) { // 2147483647:big data
94                 /*  Ignore the following warning that Adreno drivers seem to spam.
95                 source: GL_DEBUG_SOURCE_OTHER
96                 type: GL_DEBUG_TYPE_PERFORMANCE
97                 id: 2147483647
98                 severity: GL_DEBUG_SEVERITY_HIGH
99                 message: FreeAllocationOnTimestamp - WaitForTimestamp
100                 */
101                 return true;
102             }
103         }
104     }
105     return false;
106 }
107 
EglErrorStr(EGLint aError)108 const char* EglErrorStr(EGLint aError)
109 {
110     switch (aError) {
111         case EGL_SUCCESS:
112             return "The last function succeeded without error.";
113         case EGL_NOT_INITIALIZED:
114             return "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
115         case EGL_BAD_ACCESS:
116             return "EGL cannot access a requested resource(for example a context is bound in another thread).";
117         case EGL_BAD_ALLOC:
118             return "EGL failed to allocate resources for the requested operation.";
119         case EGL_BAD_ATTRIBUTE:
120             return "An unrecognized attribute or attribute value was passed in the attribute list.";
121         case EGL_BAD_CONTEXT:
122             return "An EGLContext argument does not name a valid EGL rendering context.";
123         case EGL_BAD_CONFIG:
124             return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
125         case EGL_BAD_CURRENT_SURFACE:
126             return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer "
127                    "valid.";
128         case EGL_BAD_DISPLAY:
129             return "An EGLDisplay argument does not name a valid EGL display connection.";
130         case EGL_BAD_SURFACE:
131             return "An EGLSurface argument does not name a valid surface(window, pixel buffer or pixmap) configured "
132                    "for GL rendering.";
133         case EGL_BAD_MATCH:
134             return "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid "
135                    "surface).";
136         case EGL_BAD_PARAMETER:
137             return "One or more argument values are invalid.";
138         case EGL_BAD_NATIVE_PIXMAP:
139             return "A NativePixmapType argument does not refer to a valid native pixmap.";
140         case EGL_BAD_NATIVE_WINDOW:
141             return "A NativeWindowType argument does not refer to a valid native window.";
142         case EGL_CONTEXT_LOST:
143             return "A power management event has occurred.The application must destroy all contexts and reinitialise "
144                    "OpenGL ES state and objects to continue rendering.";
145         default:
146             break;
147     }
148 
149     static char error[64];
150     if (sprintf_s(error, sizeof(error), "Unknown error %x", aError) < 0) {
151         PLUGIN_LOG_E("EglErrorStr: sprintf_s failed");
152     }
153     return error;
154 }
155 
CheckEGLError(const char * const file,int line)156 void CheckEGLError(const char* const file, int line)
157 {
158     EGLint error = eglGetError();
159     if (error != EGL_SUCCESS) {
160         PLUGIN_LOG_E("eglGetError failed : %s (%s %d)", EglErrorStr(error), file, line);
161         PLUGIN_ASSERT(false);
162     }
163 }
164 
CheckEGLError2(const char * const file,int line)165 void CheckEGLError2(const char* const file, int line)
166 {
167     EGLint error = eglGetError();
168     if (error != EGL_SUCCESS) {
169         PLUGIN_LOG_E("eglGetError failed : %s (%s %d)", EglErrorStr(error), file, line);
170     }
171 }
172 
173 #define ATTRIBUTE(_attr) \
174     {                    \
175         _attr, #_attr    \
176     }
177 
178 struct Attribute {
179     EGLint attribute;
180     char const* const Name;
181 };
182 
DumpEGLStrings(EGLDisplay dpy)183 void DumpEGLStrings(EGLDisplay dpy)
184 {
185     // extensions dumped later.
186     static constexpr Attribute strings[] = { ATTRIBUTE(EGL_CLIENT_APIS), ATTRIBUTE(EGL_VENDOR),
187         ATTRIBUTE(EGL_VERSION) };
188     for (size_t attr = 0; attr < sizeof(strings) / sizeof(Attribute); attr++) {
189         const char* const value = eglQueryString(dpy, strings[attr].attribute);
190         if (value) {
191             PLUGIN_LOG_D("\t%-32s: %s", strings[attr].Name, value);
192         } else {
193             PLUGIN_LOG_D("\t%-32s:", strings[attr].Name);
194         }
195     }
196 }
197 
198 #ifdef PLUGIN_UNUSED_EGL_HELPERS
DumpEGLConfigs(EGLDisplay dpy)199 void DumpEGLConfigs(EGLDisplay dpy)
200 {
201     EGLConfig* configs = nullptr;
202     EGLint n = 0;
203 
204     eglGetConfigs(dpy, NULL, 0, &n);
205     configs = new EGLConfig[(size_t)n];
206     eglGetConfigs(dpy, configs, n, &n);
207     for (EGLint i = 0; i < n; i++) {
208         PLUGIN_LOG_V("EGLConfig[%d]", i);
209         DumpEGLConfig(dpy, configs[i]);
210     }
211     delete[] configs;
212 }
213 #endif
214 
stringToUInt(string_view string,EGLint & value)215 bool stringToUInt(string_view string, EGLint& value)
216 {
217     value = 0;
218     for (auto digit : string) {
219         value *= 10;
220         if ((digit >= '0') && (digit <= '9')) {
221             value += digit - '0';
222         } else {
223             return false;
224         }
225     }
226     return true;
227 }
228 
DumpEGLSurface(EGLDisplay dpy,EGLSurface surf)229 void DumpEGLSurface(EGLDisplay dpy, EGLSurface surf)
230 {
231     static constexpr Attribute attribs[] = {
232         // Returns the ID of the EGL frame buffer configuration with respect to which the surface was created.
233         ATTRIBUTE(EGL_CONFIG_ID),
234         // Returns the color space used by OpenGL and OpenGL ES when rendering to the surface, either
235         // EGL_GL_COLORSPACE_SRGB or EGL_GL_COLORSPACE_LINEAR.
236         ATTRIBUTE(EGL_GL_COLORSPACE),
237         // Returns the height of the surface in pixels
238         ATTRIBUTE(EGL_HEIGHT),
239         // Returns the horizontal dot pitch of the display on which a window surface is  visible.The value returned is
240         // equal to the actual dot pitch, in pixels meter, multiplied by the constant value EGL_DISPLAY_SCALING.
241         ATTRIBUTE(EGL_HORIZONTAL_RESOLUTION),
242         // Returns the same attribute value specified when the surface was created with  eglCreatePbufferSurface.For a
243         // window or pixmap surface, value is not modified.
244         ATTRIBUTE(EGL_LARGEST_PBUFFER),
245         ATTRIBUTE(EGL_MIPMAP_LEVEL),   // Returns which level of the mipmap to render to, if texture has mipmaps.
246         ATTRIBUTE(EGL_MIPMAP_TEXTURE), // Returns EGL_TRUE if texture has mipmaps, EGL_FALSE otherwise.
247         // Returns the filter used when resolving the multisample buffer.The filter may be either
248         // EGL_MULTISAMPLE_RESOLVE_DEFAULT or EGL_MULTISAMPLE_RESOLVE_BOX, as described for eglSurfaceAttrib.
249         ATTRIBUTE(EGL_MULTISAMPLE_RESOLVE),
250         // Returns the aspect ratio of an individual pixel(the ratio of a pixel's width to its height). The value
251         // returned is equal to the actual aspect ratio multiplied by the constant value EGL_DISPLAY_SCALING.
252         ATTRIBUTE(EGL_PIXEL_ASPECT_RATIO),
253         // Returns the buffer which client API rendering is requested to use.For a window surface, this is the same
254         // attribute value specified when the surface was created.For a pbuffer surface, it is always
255         // EGL_BACK_BUFFER.For a pixmap surface, it is always EGL_SINGLE_BUFFER.To determine the actual buffer being
256         // rendered to by a context, call eglQueryContext.
257         ATTRIBUTE(EGL_RENDER_BUFFER),
258         // Returns the effect on the color buffer when posting a surface with eglSwapBuffers.Swap behavior may be either
259         // EGL_BUFFER_PRESERVED or EGL_BUFFER_DESTROYED, as described for eglSurfaceAttrib.
260         ATTRIBUTE(EGL_SWAP_BEHAVIOR),
261         // Returns format of texture.Possible values are EGL_NO_TEXTURE, EGL_TEXTURE_RGB, and EGL_TEXTURE_RGBA.
262         ATTRIBUTE(EGL_TEXTURE_FORMAT),
263         ATTRIBUTE(EGL_TEXTURE_TARGET), // Returns type of texture.Possible values are EGL_NO_TEXTURE, or EGL_TEXTURE_2D.
264         // Returns the vertical dot pitch of the display on which a window surface is visible.The value returned is
265         // equal to the actual dot pitch, in pixels  / meter, multiplied by the constant value EGL_DISPLAY_SCALING.
266         ATTRIBUTE(EGL_VERTICAL_RESOLUTION),
267         // Returns the interpretation of alpha values used by OpenVG when rendering to the surface, either
268         // EGL_VG_ALPHA_FORMAT_NONPRE or EGL_VG_ALPHA_FORMAT_PRE.
269         ATTRIBUTE(EGL_VG_ALPHA_FORMAT),
270         // Returns the color space used by OpenVG when rendering to the surface, either EGL_VG_COLORSPACE_sRGB or
271         // EGL_VG_COLORSPACE_LINEAR.
272         ATTRIBUTE(EGL_VG_COLORSPACE),
273         ATTRIBUTE(EGL_WIDTH), // Returns the width of the surface in pixels.
274     };
275     for (size_t attr = 0; attr < sizeof(attribs) / sizeof(Attribute); attr++) {
276         EGLint value;
277         if (EGL_TRUE == eglQuerySurface(dpy, surf, attribs[attr].attribute, &value)) {
278             PLUGIN_LOG_V("\t%-32s: %10d (0x%08x)", attribs[attr].Name, value, value);
279         }
280     }
281 }
282 
DumpEGLConfig(EGLDisplay dpy,const EGLConfig & config)283 void DumpEGLConfig(EGLDisplay dpy, const EGLConfig& config)
284 {
285     static constexpr Attribute attributes[] = {
286         ATTRIBUTE(EGL_ALPHA_SIZE),      // Returns the number of bits of alpha stored in the color buffer.
287         ATTRIBUTE(EGL_ALPHA_MASK_SIZE), // Returns the number of bits in the alpha mask buffer.
288         // Returns EGL_TRUE if color buffers can be bound to an RGB texture,  EGL_FALSE otherwise.
289         ATTRIBUTE(EGL_BIND_TO_TEXTURE_RGB),
290         // Returns EGL_TRUE if color buffers can be bound to an RGBA texture, EGL_FALSE otherwise.
291         ATTRIBUTE(EGL_BIND_TO_TEXTURE_RGBA),
292         ATTRIBUTE(EGL_BLUE_SIZE), // Returns the number of bits of blue stored in the color buffer.
293         // Returns the depth of the color buffer.It is the sum of EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, and
294         // EGL_ALPHA_SIZE.
295         ATTRIBUTE(EGL_BUFFER_SIZE),
296         // Returns the color buffer type.Possible types are EGL_RGB_BUFFER and  EGL_LUMINANCE_BUFFER.
297         ATTRIBUTE(EGL_COLOR_BUFFER_TYPE),
298         // Returns the caveats for the frame buffer configuration.Possible caveat values  are EGL_NONE, EGL_SLOW_CONFIG,
299         // and EGL_NON_CONFORMANT.
300         ATTRIBUTE(EGL_CONFIG_CAVEAT),
301         ATTRIBUTE(EGL_CONFIG_ID), // Returns the ID of the frame buffer configuration.
302         // Returns a bitmask indicating which client API contexts created with respect to this
303         // config are conformant.
304         ATTRIBUTE(EGL_CONFORMANT),
305         ATTRIBUTE(EGL_DEPTH_SIZE), // Returns the number of bits in the depth buffer.
306         ATTRIBUTE(EGL_GREEN_SIZE), // Returns the number of bits of green stored in the color buffer.
307         // Returns the frame buffer level.Level zero is the default frame buffer.Positive levels correspond to frame
308         // buffers that overlay the default buffer and negative levels correspond to frame buffers that underlay the
309         // default buffer.
310         ATTRIBUTE(EGL_LEVEL),
311         ATTRIBUTE(EGL_LUMINANCE_SIZE),     // Returns the number of bits of luminance stored in the luminance buffer.
312         ATTRIBUTE(EGL_MAX_PBUFFER_WIDTH),  // Returns the maximum width of a pixel buffer surface in pixels.
313         ATTRIBUTE(EGL_MAX_PBUFFER_HEIGHT), // Returns the maximum height of a pixel buffer surface in pixels.
314         ATTRIBUTE(EGL_MAX_PBUFFER_PIXELS), // Returns the maximum size of a pixel buffer surface in pixels.
315         ATTRIBUTE(EGL_MAX_SWAP_INTERVAL),  // Returns the maximum value that can be passed to eglSwapInterval.
316         ATTRIBUTE(EGL_MIN_SWAP_INTERVAL),  // Returns the minimum value that can be passed to eglSwapInterval.
317         // Returns EGL_TRUE if native rendering APIs can render into the surface, EGL_FALSE otherwise.
318         ATTRIBUTE(EGL_NATIVE_RENDERABLE),
319         ATTRIBUTE(EGL_NATIVE_VISUAL_ID),   // Returns the ID of the associated native visual.
320         ATTRIBUTE(EGL_NATIVE_VISUAL_TYPE), // Returns the type of the associated native visual.
321         ATTRIBUTE(EGL_RED_SIZE),           // Returns the number of bits of red stored in the color buffer.
322         ATTRIBUTE(EGL_RENDERABLE_TYPE),    // Returns a bitmask indicating the types of supported client API contexts.
323         ATTRIBUTE(EGL_SAMPLE_BUFFERS),     // Returns the number of multisample buffers.
324         ATTRIBUTE(EGL_SAMPLES),            // Returns the number of samples per pixel.
325         ATTRIBUTE(EGL_STENCIL_SIZE),       // Returns the number of bits in the stencil buffer.
326         ATTRIBUTE(EGL_SURFACE_TYPE),       // Returns a bitmask indicating the types of supported EGL surfaces.
327         // Returns the type of supported transparency.Possible transparency values are  EGL_NONE, and
328         // EGL_TRANSPARENT_RGB.
329         ATTRIBUTE(EGL_TRANSPARENT_TYPE),
330         ATTRIBUTE(EGL_TRANSPARENT_RED_VALUE),   // Returns the transparent red value.
331         ATTRIBUTE(EGL_TRANSPARENT_GREEN_VALUE), // Returns the transparent green value.
332         ATTRIBUTE(EGL_TRANSPARENT_BLUE_VALUE),  // Returns the transparent blue value.
333         // ATTRIBUTE(EGL_MATCH_NATIVE_PIXMAP),  While EGL_MATCH_NATIVE_PIXMAP can be specified in the attribute list
334         // passed to eglChooseConfig, it is not an attribute of the resulting config and cannot be queried using
335         // eglGetConfigAttrib.
336     };
337     for (size_t attr = 0; attr < sizeof(attributes) / sizeof(Attribute); attr++) {
338         EGLint value;
339         if (EGL_TRUE == eglGetConfigAttrib(dpy, config, attributes[attr].attribute, &value)) {
340             PLUGIN_LOG_V("\t%-32s: %10d (0x%08x)", attributes[attr].Name, value, value);
341         }
342     }
343 }
344 
ParseExtensions(const string & extensions,vector<string_view> & extensionList)345 void ParseExtensions(const string& extensions, vector<string_view>& extensionList)
346 {
347     size_t start = 0;
348     for (auto end = extensions.find(' '); end != string::npos; end = extensions.find(' ', start)) {
349         extensionList.emplace_back(extensions.data() + start, end - start);
350         start = end + 1;
351     }
352     if (start < extensions.size()) {
353         extensionList.emplace_back(extensions.data() + start);
354     }
355 }
356 
FillProperties(DevicePropertiesGLES & properties)357 void FillProperties(DevicePropertiesGLES& properties)
358 {
359     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &properties.maxCombinedTextureImageUnits);
360     glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &properties.maxCubeMapTextureSize);
361     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &properties.maxFragmentUniformVectors);
362     glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &properties.maxRenderbufferSize);
363     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &properties.maxTextureImageUnits);
364     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &properties.maxTextureSize);
365     glGetIntegerv(GL_MAX_VARYING_VECTORS, &properties.maxVaryingVectors);
366     glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &properties.maxVertexAttribs);
367     glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &properties.maxVertexTextureImageUnits);
368     glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &properties.maxVertexUniformVectors);
369     glGetFloatv(GL_MAX_VIEWPORT_DIMS, properties.maxViewportDims);
370     glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &properties.numCompressedTextureFormats);
371     glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &properties.numShaderBinaryFormats);
372     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &properties.numProgramBinaryFormats);
373 
374     glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &properties.max3DTextureSize);
375     glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &properties.maxArrayTextureLayers);
376     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &properties.maxColorAttachments);
377     glGetInteger64v(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxCombinedFragmentUniformComponents);
378     glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &properties.maxCombinedUniformBlocks);
379     glGetInteger64v(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, &properties.maxCombinedVertexUniformComponents);
380     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &properties.maxDrawBuffers);
381     glGetInteger64v(GL_MAX_ELEMENT_INDEX, &properties.maxElementIndex);
382     glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &properties.maxElementsIndices);
383     glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &properties.maxElementsVertices);
384     glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &properties.maxFragmentInputComponents);
385     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &properties.maxFragmentUniformBlocks);
386     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxFragmentUniformComponents);
387     glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &properties.minProgramTexelOffset);
388     glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &properties.maxProgramTexelOffset);
389     glGetIntegerv(GL_MAX_SAMPLES, &properties.maxSamples);
390     glGetInteger64v(GL_MAX_SERVER_WAIT_TIMEOUT, &properties.maxServerWaitTimeout);
391     glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &properties.maxTextureLodBias);
392     glGetIntegerv(
393         GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &properties.maxTransformFeedbackInterleavedComponents);
394     glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &properties.maxTransformFeedbackSeparateAttribs);
395     glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &properties.maxTransformFeedbackSeparateComponents);
396     glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &properties.maxUniformBlockSize);
397     glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &properties.maxUniformBufferBindings);
398     glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &properties.maxVaryingComponents);
399     glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &properties.maxVertexOutputComponents);
400     glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &properties.maxVertexUniformBlocks);
401     glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &properties.maxVertexUniformComponents);
402 
403     glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &properties.maxAtomicCounterBufferBindings);
404     glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &properties.maxAtomicCounterBufferSize);
405     glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &properties.maxColorTextureSamples);
406     glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &properties.maxCombinedAtomicCounters);
407     glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, &properties.maxCombinedAtomicCounterBuffers);
408     glGetIntegerv(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, &properties.maxCombinedComputeUniformComponents);
409     glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &properties.maxCombinedImageUniforms);
410     glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &properties.maxCombinedShaderOutputResources);
411     glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &properties.maxCombinedShaderStorageBlocks);
412     glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &properties.maxComputeAtomicCounters);
413     glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &properties.maxComputeAtomicCounterBuffers);
414     glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &properties.maxComputeImageUniforms);
415     glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &properties.maxComputeShaderStorageBlocks);
416     glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &properties.maxComputeSharedMemorySize);
417     glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &properties.maxComputeTextureImageUnits);
418     glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &properties.maxComputeUniformBlocks);
419     glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, &properties.maxComputeUniformComponents);
420     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, properties.maxComputeWorkGroupCount);
421     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, properties.maxComputeWorkGroupCount + 1);
422     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, properties.maxComputeWorkGroupCount + 2); // 2 : param
423     glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &properties.maxComputeWorkGroupInvocations);
424     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, properties.maxComputeWorkGroupSize);
425     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, properties.maxComputeWorkGroupSize + 1);
426     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, properties.maxComputeWorkGroupSize + 2); // 2 : param
427     glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &properties.maxDepthTextureSamples);
428     glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &properties.maxFragmentAtomicCounters);
429     glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &properties.maxFragmentAtomicCounterBuffers);
430     glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &properties.maxFragmentImageUniforms);
431     glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &properties.maxFragmentShaderStorageBlocks);
432     glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &properties.maxFramebufferHeight);
433     glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &properties.maxFramebufferSamples);
434     glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &properties.maxFramebufferWidth);
435     glGetIntegerv(GL_MAX_IMAGE_UNITS, &properties.maxImageUnits);
436     glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &properties.maxIntegerSamples);
437     glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.minProgramTextureGatherOffset);
438     glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.maxProgramTextureGatherOffset);
439     glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &properties.maxSampleMaskWords);
440     glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &properties.maxShaderStorageBlockSize);
441     glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &properties.maxShaderStorageBufferBindings);
442     glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &properties.maxUniformLocations);
443     glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &properties.maxVertexAtomicCounters);
444     glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &properties.maxVertexAtomicCounterBuffers);
445     glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &properties.maxVertexAttribBindings);
446     glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &properties.maxVertexAttribRelativeOffset);
447     glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &properties.maxVertexAttribStride);
448     glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &properties.maxVertexImageUniforms);
449     glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &properties.maxVertexShaderStorageBlocks);
450     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &properties.uniformBufferOffsetAlignment);
451     glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &properties.shaderStorageBufferOffsetAlignment);
452 
453     glGetIntegerv(GL_MIN_SAMPLE_SHADING_VALUE, &properties.minSampleShadingValue);
454     glGetIntegerv(GL_MAX_DEBUG_GROUP_STACK_DEPTH, &properties.maxDebugGroupStackDepth);
455     glGetIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES, &properties.maxDebugLoggedMessages);
456     glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &properties.maxDebugMessageLength);
457     glGetFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, &properties.minFragmentInterpolationOffset);
458     glGetFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, &properties.maxFragmentInterpolationOffset);
459     glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS, &properties.maxFramebufferLayers);
460     glGetIntegerv(GL_MAX_LABEL_LENGTH, &properties.maxLabelLength);
461     glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &properties.maxTextureBufferSize);
462 }
463 
IsSrgbSurfaceSupported(const DevicePlatformDataGLES & plat)464 bool IsSrgbSurfaceSupported(const DevicePlatformDataGLES& plat)
465 {
466     // Check if EGL supports sRGB color space (either EGL is > 1.5 or EGL_KHR_gl_colorspace extension is supported).
467     if (plat.majorVersion > 1u || (plat.majorVersion == 1u && plat.minorVersion >= 5u)) {
468         // EGL 1.5 or newer -> no need to check the extension.
469         return true;
470     }
471     // Check if the sRGB color space extension is supported.
472     return plat.hasColorSpaceExt;
473 }
474 
475 } // namespace
476 
477 #undef ATTRIBUTE
HandleExtensions()478 void EGLState::HandleExtensions()
479 {
480     if (plat_.minorVersion > 4) {
481         cextensions_ = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
482         CHECK_EGL_ERROR();
483         PLUGIN_LOG_D("\t%-32s: %s", "EGL_EXTENSIONS (CLIENT)", cextensions_.c_str());
484         ParseExtensions(cextensions_, cextensionList_);
485     }
486 
487     dextensions_ = eglQueryString(plat_.display, EGL_EXTENSIONS);
488     CHECK_EGL_ERROR();
489     ParseExtensions(dextensions_, dextensionList_);
490     PLUGIN_LOG_D("\t%-32s: %s", "EGL_EXTENSIONS (DISPLAY)", dextensions_.c_str());
491 }
492 
MajorVersion() const493 uint32_t EGLState::MajorVersion() const
494 {
495     return plat_.majorVersion;
496 }
497 
MinorVersion() const498 uint32_t EGLState::MinorVersion() const
499 {
500     return plat_.minorVersion;
501 }
502 
ChooseConfiguration(const BackendExtraGLES * backendConfig)503 void EGLState::ChooseConfiguration(const BackendExtraGLES* backendConfig)
504 {
505     EGLint num_configs;
506     // construct attribute list dynamically
507     vector<EGLint> attributes;
508     const size_t ATTRIBUTE_RESERVE = 16;       // reserve 16 attributes
509     attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
510     auto addAttribute = [&attributes](EGLint a, EGLint b) {
511         attributes.push_back(a);
512         attributes.push_back(b);
513     };
514     // Request OpenGL ES 3.x configs
515     if (IsVersionGreaterOrEqual(1, 5)) {
516         // EGL 1.5+
517         addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT);
518         addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES3_BIT);
519     } else if (HasExtension("EGL_KHR_create_context")) {
520         // "EGL_KHR_create_context"
521         addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR);
522         addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES3_BIT_KHR);
523     } else {
524         // We might be in trouble now.
525         addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
526         addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES2_BIT);
527     }
528     addAttribute(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
529     addAttribute(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
530     addAttribute(EGL_RED_SIZE, 8);
531     addAttribute(EGL_GREEN_SIZE, 8);
532     addAttribute(EGL_BLUE_SIZE, 8);
533     addAttribute(EGL_CONFIG_CAVEAT, EGL_NONE);
534     if (backendConfig) {
535         if (backendConfig->MSAASamples > 1) {
536             addAttribute(EGL_SAMPLES, (EGLint)backendConfig->MSAASamples);
537             addAttribute(EGL_SAMPLE_BUFFERS, 1);
538         }
539         addAttribute(EGL_ALPHA_SIZE, (EGLint)backendConfig->alphaBits);
540         addAttribute(EGL_DEPTH_SIZE, (EGLint)backendConfig->depthBits);
541         addAttribute(EGL_STENCIL_SIZE, (EGLint)backendConfig->stencilBits);
542         PLUGIN_LOG_I("Samples:%d Alpha:%d Depth:%d Stencil:%d", backendConfig->MSAASamples, backendConfig->alphaBits,
543             backendConfig->depthBits, backendConfig->stencilBits);
544     }
545     addAttribute(EGL_NONE, EGL_NONE); // terminate list
546     eglChooseConfig(plat_.display, attributes.data(), &plat_.config, 1, &num_configs);
547     CHECK_EGL_ERROR();
548 #if RENDER_GL_DEBUG
549     PLUGIN_LOG_I("eglChooseConfig returned:");
550     DumpEGLConfig(plat_.display, plat_.config);
551 #endif
552 }
553 
CreateContext(const BackendExtraGLES * backendConfig)554 void EGLState::CreateContext(const BackendExtraGLES* backendConfig)
555 {
556     vector<EGLint> context_attributes;
557     const size_t ATTRIBUTE_RESERVE = 16;               // reserve 16 attributes
558     context_attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
559     auto addAttribute = [&context_attributes](EGLint a, EGLint b) {
560         context_attributes.push_back(a);
561         context_attributes.push_back(b);
562     };
563     if (IsVersionGreaterOrEqual(1, 5)) {
564         // egl 1.5 or greater.
565         addAttribute(EGL_CONTEXT_MAJOR_VERSION, 3); // Select an OpenGL ES 3.x context
566         addAttribute(EGL_CONTEXT_MINOR_VERSION, 2); // Select an OpenGL ES x.2 context
567 #if RENDER_GL_DEBUG
568         // should use EGL_CONTEXT_OPENGL_DEBUG , but at least PowerVR simulator fails with this
569         if (HasExtension("EGL_KHR_create_context")) {
570             // Setting up debug context with the extension seems to work.
571             addAttribute(EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
572         }
573 #endif
574     } else if (HasExtension("EGL_KHR_create_context")) {
575         // egl 1.4 with EGL_KHR_create_context
576         addAttribute(EGL_CONTEXT_MAJOR_VERSION_KHR, 3); // Select an OpenGL ES 3.x context
577         addAttribute(EGL_CONTEXT_MINOR_VERSION_KHR, 2); // Select an OpenGL ES x.2 context
578 #if RENDER_GL_DEBUG
579         addAttribute(EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
580 #endif
581     } else {
582         // fallback to non-extended or pre 1.5 EGL, we expect 3.2 OpenGL context, this is now checked later.
583         addAttribute(EGL_CONTEXT_CLIENT_VERSION, 3); // Select an OpenGL ES 3.x context
584     }
585     addAttribute(EGL_NONE, EGL_NONE);
586 
587     EGLContext sharedContext = EGL_NO_CONTEXT;
588     if (backendConfig) {
589         sharedContext = backendConfig->sharedContext;
590     }
591     plat_.context = eglCreateContext(plat_.display, plat_.config, sharedContext, context_attributes.data());
592     CHECK_EGL_ERROR();
593 
594     if (plat_.context == EGL_NO_CONTEXT) {
595         PLUGIN_LOG_E("eglCreateContext failed : %s", EglErrorStr(eglGetError()));
596         PLUGIN_ASSERT(false);
597         return;
598     }
599 }
600 
IsVersionGreaterOrEqual(uint32_t major,uint32_t minor) const601 bool EGLState::IsVersionGreaterOrEqual(uint32_t major, uint32_t minor) const
602 {
603     if (plat_.majorVersion < major) {
604         return false;
605     }
606     if (plat_.majorVersion > major) {
607         return true;
608     }
609     if (plat_.minorVersion >= minor) {
610         return true;
611     }
612     return false;
613 }
614 
VerifyVersion()615 bool EGLState::VerifyVersion()
616 {
617     // Verify that we have at least 3.2 context.
618     EGLint glMajor = 0;
619     EGLint glMinor = 0;
620     SaveContext();
621     SetContext(nullptr); // activate the context with the dummy PBuffer.
622     string_view string((char*)glGetString(GL_VERSION));
623     // the format according to spec pdf is "OpenGL ES N.M vendor-specific information"
624     bool fail = false;
625     if (string.starts_with("OpenGL ES ")) {
626         // Must be OpenGL ES FULL. Trust this information. (even if it might mismatch with the eglQueryContext results)
627         string_view version = string.substr(10);
628         version = version.substr(0, version.find_first_of(' '));
629         auto dot = version.find_first_of('.');
630         auto majorS = version.substr(0, dot);
631         if (dot != string_view::npos) {
632             auto minorS = version.substr(dot + 1);
633             fail = (stringToUInt(minorS, glMinor)) ? fail : false;
634         }
635         fail = (stringToUInt(majorS, glMajor)) ? fail : false;
636     }
637     if (fail) {
638         // Try these then, if parsing the GL_VERSION string failed
639         glMajor = glMinor = 0;
640         eglQueryContext(plat_.display, plat_.context, EGL_CONTEXT_MAJOR_VERSION, &glMajor);
641         eglQueryContext(plat_.display, plat_.context, EGL_CONTEXT_MINOR_VERSION_KHR, &glMinor);
642     }
643 
644     if (glMajor < 3) {
645         fail = true;
646     } else if (glMajor == 3) {
647         if (glMinor < 2) {
648             // We do NOT support 3.0 or 3.1
649             fail = true;
650         }
651     }
652 
653     if (fail) {
654         // restore contexts and cleanup.
655         PLUGIN_LOG_E(
656             "Could not to Initialize required OpenGL ES version [%d.%d] [%s]", glMajor, glMinor, string.data());
657         RestoreContext();
658         // destroy the dummy surface also.
659         eglDestroySurface(plat_.display, dummySurface_);
660         dummyContext_.context = EGL_NO_CONTEXT;
661         dummyContext_.drawSurface = dummyContext_.readSurface = EGL_NO_SURFACE;
662         dummyContext_.display = EGL_NO_DISPLAY;
663     }
664     return !fail;
665 }
666 
CreateContext(DeviceCreateInfo const & createInfo)667 bool EGLState::CreateContext(DeviceCreateInfo const& createInfo)
668 {
669     auto backendConfig = static_cast<const BackendExtraGLES*>(createInfo.backendConfiguration);
670     EGLint major, minor;
671 
672     plat_.display = eglGetDisplay(backendConfig ? backendConfig->display : EGL_DEFAULT_DISPLAY);
673     const EGLContext appContext = backendConfig ? backendConfig->applicationContext : EGL_NO_CONTEXT;
674     const EGLContext sharedContext = backendConfig ? backendConfig->sharedContext : EGL_NO_CONTEXT;
675     if (appContext == EGL_NO_CONTEXT && sharedContext == EGL_NO_CONTEXT) {
676         if (!eglInitialize(plat_.display, &major, &minor)) {
677             PLUGIN_LOG_E("EGL initialization failed");
678             CHECK_EGL_ERROR();
679             PLUGIN_ASSERT(false);
680             return false;
681         }
682         plat_.eglInitialized = true;
683     } else {
684         major = 0;
685         minor = 0;
686 
687         // Check version from display as we don't call eglInitialize ourselves
688         const string_view version = eglQueryString(plat_.display, EGL_VERSION);
689         if (!version.empty()) {
690             const auto dot = version.find_first_of('.');
691             if (dot != string_view::npos) {
692                 const auto majorS = version.substr(0, dot);
693                 if (!stringToUInt(majorS, major)) {
694                     major = 0;
695                 }
696                 const auto space = version.find_first_of(' ', dot + 1);
697                 if (space != string_view::npos) {
698                     auto minorS = version.substr(dot + 1, space - (dot + 1));
699                     if (!stringToUInt(minorS, minor)) {
700                         minor = 0;
701                     }
702                 }
703             }
704         } else {
705             CHECK_EGL_ERROR();
706         }
707     }
708     plat_.majorVersion = static_cast<uint32_t>(major);
709     plat_.minorVersion = static_cast<uint32_t>(minor);
710     PLUGIN_LOG_I("EGL %d.%d Initialized", major, minor);
711 
712     if (!IsVersionGreaterOrEqual(1, 4)) {
713         // we need atleast egl 1.4
714         PLUGIN_LOG_F("EGL version too old. 1.4 or later requried.");
715         if (plat_.eglInitialized) {
716             eglTerminate(plat_.display);
717         }
718         return false;
719     }
720 
721     eglBindAPI(EGL_OPENGL_ES_API);
722     CHECK_EGL_ERROR();
723 
724     DumpEGLStrings(plat_.display);
725 
726     HandleExtensions();
727 
728     plat_.hasColorSpaceExt = hasColorSpaceExt_ = HasExtension("EGL_KHR_gl_colorspace");
729     // NOTE: "EGL_KHR_no_config_context" and "EGL_KHR_surfaceless_context" is technically working, but disabled for now.
730     hasConfiglessExt_ = false;
731     hasSurfacelessExt_ = false;
732     plat_.config = EGL_NO_CONFIG_KHR;
733     if (!hasConfiglessExt_) {
734         // we need a config for the context..
735         ChooseConfiguration(backendConfig);
736     }
737 
738     if (appContext) {
739         // use applications context
740         PLUGIN_LOG_I("Using application context in DeviceGLES");
741         plat_.context = appContext;
742     } else {
743         // Create a new context
744         CreateContext(backendConfig);
745         plat_.contextCreated = true;
746     }
747     if (plat_.context == EGL_NO_CONTEXT) {
748         // we have failed then.
749         if (plat_.eglInitialized) {
750             eglTerminate(plat_.display);
751         }
752         return false;
753     }
754 
755     if (!hasSurfacelessExt_) {
756         // Create a placeholder pbuffer, since we do NOT have a surface yet.
757         if (plat_.config == EGL_NO_CONFIG_KHR) {
758             // we need to choose a config for the surface..
759             ChooseConfiguration(backendConfig);
760         }
761         GLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
762         dummySurface_ = eglCreatePbufferSurface(plat_.display, plat_.config, surface_attribs);
763         CHECK_EGL_ERROR();
764 #if RENDER_GL_DEBUG
765         DumpEGLSurface(plat_.display, dummySurface_);
766 #endif
767     }
768 
769     dummyContext_.context = plat_.context;
770     dummyContext_.drawSurface = dummyContext_.readSurface = dummySurface_;
771     dummyContext_.display = plat_.display;
772 
773     if (!VerifyVersion()) {
774         if (plat_.contextCreated) {
775             eglDestroyContext(plat_.display, plat_.context);
776             plat_.context = EGL_NO_CONTEXT;
777         }
778         if (plat_.eglInitialized) {
779             eglTerminate(plat_.display);
780         }
781         return false;
782     }
783     return true;
784 }
785 
GlInitialize()786 void EGLState::GlInitialize()
787 {
788 #define declare(a, b)                                                                     \
789     if (b == nullptr) {                                                                   \
790         *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(eglGetProcAddress(#b)); \
791     }                                                                                     \
792     if (b == nullptr) {                                                                   \
793         PLUGIN_LOG_E("Missing %s\n", #b);                                                 \
794     }
795 #include "gles/gl_functions.h"
796 
797 #define declare(a, b)                                                                     \
798     if (b == nullptr) {                                                                   \
799         *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(eglGetProcAddress(#b)); \
800     }                                                                                     \
801     if (b == nullptr) {                                                                   \
802         PLUGIN_LOG_E("Missing %s\n", #b);                                                 \
803     }
804 #include "gles/egl_functions.h"
805     if (!HasExtension("EGL_ANDROID_get_native_client_buffer")) {
806         eglGetNativeClientBufferANDROID = nullptr;
807     }
808     if (!HasExtension("EGL_KHR_image_base")) {
809         eglCreateImageKHR = nullptr;
810         eglDestroyImageKHR = nullptr;
811     }
812 
813     plat_.deviceName = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
814     plat_.driverVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
815     BASE_NS::ClearToValue(
816         &plat_.deviceProperties, sizeof(plat_.deviceProperties), 0x00, sizeof(plat_.deviceProperties));
817     FillProperties(plat_.deviceProperties);
818 
819     SetSwapInterval(1); // default to vsync enabled.
820 }
821 
IsValid()822 bool EGLState::IsValid()
823 {
824     return (plat_.context != EGL_NO_CONTEXT);
825 }
826 
SaveContext()827 void EGLState::SaveContext()
828 {
829     PLUGIN_ASSERT(!oldIsSet_);
830     oldIsSet_ = true;
831     GetContext(oldContext_);
832 }
833 
SetContext(const SwapchainGLES * swapchain)834 void EGLState::SetContext(const SwapchainGLES* swapchain)
835 {
836     if (swapchain == nullptr) {
837         SetContext(dummyContext_, true);
838     } else {
839         ContextState newContext;
840         const auto& plat = swapchain->GetPlatformData();
841         newContext.display = plat_.display;
842         newContext.context = plat_.context;
843         newContext.drawSurface = (EGLSurface)plat.surface;
844         newContext.readSurface = (EGLSurface)plat.surface;
845         SetContext(newContext, false);
846 
847         if (vSync_ != plat.vsync) {
848             vSync_ = plat.vsync;
849             SetSwapInterval(plat.vsync ? 1u : 0u);
850         }
851     }
852 }
853 
RestoreContext()854 void EGLState::RestoreContext()
855 {
856     PLUGIN_ASSERT(oldIsSet_);
857     SetContext(oldContext_, true);
858     oldIsSet_ = false;
859 }
860 
GetContext(ContextState & state)861 void EGLState::GetContext(ContextState& state)
862 {
863     state.display = eglGetCurrentDisplay();
864     CHECK_EGL_ERROR();
865     if (state.display != EGL_NO_DISPLAY) {
866         state.context = eglGetCurrentContext();
867         CHECK_EGL_ERROR();
868         state.readSurface = eglGetCurrentSurface(EGL_READ);
869         CHECK_EGL_ERROR();
870         state.drawSurface = eglGetCurrentSurface(EGL_DRAW);
871         CHECK_EGL_ERROR();
872     } else {
873         state.context = EGL_NO_CONTEXT;
874         state.readSurface = EGL_NO_SURFACE;
875         state.drawSurface = EGL_NO_SURFACE;
876     }
877 }
878 
SetContext(const ContextState & state,bool force)879 void EGLState::SetContext(const ContextState& state, bool force)
880 {
881     PLUGIN_ASSERT(oldIsSet_);
882     if (state.display != EGL_NO_DISPLAY) {
883         if ((force) || (oldContext_.display != state.display) || (oldContext_.drawSurface != state.drawSurface) ||
884             (oldContext_.readSurface != state.readSurface) || (oldContext_.context != state.context)) {
885             if (eglMakeCurrent(state.display, state.drawSurface, state.readSurface, state.context) == EGL_FALSE) {
886                 CHECK_EGL_ERROR2();
887                 if (eglMakeCurrent(state.display, dummySurface_, dummySurface_, state.context) == EGL_FALSE) {
888                     CHECK_EGL_ERROR2();
889                 }
890             }
891         }
892     } else {
893         // Okay, do nothing.
894         // no display was active, so there can be no surface and no context.
895         // We need a display to deactivate context. (EGL_NO_DISPLAY is not a valid argument to eglMakeCurrent)
896         // so what to do, leak context?
897         // Or just disconnect context/surface from plat_.display (which currently is EGL_DEFAULT_DISPLAY...)
898         if (eglMakeCurrent(plat_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) {
899             CHECK_EGL_ERROR2();
900         }
901     }
902 }
903 
DestroyContext()904 void EGLState::DestroyContext()
905 {
906     if (plat_.display != EGL_NO_DISPLAY) {
907         eglMakeCurrent(plat_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
908         CHECK_EGL_ERROR();
909         if (dummySurface_ != EGL_NO_SURFACE) {
910             eglDestroySurface(plat_.display, dummySurface_);
911         }
912         CHECK_EGL_ERROR();
913         if (plat_.contextCreated) {
914             if (plat_.context != EGL_NO_CONTEXT) {
915                 eglDestroyContext(plat_.display, plat_.context);
916                 CHECK_EGL_ERROR();
917             }
918         }
919         if (plat_.eglInitialized) {
920             eglTerminate(plat_.display);
921             CHECK_EGL_ERROR();
922         }
923     }
924 }
925 
HasExtension(const string_view extension) const926 bool EGLState::HasExtension(const string_view extension) const
927 {
928     for (const auto& e : dextensionList_) {
929         if (extension == e)
930             return true;
931     }
932     for (const auto& e : cextensionList_) {
933         if (extension == e)
934             return true;
935     }
936     return false;
937 }
938 
SetSwapInterval(uint32_t interval)939 void EGLState::SetSwapInterval(uint32_t interval)
940 {
941     eglSwapInterval(plat_.display, (EGLint)interval);
942 }
943 
GetPlatformData() const944 const DevicePlatformData& EGLState::GetPlatformData() const
945 {
946     return plat_;
947 }
948 
ErrorFilter() const949 void* EGLState::ErrorFilter() const
950 {
951     return reinterpret_cast<void*>(FilterError);
952 }
953 
CreateSurface(uintptr_t window,uintptr_t instance) const954 uintptr_t EGLState::CreateSurface(uintptr_t window, uintptr_t instance) const noexcept
955 {
956     // Check if sRGB colorspace is supported by EGL.
957     const bool isSrgbSurfaceSupported = IsSrgbSurfaceSupported(plat_);
958 
959     EGLint attribsSrgb[] = { EGL_NONE, EGL_NONE, EGL_NONE };
960     if (isSrgbSurfaceSupported) {
961         if (IsVersionGreaterOrEqual(1, 5)) { // 5 : param
962             attribsSrgb[0] = EGL_GL_COLORSPACE;
963             attribsSrgb[1] = EGL_GL_COLORSPACE_SRGB;
964         } else if (hasColorSpaceExt_) {
965             attribsSrgb[0] = EGL_GL_COLORSPACE_KHR;
966             attribsSrgb[1] = EGL_GL_COLORSPACE_SRGB_KHR;
967         }
968     }
969     EGLSurface eglSurface = eglCreateWindowSurface(plat_.display, plat_.config,
970         reinterpret_cast<EGLNativeWindowType>(window), isSrgbSurfaceSupported ? attribsSrgb : nullptr);
971     if (eglSurface == EGL_NO_SURFACE) {
972         EGLint error = eglGetError();
973         PLUGIN_LOG_E("eglCreateWindowSurface failed (with null attributes): %d", error);
974     }
975     return reinterpret_cast<uintptr_t>(eglSurface);
976 }
977 
DestroySurface(uintptr_t surface) const978 void EGLState::DestroySurface(uintptr_t surface) const noexcept
979 {
980     if (reinterpret_cast<EGLSurface>(surface) != EGL_NO_SURFACE) {
981         eglDestroySurface(plat_.display, reinterpret_cast<EGLSurface>(surface));
982     }
983 }
984 
GetSurfaceInformation(const DevicePlatformDataGLES & plat,EGLSurface surface,GlesImplementation::SurfaceInfo & res) const985 bool EGLState::GetSurfaceInformation(
986     const DevicePlatformDataGLES& plat, EGLSurface surface, GlesImplementation::SurfaceInfo& res) const
987 {
988     EGLDisplay display = plat.display;
989 
990 #ifndef NDEBUG
991     PLUGIN_LOG_V("EGLState::GetSurfaceInformation: input surface information:");
992     DumpEGLSurface(display, surface);
993 #endif
994     EGLint configId;
995     // Get configId from surface
996     if (eglQuerySurface(display, surface, EGL_CONFIG_ID, &configId) == false) {
997         PLUGIN_LOG_E("EGLState::GetSurfaceInformation: Could not fetch surface config_id.");
998         return false;
999     }
1000 
1001     EGLConfig config = EGL_NO_CONFIG_KHR;
1002     EGLint numconfigs = 0;
1003     EGLint attrs[] = { EGL_CONFIG_ID, configId, EGL_NONE };
1004     if (eglChooseConfig(display, attrs, &config, 1, &numconfigs) == false) {
1005         PLUGIN_LOG_E("EGLState::GetSurfaceInformation: Could not fetch surface config.");
1006         return false;
1007     }
1008 
1009     PLUGIN_LOG_V("EGLState::GetSurfaceInformation: input surface configuration:");
1010     DumpEGLConfig(display, config);
1011 
1012 #ifndef NDEBUG
1013     if (!hasConfiglessExt_) {
1014         // Check that it matches the config id from "system config"
1015         EGLConfig plat_config = plat.config;
1016         if ((plat_config != EGL_NO_CONFIG_KHR) && (plat_config != config)) {
1017             PLUGIN_ASSERT_MSG(plat_config == config, "display config and surface config should match!");
1018             PLUGIN_LOG_V("EGLState::GetSurfaceInformation: plat surface configuration:");
1019             EGLHelpers::DumpEGLConfig(display, plat_config);
1020         }
1021     }
1022 #endif
1023 
1024     // Fetch surface parameters
1025     EGLint width = 0;
1026     EGLint height = 0;
1027     EGLint red_size = 0;
1028     EGLint green_size = 0;
1029     EGLint blue_size = 0;
1030     EGLint alpha_size = 0;
1031     EGLint samples = 0;
1032     EGLint depth_size = 0;
1033     EGLint stencil_size = 0;
1034     eglQuerySurface(display, surface, EGL_WIDTH, &width);
1035     eglQuerySurface(display, surface, EGL_HEIGHT, &height);
1036     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red_size);
1037     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green_size);
1038     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue_size);
1039     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha_size);
1040     eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
1041     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth_size);
1042     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil_size);
1043 
1044     res.configId = static_cast<uint32_t>(configId);
1045     res.alpha_size = static_cast<uint32_t>(alpha_size);
1046     res.blue_size = static_cast<uint32_t>(blue_size);
1047     res.depth_size = static_cast<uint32_t>(depth_size);
1048     res.green_size = static_cast<uint32_t>(green_size);
1049     res.height = static_cast<uint32_t>(height);
1050     res.red_size = static_cast<uint32_t>(red_size);
1051     res.samples = static_cast<uint32_t>(samples);
1052     res.stencil_size = static_cast<uint32_t>(stencil_size);
1053     res.width = static_cast<uint32_t>(width);
1054 
1055     EGLint colorspace = 0;
1056     EGLint COLOR_SPACE = 0;
1057     EGLint COLOR_SPACE_SRGB = 0;
1058     if (IsVersionGreaterOrEqual(1, 5)) {
1059         COLOR_SPACE = EGL_GL_COLORSPACE;
1060         COLOR_SPACE_SRGB = EGL_GL_COLORSPACE_SRGB;
1061     } else if (hasColorSpaceExt_) {
1062         COLOR_SPACE = EGL_GL_COLORSPACE_KHR;
1063         COLOR_SPACE_SRGB = EGL_GL_COLORSPACE_SRGB_KHR;
1064     }
1065 
1066     if (COLOR_SPACE > 0) {
1067         if (eglQuerySurface(display, surface, COLOR_SPACE, &colorspace)) {
1068             // EGL_GL_COLORSPACE_SRGB or EGL_GL_COLORSPACE_LINEAR.
1069             res.srgb = (colorspace == COLOR_SPACE_SRGB);
1070         }
1071     }
1072 
1073     if (colorspace == 0) {
1074         // surface is linear (no conversion made during read/write)
1075         // data should be srgb though.
1076         PLUGIN_LOG_E("EGL_GL_COLORSPACE query failed (or not available). Defaulting to linear buffer with srgb data");
1077         res.srgb = false;
1078     }
1079 
1080     return true;
1081 }
1082 
SwapBuffers(const SwapchainGLES & swapchain)1083 void EGLState::SwapBuffers(const SwapchainGLES& swapchain)
1084 {
1085     SetContext(&swapchain);
1086     const auto& platSwapchain = static_cast<const SwapchainPlatformDataGL&>(swapchain.GetPlatformData());
1087     eglSwapBuffers(plat_.display, (EGLSurface)platSwapchain.surface);
1088 }
1089 } // namespace EGLHelpers
1090 RENDER_END_NAMESPACE()
1091 #endif
1092