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