• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params)
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 &params)
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