• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #include "gles/surface_information.h"
69 #include "gles/swapchain_gles.h"
70 
71 #if RENDER_GL_DEBUG
72 #define CHECK_EGL_ERROR() EGLHelpers::CheckEGLError(__FILE__, __LINE__)
73 #define CHECK_EGL_ERROR2() EGLHelpers::CheckEGLError2(__FILE__, __LINE__)
74 #else
75 #define CHECK_EGL_ERROR()
76 #define CHECK_EGL_ERROR2() EGLHelpers::CheckEGLError2(__FILE__, __LINE__)
77 #endif
78 
79 RENDER_BEGIN_NAMESPACE()
80 using BASE_NS::string;
81 using BASE_NS::string_view;
82 using BASE_NS::vector;
83 
84 namespace EGLHelpers {
85 namespace {
FilterError(GLenum,GLenum,GLuint,GLenum,GLsizei,const GLchar *,const void *)86 bool FilterError(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, const void*) noexcept
87 {
88     return false;
89 }
90 
EglErrorStr(EGLint aError)91 const char* EglErrorStr(EGLint aError)
92 {
93     switch (aError) {
94         case EGL_SUCCESS:
95             return "The last function succeeded without error.";
96         case EGL_NOT_INITIALIZED:
97             return "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
98         case EGL_BAD_ACCESS:
99             return "EGL cannot access a requested resource(for example a context is bound in another thread).";
100         case EGL_BAD_ALLOC:
101             return "EGL failed to allocate resources for the requested operation.";
102         case EGL_BAD_ATTRIBUTE:
103             return "An unrecognized attribute or attribute value was passed in the attribute list.";
104         case EGL_BAD_CONTEXT:
105             return "An EGLContext argument does not name a valid EGL rendering context.";
106         case EGL_BAD_CONFIG:
107             return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
108         case EGL_BAD_CURRENT_SURFACE:
109             return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer "
110                    "valid.";
111         case EGL_BAD_DISPLAY:
112             return "An EGLDisplay argument does not name a valid EGL display connection.";
113         case EGL_BAD_SURFACE:
114             return "An EGLSurface argument does not name a valid surface(window, pixel buffer or pixmap) configured "
115                    "for GL rendering.";
116         case EGL_BAD_MATCH:
117             return "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid "
118                    "surface).";
119         case EGL_BAD_PARAMETER:
120             return "One or more argument values are invalid.";
121         case EGL_BAD_NATIVE_PIXMAP:
122             return "A NativePixmapType argument does not refer to a valid native pixmap.";
123         case EGL_BAD_NATIVE_WINDOW:
124             return "A NativeWindowType argument does not refer to a valid native window.";
125         case EGL_CONTEXT_LOST:
126             return "A power management event has occurred.The application must destroy all contexts and reinitialise "
127                    "OpenGL ES state and objects to continue rendering.";
128         default:
129             break;
130     }
131 
132     static char error[64];
133     if (sprintf_s(error, sizeof(error), "Unknown error %x", aError) < 0) {
134         PLUGIN_LOG_E("EglErrorStr: sprintf_s failed");
135     }
136     return error;
137 }
138 
CheckEGLError(const char * const file,int line)139 void CheckEGLError(const char* const file, int line)
140 {
141     EGLint error = eglGetError();
142     if (error != EGL_SUCCESS) {
143         PLUGIN_LOG_E("eglGetError failed : %s (%s %d)", EglErrorStr(error), file, line);
144         PLUGIN_ASSERT(false);
145     }
146 }
147 
CheckEGLError2(const char * const file,int line)148 void CheckEGLError2(const char* const file, int line)
149 {
150     EGLint error = eglGetError();
151     if (error != EGL_SUCCESS) {
152         PLUGIN_LOG_E("eglGetError failed : %s (%s %d)", EglErrorStr(error), file, line);
153     }
154 }
155 
156 #define ATTRIBUTE(_attr) \
157     {                    \
158         _attr, #_attr    \
159     }
160 
161 struct Attribute {
162     EGLint attribute;
163     char const* const Name;
164 };
165 
DumpEGLStrings(EGLDisplay dpy)166 void DumpEGLStrings(EGLDisplay dpy)
167 {
168     // extensions dumped later.
169     static constexpr Attribute strings[] = { ATTRIBUTE(EGL_CLIENT_APIS), ATTRIBUTE(EGL_VENDOR),
170         ATTRIBUTE(EGL_VERSION) };
171     for (size_t attr = 0; attr < sizeof(strings) / sizeof(Attribute); attr++) {
172         const char* const value = eglQueryString(dpy, strings[attr].attribute);
173         if (value) {
174             PLUGIN_LOG_D("\t%-32s: %s", strings[attr].Name, value);
175         } else {
176             PLUGIN_LOG_D("\t%-32s:", strings[attr].Name);
177         }
178     }
179 }
180 
181 #ifdef PLUGIN_UNUSED_EGL_HELPERS
DumpEGLConfigs(EGLDisplay dpy)182 void DumpEGLConfigs(EGLDisplay dpy)
183 {
184     EGLConfig* configs = nullptr;
185     EGLint n = 0;
186 
187     eglGetConfigs(dpy, NULL, 0, &n);
188     configs = new EGLConfig[(size_t)n];
189     eglGetConfigs(dpy, configs, n, &n);
190     for (EGLint i = 0; i < n; i++) {
191         PLUGIN_LOG_V("EGLConfig[%d]", i);
192         DumpEGLConfig(dpy, configs[i]);
193     }
194     delete[] configs;
195 }
196 #endif
197 
stringToUInt(string_view string,EGLint & value)198 bool stringToUInt(string_view string, EGLint& value)
199 {
200     value = 0;
201     for (auto digit : string) {
202         value *= 10;
203         if ((digit >= '0') && (digit <= '9')) {
204             value += digit - '0';
205         } else {
206             return false;
207         }
208     }
209     return true;
210 }
211 } // namespace
212 
DumpEGLSurface(EGLDisplay dpy,EGLSurface surf)213 void DumpEGLSurface(EGLDisplay dpy, EGLSurface surf)
214 {
215     static constexpr Attribute attribs[] = {
216         // Returns the ID of the EGL frame buffer configuration with respect to which the surface was created.
217         ATTRIBUTE(EGL_CONFIG_ID),
218         // Returns the color space used by OpenGL and OpenGL ES when rendering to the surface, either
219         // EGL_GL_COLORSPACE_SRGB or EGL_GL_COLORSPACE_LINEAR.
220         ATTRIBUTE(EGL_GL_COLORSPACE),
221         // Returns the height of the surface in pixels
222         ATTRIBUTE(EGL_HEIGHT),
223         // Returns the horizontal dot pitch of the display on which a window surface is  visible.The value returned is
224         // equal to the actual dot pitch, in pixels meter, multiplied by the constant value EGL_DISPLAY_SCALING.
225         ATTRIBUTE(EGL_HORIZONTAL_RESOLUTION),
226         // Returns the same attribute value specified when the surface was created with  eglCreatePbufferSurface.For a
227         // window or pixmap surface, value is not modified.
228         ATTRIBUTE(EGL_LARGEST_PBUFFER),
229         ATTRIBUTE(EGL_MIPMAP_LEVEL),   // Returns which level of the mipmap to render to, if texture has mipmaps.
230         ATTRIBUTE(EGL_MIPMAP_TEXTURE), // Returns EGL_TRUE if texture has mipmaps, EGL_FALSE otherwise.
231         // Returns the filter used when resolving the multisample buffer.The filter may be either
232         // EGL_MULTISAMPLE_RESOLVE_DEFAULT or EGL_MULTISAMPLE_RESOLVE_BOX, as described for eglSurfaceAttrib.
233         ATTRIBUTE(EGL_MULTISAMPLE_RESOLVE),
234         // Returns the aspect ratio of an individual pixel(the ratio of a pixel's width to its height). The value
235         // returned is equal to the actual aspect ratio multiplied by the constant value EGL_DISPLAY_SCALING.
236         ATTRIBUTE(EGL_PIXEL_ASPECT_RATIO),
237         // Returns the buffer which client API rendering is requested to use.For a window surface, this is the same
238         // attribute value specified when the surface was created.For a pbuffer surface, it is always
239         // EGL_BACK_BUFFER.For a pixmap surface, it is always EGL_SINGLE_BUFFER.To determine the actual buffer being
240         // rendered to by a context, call eglQueryContext.
241         ATTRIBUTE(EGL_RENDER_BUFFER),
242         // Returns the effect on the color buffer when posting a surface with eglSwapBuffers.Swap behavior may be either
243         // EGL_BUFFER_PRESERVED or EGL_BUFFER_DESTROYED, as described for eglSurfaceAttrib.
244         ATTRIBUTE(EGL_SWAP_BEHAVIOR),
245         // Returns format of texture.Possible values are EGL_NO_TEXTURE, EGL_TEXTURE_RGB, and EGL_TEXTURE_RGBA.
246         ATTRIBUTE(EGL_TEXTURE_FORMAT),
247         ATTRIBUTE(EGL_TEXTURE_TARGET), // Returns type of texture.Possible values are EGL_NO_TEXTURE, or EGL_TEXTURE_2D.
248         // Returns the vertical dot pitch of the display on which a window surface is visible.The value returned is
249         // equal to the actual dot pitch, in pixels  / meter, multiplied by the constant value EGL_DISPLAY_SCALING.
250         ATTRIBUTE(EGL_VERTICAL_RESOLUTION),
251         // Returns the interpretation of alpha values used by OpenVG when rendering to the surface, either
252         // EGL_VG_ALPHA_FORMAT_NONPRE or EGL_VG_ALPHA_FORMAT_PRE.
253         ATTRIBUTE(EGL_VG_ALPHA_FORMAT),
254         // Returns the color space used by OpenVG when rendering to the surface, either EGL_VG_COLORSPACE_sRGB or
255         // EGL_VG_COLORSPACE_LINEAR.
256         ATTRIBUTE(EGL_VG_COLORSPACE),
257         ATTRIBUTE(EGL_WIDTH), // Returns the width of the surface in pixels.
258     };
259     for (size_t attr = 0; attr < sizeof(attribs) / sizeof(Attribute); attr++) {
260         EGLint value;
261         if (EGL_TRUE == eglQuerySurface(dpy, surf, attribs[attr].attribute, &value)) {
262             PLUGIN_LOG_V("\t%-32s: %10d (0x%08x)", attribs[attr].Name, value, value);
263         }
264     }
265 }
266 
DumpEGLConfig(EGLDisplay dpy,const EGLConfig & config)267 void DumpEGLConfig(EGLDisplay dpy, const EGLConfig& config)
268 {
269     static constexpr Attribute attributes[] = {
270         ATTRIBUTE(EGL_ALPHA_SIZE),      // Returns the number of bits of alpha stored in the color buffer.
271         ATTRIBUTE(EGL_ALPHA_MASK_SIZE), // Returns the number of bits in the alpha mask buffer.
272         // Returns EGL_TRUE if color buffers can be bound to an RGB texture,  EGL_FALSE otherwise.
273         ATTRIBUTE(EGL_BIND_TO_TEXTURE_RGB),
274         // Returns EGL_TRUE if color buffers can be bound to an RGBA texture, EGL_FALSE otherwise.
275         ATTRIBUTE(EGL_BIND_TO_TEXTURE_RGBA),
276         ATTRIBUTE(EGL_BLUE_SIZE), // Returns the number of bits of blue stored in the color buffer.
277         // Returns the depth of the color buffer.It is the sum of EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, and
278         // EGL_ALPHA_SIZE.
279         ATTRIBUTE(EGL_BUFFER_SIZE),
280         // Returns the color buffer type.Possible types are EGL_RGB_BUFFER and  EGL_LUMINANCE_BUFFER.
281         ATTRIBUTE(EGL_COLOR_BUFFER_TYPE),
282         // Returns the caveats for the frame buffer configuration.Possible caveat values  are EGL_NONE, EGL_SLOW_CONFIG,
283         // and EGL_NON_CONFORMANT.
284         ATTRIBUTE(EGL_CONFIG_CAVEAT),
285         ATTRIBUTE(EGL_CONFIG_ID), // Returns the ID of the frame buffer configuration.
286         // Returns a bitmask indicating which client API contexts created with respect to this
287         // config are conformant.
288         ATTRIBUTE(EGL_CONFORMANT),
289         ATTRIBUTE(EGL_DEPTH_SIZE), // Returns the number of bits in the depth buffer.
290         ATTRIBUTE(EGL_GREEN_SIZE), // Returns the number of bits of green stored in the color buffer.
291         // Returns the frame buffer level.Level zero is the default frame buffer.Positive levels correspond to frame
292         // buffers that overlay the default buffer and negative levels correspond to frame buffers that underlay the
293         // default buffer.
294         ATTRIBUTE(EGL_LEVEL),
295         ATTRIBUTE(EGL_LUMINANCE_SIZE),     // Returns the number of bits of luminance stored in the luminance buffer.
296         ATTRIBUTE(EGL_MAX_PBUFFER_WIDTH),  // Returns the maximum width of a pixel buffer surface in pixels.
297         ATTRIBUTE(EGL_MAX_PBUFFER_HEIGHT), // Returns the maximum height of a pixel buffer surface in pixels.
298         ATTRIBUTE(EGL_MAX_PBUFFER_PIXELS), // Returns the maximum size of a pixel buffer surface in pixels.
299         ATTRIBUTE(EGL_MAX_SWAP_INTERVAL),  // Returns the maximum value that can be passed to eglSwapInterval.
300         ATTRIBUTE(EGL_MIN_SWAP_INTERVAL),  // Returns the minimum value that can be passed to eglSwapInterval.
301         // Returns EGL_TRUE if native rendering APIs can render into the surface, EGL_FALSE otherwise.
302         ATTRIBUTE(EGL_NATIVE_RENDERABLE),
303         ATTRIBUTE(EGL_NATIVE_VISUAL_ID),   // Returns the ID of the associated native visual.
304         ATTRIBUTE(EGL_NATIVE_VISUAL_TYPE), // Returns the type of the associated native visual.
305         ATTRIBUTE(EGL_RED_SIZE),           // Returns the number of bits of red stored in the color buffer.
306         ATTRIBUTE(EGL_RENDERABLE_TYPE),    // Returns a bitmask indicating the types of supported client API contexts.
307         ATTRIBUTE(EGL_SAMPLE_BUFFERS),     // Returns the number of multisample buffers.
308         ATTRIBUTE(EGL_SAMPLES),            // Returns the number of samples per pixel.
309         ATTRIBUTE(EGL_STENCIL_SIZE),       // Returns the number of bits in the stencil buffer.
310         ATTRIBUTE(EGL_SURFACE_TYPE),       // Returns a bitmask indicating the types of supported EGL surfaces.
311         // Returns the type of supported transparency.Possible transparency values are  EGL_NONE, and
312         // EGL_TRANSPARENT_RGB.
313         ATTRIBUTE(EGL_TRANSPARENT_TYPE),
314         ATTRIBUTE(EGL_TRANSPARENT_RED_VALUE),   // Returns the transparent red value.
315         ATTRIBUTE(EGL_TRANSPARENT_GREEN_VALUE), // Returns the transparent green value.
316         ATTRIBUTE(EGL_TRANSPARENT_BLUE_VALUE),  // Returns the transparent blue value.
317         // ATTRIBUTE(EGL_MATCH_NATIVE_PIXMAP),  While EGL_MATCH_NATIVE_PIXMAP can be specified in the attribute list
318         // passed to eglChooseConfig, it is not an attribute of the resulting config and cannot be queried using
319         // eglGetConfigAttrib.
320     };
321     for (size_t attr = 0; attr < sizeof(attributes) / sizeof(Attribute); attr++) {
322         EGLint value;
323         if (EGL_TRUE == eglGetConfigAttrib(dpy, config, attributes[attr].attribute, &value)) {
324             PLUGIN_LOG_V("\t%-32s: %10d (0x%08x)", attributes[attr].Name, value, value);
325         }
326     }
327 }
328 
ParseExtensions(const string & extensions,vector<string_view> & extensionList)329 void ParseExtensions(const string& extensions, vector<string_view>& extensionList)
330 {
331     size_t start = 0;
332     for (auto end = extensions.find(' '); end != string::npos; end = extensions.find(' ', start)) {
333         extensionList.emplace_back(extensions.data() + start, end - start);
334         start = end + 1;
335     }
336     if (start < extensions.size()) {
337         extensionList.emplace_back(extensions.data() + start);
338     }
339 }
340 
341 #undef ATTRIBUTE
HandleExtensions()342 void EGLState::HandleExtensions()
343 {
344     if (plat_.minorVersion > 4) {
345         cextensions_ = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
346         CHECK_EGL_ERROR();
347         PLUGIN_LOG_D("\t%-32s: %s", "EGL_EXTENSIONS (CLIENT)", cextensions_.c_str());
348         ParseExtensions(cextensions_, cextensionList_);
349     }
350 
351     dextensions_ = eglQueryString(plat_.display, EGL_EXTENSIONS);
352     CHECK_EGL_ERROR();
353     ParseExtensions(dextensions_, dextensionList_);
354     PLUGIN_LOG_D("\t%-32s: %s", "EGL_EXTENSIONS (DISPLAY)", dextensions_.c_str());
355 }
356 
MajorVersion() const357 uint32_t EGLState::MajorVersion() const
358 {
359     return plat_.majorVersion;
360 }
361 
MinorVersion() const362 uint32_t EGLState::MinorVersion() const
363 {
364     return plat_.minorVersion;
365 }
366 
ChooseConfiguration(const BackendExtraGLES * backendConfig)367 void EGLState::ChooseConfiguration(const BackendExtraGLES* backendConfig)
368 {
369     EGLint num_configs;
370     // construct attribute list dynamically
371     vector<EGLint> attributes;
372     const size_t ATTRIBUTE_RESERVE = 16;       // reserve 16 attributes
373     attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
374     auto addAttribute = [&attributes](EGLint a, EGLint b) {
375         attributes.push_back(a);
376         attributes.push_back(b);
377     };
378     // Request OpenGL ES 3.x configs
379     if (IsVersionGreaterOrEqual(1, 5)) {
380         // EGL 1.5+
381         addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT);
382         addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES3_BIT);
383     } else if (HasExtension("EGL_KHR_create_context")) {
384         // "EGL_KHR_create_context"
385         addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR);
386         addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES3_BIT_KHR);
387     } else {
388         // We might be in trouble now.
389         addAttribute(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
390         addAttribute(EGL_CONFORMANT, EGL_OPENGL_ES2_BIT);
391     }
392     addAttribute(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
393     addAttribute(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
394     addAttribute(EGL_RED_SIZE, 8);
395     addAttribute(EGL_GREEN_SIZE, 8);
396     addAttribute(EGL_BLUE_SIZE, 8);
397     addAttribute(EGL_CONFIG_CAVEAT, EGL_NONE);
398     if (backendConfig) {
399         if (backendConfig->MSAASamples > 1) {
400             addAttribute(EGL_SAMPLES, (EGLint)backendConfig->MSAASamples);
401             addAttribute(EGL_SAMPLE_BUFFERS, 1);
402         }
403         addAttribute(EGL_ALPHA_SIZE, (EGLint)backendConfig->alphaBits);
404         addAttribute(EGL_DEPTH_SIZE, (EGLint)backendConfig->depthBits);
405         addAttribute(EGL_STENCIL_SIZE, (EGLint)backendConfig->stencilBits);
406         PLUGIN_LOG_I("Samples:%d Alpha:%d Depth:%d Stencil:%d", backendConfig->MSAASamples, backendConfig->alphaBits,
407             backendConfig->depthBits, backendConfig->stencilBits);
408     }
409     addAttribute(EGL_NONE, EGL_NONE); // terminate list
410     eglChooseConfig(plat_.display, attributes.data(), &plat_.config, 1, &num_configs);
411     CheckEGLError(__FILE__, __LINE__);
412 #if RENDER_GL_DEBUG
413     PLUGIN_LOG_I("eglChooseConfig returned:");
414     DumpEGLConfig(plat_.display, plat_.config);
415 #endif
416 }
417 
CreateContext(const BackendExtraGLES * backendConfig)418 void EGLState::CreateContext(const BackendExtraGLES* backendConfig)
419 {
420     vector<EGLint> context_attributes;
421     const size_t ATTRIBUTE_RESERVE = 16;               // reserve 16 attributes
422     context_attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
423     auto addAttribute = [&context_attributes](EGLint a, EGLint b) {
424         context_attributes.push_back(a);
425         context_attributes.push_back(b);
426     };
427     if (IsVersionGreaterOrEqual(1, 5)) {
428         // egl 1.5 or greater.
429         addAttribute(EGL_CONTEXT_MAJOR_VERSION, 3); // Select an OpenGL ES 3.x context
430         addAttribute(EGL_CONTEXT_MINOR_VERSION, 2); // Select an OpenGL ES x.2 context
431 #if RENDER_GL_DEBUG
432         // should use EGL_CONTEXT_OPENGL_DEBUG , but at least PowerVR simulator fails with this
433         if (HasExtension("EGL_KHR_create_context")) {
434             // Setting up debug context with the extension seems to work.
435             addAttribute(EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
436         }
437 #endif
438     } else if (HasExtension("EGL_KHR_create_context")) {
439         // egl 1.4 with EGL_KHR_create_context
440         addAttribute(EGL_CONTEXT_MAJOR_VERSION_KHR, 3); // Select an OpenGL ES 3.x context
441         addAttribute(EGL_CONTEXT_MINOR_VERSION_KHR, 2); // Select an OpenGL ES x.2 context
442 #if RENDER_GL_DEBUG
443         addAttribute(EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
444 #endif
445     } else {
446         // fallback to non-extended or pre 1.5 EGL, we expect 3.2 OpenGL context, this is now checked later.
447         addAttribute(EGL_CONTEXT_CLIENT_VERSION, 3); // Select an OpenGL ES 3.x context
448     }
449     addAttribute(EGL_NONE, EGL_NONE);
450 
451     EGLContext sharedContext = EGL_NO_CONTEXT;
452     if (backendConfig) {
453         sharedContext = backendConfig->sharedContext;
454     }
455     plat_.context = eglCreateContext(plat_.display, plat_.config, sharedContext, context_attributes.data());
456     CheckEGLError(__FILE__, __LINE__);
457 
458     if (plat_.context == EGL_NO_CONTEXT) {
459         PLUGIN_LOG_E("eglCreateContext failed : %s", EglErrorStr(eglGetError()));
460         PLUGIN_ASSERT(false);
461         return;
462     }
463 }
464 
IsVersionGreaterOrEqual(uint32_t major,uint32_t minor) const465 bool EGLState::IsVersionGreaterOrEqual(uint32_t major, uint32_t minor) const
466 {
467     if (plat_.majorVersion < major) {
468         return false;
469     }
470     if (plat_.majorVersion > major) {
471         return true;
472     }
473     if (plat_.minorVersion >= minor) {
474         return true;
475     }
476     return false;
477 }
478 
VerifyVersion()479 bool EGLState::VerifyVersion()
480 {
481     // Verify that we have atleast 3.2 context.
482     EGLint glMajor = 0;
483     EGLint glMinor = 0;
484     SaveContext();
485     SetContext(nullptr); // activate the context with the dummy PBuffer.
486     string_view string((char*)glGetString(GL_VERSION));
487     // the format according to spec pdf is "OpenGL ES N.M vendor-specific information"
488     bool fail = false;
489     if (string.substr(0, 10) == "OpenGL ES ") {
490         // Must be OpenGL ES FULL. Trust this information. (even if it might mismatch with the eglQueryContext results)
491         string_view version = string.substr(10);
492         version = version.substr(0, version.find_first_of(' '));
493         auto dot = version.find_first_of('.');
494         auto majorS = version.substr(0, dot);
495         if (dot != string_view::npos) {
496             auto minorS = version.substr(dot + 1);
497             fail = (stringToUInt(minorS, glMinor)) ? fail : false;
498         }
499         fail = (stringToUInt(majorS, glMajor)) ? fail : false;
500     }
501     if (fail) {
502         // Try these then, if parsing the GL_VERSION string failed
503         glMajor = glMinor = 0;
504         eglQueryContext(plat_.display, plat_.context, EGL_CONTEXT_MAJOR_VERSION, &glMajor);
505         eglQueryContext(plat_.display, plat_.context, EGL_CONTEXT_MINOR_VERSION_KHR, &glMinor);
506     }
507 
508     if (glMajor < 3) {
509         fail = true;
510     } else if (glMajor == 3) {
511         if (glMinor < 2) {
512             // We do NOT support 3.0 or 3.1
513             fail = true;
514         }
515     }
516 
517     if (fail) {
518         // restore contexts and cleanup.
519         PLUGIN_LOG_E(
520             "Could not to Initialize required OpenGL ES version [%d.%d] [%s]", glMajor, glMinor, string.data());
521         RestoreContext();
522         // destroy the dummy surface also.
523         eglDestroySurface(plat_.display, dummySurface_);
524         dummyContext_.context = EGL_NO_CONTEXT;
525         dummyContext_.drawSurface = dummyContext_.readSurface = EGL_NO_SURFACE;
526         dummyContext_.display = EGL_NO_DISPLAY;
527     }
528     return !fail;
529 }
CreateContext(DeviceCreateInfo const & createInfo)530 bool EGLState::CreateContext(DeviceCreateInfo const& createInfo)
531 {
532     auto backendConfig = static_cast<const BackendExtraGLES*>(createInfo.backendConfiguration);
533     EGLint major, minor;
534 
535     plat_.display = eglGetDisplay(backendConfig->display);
536 
537     EGLContext appContext = EGL_NO_CONTEXT;
538     if (backendConfig) {
539         appContext = backendConfig->applicationContext;
540     }
541     if (appContext == EGL_NO_CONTEXT && backendConfig->sharedContext == EGL_NO_CONTEXT) {
542         if (!eglInitialize(plat_.display, &major, &minor)) {
543             PLUGIN_LOG_E("EGL initialization failed");
544             CHECK_EGL_ERROR();
545             PLUGIN_ASSERT(false);
546             return false;
547         }
548         plat_.eglInitialized = true;
549     } else {
550         major = 0;
551         minor = 0;
552 
553         // Check version from display as we don't call eglInitialize ourselves
554         const string_view version = eglQueryString(plat_.display, EGL_VERSION);
555         if (!version.empty()) {
556             const auto dot = version.find_first_of('.');
557             if (dot != string_view::npos) {
558                 const auto majorS = version.substr(0, dot);
559                 if (!stringToUInt(majorS, major)) {
560                     major = 0;
561                 }
562                 const auto space = version.find_first_of(' ', dot + 1);
563                 if (space != string_view::npos) {
564                     auto minorS = version.substr(dot + 1, space - (dot + 1));
565                     if (!stringToUInt(minorS, minor)) {
566                         minor = 0;
567                     }
568                 }
569             }
570         } else {
571             CHECK_EGL_ERROR();
572         }
573     }
574     plat_.majorVersion = static_cast<uint32_t>(major);
575     plat_.minorVersion = static_cast<uint32_t>(minor);
576     PLUGIN_LOG_I("EGL %d.%d Initialized", major, minor);
577 
578     if (!IsVersionGreaterOrEqual(1, 4)) {
579         // we need atleast egl 1.4
580         PLUGIN_LOG_F("EGL version too old. 1.4 or later requried.");
581         if (plat_.eglInitialized) {
582             eglTerminate(plat_.display);
583         }
584         return false;
585     }
586 
587     eglBindAPI(EGL_OPENGL_ES_API);
588     CHECK_EGL_ERROR();
589 
590     DumpEGLStrings(plat_.display);
591 
592     HandleExtensions();
593 
594     plat_.hasColorSpaceExt = hasColorSpaceExt_ = HasExtension("EGL_KHR_gl_colorspace");
595     // NOTE: "EGL_KHR_no_config_context" and "EGL_KHR_surfaceless_context" is technically working, but disabled for now.
596     hasConfiglessExt_ = false;
597     hasSurfacelessExt_ = false;
598     plat_.config = EGL_NO_CONFIG_KHR;
599     if (!hasConfiglessExt_) {
600         // we need a config for the context..
601         ChooseConfiguration(backendConfig);
602     }
603 
604     if (appContext) {
605         // use applications context
606         PLUGIN_LOG_I("Using application context in DeviceGLES");
607         plat_.context = appContext;
608     } else {
609         // Create a new context
610         CreateContext(backendConfig);
611         plat_.contextCreated = true;
612     }
613     if (plat_.context == EGL_NO_CONTEXT) {
614         // we have failed then.
615         if (plat_.eglInitialized) {
616             eglTerminate(plat_.display);
617         }
618         return false;
619     }
620 
621     if (!hasSurfacelessExt_) {
622         // Create a placeholder pbuffer, since we do NOT have a surface yet.
623         if (plat_.config == EGL_NO_CONFIG_KHR) {
624             // we need to choose a config for the surface..
625             ChooseConfiguration(backendConfig);
626         }
627         GLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
628         dummySurface_ = eglCreatePbufferSurface(plat_.display, plat_.config, surface_attribs);
629         CheckEGLError(__FILE__, __LINE__);
630 #if RENDER_GL_DEBUG
631         DumpEGLSurface(plat_.display, dummySurface_);
632 #endif
633     }
634 
635     dummyContext_.context = plat_.context;
636     dummyContext_.drawSurface = dummyContext_.readSurface = dummySurface_;
637     dummyContext_.display = plat_.display;
638 
639     if (!VerifyVersion()) {
640         if (plat_.contextCreated) {
641             eglDestroyContext(plat_.display, plat_.context);
642             plat_.context = EGL_NO_CONTEXT;
643         }
644         if (plat_.eglInitialized) {
645             eglTerminate(plat_.display);
646         }
647         return false;
648     }
649     return true;
650 }
651 
GlInitialize()652 void EGLState::GlInitialize()
653 {
654 #define declare(a, b)                                                                     \
655     if (b == nullptr) {                                                                   \
656         *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(eglGetProcAddress(#b)); \
657     }                                                                                     \
658     if (b == nullptr) {                                                                   \
659         PLUGIN_LOG_E("Missing %s\n", #b);                                                 \
660     }
661 
662 #include "gles/gl_functions.h"
663 
664     vSync_ = true;
665     SetSwapInterval(1); // default to vsync enabled.
666 }
667 
IsValid()668 bool EGLState::IsValid()
669 {
670     return (plat_.context != EGL_NO_CONTEXT);
671 }
672 
SaveContext()673 void EGLState::SaveContext()
674 {
675     PLUGIN_ASSERT(!oldIsSet_);
676     oldIsSet_ = true;
677     GetContext(oldContext_);
678 }
679 
SetContext(Swapchain * swapChain)680 void EGLState::SetContext(Swapchain* swapChain)
681 {
682     if (swapChain == nullptr) {
683         SetContext(dummyContext_, true);
684     } else {
685         SwapchainGLES* swap = static_cast<SwapchainGLES*>(swapChain);
686         ContextState newContext;
687         const auto& plat = (const SwapchainPlatformDataGL&)swap->GetPlatformData();
688         newContext.display = plat_.display;
689         newContext.context = plat_.context;
690         newContext.drawSurface = (EGLSurface)plat.surface;
691         newContext.readSurface = (EGLSurface)plat.surface;
692         SetContext(newContext, false);
693 
694         if (vSync_ != plat.vsync) {
695             vSync_ = plat.vsync;
696             SetSwapInterval(plat.vsync ? 1u : 0u);
697         }
698     }
699 }
700 
RestoreContext()701 void EGLState::RestoreContext()
702 {
703     PLUGIN_ASSERT(oldIsSet_);
704     SetContext(oldContext_, true);
705     oldIsSet_ = false;
706 }
707 
GetContext(ContextState & state)708 void EGLState::GetContext(ContextState& state)
709 {
710     state.display = eglGetCurrentDisplay();
711     CHECK_EGL_ERROR();
712     if (state.display != EGL_NO_DISPLAY) {
713         state.context = eglGetCurrentContext();
714         CHECK_EGL_ERROR();
715         state.readSurface = eglGetCurrentSurface(EGL_READ);
716         CHECK_EGL_ERROR();
717         state.drawSurface = eglGetCurrentSurface(EGL_DRAW);
718         CHECK_EGL_ERROR();
719     } else {
720         state.context = EGL_NO_CONTEXT;
721         state.readSurface = EGL_NO_SURFACE;
722         state.drawSurface = EGL_NO_SURFACE;
723     }
724 }
725 
SetContext(const ContextState & state,bool aForce)726 void EGLState::SetContext(const ContextState& state, bool aForce)
727 {
728     PLUGIN_ASSERT(oldIsSet_);
729     if (state.display != EGL_NO_DISPLAY) {
730         if ((aForce) || (oldContext_.display != state.display) || (oldContext_.drawSurface != state.drawSurface) ||
731             (oldContext_.readSurface != state.readSurface) || (oldContext_.context != state.context)) {
732             if (eglMakeCurrent(state.display, state.drawSurface, state.readSurface, state.context) == EGL_FALSE) {
733                 CHECK_EGL_ERROR2();
734             }
735         }
736     } else {
737         // Okay, do nothing.
738         // no display was active, so there can be no surface and no context.
739         // We need a display to deactivate context. (EGL_NO_DISPLAY is not a valid argument to eglMakeCurrent)
740         // so what to do, leak context?
741         // Or just disconnect context/surface from plat_.display (which currently is EGL_DEFAULT_DISPLAY...)
742         if (eglMakeCurrent(plat_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) {
743             CHECK_EGL_ERROR2();
744         }
745     }
746 }
747 
DestroyContext()748 void EGLState::DestroyContext()
749 {
750     if (plat_.display != EGL_NO_DISPLAY) {
751         eglMakeCurrent(plat_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
752         CHECK_EGL_ERROR();
753         if (dummySurface_ != EGL_NO_SURFACE) {
754             eglDestroySurface(plat_.display, dummySurface_);
755         }
756         CHECK_EGL_ERROR();
757         if (plat_.contextCreated) {
758             if (plat_.context != EGL_NO_CONTEXT) {
759                 eglDestroyContext(plat_.display, plat_.context);
760                 CHECK_EGL_ERROR();
761             }
762         }
763         if (plat_.eglInitialized) {
764             eglTerminate(plat_.display);
765             CHECK_EGL_ERROR();
766         }
767     }
768 }
769 
HasExtension(const string_view extension) const770 bool EGLState::HasExtension(const string_view extension) const
771 {
772     for (const auto& e : dextensionList_) {
773         if (extension == e)
774             return true;
775     }
776     for (const auto& e : cextensionList_) {
777         if (extension == e)
778             return true;
779     }
780     return false;
781 }
782 
SetSwapInterval(uint32_t interval)783 void EGLState::SetSwapInterval(uint32_t interval)
784 {
785     eglSwapInterval(plat_.display, (EGLint)interval);
786 }
787 
GetPlatformData() const788 const DevicePlatformData& EGLState::GetPlatformData() const
789 {
790     return plat_;
791 }
792 
ErrorFilter() const793 void* EGLState::ErrorFilter() const
794 {
795     return reinterpret_cast<void*>(FilterError);
796 }
797 
GetSurfaceInformation(const DevicePlatformDataGLES & plat,EGLSurface surface,GlesImplementation::SurfaceInfo & res) const798 bool EGLState::GetSurfaceInformation(
799     const DevicePlatformDataGLES& plat, EGLSurface surface, GlesImplementation::SurfaceInfo& res) const
800 {
801     EGLDisplay display = plat.display;
802 
803 #ifndef NDEBUG
804     PLUGIN_LOG_V("EGLState::GetSurfaceInformation: input surface information:");
805     EGLHelpers::DumpEGLSurface(display, surface);
806 #endif
807     EGLint configId;
808     // Get configId from surface
809     if (eglQuerySurface(display, surface, EGL_CONFIG_ID, &configId) == false) {
810         PLUGIN_LOG_E("EGLState::GetSurfaceInformation: Could not fetch surface config_id.");
811         return false;
812     }
813 
814     EGLConfig config = EGL_NO_CONFIG_KHR;
815     EGLint numconfigs = 0;
816     EGLint attrs[] = { EGL_CONFIG_ID, configId, EGL_NONE };
817     if (eglChooseConfig(display, attrs, &config, 1, &numconfigs) == false) {
818         PLUGIN_LOG_E("EGLState::GetSurfaceInformation: Could not fetch surface config.");
819         return false;
820     }
821 
822     PLUGIN_LOG_V("EGLState::GetSurfaceInformation: input surface configuration:");
823     EGLHelpers::DumpEGLConfig(display, config);
824 
825 #ifndef NDEBUG
826     if (!hasConfiglessExt_) {
827         // Check that it matches the config id from "system config"
828         EGLConfig plat_config = plat.config;
829         if ((plat_config != EGL_NO_CONFIG_KHR) && (plat_config != config)) {
830             PLUGIN_ASSERT_MSG(plat_config == config, "display config and surface config should match!");
831             PLUGIN_LOG_V("EGLState::GetSurfaceInformation: plat surface configuration:");
832             EGLHelpers::DumpEGLConfig(display, plat_config);
833         }
834     }
835 #endif
836 
837     // Fetch surface parameters
838     EGLint width = 0;
839     EGLint height = 0;
840     EGLint red_size = 0;
841     EGLint green_size = 0;
842     EGLint blue_size = 0;
843     EGLint alpha_size = 0;
844     EGLint samples = 0;
845     EGLint depth_size = 0;
846     EGLint stencil_size = 0;
847     eglQuerySurface(display, surface, EGL_WIDTH, &width);
848     eglQuerySurface(display, surface, EGL_HEIGHT, &height);
849     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red_size);
850     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green_size);
851     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue_size);
852     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha_size);
853     eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
854     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth_size);
855     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil_size);
856 
857     res.configId = (uint32_t)configId;
858     res.alpha_size = (uint32_t)alpha_size;
859     res.blue_size = (uint32_t)blue_size;
860     res.depth_size = (uint32_t)depth_size;
861     res.green_size = (uint32_t)green_size;
862     res.height = (uint32_t)height;
863     res.red_size = (uint32_t)red_size;
864     res.samples = (uint32_t)samples;
865     res.stencil_size = (uint32_t)stencil_size;
866     res.width = (uint32_t)width;
867 
868     EGLint colorspace = 0;
869     EGLint COLOR_SPACE = 0;
870     EGLint COLOR_SPACE_SRGB = 0;
871     if (IsVersionGreaterOrEqual(1, 5)) {
872         COLOR_SPACE = EGL_GL_COLORSPACE;
873         COLOR_SPACE_SRGB = EGL_GL_COLORSPACE_SRGB;
874     } else if (hasColorSpaceExt_) {
875         COLOR_SPACE = EGL_GL_COLORSPACE_KHR;
876         COLOR_SPACE_SRGB = EGL_GL_COLORSPACE_SRGB_KHR;
877     }
878 
879     if (COLOR_SPACE > 0) {
880         if (eglQuerySurface(display, surface, COLOR_SPACE, &colorspace)) {
881             // EGL_GL_COLORSPACE_SRGB or EGL_GL_COLORSPACE_LINEAR.
882             res.srgb = (colorspace == COLOR_SPACE_SRGB);
883         }
884     }
885 
886     if (colorspace == 0) {
887         // surface is linear (no conversion made during read/write)
888         // data should be srgb though.
889         PLUGIN_LOG_E("EGL_GL_COLORSPACE query failed (or not available). Defaulting to linear buffer with srgb data");
890         res.srgb = false;
891     }
892 
893     return true;
894 }
895 } // namespace EGLHelpers
896 RENDER_END_NAMESPACE()
897 #endif
898