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