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