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