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 ¶ms)
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 ¶ms)
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