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