[ANGLE - iOS] fast/canvas/webgl/uninitialized-test.html is still failing
[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 (params.emulateCopyTexImage2DFromRenderbuffers == EGL_TRUE)
195     {
196         enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers");
197     }
198
199     if (!disabledFeatureOverrides.empty())
200     {
201         if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
202         {
203             fprintf(stderr, "Missing EGL_ANGLE_feature_control.\n");
204             destroyGL();
205             return false;
206         }
207
208         disabledFeatureOverrides.push_back(nullptr);
209
210         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
211         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(disabledFeatureOverrides.data()));
212     }
213
214     if (!enabledFeatureOverrides.empty())
215     {
216         if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
217         {
218             fprintf(stderr, "Missing EGL_ANGLE_feature_control.\n");
219             destroyGL();
220             return false;
221         }
222
223         enabledFeatureOverrides.push_back(nullptr);
224
225         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
226         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(enabledFeatureOverrides.data()));
227     }
228
229     displayAttributes.push_back(EGL_NONE);
230
231     if (driverType == angle::GLESDriverType::SystemWGL)
232         return false;
233
234     if (driverType == angle::GLESDriverType::AngleEGL &&
235         strstr(extensionString, "EGL_ANGLE_platform_angle"))
236     {
237         mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
238                                          reinterpret_cast<void *>(osWindow->getNativeDisplay()),
239                                          &displayAttributes[0]);
240     }
241     else
242     {
243         mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
244     }
245
246     if (mDisplay == EGL_NO_DISPLAY)
247     {
248         fprintf(stderr, "Failed to get display: 0x%X\n", eglGetError());
249         destroyGL();
250         return false;
251     }
252
253     if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
254     {
255         fprintf(stderr, "eglInitialize failed: 0x%X\n", eglGetError());
256         destroyGL();
257         return false;
258     }
259
260     mPlatform = params;
261     return true;
262 }
263
264 bool EGLWindow::initializeSurface(OSWindow *osWindow,
265                                   angle::Library *glWindowingLibrary,
266                                   const ConfigParameters &params)
267 {
268     mConfigParams                 = params;
269     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
270
271     std::vector<EGLint> configAttributes = {
272         EGL_RED_SIZE,
273         (mConfigParams.redBits >= 0) ? mConfigParams.redBits : EGL_DONT_CARE,
274         EGL_GREEN_SIZE,
275         (mConfigParams.greenBits >= 0) ? mConfigParams.greenBits : EGL_DONT_CARE,
276         EGL_BLUE_SIZE,
277         (mConfigParams.blueBits >= 0) ? mConfigParams.blueBits : EGL_DONT_CARE,
278         EGL_ALPHA_SIZE,
279         (mConfigParams.alphaBits >= 0) ? mConfigParams.alphaBits : EGL_DONT_CARE,
280         EGL_DEPTH_SIZE,
281         (mConfigParams.depthBits >= 0) ? mConfigParams.depthBits : EGL_DONT_CARE,
282         EGL_STENCIL_SIZE,
283         (mConfigParams.stencilBits >= 0) ? mConfigParams.stencilBits : EGL_DONT_CARE,
284         EGL_SAMPLE_BUFFERS,
285         mConfigParams.multisample ? 1 : 0,
286         EGL_SAMPLES,
287         (mConfigParams.samples >= 0) ? mConfigParams.samples : EGL_DONT_CARE,
288     };
289
290     // Add dynamic attributes
291     bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
292     if (!hasPixelFormatFloat && mConfigParams.componentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
293     {
294         fprintf(stderr, "Mising EGL_EXT_pixel_format_float.\n");
295         destroyGL();
296         return false;
297     }
298     if (hasPixelFormatFloat)
299     {
300         configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
301         configAttributes.push_back(mConfigParams.componentType);
302     }
303
304     // Finish the attribute list
305     configAttributes.push_back(EGL_NONE);
306
307     if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
308     {
309         fprintf(stderr, "Could not find a suitable EGL config!\n");
310         destroyGL();
311         return false;
312     }
313
314     eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mConfigParams.redBits);
315     eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mConfigParams.greenBits);
316     eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mConfigParams.blueBits);
317     eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mConfigParams.alphaBits);
318     eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mConfigParams.depthBits);
319     eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mConfigParams.stencilBits);
320     eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mConfigParams.samples);
321
322     std::vector<EGLint> surfaceAttributes;
323     if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
324     {
325         surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
326         surfaceAttributes.push_back(EGL_TRUE);
327     }
328
329     bool hasRobustResourceInit =
330         strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
331     if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
332     {
333         surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
334         surfaceAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
335                                                                              : EGL_FALSE);
336     }
337
338     surfaceAttributes.push_back(EGL_NONE);
339
340     osWindow->resetNativeWindow();
341
342     mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
343                                       &surfaceAttributes[0]);
344     if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
345     {
346         fprintf(stderr, "eglCreateWindowSurface failed: 0x%X\n", eglGetError());
347         destroyGL();
348         return false;
349     }
350
351 #if defined(ANGLE_USE_UTIL_LOADER)
352     angle::LoadGLES(eglGetProcAddress);
353 #endif  // defined(ANGLE_USE_UTIL_LOADER)
354
355     return true;
356 }
357
358 EGLContext EGLWindow::createContext(EGLContext share) const
359 {
360     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
361
362     // EGL_KHR_create_context is required to request a ES3+ context.
363     bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
364     if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
365         !hasKHRCreateContext)
366     {
367         fprintf(stderr, "EGL_KHR_create_context incompatibility.\n");
368         return EGL_NO_CONTEXT;
369     }
370
371     // EGL_CONTEXT_OPENGL_DEBUG is only valid as of EGL 1.5.
372     bool hasDebug = mEGLMinorVersion >= 5;
373     if (mConfigParams.debug && !hasDebug)
374     {
375         fprintf(stderr, "EGL 1.5 is required for EGL_CONTEXT_OPENGL_DEBUG.\n");
376         return EGL_NO_CONTEXT;
377     }
378
379     bool hasWebGLCompatibility =
380         strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
381     if (mConfigParams.webGLCompatibility.valid() && !hasWebGLCompatibility)
382     {
383         fprintf(stderr, "EGL_ANGLE_create_context_webgl_compatibility missing.\n");
384         return EGL_NO_CONTEXT;
385     }
386
387     bool hasCreateContextExtensionsEnabled =
388         strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
389     if (mConfigParams.extensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
390     {
391         fprintf(stderr, "EGL_ANGLE_create_context_extensions_enabled missing.\n");
392         return EGL_NO_CONTEXT;
393     }
394
395     bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
396     if ((mConfigParams.robustAccess ||
397          mConfigParams.resetStrategy != EGL_NO_RESET_NOTIFICATION_EXT) &&
398         !hasRobustness)
399     {
400         fprintf(stderr, "EGL_EXT_create_context_robustness missing.\n");
401         return EGL_NO_CONTEXT;
402     }
403
404     bool hasBindGeneratesResource =
405         strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
406     if (!mConfigParams.bindGeneratesResource && !hasBindGeneratesResource)
407     {
408         fprintf(stderr, "EGL_CHROMIUM_create_context_bind_generates_resource missing.\n");
409         return EGL_NO_CONTEXT;
410     }
411
412     bool hasClientArraysExtension =
413         strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
414     if (!mConfigParams.clientArraysEnabled && !hasClientArraysExtension)
415     {
416         // Non-default state requested without the extension present
417         fprintf(stderr, "EGL_ANGLE_create_context_client_arrays missing.\n");
418         return EGL_NO_CONTEXT;
419     }
420
421     bool hasProgramCacheControlExtension =
422         strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
423     if (mConfigParams.contextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
424     {
425         fprintf(stderr, "EGL_ANGLE_program_cache_control missing.\n");
426         return EGL_NO_CONTEXT;
427     }
428
429     bool hasKHRCreateContextNoError =
430         strstr(displayExtensions, "EGL_KHR_create_context_no_error") != nullptr;
431     if (mConfigParams.noError && !hasKHRCreateContextNoError)
432     {
433         fprintf(stderr, "EGL_KHR_create_context_no_error missing.\n");
434         return EGL_NO_CONTEXT;
435     }
436
437     eglBindAPI(EGL_OPENGL_ES_API);
438     if (eglGetError() != EGL_SUCCESS)
439     {
440         fprintf(stderr, "Error on eglBindAPI.\n");
441         return EGL_NO_CONTEXT;
442     }
443
444     std::vector<EGLint> contextAttributes;
445     if (hasKHRCreateContext)
446     {
447         contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
448         contextAttributes.push_back(mClientMajorVersion);
449
450         contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
451         contextAttributes.push_back(mClientMinorVersion);
452
453         // Note that the Android loader currently doesn't handle this flag despite reporting 1.5.
454         // Work around this by only using the debug bit when we request a debug context.
455         if (hasDebug && mConfigParams.debug)
456         {
457             contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
458             contextAttributes.push_back(mConfigParams.debug ? EGL_TRUE : EGL_FALSE);
459         }
460
461         if (hasKHRCreateContextNoError)
462         {
463             contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
464             contextAttributes.push_back(mConfigParams.noError ? EGL_TRUE : EGL_FALSE);
465         }
466
467         if (mConfigParams.webGLCompatibility.valid())
468         {
469             contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
470             contextAttributes.push_back(mConfigParams.webGLCompatibility.value() ? EGL_TRUE
471                                                                                  : EGL_FALSE);
472         }
473
474         if (mConfigParams.extensionsEnabled.valid())
475         {
476             contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
477             contextAttributes.push_back(mConfigParams.extensionsEnabled.value() ? EGL_TRUE
478                                                                                 : EGL_FALSE);
479         }
480
481         if (hasRobustness)
482         {
483             contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
484             contextAttributes.push_back(mConfigParams.robustAccess ? EGL_TRUE : EGL_FALSE);
485
486             contextAttributes.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
487             contextAttributes.push_back(mConfigParams.resetStrategy);
488         }
489
490         if (hasBindGeneratesResource)
491         {
492             contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
493             contextAttributes.push_back(mConfigParams.bindGeneratesResource ? EGL_TRUE : EGL_FALSE);
494         }
495
496         if (hasClientArraysExtension)
497         {
498             contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
499             contextAttributes.push_back(mConfigParams.clientArraysEnabled ? EGL_TRUE : EGL_FALSE);
500         }
501
502         if (mConfigParams.contextProgramCacheEnabled.valid())
503         {
504             contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
505             contextAttributes.push_back(
506                 mConfigParams.contextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
507         }
508
509         bool hasBackwardsCompatibleContextExtension =
510             strstr(displayExtensions, "EGL_ANGLE_create_context_backwards_compatible") != nullptr;
511         if (hasBackwardsCompatibleContextExtension)
512         {
513             // Always request the exact context version that the config wants
514             contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
515             contextAttributes.push_back(EGL_FALSE);
516         }
517
518         bool hasRobustResourceInit =
519             strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
520         if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
521         {
522             contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
523             contextAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
524                                                                                  : EGL_FALSE);
525         }
526     }
527     contextAttributes.push_back(EGL_NONE);
528
529     EGLContext context = eglCreateContext(mDisplay, mConfig, share, &contextAttributes[0]);
530     if (context == EGL_NO_CONTEXT)
531     {
532         fprintf(stderr, "eglCreateContext failed: 0x%X\n", eglGetError());
533         return EGL_NO_CONTEXT;
534     }
535
536     return context;
537 }
538
539 bool EGLWindow::initializeContext()
540 {
541     mContext = createContext(EGL_NO_CONTEXT);
542     if (mContext == EGL_NO_CONTEXT)
543     {
544         destroyGL();
545         return false;
546     }
547
548     if (!makeCurrent())
549     {
550         destroyGL();
551         return false;
552     }
553
554     return true;
555 }
556
557 void EGLWindow::destroyGL()
558 {
559     destroyContext();
560     destroySurface();
561
562     if (mDisplay != EGL_NO_DISPLAY)
563     {
564         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
565         eglTerminate(mDisplay);
566         mDisplay = EGL_NO_DISPLAY;
567     }
568 }
569
570 void EGLWindow::destroySurface()
571 {
572     if (mSurface != EGL_NO_SURFACE)
573     {
574         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
575         assert(mDisplay != EGL_NO_DISPLAY);
576         eglDestroySurface(mDisplay, mSurface);
577         mSurface = EGL_NO_SURFACE;
578     }
579 }
580
581 void EGLWindow::destroyContext()
582 {
583     if (mContext != EGL_NO_CONTEXT)
584     {
585         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
586         assert(mDisplay != EGL_NO_DISPLAY);
587         eglDestroyContext(mDisplay, mContext);
588         mContext = EGL_NO_CONTEXT;
589     }
590 }
591
592 bool EGLWindow::isGLInitialized() const
593 {
594     return mSurface != EGL_NO_SURFACE && mContext != EGL_NO_CONTEXT && mDisplay != EGL_NO_DISPLAY;
595 }
596
597 // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
598 // the EGLConfig is found.  This indicates that the EGLConfig is not supported.
599 EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
600 {
601     EGLint numConfigs = 0;
602     eglGetConfigs(dpy, nullptr, 0, &numConfigs);
603     std::vector<EGLConfig> allConfigs(numConfigs);
604     eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
605
606     for (size_t i = 0; i < allConfigs.size(); i++)
607     {
608         bool matchFound = true;
609         for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
610         {
611             if (curAttrib[1] == EGL_DONT_CARE)
612             {
613                 continue;
614             }
615
616             EGLint actualValue = EGL_DONT_CARE;
617             eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
618             if (curAttrib[1] != actualValue)
619             {
620                 matchFound = false;
621                 break;
622             }
623         }
624
625         if (matchFound)
626         {
627             *config = allConfigs[i];
628             return EGL_TRUE;
629         }
630     }
631
632     return EGL_FALSE;
633 }
634
635 bool EGLWindow::makeCurrent()
636 {
637     if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE ||
638         eglGetError() != EGL_SUCCESS)
639     {
640         fprintf(stderr, "Error during eglMakeCurrent.\n");
641         return false;
642     }
643
644     return true;
645 }
646
647 bool EGLWindow::setSwapInterval(EGLint swapInterval)
648 {
649     if (eglSwapInterval(mDisplay, swapInterval) == EGL_FALSE || eglGetError() != EGL_SUCCESS)
650     {
651         fprintf(stderr, "Error during eglSwapInterval.\n");
652         return false;
653     }
654
655     return true;
656 }
657
658 bool EGLWindow::hasError() const
659 {
660     return eglGetError() != EGL_SUCCESS;
661 }
662
663 // static
664 void GLWindowBase::Delete(GLWindowBase **window)
665 {
666     delete *window;
667     *window = nullptr;
668 }
669
670 // static
671 EGLWindow *EGLWindow::New(EGLint glesMajorVersion, EGLint glesMinorVersion)
672 {
673     return new EGLWindow(glesMajorVersion, glesMinorVersion);
674 }
675
676 // static
677 void EGLWindow::Delete(EGLWindow **window)
678 {
679     delete *window;
680     *window = nullptr;
681 }