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