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