• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/PlatformMethods.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 
isContextVersion(EGLint glesMajorVersion,EGLint glesMinorVersion) const93 bool EGLWindow::isContextVersion(EGLint glesMajorVersion, EGLint glesMinorVersion) const
94 {
95     return mClientMajorVersion == glesMajorVersion && mClientMinorVersion == glesMinorVersion;
96 }
97 
initializeGL(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)98 bool EGLWindow::initializeGL(OSWindow *osWindow,
99                              angle::Library *glWindowingLibrary,
100                              angle::GLESDriverType driverType,
101                              const EGLPlatformParameters &platformParams,
102                              const ConfigParameters &configParams)
103 {
104     if (!initializeDisplay(osWindow, glWindowingLibrary, driverType, platformParams))
105         return false;
106     if (!initializeSurface(osWindow, glWindowingLibrary, configParams))
107         return false;
108     if (!initializeContext())
109         return false;
110     return true;
111 }
112 
initializeDisplay(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & params)113 bool EGLWindow::initializeDisplay(OSWindow *osWindow,
114                                   angle::Library *glWindowingLibrary,
115                                   angle::GLESDriverType driverType,
116                                   const EGLPlatformParameters &params)
117 {
118 #if defined(ANGLE_USE_UTIL_LOADER)
119     PFNEGLGETPROCADDRESSPROC getProcAddress;
120     glWindowingLibrary->getAs("eglGetProcAddress", &getProcAddress);
121     if (!getProcAddress)
122     {
123         fprintf(stderr, "Cannot load eglGetProcAddress\n");
124         return false;
125     }
126 
127     // Likely we will need to use a fallback to Library::getAs on non-ANGLE platforms.
128     angle::LoadEGL(getProcAddress);
129 #endif  // defined(ANGLE_USE_UTIL_LOADER)
130 
131     const char *extensionString =
132         static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
133 
134     std::vector<EGLAttrib> displayAttributes;
135     displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
136     displayAttributes.push_back(params.renderer);
137     displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
138     displayAttributes.push_back(params.majorVersion);
139     displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
140     displayAttributes.push_back(params.minorVersion);
141 
142     if (params.deviceType != EGL_DONT_CARE)
143     {
144         displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
145         displayAttributes.push_back(params.deviceType);
146     }
147 
148     if (params.presentPath != EGL_DONT_CARE)
149     {
150         if (strstr(extensionString, "EGL_ANGLE_experimental_present_path") == nullptr)
151         {
152             destroyGL();
153             return false;
154         }
155 
156         displayAttributes.push_back(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE);
157         displayAttributes.push_back(params.presentPath);
158     }
159 
160     // Set debug layer settings if requested.
161     if (params.debugLayersEnabled != EGL_DONT_CARE)
162     {
163         displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
164         displayAttributes.push_back(params.debugLayersEnabled);
165     }
166 
167     const bool hasFeatureVirtualizationANGLE =
168         strstr(extensionString, "EGL_ANGLE_platform_angle_context_virtualization") != nullptr;
169 
170     if (params.contextVirtualization != EGL_DONT_CARE)
171     {
172         if (hasFeatureVirtualizationANGLE)
173         {
174             displayAttributes.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
175             displayAttributes.push_back(params.contextVirtualization);
176         }
177         else
178         {
179             fprintf(stderr,
180                     "EGL_ANGLE_platform_angle_context_virtualization extension not active\n");
181         }
182     }
183 
184     if (params.platformMethods)
185     {
186         static_assert(sizeof(EGLAttrib) == sizeof(params.platformMethods),
187                       "Unexpected pointer size");
188         displayAttributes.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
189         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(params.platformMethods));
190     }
191 
192     std::vector<const char *> disabledFeatureOverrides;
193     std::vector<const char *> enabledFeatureOverrides;
194 
195     if (params.transformFeedbackFeature == EGL_FALSE)
196     {
197         disabledFeatureOverrides.push_back("supportsTransformFeedbackExtension");
198         disabledFeatureOverrides.push_back("emulateTransformFeedback");
199     }
200 
201     if (params.allocateNonZeroMemoryFeature == EGL_TRUE)
202     {
203         enabledFeatureOverrides.push_back("allocateNonZeroMemory");
204     }
205     else if (params.allocateNonZeroMemoryFeature == EGL_FALSE)
206     {
207         disabledFeatureOverrides.push_back("allocateNonZeroMemory");
208     }
209 
210     if (params.emulateCopyTexImage2DFromRenderbuffers == EGL_TRUE)
211     {
212         enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers");
213     }
214 
215     if (params.shaderStencilOutputFeature == EGL_FALSE)
216     {
217         disabledFeatureOverrides.push_back("has_shader_stencil_output");
218     }
219 
220     if (params.genMultipleMipsPerPassFeature == EGL_FALSE)
221     {
222         disabledFeatureOverrides.push_back("gen_multiple_mips_per_pass");
223     }
224 
225     if (params.supportsVulkanViewportFlip == EGL_TRUE)
226     {
227         enabledFeatureOverrides.push_back("supportsViewportFlip");
228     }
229     else if (params.supportsVulkanViewportFlip == EGL_FALSE)
230     {
231         disabledFeatureOverrides.push_back("supportsViewportFlip");
232     }
233 
234     switch (params.emulatedPrerotation)
235     {
236         case 90:
237             enabledFeatureOverrides.push_back("emulatedPrerotation90");
238             break;
239         case 180:
240             enabledFeatureOverrides.push_back("emulatedPrerotation180");
241             break;
242         case 270:
243             enabledFeatureOverrides.push_back("emulatedPrerotation270");
244             break;
245         default:
246             break;
247     }
248 
249     if (params.asyncCommandQueueFeatureVulkan == EGL_TRUE)
250     {
251         // TODO(jmadill): Update feature names. b/172704839
252         enabledFeatureOverrides.push_back("commandProcessor");
253         enabledFeatureOverrides.push_back("asynchronousCommandProcessing");
254     }
255 
256     if (params.directSPIRVGeneration == EGL_TRUE)
257     {
258         enabledFeatureOverrides.push_back("directSPIRVGeneration");
259     }
260 
261     if (params.hasExplicitMemBarrierFeatureMtl == EGL_FALSE)
262     {
263         disabledFeatureOverrides.push_back("has_explicit_mem_barrier_mtl");
264     }
265 
266     if (params.hasCheapRenderPassFeatureMtl == EGL_FALSE)
267     {
268         disabledFeatureOverrides.push_back("has_cheap_render_pass_mtl");
269     }
270 
271     if (params.forceBufferGPUStorageFeatureMtl == EGL_TRUE)
272     {
273         enabledFeatureOverrides.push_back("force_buffer_gpu_storage_mtl");
274     }
275 
276     if (params.emulatedVAOs == EGL_TRUE)
277     {
278         enabledFeatureOverrides.push_back("sync_vertex_arrays_to_default");
279     }
280 
281     const bool hasFeatureControlANGLE =
282         strstr(extensionString, "EGL_ANGLE_feature_control") != nullptr;
283 
284     if (!hasFeatureControlANGLE &&
285         (!enabledFeatureOverrides.empty() || !disabledFeatureOverrides.empty()))
286     {
287         fprintf(stderr, "Missing EGL_ANGLE_feature_control.\n");
288         destroyGL();
289         return false;
290     }
291 
292     if (!disabledFeatureOverrides.empty())
293     {
294         disabledFeatureOverrides.push_back(nullptr);
295 
296         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
297         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(disabledFeatureOverrides.data()));
298     }
299 
300     if (hasFeatureControlANGLE)
301     {
302         // Always enable exposeNonConformantExtensionsAndVersions in ANGLE tests.
303         enabledFeatureOverrides.push_back("exposeNonConformantExtensionsAndVersions");
304         enabledFeatureOverrides.push_back(nullptr);
305 
306         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
307         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(enabledFeatureOverrides.data()));
308     }
309 
310     displayAttributes.push_back(EGL_NONE);
311 
312     if (driverType == angle::GLESDriverType::SystemWGL)
313         return false;
314 
315     if (driverType == angle::GLESDriverType::AngleEGL &&
316         strstr(extensionString, "EGL_ANGLE_platform_angle"))
317     {
318         mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
319                                          reinterpret_cast<void *>(osWindow->getNativeDisplay()),
320                                          &displayAttributes[0]);
321     }
322     else
323     {
324         mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
325     }
326 
327     if (mDisplay == EGL_NO_DISPLAY)
328     {
329         fprintf(stderr, "Failed to get display: 0x%X\n", eglGetError());
330         destroyGL();
331         return false;
332     }
333 
334     if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
335     {
336         fprintf(stderr, "eglInitialize failed: 0x%X\n", eglGetError());
337         destroyGL();
338         return false;
339     }
340 
341     mPlatform = params;
342     return true;
343 }
344 
initializeSurface(OSWindow * osWindow,angle::Library * glWindowingLibrary,const ConfigParameters & params)345 bool EGLWindow::initializeSurface(OSWindow *osWindow,
346                                   angle::Library *glWindowingLibrary,
347                                   const ConfigParameters &params)
348 {
349     mConfigParams                 = params;
350     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
351 
352     std::vector<EGLint> configAttributes = {
353         EGL_SURFACE_TYPE,
354         EGL_WINDOW_BIT,
355         EGL_RED_SIZE,
356         (mConfigParams.redBits >= 0) ? mConfigParams.redBits : EGL_DONT_CARE,
357         EGL_GREEN_SIZE,
358         (mConfigParams.greenBits >= 0) ? mConfigParams.greenBits : EGL_DONT_CARE,
359         EGL_BLUE_SIZE,
360         (mConfigParams.blueBits >= 0) ? mConfigParams.blueBits : EGL_DONT_CARE,
361         EGL_ALPHA_SIZE,
362         (mConfigParams.alphaBits >= 0) ? mConfigParams.alphaBits : EGL_DONT_CARE,
363         EGL_DEPTH_SIZE,
364         (mConfigParams.depthBits >= 0) ? mConfigParams.depthBits : EGL_DONT_CARE,
365         EGL_STENCIL_SIZE,
366         (mConfigParams.stencilBits >= 0) ? mConfigParams.stencilBits : EGL_DONT_CARE,
367         EGL_SAMPLE_BUFFERS,
368         mConfigParams.multisample ? 1 : 0,
369         EGL_SAMPLES,
370         (mConfigParams.samples >= 0) ? mConfigParams.samples : EGL_DONT_CARE,
371     };
372 
373     // Add dynamic attributes
374     bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
375     if (!hasPixelFormatFloat && mConfigParams.componentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
376     {
377         fprintf(stderr, "Mising EGL_EXT_pixel_format_float.\n");
378         destroyGL();
379         return false;
380     }
381     if (hasPixelFormatFloat)
382     {
383         configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
384         configAttributes.push_back(mConfigParams.componentType);
385     }
386 
387     // Finish the attribute list
388     configAttributes.push_back(EGL_NONE);
389 
390     if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
391     {
392         fprintf(stderr, "Could not find a suitable EGL config!\n");
393         destroyGL();
394         return false;
395     }
396 
397     eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mConfigParams.redBits);
398     eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mConfigParams.greenBits);
399     eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mConfigParams.blueBits);
400     eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mConfigParams.alphaBits);
401     eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mConfigParams.depthBits);
402     eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mConfigParams.stencilBits);
403     eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mConfigParams.samples);
404 
405     std::vector<EGLint> surfaceAttributes;
406     if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
407     {
408         surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
409         surfaceAttributes.push_back(EGL_TRUE);
410     }
411 
412     bool hasRobustResourceInit =
413         strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
414     if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
415     {
416         surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
417         surfaceAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
418                                                                              : EGL_FALSE);
419     }
420 
421     surfaceAttributes.push_back(EGL_NONE);
422 
423     osWindow->resetNativeWindow();
424 
425     mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
426                                       &surfaceAttributes[0]);
427     if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
428     {
429         fprintf(stderr, "eglCreateWindowSurface failed: 0x%X\n", eglGetError());
430         destroyGL();
431         return false;
432     }
433 
434 #if defined(ANGLE_USE_UTIL_LOADER)
435     angle::LoadGLES(eglGetProcAddress);
436 #endif  // defined(ANGLE_USE_UTIL_LOADER)
437 
438     return true;
439 }
440 
createContext(EGLContext share) const441 EGLContext EGLWindow::createContext(EGLContext share) const
442 {
443     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
444 
445     // EGL_KHR_create_context is required to request a ES3+ context.
446     bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
447     if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
448         !hasKHRCreateContext)
449     {
450         fprintf(stderr, "EGL_KHR_create_context incompatibility.\n");
451         return EGL_NO_CONTEXT;
452     }
453 
454     // EGL_CONTEXT_OPENGL_DEBUG is only valid as of EGL 1.5.
455     bool hasDebug = mEGLMinorVersion >= 5;
456     if (mConfigParams.debug && !hasDebug)
457     {
458         fprintf(stderr, "EGL 1.5 is required for EGL_CONTEXT_OPENGL_DEBUG.\n");
459         return EGL_NO_CONTEXT;
460     }
461 
462     bool hasWebGLCompatibility =
463         strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
464     if (mConfigParams.webGLCompatibility.valid() && !hasWebGLCompatibility)
465     {
466         fprintf(stderr, "EGL_ANGLE_create_context_webgl_compatibility missing.\n");
467         return EGL_NO_CONTEXT;
468     }
469 
470     bool hasCreateContextExtensionsEnabled =
471         strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
472     if (mConfigParams.extensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
473     {
474         fprintf(stderr, "EGL_ANGLE_create_context_extensions_enabled missing.\n");
475         return EGL_NO_CONTEXT;
476     }
477 
478     bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
479     if ((mConfigParams.robustAccess ||
480          mConfigParams.resetStrategy != EGL_NO_RESET_NOTIFICATION_EXT) &&
481         !hasRobustness)
482     {
483         fprintf(stderr, "EGL_EXT_create_context_robustness missing.\n");
484         return EGL_NO_CONTEXT;
485     }
486 
487     bool hasBindGeneratesResource =
488         strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
489     if (!mConfigParams.bindGeneratesResource && !hasBindGeneratesResource)
490     {
491         fprintf(stderr, "EGL_CHROMIUM_create_context_bind_generates_resource missing.\n");
492         return EGL_NO_CONTEXT;
493     }
494 
495     bool hasClientArraysExtension =
496         strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
497     if (!mConfigParams.clientArraysEnabled && !hasClientArraysExtension)
498     {
499         // Non-default state requested without the extension present
500         fprintf(stderr, "EGL_ANGLE_create_context_client_arrays missing.\n");
501         return EGL_NO_CONTEXT;
502     }
503 
504     bool hasProgramCacheControlExtension =
505         strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
506     if (mConfigParams.contextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
507     {
508         fprintf(stderr, "EGL_ANGLE_program_cache_control missing.\n");
509         return EGL_NO_CONTEXT;
510     }
511 
512     bool hasKHRCreateContextNoError =
513         strstr(displayExtensions, "EGL_KHR_create_context_no_error") != nullptr;
514     if (mConfigParams.noError && !hasKHRCreateContextNoError)
515     {
516         fprintf(stderr, "EGL_KHR_create_context_no_error missing.\n");
517         return EGL_NO_CONTEXT;
518     }
519 
520     eglBindAPI(EGL_OPENGL_ES_API);
521     if (eglGetError() != EGL_SUCCESS)
522     {
523         fprintf(stderr, "Error on eglBindAPI.\n");
524         return EGL_NO_CONTEXT;
525     }
526 
527     std::vector<EGLint> contextAttributes;
528     if (hasKHRCreateContext)
529     {
530         contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
531         contextAttributes.push_back(mClientMajorVersion);
532 
533         contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
534         contextAttributes.push_back(mClientMinorVersion);
535 
536         // Note that the Android loader currently doesn't handle this flag despite reporting 1.5.
537         // Work around this by only using the debug bit when we request a debug context.
538         if (hasDebug && mConfigParams.debug)
539         {
540             contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
541             contextAttributes.push_back(mConfigParams.debug ? EGL_TRUE : EGL_FALSE);
542         }
543 
544         // TODO (http://anglebug.com/5809)
545         // Mesa does not allow EGL_CONTEXT_OPENGL_NO_ERROR_KHR for GLES1.
546         if (hasKHRCreateContextNoError && mConfigParams.noError)
547         {
548             contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
549             contextAttributes.push_back(mConfigParams.noError ? EGL_TRUE : EGL_FALSE);
550         }
551 
552         if (mConfigParams.webGLCompatibility.valid())
553         {
554             contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
555             contextAttributes.push_back(mConfigParams.webGLCompatibility.value() ? EGL_TRUE
556                                                                                  : EGL_FALSE);
557         }
558 
559         if (mConfigParams.extensionsEnabled.valid())
560         {
561             contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
562             contextAttributes.push_back(mConfigParams.extensionsEnabled.value() ? EGL_TRUE
563                                                                                 : EGL_FALSE);
564         }
565 
566         if (hasRobustness)
567         {
568             contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
569             contextAttributes.push_back(mConfigParams.robustAccess ? EGL_TRUE : EGL_FALSE);
570 
571             contextAttributes.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
572             contextAttributes.push_back(mConfigParams.resetStrategy);
573         }
574 
575         if (hasBindGeneratesResource)
576         {
577             contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
578             contextAttributes.push_back(mConfigParams.bindGeneratesResource ? EGL_TRUE : EGL_FALSE);
579         }
580 
581         if (hasClientArraysExtension)
582         {
583             contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
584             contextAttributes.push_back(mConfigParams.clientArraysEnabled ? EGL_TRUE : EGL_FALSE);
585         }
586 
587         if (mConfigParams.contextProgramCacheEnabled.valid())
588         {
589             contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
590             contextAttributes.push_back(
591                 mConfigParams.contextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
592         }
593 
594         bool hasBackwardsCompatibleContextExtension =
595             strstr(displayExtensions, "EGL_ANGLE_create_context_backwards_compatible") != nullptr;
596         if (hasBackwardsCompatibleContextExtension)
597         {
598             // Always request the exact context version that the config wants
599             contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
600             contextAttributes.push_back(EGL_FALSE);
601         }
602 
603         bool hasRobustResourceInit =
604             strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
605         if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
606         {
607             contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
608             contextAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
609                                                                                  : EGL_FALSE);
610         }
611     }
612     contextAttributes.push_back(EGL_NONE);
613 
614     EGLContext context = eglCreateContext(mDisplay, mConfig, share, &contextAttributes[0]);
615     if (context == EGL_NO_CONTEXT)
616     {
617         fprintf(stderr, "eglCreateContext failed: 0x%X\n", eglGetError());
618         return EGL_NO_CONTEXT;
619     }
620 
621     return context;
622 }
623 
initializeContext()624 bool EGLWindow::initializeContext()
625 {
626     mContext = createContext(EGL_NO_CONTEXT);
627     if (mContext == EGL_NO_CONTEXT)
628     {
629         destroyGL();
630         return false;
631     }
632 
633     if (!makeCurrent())
634     {
635         destroyGL();
636         return false;
637     }
638 
639     return true;
640 }
641 
destroyGL()642 void EGLWindow::destroyGL()
643 {
644     destroyContext();
645     destroySurface();
646 
647     if (mDisplay != EGL_NO_DISPLAY)
648     {
649         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
650         eglTerminate(mDisplay);
651         mDisplay = EGL_NO_DISPLAY;
652     }
653 }
654 
destroySurface()655 void EGLWindow::destroySurface()
656 {
657     if (mSurface != EGL_NO_SURFACE)
658     {
659         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
660         assert(mDisplay != EGL_NO_DISPLAY);
661         eglDestroySurface(mDisplay, mSurface);
662         mSurface = EGL_NO_SURFACE;
663     }
664 }
665 
destroyContext()666 void EGLWindow::destroyContext()
667 {
668     if (mContext != EGL_NO_CONTEXT)
669     {
670         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
671         assert(mDisplay != EGL_NO_DISPLAY);
672         eglDestroyContext(mDisplay, mContext);
673         mContext = EGL_NO_CONTEXT;
674     }
675 }
676 
isGLInitialized() const677 bool EGLWindow::isGLInitialized() const
678 {
679     return mSurface != EGL_NO_SURFACE && mContext != EGL_NO_CONTEXT && mDisplay != EGL_NO_DISPLAY;
680 }
681 
682 // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
683 // the EGLConfig is found.  This indicates that the EGLConfig is not supported.  Surface type is
684 // special-cased as it's possible for a config to return support for both EGL_WINDOW_BIT and
685 // EGL_PBUFFER_BIT even though only one of them is requested.
FindEGLConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * config)686 EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
687 {
688     EGLint numConfigs = 0;
689     eglGetConfigs(dpy, nullptr, 0, &numConfigs);
690     std::vector<EGLConfig> allConfigs(numConfigs);
691     eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
692 
693     for (size_t i = 0; i < allConfigs.size(); i++)
694     {
695         bool matchFound = true;
696         for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
697         {
698             if (curAttrib[1] == EGL_DONT_CARE)
699             {
700                 continue;
701             }
702 
703             EGLint actualValue = EGL_DONT_CARE;
704             eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
705             if ((curAttrib[0] == EGL_SURFACE_TYPE &&
706                  (curAttrib[1] & actualValue) != curAttrib[1]) ||
707                 (curAttrib[0] != EGL_SURFACE_TYPE && curAttrib[1] != actualValue))
708             {
709                 matchFound = false;
710                 break;
711             }
712         }
713 
714         if (matchFound)
715         {
716             *config = allConfigs[i];
717             return EGL_TRUE;
718         }
719     }
720 
721     return EGL_FALSE;
722 }
723 
makeCurrent()724 bool EGLWindow::makeCurrent()
725 {
726     if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE ||
727         eglGetError() != EGL_SUCCESS)
728     {
729         fprintf(stderr, "Error during eglMakeCurrent.\n");
730         return false;
731     }
732 
733     return true;
734 }
735 
setSwapInterval(EGLint swapInterval)736 bool EGLWindow::setSwapInterval(EGLint swapInterval)
737 {
738     if (eglSwapInterval(mDisplay, swapInterval) == EGL_FALSE || eglGetError() != EGL_SUCCESS)
739     {
740         fprintf(stderr, "Error during eglSwapInterval.\n");
741         return false;
742     }
743 
744     return true;
745 }
746 
hasError() const747 bool EGLWindow::hasError() const
748 {
749     return eglGetError() != EGL_SUCCESS;
750 }
751 
getProcAddress(const char * name)752 angle::GenericProc EGLWindow::getProcAddress(const char *name)
753 {
754     return eglGetProcAddress(name);
755 }
756 
757 // static
Delete(GLWindowBase ** window)758 void GLWindowBase::Delete(GLWindowBase **window)
759 {
760     delete *window;
761     *window = nullptr;
762 }
763 
764 // static
New(EGLint glesMajorVersion,EGLint glesMinorVersion)765 EGLWindow *EGLWindow::New(EGLint glesMajorVersion, EGLint glesMinorVersion)
766 {
767     return new EGLWindow(glesMajorVersion, glesMinorVersion);
768 }
769 
770 // static
Delete(EGLWindow ** window)771 void EGLWindow::Delete(EGLWindow **window)
772 {
773     delete *window;
774     *window = nullptr;
775 }
776