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 *> disabledFeatureOverrides;
206 std::vector<const char *> enabledFeatureOverrides;
207
208 if (params.transformFeedbackFeature == EGL_FALSE)
209 {
210 disabledFeatureOverrides.push_back("supportsTransformFeedbackExtension");
211 disabledFeatureOverrides.push_back("supportsGeometryStreamsCapability");
212 disabledFeatureOverrides.push_back("emulateTransformFeedback");
213 }
214
215 if (params.allocateNonZeroMemoryFeature == EGL_TRUE)
216 {
217 enabledFeatureOverrides.push_back("allocateNonZeroMemory");
218 }
219 else if (params.allocateNonZeroMemoryFeature == EGL_FALSE)
220 {
221 disabledFeatureOverrides.push_back("allocateNonZeroMemory");
222 }
223
224 if (params.emulateCopyTexImage2DFromRenderbuffers == EGL_TRUE)
225 {
226 enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers");
227 }
228
229 if (params.shaderStencilOutputFeature == EGL_FALSE)
230 {
231 disabledFeatureOverrides.push_back("has_shader_stencil_output");
232 }
233
234 if (params.genMultipleMipsPerPassFeature == EGL_FALSE)
235 {
236 disabledFeatureOverrides.push_back("gen_multiple_mips_per_pass");
237 }
238
239 if (params.supportsVulkanViewportFlip == EGL_TRUE)
240 {
241 enabledFeatureOverrides.push_back("supportsViewportFlip");
242 }
243 else if (params.supportsVulkanViewportFlip == EGL_FALSE)
244 {
245 disabledFeatureOverrides.push_back("supportsViewportFlip");
246 }
247
248 if (params.supportsVulkanMultiDrawIndirect == EGL_TRUE)
249 {
250 enabledFeatureOverrides.push_back("supportsMultiDrawIndirect");
251 }
252 else if (params.supportsVulkanMultiDrawIndirect == EGL_FALSE)
253 {
254 disabledFeatureOverrides.push_back("supportsMultiDrawIndirect");
255 }
256
257 switch (params.emulatedPrerotation)
258 {
259 case 90:
260 enabledFeatureOverrides.push_back("emulatedPrerotation90");
261 break;
262 case 180:
263 enabledFeatureOverrides.push_back("emulatedPrerotation180");
264 break;
265 case 270:
266 enabledFeatureOverrides.push_back("emulatedPrerotation270");
267 break;
268 default:
269 break;
270 }
271
272 if (params.asyncCommandQueueFeatureVulkan == EGL_TRUE)
273 {
274 enabledFeatureOverrides.push_back("asyncCommandQueue");
275 }
276
277 if (params.generateSPIRVThroughGlslang == EGL_TRUE)
278 {
279 enabledFeatureOverrides.push_back("generateSPIRVThroughGlslang");
280 }
281
282 if (params.directMetalGeneration == EGL_TRUE)
283 {
284 enabledFeatureOverrides.push_back("directMetalGeneration");
285 }
286
287 if (params.hasExplicitMemBarrierFeatureMtl == EGL_FALSE)
288 {
289 disabledFeatureOverrides.push_back("has_explicit_mem_barrier_mtl");
290 }
291
292 if (params.hasCheapRenderPassFeatureMtl == EGL_FALSE)
293 {
294 disabledFeatureOverrides.push_back("has_cheap_render_pass_mtl");
295 }
296
297 if (params.forceBufferGPUStorageFeatureMtl == EGL_TRUE)
298 {
299 enabledFeatureOverrides.push_back("force_buffer_gpu_storage_mtl");
300 }
301
302 if (params.emulatedVAOs == EGL_TRUE)
303 {
304 enabledFeatureOverrides.push_back("sync_vertex_arrays_to_default");
305 }
306
307 if (params.captureLimits == EGL_TRUE)
308 {
309 enabledFeatureOverrides.push_back("enable_capture_limits");
310 }
311
312 if (params.forceRobustResourceInit == EGL_TRUE)
313 {
314 enabledFeatureOverrides.push_back("forceRobustResourceInit");
315 }
316
317 if (params.forceInitShaderVariables == EGL_TRUE)
318 {
319 enabledFeatureOverrides.push_back("forceInitShaderVariables");
320 }
321
322 if (params.forceVulkanFallbackFormat == EGL_TRUE)
323 {
324 enabledFeatureOverrides.push_back("forceFallbackFormat");
325 }
326
327 const bool hasFeatureControlANGLE =
328 strstr(extensionString, "EGL_ANGLE_feature_control") != nullptr;
329
330 if (!hasFeatureControlANGLE &&
331 (!enabledFeatureOverrides.empty() || !disabledFeatureOverrides.empty()))
332 {
333 fprintf(stderr, "Missing EGL_ANGLE_feature_control.\n");
334 destroyGL();
335 return false;
336 }
337
338 if (!disabledFeatureOverrides.empty())
339 {
340 disabledFeatureOverrides.push_back(nullptr);
341
342 displayAttributes.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
343 displayAttributes.push_back(reinterpret_cast<EGLAttrib>(disabledFeatureOverrides.data()));
344 }
345
346 if (hasFeatureControlANGLE)
347 {
348 // Always enable exposeNonConformantExtensionsAndVersions in ANGLE tests.
349 enabledFeatureOverrides.push_back("exposeNonConformantExtensionsAndVersions");
350 enabledFeatureOverrides.push_back(nullptr);
351
352 displayAttributes.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
353 displayAttributes.push_back(reinterpret_cast<EGLAttrib>(enabledFeatureOverrides.data()));
354 }
355
356 displayAttributes.push_back(EGL_NONE);
357
358 if (driverType == angle::GLESDriverType::SystemWGL)
359 return false;
360
361 if (driverType == angle::GLESDriverType::AngleEGL &&
362 strstr(extensionString, "EGL_ANGLE_platform_angle"))
363 {
364 mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
365 reinterpret_cast<void *>(osWindow->getNativeDisplay()),
366 &displayAttributes[0]);
367 }
368 else
369 {
370 mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
371 }
372
373 if (mDisplay == EGL_NO_DISPLAY)
374 {
375 fprintf(stderr, "Failed to get display: 0x%X\n", eglGetError());
376 destroyGL();
377 return false;
378 }
379
380 if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
381 {
382 fprintf(stderr, "eglInitialize failed: 0x%X\n", eglGetError());
383 destroyGL();
384 return false;
385 }
386
387 mPlatform = params;
388 return true;
389 }
390
initializeSurface(OSWindow * osWindow,angle::Library * glWindowingLibrary,const ConfigParameters & params)391 GLWindowResult EGLWindow::initializeSurface(OSWindow *osWindow,
392 angle::Library *glWindowingLibrary,
393 const ConfigParameters ¶ms)
394 {
395 mConfigParams = params;
396 const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
397
398 std::vector<EGLint> configAttributes = {
399 EGL_SURFACE_TYPE,
400 EGL_WINDOW_BIT,
401 EGL_RED_SIZE,
402 (mConfigParams.redBits >= 0) ? mConfigParams.redBits : EGL_DONT_CARE,
403 EGL_GREEN_SIZE,
404 (mConfigParams.greenBits >= 0) ? mConfigParams.greenBits : EGL_DONT_CARE,
405 EGL_BLUE_SIZE,
406 (mConfigParams.blueBits >= 0) ? mConfigParams.blueBits : EGL_DONT_CARE,
407 EGL_ALPHA_SIZE,
408 (mConfigParams.alphaBits >= 0) ? mConfigParams.alphaBits : EGL_DONT_CARE,
409 EGL_DEPTH_SIZE,
410 (mConfigParams.depthBits >= 0) ? mConfigParams.depthBits : EGL_DONT_CARE,
411 EGL_STENCIL_SIZE,
412 (mConfigParams.stencilBits >= 0) ? mConfigParams.stencilBits : EGL_DONT_CARE,
413 EGL_SAMPLE_BUFFERS,
414 mConfigParams.multisample ? 1 : 0,
415 EGL_SAMPLES,
416 (mConfigParams.samples >= 0) ? mConfigParams.samples : EGL_DONT_CARE,
417 };
418
419 // Add dynamic attributes
420 bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
421 if (!hasPixelFormatFloat && mConfigParams.componentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
422 {
423 fprintf(stderr, "Mising EGL_EXT_pixel_format_float.\n");
424 destroyGL();
425 return GLWindowResult::Error;
426 }
427 if (hasPixelFormatFloat)
428 {
429 configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
430 configAttributes.push_back(mConfigParams.componentType);
431 }
432
433 // Finish the attribute list
434 configAttributes.push_back(EGL_NONE);
435
436 if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
437 {
438 fprintf(stderr, "Could not find a suitable EGL config!\n");
439 destroyGL();
440 return GLWindowResult::Error;
441 }
442
443 eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mConfigParams.redBits);
444 eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mConfigParams.greenBits);
445 eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mConfigParams.blueBits);
446 eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mConfigParams.alphaBits);
447 eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mConfigParams.depthBits);
448 eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mConfigParams.stencilBits);
449 eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mConfigParams.samples);
450
451 std::vector<EGLint> surfaceAttributes;
452 if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
453 {
454 surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
455 surfaceAttributes.push_back(EGL_TRUE);
456 }
457
458 bool hasRobustResourceInit =
459 strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
460 if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
461 {
462 surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
463 surfaceAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
464 : EGL_FALSE);
465 }
466
467 bool hasGLColorSpace = strstr(displayExtensions, "EGL_KHR_gl_colorspace") != nullptr;
468 if (!hasGLColorSpace && mConfigParams.colorSpace != EGL_COLORSPACE_LINEAR)
469 {
470 fprintf(stderr, "Mising EGL_KHR_gl_colorspace.\n");
471 destroyGL();
472 return GLWindowResult::NoColorspaceSupport;
473 }
474 if (hasGLColorSpace)
475 {
476 surfaceAttributes.push_back(EGL_GL_COLORSPACE_KHR);
477 surfaceAttributes.push_back(mConfigParams.colorSpace);
478 }
479
480 bool hasCreateSurfaceSwapInterval =
481 strstr(displayExtensions, "EGL_ANGLE_create_surface_swap_interval") != nullptr;
482 if (hasCreateSurfaceSwapInterval && mConfigParams.swapInterval != kDefaultSwapInterval)
483 {
484 surfaceAttributes.push_back(EGL_SWAP_INTERVAL_ANGLE);
485 surfaceAttributes.push_back(mConfigParams.swapInterval);
486 }
487
488 surfaceAttributes.push_back(EGL_NONE);
489
490 osWindow->resetNativeWindow();
491
492 mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
493 &surfaceAttributes[0]);
494 if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
495 {
496 fprintf(stderr, "eglCreateWindowSurface failed: 0x%X\n", eglGetError());
497 destroyGL();
498 return GLWindowResult::Error;
499 }
500
501 #if defined(ANGLE_USE_UTIL_LOADER)
502 angle::LoadGLES(eglGetProcAddress);
503 #endif // defined(ANGLE_USE_UTIL_LOADER)
504
505 return GLWindowResult::NoError;
506 }
507
getCurrentContextGeneric()508 GLWindowContext EGLWindow::getCurrentContextGeneric()
509 {
510 return reinterpret_cast<GLWindowContext>(mContext);
511 }
512
createContextGeneric(GLWindowContext share)513 GLWindowContext EGLWindow::createContextGeneric(GLWindowContext share)
514 {
515 EGLContext shareContext = reinterpret_cast<EGLContext>(share);
516 return reinterpret_cast<GLWindowContext>(createContext(shareContext, nullptr));
517 }
518
createContext(EGLContext share,EGLint * extraAttributes)519 EGLContext EGLWindow::createContext(EGLContext share, EGLint *extraAttributes)
520 {
521 const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
522
523 // EGL_KHR_create_context is required to request a ES3+ context.
524 bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
525 if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
526 !hasKHRCreateContext)
527 {
528 fprintf(stderr, "EGL_KHR_create_context incompatibility.\n");
529 return EGL_NO_CONTEXT;
530 }
531
532 // EGL_CONTEXT_OPENGL_DEBUG is only valid as of EGL 1.5.
533 bool hasDebug = mEGLMinorVersion >= 5;
534 if (mConfigParams.debug && !hasDebug)
535 {
536 fprintf(stderr, "EGL 1.5 is required for EGL_CONTEXT_OPENGL_DEBUG.\n");
537 return EGL_NO_CONTEXT;
538 }
539
540 bool hasWebGLCompatibility =
541 strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
542 if (mConfigParams.webGLCompatibility.valid() && !hasWebGLCompatibility)
543 {
544 fprintf(stderr, "EGL_ANGLE_create_context_webgl_compatibility missing.\n");
545 return EGL_NO_CONTEXT;
546 }
547
548 bool hasCreateContextExtensionsEnabled =
549 strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
550 if (mConfigParams.extensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
551 {
552 fprintf(stderr, "EGL_ANGLE_create_context_extensions_enabled missing.\n");
553 return EGL_NO_CONTEXT;
554 }
555
556 bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
557 if ((mConfigParams.robustAccess ||
558 mConfigParams.resetStrategy != EGL_NO_RESET_NOTIFICATION_EXT) &&
559 !hasRobustness)
560 {
561 fprintf(stderr, "EGL_EXT_create_context_robustness missing.\n");
562 return EGL_NO_CONTEXT;
563 }
564
565 bool hasBindGeneratesResource =
566 strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
567 if (!mConfigParams.bindGeneratesResource && !hasBindGeneratesResource)
568 {
569 fprintf(stderr, "EGL_CHROMIUM_create_context_bind_generates_resource missing.\n");
570 return EGL_NO_CONTEXT;
571 }
572
573 bool hasClientArraysExtension =
574 strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
575 if (!mConfigParams.clientArraysEnabled && !hasClientArraysExtension)
576 {
577 // Non-default state requested without the extension present
578 fprintf(stderr, "EGL_ANGLE_create_context_client_arrays missing.\n");
579 return EGL_NO_CONTEXT;
580 }
581
582 bool hasProgramCacheControlExtension =
583 strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
584 if (mConfigParams.contextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
585 {
586 fprintf(stderr, "EGL_ANGLE_program_cache_control missing.\n");
587 return EGL_NO_CONTEXT;
588 }
589
590 bool hasKHRCreateContextNoError =
591 strstr(displayExtensions, "EGL_KHR_create_context_no_error") != nullptr;
592 if (mConfigParams.noError && !hasKHRCreateContextNoError)
593 {
594 fprintf(stderr, "EGL_KHR_create_context_no_error missing.\n");
595 return EGL_NO_CONTEXT;
596 }
597
598 eglBindAPI(EGL_OPENGL_ES_API);
599 if (eglGetError() != EGL_SUCCESS)
600 {
601 fprintf(stderr, "Error on eglBindAPI.\n");
602 return EGL_NO_CONTEXT;
603 }
604
605 std::vector<EGLint> contextAttributes;
606 for (EGLint *extraAttrib = extraAttributes;
607 extraAttrib != nullptr && extraAttrib[0] != EGL_NONE; extraAttrib += 2)
608 {
609 contextAttributes.push_back(extraAttrib[0]);
610 contextAttributes.push_back(extraAttrib[1]);
611 }
612
613 if (hasKHRCreateContext)
614 {
615 contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
616 contextAttributes.push_back(mClientMajorVersion);
617
618 contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
619 contextAttributes.push_back(mClientMinorVersion);
620
621 // Note that the Android loader currently doesn't handle this flag despite reporting 1.5.
622 // Work around this by only using the debug bit when we request a debug context.
623 if (hasDebug && mConfigParams.debug)
624 {
625 contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
626 contextAttributes.push_back(mConfigParams.debug ? EGL_TRUE : EGL_FALSE);
627 }
628
629 // TODO (http://anglebug.com/5809)
630 // Mesa does not allow EGL_CONTEXT_OPENGL_NO_ERROR_KHR for GLES1.
631 if (hasKHRCreateContextNoError && mConfigParams.noError)
632 {
633 contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
634 contextAttributes.push_back(mConfigParams.noError ? EGL_TRUE : EGL_FALSE);
635 }
636
637 if (mConfigParams.webGLCompatibility.valid())
638 {
639 contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
640 contextAttributes.push_back(mConfigParams.webGLCompatibility.value() ? EGL_TRUE
641 : EGL_FALSE);
642 }
643
644 if (mConfigParams.extensionsEnabled.valid())
645 {
646 contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
647 contextAttributes.push_back(mConfigParams.extensionsEnabled.value() ? EGL_TRUE
648 : EGL_FALSE);
649 }
650
651 if (hasRobustness)
652 {
653 contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
654 contextAttributes.push_back(mConfigParams.robustAccess ? EGL_TRUE : EGL_FALSE);
655
656 contextAttributes.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
657 contextAttributes.push_back(mConfigParams.resetStrategy);
658 }
659
660 if (hasBindGeneratesResource)
661 {
662 contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
663 contextAttributes.push_back(mConfigParams.bindGeneratesResource ? EGL_TRUE : EGL_FALSE);
664 }
665
666 if (hasClientArraysExtension)
667 {
668 contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
669 contextAttributes.push_back(mConfigParams.clientArraysEnabled ? EGL_TRUE : EGL_FALSE);
670 }
671
672 if (mConfigParams.contextProgramCacheEnabled.valid())
673 {
674 contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
675 contextAttributes.push_back(
676 mConfigParams.contextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
677 }
678
679 bool hasBackwardsCompatibleContextExtension =
680 strstr(displayExtensions, "EGL_ANGLE_create_context_backwards_compatible") != nullptr;
681 if (hasBackwardsCompatibleContextExtension)
682 {
683 // Always request the exact context version that the config wants
684 contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
685 contextAttributes.push_back(EGL_FALSE);
686 }
687
688 bool hasRobustResourceInit =
689 strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
690 if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
691 {
692 contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
693 contextAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
694 : EGL_FALSE);
695 }
696 }
697 contextAttributes.push_back(EGL_NONE);
698
699 EGLContext context = eglCreateContext(mDisplay, mConfig, share, &contextAttributes[0]);
700 if (context == EGL_NO_CONTEXT)
701 {
702 fprintf(stderr, "eglCreateContext failed: 0x%X\n", eglGetError());
703 return EGL_NO_CONTEXT;
704 }
705
706 return context;
707 }
708
initializeContext()709 bool EGLWindow::initializeContext()
710 {
711 mContext = createContext(EGL_NO_CONTEXT, nullptr);
712 if (mContext == EGL_NO_CONTEXT)
713 {
714 destroyGL();
715 return false;
716 }
717
718 if (!makeCurrent())
719 {
720 destroyGL();
721 return false;
722 }
723
724 return true;
725 }
726
destroyGL()727 void EGLWindow::destroyGL()
728 {
729 destroyContext();
730 destroySurface();
731
732 if (mDisplay != EGL_NO_DISPLAY)
733 {
734 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
735 eglTerminate(mDisplay);
736 mDisplay = EGL_NO_DISPLAY;
737 }
738 }
739
destroySurface()740 void EGLWindow::destroySurface()
741 {
742 if (mSurface != EGL_NO_SURFACE)
743 {
744 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
745 assert(mDisplay != EGL_NO_DISPLAY);
746 eglDestroySurface(mDisplay, mSurface);
747 mSurface = EGL_NO_SURFACE;
748 }
749 }
750
destroyContext()751 void EGLWindow::destroyContext()
752 {
753 if (mContext != EGL_NO_CONTEXT)
754 {
755 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
756 assert(mDisplay != EGL_NO_DISPLAY);
757 eglDestroyContext(mDisplay, mContext);
758 mContext = EGL_NO_CONTEXT;
759 }
760 }
761
isGLInitialized() const762 bool EGLWindow::isGLInitialized() const
763 {
764 return mSurface != EGL_NO_SURFACE && mContext != EGL_NO_CONTEXT && mDisplay != EGL_NO_DISPLAY;
765 }
766
767 // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
768 // the EGLConfig is found. This indicates that the EGLConfig is not supported. Surface type is
769 // special-cased as it's possible for a config to return support for both EGL_WINDOW_BIT and
770 // EGL_PBUFFER_BIT even though only one of them is requested.
FindEGLConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * config)771 EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
772 {
773 EGLint numConfigs = 0;
774 eglGetConfigs(dpy, nullptr, 0, &numConfigs);
775 std::vector<EGLConfig> allConfigs(numConfigs);
776 eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
777
778 for (size_t i = 0; i < allConfigs.size(); i++)
779 {
780 bool matchFound = true;
781 for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
782 {
783 if (curAttrib[1] == EGL_DONT_CARE)
784 {
785 continue;
786 }
787
788 EGLint actualValue = EGL_DONT_CARE;
789 eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
790 if ((curAttrib[0] == EGL_SURFACE_TYPE &&
791 (curAttrib[1] & actualValue) != curAttrib[1]) ||
792 (curAttrib[0] != EGL_SURFACE_TYPE && curAttrib[1] != actualValue))
793 {
794 matchFound = false;
795 break;
796 }
797 }
798
799 if (matchFound)
800 {
801 *config = allConfigs[i];
802 return EGL_TRUE;
803 }
804 }
805
806 return EGL_FALSE;
807 }
808
makeCurrentGeneric(GLWindowContext context)809 bool EGLWindow::makeCurrentGeneric(GLWindowContext context)
810 {
811 EGLContext eglContext = reinterpret_cast<EGLContext>(context);
812 return makeCurrent(eglContext);
813 }
814
makeCurrent()815 bool EGLWindow::makeCurrent()
816 {
817 return makeCurrent(mContext);
818 }
819
makeCurrent(EGLContext context)820 bool EGLWindow::makeCurrent(EGLContext context)
821 {
822 if (eglMakeCurrent(mDisplay, mSurface, mSurface, context) == EGL_FALSE ||
823 eglGetError() != EGL_SUCCESS)
824 {
825 fprintf(stderr, "Error during eglMakeCurrent.\n");
826 return false;
827 }
828
829 return true;
830 }
831
setSwapInterval(EGLint swapInterval)832 bool EGLWindow::setSwapInterval(EGLint swapInterval)
833 {
834 if (eglSwapInterval(mDisplay, swapInterval) == EGL_FALSE || eglGetError() != EGL_SUCCESS)
835 {
836 fprintf(stderr, "Error during eglSwapInterval.\n");
837 return false;
838 }
839
840 return true;
841 }
842
hasError() const843 bool EGLWindow::hasError() const
844 {
845 return eglGetError() != EGL_SUCCESS;
846 }
847
getProcAddress(const char * name)848 angle::GenericProc EGLWindow::getProcAddress(const char *name)
849 {
850 return eglGetProcAddress(name);
851 }
852
853 // static
Delete(GLWindowBase ** window)854 void GLWindowBase::Delete(GLWindowBase **window)
855 {
856 delete *window;
857 *window = nullptr;
858 }
859
860 // static
New(EGLint glesMajorVersion,EGLint glesMinorVersion)861 EGLWindow *EGLWindow::New(EGLint glesMajorVersion, EGLint glesMinorVersion)
862 {
863 return new EGLWindow(glesMajorVersion, glesMinorVersion);
864 }
865
866 // static
Delete(EGLWindow ** window)867 void EGLWindow::Delete(EGLWindow **window)
868 {
869 delete *window;
870 *window = nullptr;
871 }
872