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