• 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/Feature.h"
17 #include "platform/PlatformMethods.h"
18 #include "util/OSWindow.h"
19 
20 namespace
21 {
22 constexpr EGLint kDefaultSwapInterval = 1;
23 }  // anonymous namespace
24 
25 // ConfigParameters implementation.
ConfigParameters()26 ConfigParameters::ConfigParameters()
27     : redBits(-1),
28       greenBits(-1),
29       blueBits(-1),
30       alphaBits(-1),
31       depthBits(-1),
32       stencilBits(-1),
33       componentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT),
34       multisample(false),
35       debug(false),
36       noError(false),
37       bindGeneratesResource(true),
38       clientArraysEnabled(true),
39       robustAccess(false),
40       mutableRenderBuffer(false),
41       samples(-1),
42       resetStrategy(EGL_NO_RESET_NOTIFICATION_EXT),
43       colorSpace(EGL_COLORSPACE_LINEAR),
44       swapInterval(kDefaultSwapInterval)
45 {}
46 
47 ConfigParameters::~ConfigParameters() = default;
48 
reset()49 void ConfigParameters::reset()
50 {
51     *this = ConfigParameters();
52 }
53 
54 // GLWindowBase implementation.
GLWindowBase(EGLenum clientType,GLint glesMajorVersion,EGLint glesMinorVersion,EGLint profileMask)55 GLWindowBase::GLWindowBase(EGLenum clientType,
56                            GLint glesMajorVersion,
57                            EGLint glesMinorVersion,
58                            EGLint profileMask)
59     : mClientType(clientType),
60       mClientMajorVersion(glesMajorVersion),
61       mClientMinorVersion(glesMinorVersion),
62       mProfileMask(profileMask)
63 {}
64 
65 GLWindowBase::~GLWindowBase() = default;
66 
67 // EGLWindow implementation.
EGLWindow(EGLenum clientType,EGLint glesMajorVersion,EGLint glesMinorVersion,EGLint profileMask)68 EGLWindow::EGLWindow(EGLenum clientType,
69                      EGLint glesMajorVersion,
70                      EGLint glesMinorVersion,
71                      EGLint profileMask)
72     : GLWindowBase(clientType, glesMajorVersion, glesMinorVersion, profileMask),
73       mConfig(0),
74       mDisplay(EGL_NO_DISPLAY),
75       mSurface(EGL_NO_SURFACE),
76       mContext(EGL_NO_CONTEXT),
77       mEGLMajorVersion(0),
78       mEGLMinorVersion(0)
79 {
80     std::fill(mFeatures.begin(), mFeatures.end(), ANGLEFeatureStatus::Unknown);
81 }
82 
~EGLWindow()83 EGLWindow::~EGLWindow()
84 {
85     destroyGL();
86 }
87 
swap()88 void EGLWindow::swap()
89 {
90     eglSwapBuffers(mDisplay, mSurface);
91 }
92 
getConfig() const93 EGLConfig EGLWindow::getConfig() const
94 {
95     return mConfig;
96 }
97 
getDisplay() const98 EGLDisplay EGLWindow::getDisplay() const
99 {
100     return mDisplay;
101 }
102 
getSurface() const103 EGLSurface EGLWindow::getSurface() const
104 {
105     return mSurface;
106 }
107 
getContext() const108 EGLContext EGLWindow::getContext() const
109 {
110     return mContext;
111 }
112 
isContextVersion(EGLint glesMajorVersion,EGLint glesMinorVersion) const113 bool EGLWindow::isContextVersion(EGLint glesMajorVersion, EGLint glesMinorVersion) const
114 {
115     return mClientMajorVersion == glesMajorVersion && mClientMinorVersion == glesMinorVersion;
116 }
117 
initializeGLWithResult(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)118 GLWindowResult EGLWindow::initializeGLWithResult(OSWindow *osWindow,
119                                                  angle::Library *glWindowingLibrary,
120                                                  angle::GLESDriverType driverType,
121                                                  const EGLPlatformParameters &platformParams,
122                                                  const ConfigParameters &configParams)
123 {
124     if (!initializeDisplay(osWindow, glWindowingLibrary, driverType, platformParams))
125     {
126         return GLWindowResult::Error;
127     }
128     GLWindowResult res = initializeSurface(osWindow, glWindowingLibrary, configParams);
129     if (res != GLWindowResult::NoError)
130     {
131         return res;
132     }
133     if (!initializeContext())
134     {
135         return GLWindowResult::Error;
136     }
137     return GLWindowResult::NoError;
138 }
139 
initializeGL(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)140 bool EGLWindow::initializeGL(OSWindow *osWindow,
141                              angle::Library *glWindowingLibrary,
142                              angle::GLESDriverType driverType,
143                              const EGLPlatformParameters &platformParams,
144                              const ConfigParameters &configParams)
145 {
146     return initializeGLWithResult(osWindow, glWindowingLibrary, driverType, platformParams,
147                                   configParams) == GLWindowResult::NoError;
148 }
149 
initializeDisplay(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & params)150 bool EGLWindow::initializeDisplay(OSWindow *osWindow,
151                                   angle::Library *glWindowingLibrary,
152                                   angle::GLESDriverType driverType,
153                                   const EGLPlatformParameters &params)
154 {
155     if (driverType == angle::GLESDriverType::ZinkEGL)
156     {
157         std::stringstream driDirStream;
158         char s = angle::GetPathSeparator();
159         driDirStream << angle::GetModuleDirectory() << "mesa" << s << "src" << s << "gallium" << s
160                      << "targets" << s << "dri";
161 
162         std::string driDir = driDirStream.str();
163 
164         angle::SetEnvironmentVar("MESA_LOADER_DRIVER_OVERRIDE", "zink");
165         angle::SetEnvironmentVar("LIBGL_DRIVERS_PATH", driDir.c_str());
166     }
167 
168 #if defined(ANGLE_USE_UTIL_LOADER)
169     PFNEGLGETPROCADDRESSPROC getProcAddress;
170     glWindowingLibrary->getAs("eglGetProcAddress", &getProcAddress);
171     if (!getProcAddress)
172     {
173         fprintf(stderr, "Cannot load eglGetProcAddress\n");
174         return false;
175     }
176 
177     // Likely we will need to use a fallback to Library::getAs on non-ANGLE platforms.
178     LoadUtilEGL(getProcAddress);
179 #endif  // defined(ANGLE_USE_UTIL_LOADER)
180 
181     // EGL_NO_DISPLAY + EGL_EXTENSIONS returns NULL before Android 10
182     const char *extensionString =
183         static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
184     if (!extensionString)
185     {
186         // fallback to an empty string for strstr
187         extensionString = "";
188     }
189 
190     std::vector<EGLAttrib> displayAttributes;
191     displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
192     displayAttributes.push_back(params.renderer);
193     displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
194     displayAttributes.push_back(params.majorVersion);
195     displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
196     displayAttributes.push_back(params.minorVersion);
197 
198     if (params.deviceType != EGL_DONT_CARE)
199     {
200         displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
201         displayAttributes.push_back(params.deviceType);
202     }
203 
204     if (params.presentPath != EGL_DONT_CARE)
205     {
206         if (strstr(extensionString, "EGL_ANGLE_experimental_present_path") == nullptr)
207         {
208             destroyGL();
209             return false;
210         }
211 
212         displayAttributes.push_back(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE);
213         displayAttributes.push_back(params.presentPath);
214     }
215 
216     // Set debug layer settings if requested.
217     if (params.debugLayersEnabled != EGL_DONT_CARE)
218     {
219         displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
220         displayAttributes.push_back(params.debugLayersEnabled);
221     }
222 
223     if (params.platformMethods)
224     {
225         static_assert(sizeof(EGLAttrib) == sizeof(params.platformMethods),
226                       "Unexpected pointer size");
227         displayAttributes.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
228         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(params.platformMethods));
229     }
230 
231     if (params.displayPowerPreference != EGL_DONT_CARE)
232     {
233         displayAttributes.push_back(EGL_POWER_PREFERENCE_ANGLE);
234         displayAttributes.push_back(params.displayPowerPreference);
235     }
236 
237     std::vector<const char *> enabledFeatureOverrides;
238     std::vector<const char *> disabledFeatureOverrides;
239 
240     for (angle::Feature feature : params.enabledFeatureOverrides)
241     {
242         enabledFeatureOverrides.push_back(angle::GetFeatureName(feature));
243     }
244     for (angle::Feature feature : params.disabledFeatureOverrides)
245     {
246         disabledFeatureOverrides.push_back(angle::GetFeatureName(feature));
247     }
248 
249     const bool hasFeatureControlANGLE =
250         strstr(extensionString, "EGL_ANGLE_feature_control") != nullptr;
251 
252     if (!hasFeatureControlANGLE &&
253         (!enabledFeatureOverrides.empty() || !disabledFeatureOverrides.empty()))
254     {
255         fprintf(stderr, "Missing EGL_ANGLE_feature_control.\n");
256         destroyGL();
257         return false;
258     }
259 
260     if (!disabledFeatureOverrides.empty())
261     {
262         disabledFeatureOverrides.push_back(nullptr);
263 
264         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
265         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(disabledFeatureOverrides.data()));
266     }
267 
268     if (hasFeatureControlANGLE)
269     {
270         // Always enable exposeNonConformantExtensionsAndVersions in ANGLE tests.
271         enabledFeatureOverrides.push_back("exposeNonConformantExtensionsAndVersions");
272         enabledFeatureOverrides.push_back(nullptr);
273 
274         displayAttributes.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
275         displayAttributes.push_back(reinterpret_cast<EGLAttrib>(enabledFeatureOverrides.data()));
276     }
277 
278     displayAttributes.push_back(EGL_NONE);
279 
280     if (driverType == angle::GLESDriverType::SystemWGL)
281         return false;
282 
283     if (IsANGLE(driverType) && strstr(extensionString, "EGL_ANGLE_platform_angle"))
284     {
285         mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
286                                          reinterpret_cast<void *>(osWindow->getNativeDisplay()),
287                                          &displayAttributes[0]);
288     }
289     else
290     {
291         mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
292     }
293 
294     if (mDisplay == EGL_NO_DISPLAY)
295     {
296         fprintf(stderr, "Failed to get display: 0x%X\n", eglGetError());
297         destroyGL();
298         return false;
299     }
300 
301     if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
302     {
303         fprintf(stderr, "eglInitialize failed: 0x%X\n", eglGetError());
304         destroyGL();
305         return false;
306     }
307 
308     queryFeatures();
309 
310     mPlatform = params;
311     return true;
312 }
313 
initializeSurface(OSWindow * osWindow,angle::Library * glWindowingLibrary,const ConfigParameters & params)314 GLWindowResult EGLWindow::initializeSurface(OSWindow *osWindow,
315                                             angle::Library *glWindowingLibrary,
316                                             const ConfigParameters &params)
317 {
318     mConfigParams                 = params;
319     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
320 
321     bool hasMutableRenderBuffer =
322         strstr(displayExtensions, "EGL_KHR_mutable_render_buffer") != nullptr;
323     if (mConfigParams.mutableRenderBuffer && !hasMutableRenderBuffer)
324     {
325         fprintf(stderr, "Mising EGL_KHR_mutable_render_buffer.\n");
326         destroyGL();
327         return GLWindowResult::NoMutableRenderBufferSupport;
328     }
329 
330     std::vector<EGLint> configAttributes = {
331         EGL_SURFACE_TYPE,
332         EGL_WINDOW_BIT | (params.mutableRenderBuffer ? EGL_MUTABLE_RENDER_BUFFER_BIT_KHR : 0),
333         EGL_RED_SIZE,
334         (mConfigParams.redBits >= 0) ? mConfigParams.redBits : EGL_DONT_CARE,
335         EGL_GREEN_SIZE,
336         (mConfigParams.greenBits >= 0) ? mConfigParams.greenBits : EGL_DONT_CARE,
337         EGL_BLUE_SIZE,
338         (mConfigParams.blueBits >= 0) ? mConfigParams.blueBits : EGL_DONT_CARE,
339         EGL_ALPHA_SIZE,
340         (mConfigParams.alphaBits >= 0) ? mConfigParams.alphaBits : EGL_DONT_CARE,
341         EGL_DEPTH_SIZE,
342         (mConfigParams.depthBits >= 0) ? mConfigParams.depthBits : EGL_DONT_CARE,
343         EGL_STENCIL_SIZE,
344         (mConfigParams.stencilBits >= 0) ? mConfigParams.stencilBits : EGL_DONT_CARE,
345         EGL_SAMPLE_BUFFERS,
346         mConfigParams.multisample ? 1 : 0,
347         EGL_SAMPLES,
348         (mConfigParams.samples >= 0) ? mConfigParams.samples : EGL_DONT_CARE,
349     };
350 
351     // Add dynamic attributes
352     bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
353     if (!hasPixelFormatFloat && mConfigParams.componentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
354     {
355         fprintf(stderr, "Mising EGL_EXT_pixel_format_float.\n");
356         destroyGL();
357         return GLWindowResult::Error;
358     }
359     if (hasPixelFormatFloat)
360     {
361         configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
362         configAttributes.push_back(mConfigParams.componentType);
363     }
364 
365     // Finish the attribute list
366     configAttributes.push_back(EGL_NONE);
367 
368     if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
369     {
370         fprintf(stderr, "Could not find a suitable EGL config!\n");
371         destroyGL();
372         return GLWindowResult::Error;
373     }
374 
375     eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mConfigParams.redBits);
376     eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mConfigParams.greenBits);
377     eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mConfigParams.blueBits);
378     eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mConfigParams.alphaBits);
379     eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mConfigParams.depthBits);
380     eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mConfigParams.stencilBits);
381     eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mConfigParams.samples);
382 
383     std::vector<EGLint> surfaceAttributes;
384     if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
385     {
386         surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
387         surfaceAttributes.push_back(EGL_TRUE);
388     }
389 
390     bool hasRobustResourceInit =
391         strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
392     if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
393     {
394         surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
395         surfaceAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
396                                                                              : EGL_FALSE);
397     }
398 
399     bool hasGLColorSpace = strstr(displayExtensions, "EGL_KHR_gl_colorspace") != nullptr;
400     if (!hasGLColorSpace && mConfigParams.colorSpace != EGL_COLORSPACE_LINEAR)
401     {
402         fprintf(stderr, "Mising EGL_KHR_gl_colorspace.\n");
403         destroyGL();
404         return GLWindowResult::NoColorspaceSupport;
405     }
406     if (hasGLColorSpace)
407     {
408         surfaceAttributes.push_back(EGL_GL_COLORSPACE_KHR);
409         surfaceAttributes.push_back(mConfigParams.colorSpace);
410     }
411 
412     bool hasCreateSurfaceSwapInterval =
413         strstr(displayExtensions, "EGL_ANGLE_create_surface_swap_interval") != nullptr;
414     if (hasCreateSurfaceSwapInterval && mConfigParams.swapInterval != kDefaultSwapInterval)
415     {
416         surfaceAttributes.push_back(EGL_SWAP_INTERVAL_ANGLE);
417         surfaceAttributes.push_back(mConfigParams.swapInterval);
418     }
419 
420     surfaceAttributes.push_back(EGL_NONE);
421 
422     osWindow->resetNativeWindow();
423 
424     mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
425                                       &surfaceAttributes[0]);
426     if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
427     {
428         fprintf(stderr, "eglCreateWindowSurface failed: 0x%X\n", eglGetError());
429         destroyGL();
430         return GLWindowResult::Error;
431     }
432 
433 #if defined(ANGLE_USE_UTIL_LOADER)
434     LoadUtilGLES(eglGetProcAddress);
435 #endif  // defined(ANGLE_USE_UTIL_LOADER)
436 
437     return GLWindowResult::NoError;
438 }
439 
getCurrentContextGeneric()440 GLWindowContext EGLWindow::getCurrentContextGeneric()
441 {
442     return reinterpret_cast<GLWindowContext>(mContext);
443 }
444 
createContextGeneric(GLWindowContext share)445 GLWindowContext EGLWindow::createContextGeneric(GLWindowContext share)
446 {
447     EGLContext shareContext = reinterpret_cast<EGLContext>(share);
448     return reinterpret_cast<GLWindowContext>(createContext(shareContext, nullptr));
449 }
450 
createContext(EGLContext share,EGLint * extraAttributes)451 EGLContext EGLWindow::createContext(EGLContext share, EGLint *extraAttributes)
452 {
453     const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
454 
455     // EGL_KHR_create_context is required to request a ES3+ context.
456     bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
457     if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
458         !hasKHRCreateContext)
459     {
460         fprintf(stderr, "EGL_KHR_create_context incompatibility.\n");
461         return EGL_NO_CONTEXT;
462     }
463 
464     // EGL_CONTEXT_OPENGL_DEBUG is only valid as of EGL 1.5.
465     bool hasDebug = mEGLMinorVersion >= 5;
466     if (mConfigParams.debug && !hasDebug)
467     {
468         fprintf(stderr, "EGL 1.5 is required for EGL_CONTEXT_OPENGL_DEBUG.\n");
469         return EGL_NO_CONTEXT;
470     }
471 
472     bool hasWebGLCompatibility =
473         strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
474     if (mConfigParams.webGLCompatibility.valid() && !hasWebGLCompatibility)
475     {
476         fprintf(stderr, "EGL_ANGLE_create_context_webgl_compatibility missing.\n");
477         return EGL_NO_CONTEXT;
478     }
479 
480     bool hasCreateContextExtensionsEnabled =
481         strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
482     if (mConfigParams.extensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
483     {
484         fprintf(stderr, "EGL_ANGLE_create_context_extensions_enabled missing.\n");
485         return EGL_NO_CONTEXT;
486     }
487 
488     bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
489     if ((mConfigParams.robustAccess ||
490          mConfigParams.resetStrategy != EGL_NO_RESET_NOTIFICATION_EXT) &&
491         !hasRobustness)
492     {
493         fprintf(stderr, "EGL_EXT_create_context_robustness missing.\n");
494         return EGL_NO_CONTEXT;
495     }
496 
497     bool hasBindGeneratesResource =
498         strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
499     if (!mConfigParams.bindGeneratesResource && !hasBindGeneratesResource)
500     {
501         fprintf(stderr, "EGL_CHROMIUM_create_context_bind_generates_resource missing.\n");
502         return EGL_NO_CONTEXT;
503     }
504 
505     bool hasClientArraysExtension =
506         strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
507     if (!mConfigParams.clientArraysEnabled && !hasClientArraysExtension)
508     {
509         // Non-default state requested without the extension present
510         fprintf(stderr, "EGL_ANGLE_create_context_client_arrays missing.\n");
511         return EGL_NO_CONTEXT;
512     }
513 
514     bool hasProgramCacheControlExtension =
515         strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
516     if (mConfigParams.contextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
517     {
518         fprintf(stderr, "EGL_ANGLE_program_cache_control missing.\n");
519         return EGL_NO_CONTEXT;
520     }
521 
522     bool hasKHRCreateContextNoError =
523         strstr(displayExtensions, "EGL_KHR_create_context_no_error") != nullptr;
524     if (mConfigParams.noError && !hasKHRCreateContextNoError)
525     {
526         fprintf(stderr, "EGL_KHR_create_context_no_error missing.\n");
527         return EGL_NO_CONTEXT;
528     }
529 
530     eglBindAPI(mClientType);
531     if (eglGetError() != EGL_SUCCESS)
532     {
533         fprintf(stderr, "Error on eglBindAPI.\n");
534         return EGL_NO_CONTEXT;
535     }
536 
537     std::vector<EGLint> contextAttributes;
538     for (EGLint *extraAttrib = extraAttributes;
539          extraAttrib != nullptr && extraAttrib[0] != EGL_NONE; extraAttrib += 2)
540     {
541         contextAttributes.push_back(extraAttrib[0]);
542         contextAttributes.push_back(extraAttrib[1]);
543     }
544 
545     if (hasKHRCreateContext)
546     {
547         contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
548         contextAttributes.push_back(mClientMajorVersion);
549 
550         contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
551         contextAttributes.push_back(mClientMinorVersion);
552 
553         if (mProfileMask != 0)
554         {
555             contextAttributes.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK);
556             contextAttributes.push_back(mProfileMask);
557         }
558 
559         // Note that the Android loader currently doesn't handle this flag despite reporting 1.5.
560         // Work around this by only using the debug bit when we request a debug context.
561         if (hasDebug && mConfigParams.debug)
562         {
563             contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
564             contextAttributes.push_back(mConfigParams.debug ? EGL_TRUE : EGL_FALSE);
565         }
566 
567         // TODO (http://anglebug.com/5809)
568         // Mesa does not allow EGL_CONTEXT_OPENGL_NO_ERROR_KHR for GLES1.
569         if (hasKHRCreateContextNoError && mConfigParams.noError)
570         {
571             contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
572             contextAttributes.push_back(mConfigParams.noError ? EGL_TRUE : EGL_FALSE);
573         }
574 
575         if (mConfigParams.webGLCompatibility.valid())
576         {
577             contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
578             contextAttributes.push_back(mConfigParams.webGLCompatibility.value() ? EGL_TRUE
579                                                                                  : EGL_FALSE);
580         }
581 
582         if (mConfigParams.extensionsEnabled.valid())
583         {
584             contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
585             contextAttributes.push_back(mConfigParams.extensionsEnabled.value() ? EGL_TRUE
586                                                                                 : EGL_FALSE);
587         }
588 
589         if (hasRobustness)
590         {
591             contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
592             contextAttributes.push_back(mConfigParams.robustAccess ? EGL_TRUE : EGL_FALSE);
593 
594             contextAttributes.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
595             contextAttributes.push_back(mConfigParams.resetStrategy);
596         }
597 
598         if (hasBindGeneratesResource)
599         {
600             contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
601             contextAttributes.push_back(mConfigParams.bindGeneratesResource ? EGL_TRUE : EGL_FALSE);
602         }
603 
604         if (hasClientArraysExtension)
605         {
606             contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
607             contextAttributes.push_back(mConfigParams.clientArraysEnabled ? EGL_TRUE : EGL_FALSE);
608         }
609 
610         if (mConfigParams.contextProgramCacheEnabled.valid())
611         {
612             contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
613             contextAttributes.push_back(
614                 mConfigParams.contextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
615         }
616 
617         bool hasBackwardsCompatibleContextExtension =
618             strstr(displayExtensions, "EGL_ANGLE_create_context_backwards_compatible") != nullptr;
619         if (hasBackwardsCompatibleContextExtension)
620         {
621             // Always request the exact context version that the config wants
622             contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
623             contextAttributes.push_back(EGL_FALSE);
624         }
625 
626         bool hasRobustResourceInit =
627             strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
628         if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
629         {
630             contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
631             contextAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
632                                                                                  : EGL_FALSE);
633         }
634     }
635     contextAttributes.push_back(EGL_NONE);
636 
637     EGLContext context = eglCreateContext(mDisplay, mConfig, share, &contextAttributes[0]);
638     if (context == EGL_NO_CONTEXT)
639     {
640         fprintf(stderr, "eglCreateContext failed: 0x%X\n", eglGetError());
641         return EGL_NO_CONTEXT;
642     }
643 
644     return context;
645 }
646 
initializeContext()647 bool EGLWindow::initializeContext()
648 {
649     mContext = createContext(EGL_NO_CONTEXT, nullptr);
650     if (mContext == EGL_NO_CONTEXT)
651     {
652         destroyGL();
653         return false;
654     }
655 
656     if (!makeCurrent())
657     {
658         destroyGL();
659         return false;
660     }
661 
662     return true;
663 }
664 
destroyGL()665 void EGLWindow::destroyGL()
666 {
667     destroyContext();
668     destroySurface();
669 
670     if (mDisplay != EGL_NO_DISPLAY)
671     {
672         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
673         eglTerminate(mDisplay);
674         mDisplay = EGL_NO_DISPLAY;
675     }
676 }
677 
destroySurface()678 void EGLWindow::destroySurface()
679 {
680     if (mSurface != EGL_NO_SURFACE)
681     {
682         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
683         assert(mDisplay != EGL_NO_DISPLAY);
684         eglDestroySurface(mDisplay, mSurface);
685         mSurface = EGL_NO_SURFACE;
686     }
687 }
688 
destroyContext()689 void EGLWindow::destroyContext()
690 {
691     if (mContext != EGL_NO_CONTEXT)
692     {
693         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
694         assert(mDisplay != EGL_NO_DISPLAY);
695         eglDestroyContext(mDisplay, mContext);
696         mContext = EGL_NO_CONTEXT;
697     }
698 }
699 
isGLInitialized() const700 bool EGLWindow::isGLInitialized() const
701 {
702     return mSurface != EGL_NO_SURFACE && mContext != EGL_NO_CONTEXT && mDisplay != EGL_NO_DISPLAY;
703 }
704 
705 // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
706 // the EGLConfig is found.  This indicates that the EGLConfig is not supported.  Surface type is
707 // special-cased as it's possible for a config to return support for both EGL_WINDOW_BIT and
708 // EGL_PBUFFER_BIT even though only one of them is requested.
FindEGLConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * config)709 EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
710 {
711     EGLint numConfigs = 0;
712     eglGetConfigs(dpy, nullptr, 0, &numConfigs);
713     std::vector<EGLConfig> allConfigs(numConfigs);
714     eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
715 
716     for (size_t i = 0; i < allConfigs.size(); i++)
717     {
718         bool matchFound = true;
719         for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
720         {
721             if (curAttrib[1] == EGL_DONT_CARE)
722             {
723                 continue;
724             }
725 
726             EGLint actualValue = EGL_DONT_CARE;
727             eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
728             if ((curAttrib[0] == EGL_SURFACE_TYPE &&
729                  (curAttrib[1] & actualValue) != curAttrib[1]) ||
730                 (curAttrib[0] != EGL_SURFACE_TYPE && curAttrib[1] != actualValue))
731             {
732                 matchFound = false;
733                 break;
734             }
735         }
736 
737         if (matchFound)
738         {
739             *config = allConfigs[i];
740             return EGL_TRUE;
741         }
742     }
743 
744     return EGL_FALSE;
745 }
746 
makeCurrentGeneric(GLWindowContext context)747 bool EGLWindow::makeCurrentGeneric(GLWindowContext context)
748 {
749     EGLContext eglContext = reinterpret_cast<EGLContext>(context);
750     return makeCurrent(eglContext);
751 }
752 
makeCurrent()753 bool EGLWindow::makeCurrent()
754 {
755     return makeCurrent(mContext);
756 }
757 
createImage(GLWindowContext context,Enum target,ClientBuffer buffer,const Attrib * attrib_list)758 EGLWindow::Image EGLWindow::createImage(GLWindowContext context,
759                                         Enum target,
760                                         ClientBuffer buffer,
761                                         const Attrib *attrib_list)
762 {
763     return eglCreateImage(getDisplay(), context, target, buffer, attrib_list);
764 }
765 
createImageKHR(GLWindowContext context,Enum target,ClientBuffer buffer,const AttribKHR * attrib_list)766 EGLWindow::Image EGLWindow::createImageKHR(GLWindowContext context,
767                                            Enum target,
768                                            ClientBuffer buffer,
769                                            const AttribKHR *attrib_list)
770 {
771     return eglCreateImageKHR(getDisplay(), context, target, buffer, attrib_list);
772 }
773 
destroyImage(Image image)774 EGLBoolean EGLWindow::destroyImage(Image image)
775 {
776     return eglDestroyImage(getDisplay(), image);
777 }
778 
destroyImageKHR(Image image)779 EGLBoolean EGLWindow::destroyImageKHR(Image image)
780 {
781     return eglDestroyImageKHR(getDisplay(), image);
782 }
783 
createSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)784 EGLWindow::Sync EGLWindow::createSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
785 {
786     return eglCreateSync(dpy, type, attrib_list);
787 }
788 
createSyncKHR(EGLDisplay dpy,EGLenum type,const EGLint * attrib_list)789 EGLWindow::Sync EGLWindow::createSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
790 {
791     return eglCreateSyncKHR(dpy, type, attrib_list);
792 }
793 
destroySync(EGLDisplay dpy,Sync sync)794 EGLBoolean EGLWindow::destroySync(EGLDisplay dpy, Sync sync)
795 {
796     return eglDestroySync(dpy, sync);
797 }
798 
destroySyncKHR(EGLDisplay dpy,Sync sync)799 EGLBoolean EGLWindow::destroySyncKHR(EGLDisplay dpy, Sync sync)
800 {
801     return eglDestroySyncKHR(dpy, sync);
802 }
803 
clientWaitSync(EGLDisplay dpy,Sync sync,EGLint flags,EGLTimeKHR timeout)804 EGLint EGLWindow::clientWaitSync(EGLDisplay dpy, Sync sync, EGLint flags, EGLTimeKHR timeout)
805 {
806     return eglClientWaitSync(dpy, sync, flags, timeout);
807 }
808 
clientWaitSyncKHR(EGLDisplay dpy,Sync sync,EGLint flags,EGLTimeKHR timeout)809 EGLint EGLWindow::clientWaitSyncKHR(EGLDisplay dpy, Sync sync, EGLint flags, EGLTimeKHR timeout)
810 {
811     return eglClientWaitSyncKHR(dpy, sync, flags, timeout);
812 }
813 
getEGLError()814 EGLint EGLWindow::getEGLError()
815 {
816     return eglGetError();
817 }
818 
getCurrentDisplay()819 EGLWindow::Display EGLWindow::getCurrentDisplay()
820 {
821     return eglGetCurrentDisplay();
822 }
823 
createPbufferSurface(const EGLint * attrib_list)824 GLWindowBase::Surface EGLWindow::createPbufferSurface(const EGLint *attrib_list)
825 {
826     return eglCreatePbufferSurface(getDisplay(), getConfig(), attrib_list);
827 }
828 
destroySurface(Surface surface)829 EGLBoolean EGLWindow::destroySurface(Surface surface)
830 {
831     return eglDestroySurface(getDisplay(), surface);
832 }
833 
bindTexImage(EGLSurface surface,EGLint buffer)834 EGLBoolean EGLWindow::bindTexImage(EGLSurface surface, EGLint buffer)
835 {
836     return eglBindTexImage(getDisplay(), surface, buffer);
837 }
838 
releaseTexImage(EGLSurface surface,EGLint buffer)839 EGLBoolean EGLWindow::releaseTexImage(EGLSurface surface, EGLint buffer)
840 {
841     return eglReleaseTexImage(getDisplay(), surface, buffer);
842 }
843 
makeCurrent(EGLSurface draw,EGLSurface read,EGLContext context)844 bool EGLWindow::makeCurrent(EGLSurface draw, EGLSurface read, EGLContext context)
845 {
846     if ((draw && !read) || (!draw && read))
847     {
848         fprintf(stderr, "eglMakeCurrent: setting only one of draw and read buffer is illegal\n");
849         return false;
850     }
851 
852     // if the draw buffer is a nullptr and a context is given, then we use mSurface,
853     // because we didn't add this the gSurfaceMap, and it is the most likely
854     // case that we actually wanted the default surface here.
855     // TODO: This will need additional work when we want to support capture/replay
856     // with a sourfaceless context.
857     //
858     // If no context is given then we also don't assign a surface
859     if (!draw)
860     {
861         draw = read = context != EGL_NO_CONTEXT ? mSurface : EGL_NO_SURFACE;
862     }
863 
864     if (isGLInitialized())
865     {
866         if (eglMakeCurrent(mDisplay, draw, read, context) == EGL_FALSE ||
867             eglGetError() != EGL_SUCCESS)
868         {
869             fprintf(stderr, "Error during eglMakeCurrent.\n");
870             return false;
871         }
872     }
873     return true;
874 }
875 
makeCurrent(EGLContext context)876 bool EGLWindow::makeCurrent(EGLContext context)
877 {
878     return makeCurrent(mSurface, mSurface, context);
879 }
880 
setSwapInterval(EGLint swapInterval)881 bool EGLWindow::setSwapInterval(EGLint swapInterval)
882 {
883     if (eglSwapInterval(mDisplay, swapInterval) == EGL_FALSE || eglGetError() != EGL_SUCCESS)
884     {
885         fprintf(stderr, "Error during eglSwapInterval.\n");
886         return false;
887     }
888 
889     return true;
890 }
891 
hasError() const892 bool EGLWindow::hasError() const
893 {
894     return eglGetError() != EGL_SUCCESS;
895 }
896 
getProcAddress(const char * name)897 angle::GenericProc EGLWindow::getProcAddress(const char *name)
898 {
899     return eglGetProcAddress(name);
900 }
901 
902 // static
Delete(GLWindowBase ** window)903 void GLWindowBase::Delete(GLWindowBase **window)
904 {
905     delete *window;
906     *window = nullptr;
907 }
908 
909 // static
New(EGLenum clientType,EGLint glesMajorVersion,EGLint glesMinorVersion,EGLint profileMask)910 EGLWindow *EGLWindow::New(EGLenum clientType,
911                           EGLint glesMajorVersion,
912                           EGLint glesMinorVersion,
913                           EGLint profileMask)
914 {
915     return new EGLWindow(clientType, glesMajorVersion, glesMinorVersion, profileMask);
916 }
917 
918 // static
Delete(EGLWindow ** window)919 void EGLWindow::Delete(EGLWindow **window)
920 {
921     delete *window;
922     *window = nullptr;
923 }
924 
queryFeatures()925 void EGLWindow::queryFeatures()
926 {
927     // EGL_NO_DISPLAY + EGL_EXTENSIONS returns NULL before Android 10
928     const char *extensionString =
929         static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
930     const bool hasFeatureControlANGLE =
931         extensionString && strstr(extensionString, "EGL_ANGLE_feature_control") != nullptr;
932 
933     if (!hasFeatureControlANGLE)
934     {
935         return;
936     }
937 
938     angle::HashMap<std::string, angle::Feature> featureFromName;
939     for (angle::Feature feature : angle::AllEnums<angle::Feature>())
940     {
941         featureFromName[angle::GetFeatureName(feature)] = feature;
942     }
943 
944     EGLAttrib featureCount = -1;
945     eglQueryDisplayAttribANGLE(mDisplay, EGL_FEATURE_COUNT_ANGLE, &featureCount);
946 
947     for (int index = 0; index < featureCount; index++)
948     {
949         const char *featureName   = eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE, index);
950         const char *featureStatus = eglQueryStringiANGLE(mDisplay, EGL_FEATURE_STATUS_ANGLE, index);
951         ASSERT(featureName != nullptr);
952         ASSERT(featureStatus != nullptr);
953 
954         const angle::Feature feature = featureFromName[featureName];
955 
956         const bool isEnabled  = strcmp(featureStatus, angle::kFeatureStatusEnabled) == 0;
957         const bool isDisabled = strcmp(featureStatus, angle::kFeatureStatusDisabled) == 0;
958         ASSERT(isEnabled || isDisabled);
959 
960         mFeatures[feature] = isEnabled ? ANGLEFeatureStatus::Enabled : ANGLEFeatureStatus::Disabled;
961     }
962 }
963 
isFeatureEnabled(angle::Feature feature)964 bool EGLWindow::isFeatureEnabled(angle::Feature feature)
965 {
966     return mFeatures[feature] == ANGLEFeatureStatus::Enabled;
967 }
968