1 //
2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "util/EGLWindow.h"
8 
9 #include <cassert>
10 #include <iostream>
11 #include <vector>
12 
13 #include <string.h>
14 
15 #include "common/system_utils.h"
16 #include "platform/Platform.h"
17 #include "util/OSWindow.h"
18 
19 // ConfigParameters implementation.
ConfigParameters()20 ConfigParameters::ConfigParameters()
21     : redBits(-1),
22       greenBits(-1),
23       blueBits(-1),
24       alphaBits(-1),
25       depthBits(-1),
26       stencilBits(-1),
27       componentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT),
28       multisample(false),
29       debug(false),
30       noError(false),
31       bindGeneratesResource(true),
32       clientArraysEnabled(true),
33       robustAccess(false),
34       samples(-1),
35       resetStrategy(EGL_NO_RESET_NOTIFICATION_EXT)
36 {}
37 
38 ConfigParameters::~ConfigParameters() = default;
39 
reset()40 void ConfigParameters::reset()
41 {
42     *this = ConfigParameters();
43 }
44 
45 // GLWindowBase implementation.
GLWindowBase(EGLint glesMajorVersion,EGLint glesMinorVersion)46 GLWindowBase::GLWindowBase(EGLint glesMajorVersion, EGLint glesMinorVersion)
47     : mClientMajorVersion(glesMajorVersion), mClientMinorVersion(glesMinorVersion)
48 {}
49 
50 GLWindowBase::~GLWindowBase() = default;
51 
52 // EGLWindow implementation.
EGLWindow(EGLint glesMajorVersion,EGLint glesMinorVersion)53 EGLWindow::EGLWindow(EGLint glesMajorVersion, EGLint glesMinorVersion)
54     : GLWindowBase(glesMajorVersion, glesMinorVersion),
55       mConfig(0),
56       mDisplay(EGL_NO_DISPLAY),
57       mSurface(EGL_NO_SURFACE),
58       mContext(EGL_NO_CONTEXT),
59       mEGLMajorVersion(0),
60       mEGLMinorVersion(0)
61 {}
62 
~EGLWindow()63 EGLWindow::~EGLWindow()
64 {
65     destroyGL();
66 }
67 
swap()68 void EGLWindow::swap()
69 {
70     eglSwapBuffers(mDisplay, mSurface);
71 }
72 
getConfig() const73 EGLConfig EGLWindow::getConfig() const
74 {
75     return mConfig;
76 }
77 
getDisplay() const78 EGLDisplay EGLWindow::getDisplay() const
79 {
80     return mDisplay;
81 }
82 
getSurface() const83 EGLSurface EGLWindow::getSurface() const
84 {
85     return mSurface;
86 }
87 
getContext() const88 EGLContext EGLWindow::getContext() const
89 {
90     return mContext;
91 }
92 
initializeGL(OSWindow * osWindow,angle::Library * glWindowingLibrary,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)93 bool EGLWindow::initializeGL(OSWindow *osWindow,
94                              angle::Library *glWindowingLibrary,
95                              const EGLPlatformParameters &platformParams,
96                              const ConfigParameters &configParams)
97 {
98     if (!initializeDisplay(osWindow, glWindowingLibrary, platformParams))
99         return false;
100     if (!initializeSurface(osWindow, glWindowingLibrary, configParams))
101         return false;
102     if (!initializeContext())
103         return false;
104     return true;
105 }
106 
initializeDisplay(OSWindow * osWindow,angle::Library * glWindowingLibrary,const EGLPlatformParameters & params)107 bool EGLWindow::initializeDisplay(OSWindow *osWindow,
108                                   angle::Library *glWindowingLibrary,
109                                   const EGLPlatformParameters &params)
110 {
111 #if defined(ANGLE_USE_UTIL_LOADER)
112     PFNEGLGETPROCADDRESSPROC getProcAddress;
113     glWindowingLibrary->getAs("eglGetProcAddress", &getProcAddress);
114     if (!getProcAddress)
115     {
116         return false;
117     }
118 
119     // Likely we will need to use a fallback to Library::getAs on non-ANGLE platforms.
120     angle::LoadEGL(getProcAddress);
121 #endif  // defined(ANGLE_USE_UTIL_LOADER)
122 
123     const char *extensionString =
124         static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
125 
126     std::vector<EGLAttrib> displayAttributes;
127     displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
128     displayAttributes.push_back(params.renderer);
129     displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
130     displayAttributes.push_back(params.majorVersion);
131     displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
132     displayAttributes.push_back(params.minorVersion);
133 
134     if (params.deviceType != EGL_DONT_CARE)
135     {
136         displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
137         displayAttributes.push_back(params.deviceType);
138     }
139 
140     if (params.presentPath != EGL_DONT_CARE)
141     {
142         if (strstr(extensionString, "EGL_ANGLE_experimental_present_path") == nullptr)
143         {
144             destroyGL();
145             return false;
146         }
147 
148         displayAttributes.push_back(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE);
149         displayAttributes.push_back(params.presentPath);
150     }
151 
152     // Set debug layer settings if requested.
153     if (params.debugLayersEnabled != EGL_DONT_CARE)
154     {
155         displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
156         displayAttributes.push_back(params.debugLayersEnabled);
157     }
158 
159     if (params.contextVirtualization != EGL_DONT_CARE)
160     {
161         displayAttributes.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
162         displayAttributes.push_back(params.contextVirtualization);
163     }
164 
165     if (params.platformMethods)
166     {
167         static_assert(sizeof(EGLAttrib) == sizeof(params.platformMethods),
168                       "Unexpected pointer size");
169         displayAttributes.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
170         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(params.platformMethods));
171     }
172 
173     std::vector<const char *> disabledFeatureOverrides;
174     std::vector<const char *> enabledFeatureOverrides;
175 
176     if (params.transformFeedbackFeature == EGL_FALSE)
177     {
178         disabledFeatureOverrides.push_back("supports_transform_feedback_extension");
179         disabledFeatureOverrides.push_back("emulate_transform_feedback");
180     }
181 
182     if (params.allocateNonZeroMemoryFeature == EGL_TRUE)
183     {
184         enabledFeatureOverrides.push_back("allocate_non_zero_memory");
185     }
186     else if (params.allocateNonZeroMemoryFeature == EGL_FALSE)
187     {
188         disabledFeatureOverrides.push_back("allocate_non_zero_memory");
189     }
190 
191     if (!disabledFeatureOverrides.empty())
192     {
193         if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
194         {
195             std::cout << "Missing EGL_ANGLE_feature_control.\n";
196             destroyGL();
197             return false;
198         }
199 
200         disabledFeatureOverrides.push_back(nullptr);
201 
202         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
203         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(disabledFeatureOverrides.data()));
204     }
205 
206     if (!enabledFeatureOverrides.empty())
207     {
208         if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
209         {
210             std::cout << "Missing EGL_ANGLE_feature_control.\n";
211             destroyGL();
212             return false;
213         }
214 
215         enabledFeatureOverrides.push_back(nullptr);
216 
217         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
218         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(enabledFeatureOverrides.data()));
219     }
220 
221     displayAttributes.push_back(EGL_NONE);
222 
223     mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
224                                      reinterpret_cast<void *>(osWindow->getNativeDisplay()),
225                                      &displayAttributes[0]);
226     if (mDisplay == EGL_NO_DISPLAY)
227     {
228         destroyGL();
229         return false;
230     }
231 
232     if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
233     {
234         destroyGL();
235         return false;
236     }
237 
238     mPlatform = params;
239     return true;
240 }
241 
initializeSurface(OSWindow * osWindow,angle::Library * glWindowingLibrary,const ConfigParameters & params)242 bool EGLWindow::initializeSurface(OSWindow *osWindow,
243                                   angle::Library *glWindowingLibrary,
244                                   const ConfigParameters &params)
245 {
246     mConfigParams                 = params;
247     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
248 
249     std::vector<EGLint> configAttributes = {
250         EGL_RED_SIZE,
251         (mConfigParams.redBits >= 0) ? mConfigParams.redBits : EGL_DONT_CARE,
252         EGL_GREEN_SIZE,
253         (mConfigParams.greenBits >= 0) ? mConfigParams.greenBits : EGL_DONT_CARE,
254         EGL_BLUE_SIZE,
255         (mConfigParams.blueBits >= 0) ? mConfigParams.blueBits : EGL_DONT_CARE,
256         EGL_ALPHA_SIZE,
257         (mConfigParams.alphaBits >= 0) ? mConfigParams.alphaBits : EGL_DONT_CARE,
258         EGL_DEPTH_SIZE,
259         (mConfigParams.depthBits >= 0) ? mConfigParams.depthBits : EGL_DONT_CARE,
260         EGL_STENCIL_SIZE,
261         (mConfigParams.stencilBits >= 0) ? mConfigParams.stencilBits : EGL_DONT_CARE,
262         EGL_SAMPLE_BUFFERS,
263         mConfigParams.multisample ? 1 : 0,
264         EGL_SAMPLES,
265         (mConfigParams.samples >= 0) ? mConfigParams.samples : EGL_DONT_CARE,
266     };
267 
268     // Add dynamic attributes
269     bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
270     if (!hasPixelFormatFloat && mConfigParams.componentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
271     {
272         destroyGL();
273         return false;
274     }
275     if (hasPixelFormatFloat)
276     {
277         configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
278         configAttributes.push_back(mConfigParams.componentType);
279     }
280 
281     // Finish the attribute list
282     configAttributes.push_back(EGL_NONE);
283 
284     if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
285     {
286         std::cout << "Could not find a suitable EGL config!" << std::endl;
287         destroyGL();
288         return false;
289     }
290 
291     eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mConfigParams.redBits);
292     eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mConfigParams.greenBits);
293     eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mConfigParams.blueBits);
294     eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mConfigParams.alphaBits);
295     eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mConfigParams.depthBits);
296     eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mConfigParams.stencilBits);
297     eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mConfigParams.samples);
298 
299     std::vector<EGLint> surfaceAttributes;
300     if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
301     {
302         surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
303         surfaceAttributes.push_back(EGL_TRUE);
304     }
305 
306     bool hasRobustResourceInit =
307         strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
308     if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
309     {
310         surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
311         surfaceAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
312                                                                              : EGL_FALSE);
313     }
314 
315     surfaceAttributes.push_back(EGL_NONE);
316 
317     osWindow->resetNativeWindow();
318 
319     mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
320                                       &surfaceAttributes[0]);
321     if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
322     {
323         destroyGL();
324         return false;
325     }
326 
327 #if defined(ANGLE_USE_UTIL_LOADER)
328     angle::LoadGLES(eglGetProcAddress);
329 #endif  // defined(ANGLE_USE_UTIL_LOADER)
330 
331     return true;
332 }
333 
createContext(EGLContext share) const334 EGLContext EGLWindow::createContext(EGLContext share) const
335 {
336     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
337 
338     // EGL_KHR_create_context is required to request a ES3+ context.
339     bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
340     if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
341         !hasKHRCreateContext)
342     {
343         std::cerr << "EGL_KHR_create_context incompatibility.\n";
344         return EGL_NO_CONTEXT;
345     }
346 
347     bool hasWebGLCompatibility =
348         strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
349     if (mConfigParams.webGLCompatibility.valid() && !hasWebGLCompatibility)
350     {
351         std::cerr << "EGL_ANGLE_create_context_webgl_compatibility missing.\n";
352         return EGL_NO_CONTEXT;
353     }
354 
355     bool hasCreateContextExtensionsEnabled =
356         strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
357     if (mConfigParams.extensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
358     {
359         std::cerr << "EGL_ANGLE_create_context_extensions_enabled missing.\n";
360         return EGL_NO_CONTEXT;
361     }
362 
363     bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
364     if ((mConfigParams.robustAccess ||
365          mConfigParams.resetStrategy != EGL_NO_RESET_NOTIFICATION_EXT) &&
366         !hasRobustness)
367     {
368         std::cerr << "EGL_EXT_create_context_robustness missing.\n";
369         return EGL_NO_CONTEXT;
370     }
371 
372     bool hasBindGeneratesResource =
373         strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
374     if (!mConfigParams.bindGeneratesResource && !hasBindGeneratesResource)
375     {
376         std::cerr << "EGL_CHROMIUM_create_context_bind_generates_resource missing.\n";
377         return EGL_NO_CONTEXT;
378     }
379 
380     bool hasClientArraysExtension =
381         strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
382     if (!mConfigParams.clientArraysEnabled && !hasClientArraysExtension)
383     {
384         // Non-default state requested without the extension present
385         std::cerr << "EGL_ANGLE_create_context_client_arrays missing.\n";
386         return EGL_NO_CONTEXT;
387     }
388 
389     bool hasProgramCacheControlExtension =
390         strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
391     if (mConfigParams.contextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
392     {
393         std::cerr << "EGL_ANGLE_program_cache_control missing.\n";
394         return EGL_NO_CONTEXT;
395     }
396 
397     bool hasBackwardsCompatibleContextExtension =
398         strstr(displayExtensions, "EGL_ANGLE_create_context_backwards_compatible") != nullptr;
399     if (!hasProgramCacheControlExtension)
400     {
401         std::cerr << "EGL_ANGLE_create_context_backwards_compatible missing.\n";
402         return EGL_NO_CONTEXT;
403     }
404 
405     eglBindAPI(EGL_OPENGL_ES_API);
406     if (eglGetError() != EGL_SUCCESS)
407     {
408         std::cerr << "Error on eglBindAPI.\n";
409         return EGL_NO_CONTEXT;
410     }
411 
412     std::vector<EGLint> contextAttributes;
413     if (hasKHRCreateContext)
414     {
415         contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
416         contextAttributes.push_back(mClientMajorVersion);
417 
418         contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
419         contextAttributes.push_back(mClientMinorVersion);
420 
421         contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
422         contextAttributes.push_back(mConfigParams.debug ? EGL_TRUE : EGL_FALSE);
423 
424         // TODO(jmadill): Check for the extension string.
425         // bool hasKHRCreateContextNoError = strstr(displayExtensions,
426         // "EGL_KHR_create_context_no_error") != nullptr;
427 
428         contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
429         contextAttributes.push_back(mConfigParams.noError ? EGL_TRUE : EGL_FALSE);
430 
431         if (mConfigParams.webGLCompatibility.valid())
432         {
433             contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
434             contextAttributes.push_back(mConfigParams.webGLCompatibility.value() ? EGL_TRUE
435                                                                                  : EGL_FALSE);
436         }
437 
438         if (mConfigParams.extensionsEnabled.valid())
439         {
440             contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
441             contextAttributes.push_back(mConfigParams.extensionsEnabled.value() ? EGL_TRUE
442                                                                                 : EGL_FALSE);
443         }
444 
445         if (hasRobustness)
446         {
447             contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
448             contextAttributes.push_back(mConfigParams.robustAccess ? EGL_TRUE : EGL_FALSE);
449 
450             contextAttributes.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
451             contextAttributes.push_back(mConfigParams.resetStrategy);
452         }
453 
454         if (hasBindGeneratesResource)
455         {
456             contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
457             contextAttributes.push_back(mConfigParams.bindGeneratesResource ? EGL_TRUE : EGL_FALSE);
458         }
459 
460         if (hasClientArraysExtension)
461         {
462             contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
463             contextAttributes.push_back(mConfigParams.clientArraysEnabled ? EGL_TRUE : EGL_FALSE);
464         }
465 
466         if (mConfigParams.contextProgramCacheEnabled.valid())
467         {
468             contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
469             contextAttributes.push_back(
470                 mConfigParams.contextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
471         }
472 
473         if (hasBackwardsCompatibleContextExtension)
474         {
475             // Always request the exact context version that the config wants
476             contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
477             contextAttributes.push_back(EGL_FALSE);
478         }
479 
480         bool hasRobustResourceInit =
481             strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
482         if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
483         {
484             contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
485             contextAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
486                                                                                  : EGL_FALSE);
487         }
488     }
489     contextAttributes.push_back(EGL_NONE);
490 
491     EGLContext context = eglCreateContext(mDisplay, mConfig, share, &contextAttributes[0]);
492     if (eglGetError() != EGL_SUCCESS)
493     {
494         std::cerr << "Error on eglCreateContext.\n";
495         return EGL_NO_CONTEXT;
496     }
497 
498     return context;
499 }
500 
initializeContext()501 bool EGLWindow::initializeContext()
502 {
503     mContext = createContext(EGL_NO_CONTEXT);
504     if (mContext == EGL_NO_CONTEXT)
505     {
506         destroyGL();
507         return false;
508     }
509 
510     if (!makeCurrent())
511     {
512         destroyGL();
513         return false;
514     }
515 
516     return true;
517 }
518 
destroyGL()519 void EGLWindow::destroyGL()
520 {
521     destroyContext();
522     destroySurface();
523 
524     if (mDisplay != EGL_NO_DISPLAY)
525     {
526         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
527         eglTerminate(mDisplay);
528         mDisplay = EGL_NO_DISPLAY;
529     }
530 }
531 
destroySurface()532 void EGLWindow::destroySurface()
533 {
534     if (mSurface != EGL_NO_SURFACE)
535     {
536         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
537         assert(mDisplay != EGL_NO_DISPLAY);
538         eglDestroySurface(mDisplay, mSurface);
539         mSurface = EGL_NO_SURFACE;
540     }
541 }
542 
destroyContext()543 void EGLWindow::destroyContext()
544 {
545     if (mContext != EGL_NO_CONTEXT)
546     {
547         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
548         assert(mDisplay != EGL_NO_DISPLAY);
549         eglDestroyContext(mDisplay, mContext);
550         mContext = EGL_NO_CONTEXT;
551     }
552 }
553 
isGLInitialized() const554 bool EGLWindow::isGLInitialized() const
555 {
556     return mSurface != EGL_NO_SURFACE && mContext != EGL_NO_CONTEXT && mDisplay != EGL_NO_DISPLAY;
557 }
558 
559 // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
560 // the EGLConfig is found.  This indicates that the EGLConfig is not supported.
FindEGLConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * config)561 EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
562 {
563     EGLint numConfigs = 0;
564     eglGetConfigs(dpy, nullptr, 0, &numConfigs);
565     std::vector<EGLConfig> allConfigs(numConfigs);
566     eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
567 
568     for (size_t i = 0; i < allConfigs.size(); i++)
569     {
570         bool matchFound = true;
571         for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
572         {
573             if (curAttrib[1] == EGL_DONT_CARE)
574             {
575                 continue;
576             }
577 
578             EGLint actualValue = EGL_DONT_CARE;
579             eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
580             if (curAttrib[1] != actualValue)
581             {
582                 matchFound = false;
583                 break;
584             }
585         }
586 
587         if (matchFound)
588         {
589             *config = allConfigs[i];
590             return EGL_TRUE;
591         }
592     }
593 
594     return EGL_FALSE;
595 }
596 
makeCurrent()597 bool EGLWindow::makeCurrent()
598 {
599     if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE ||
600         eglGetError() != EGL_SUCCESS)
601     {
602         std::cerr << "Error during eglMakeCurrent.\n";
603         return false;
604     }
605 
606     return true;
607 }
608 
setSwapInterval(EGLint swapInterval)609 bool EGLWindow::setSwapInterval(EGLint swapInterval)
610 {
611     if (eglSwapInterval(mDisplay, swapInterval) == EGL_FALSE || eglGetError() != EGL_SUCCESS)
612     {
613         std::cerr << "Error during eglSwapInterval.\n";
614         return false;
615     }
616 
617     return true;
618 }
619 
hasError() const620 bool EGLWindow::hasError() const
621 {
622     return eglGetError() != EGL_SUCCESS;
623 }
624 
625 // static
Delete(GLWindowBase ** window)626 void GLWindowBase::Delete(GLWindowBase **window)
627 {
628     delete *window;
629     *window = nullptr;
630 }
631 
632 // static
New(EGLint glesMajorVersion,EGLint glesMinorVersion)633 EGLWindow *EGLWindow::New(EGLint glesMajorVersion, EGLint glesMinorVersion)
634 {
635     return new EGLWindow(glesMajorVersion, glesMinorVersion);
636 }
637 
638 // static
Delete(EGLWindow ** window)639 void EGLWindow::Delete(EGLWindow **window)
640 {
641     delete *window;
642     *window = nullptr;
643 }
644