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 "platform/Platform.h"
16 #include "util/OSWindow.h"
17 #include "util/system_utils.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
initializeGL(OSWindow * osWindow,angle::Library * glWindowingLibrary,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)93 bool EGLWindow::initializeGL(OSWindow *osWindow,
94 angle::Library *glWindowingLibrary,
95 const EGLPlatformParameters &platformParams,
96 const ConfigParameters &configParams)
97 {
98 if (!initializeDisplay(osWindow, glWindowingLibrary, platformParams))
99 return false;
100 if (!initializeSurface(osWindow, glWindowingLibrary, configParams))
101 return false;
102 if (!initializeContext())
103 return false;
104 return true;
105 }
106
initializeDisplay(OSWindow * osWindow,angle::Library * glWindowingLibrary,const EGLPlatformParameters & params)107 bool EGLWindow::initializeDisplay(OSWindow *osWindow,
108 angle::Library *glWindowingLibrary,
109 const EGLPlatformParameters ¶ms)
110 {
111 #if defined(ANGLE_USE_UTIL_LOADER)
112 PFNEGLGETPROCADDRESSPROC getProcAddress;
113 glWindowingLibrary->getAs("eglGetProcAddress", &getProcAddress);
114 if (!getProcAddress)
115 {
116 return false;
117 }
118
119 // Likely we will need to use a fallback to Library::getAs on non-ANGLE platforms.
120 angle::LoadEGL(getProcAddress);
121 #endif // defined(ANGLE_USE_UTIL_LOADER)
122
123 std::vector<EGLAttrib> displayAttributes;
124 displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
125 displayAttributes.push_back(params.renderer);
126 displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
127 displayAttributes.push_back(params.majorVersion);
128 displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
129 displayAttributes.push_back(params.minorVersion);
130
131 if (params.deviceType != EGL_DONT_CARE)
132 {
133 displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
134 displayAttributes.push_back(params.deviceType);
135 }
136
137 if (params.presentPath != EGL_DONT_CARE)
138 {
139 const char *extensionString =
140 static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
141 if (strstr(extensionString, "EGL_ANGLE_experimental_present_path") == nullptr)
142 {
143 destroyGL();
144 return false;
145 }
146
147 displayAttributes.push_back(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE);
148 displayAttributes.push_back(params.presentPath);
149 }
150
151 // Set debug layer settings if requested.
152 if (params.debugLayersEnabled != EGL_DONT_CARE)
153 {
154 displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
155 displayAttributes.push_back(params.debugLayersEnabled);
156 }
157
158 if (params.contextVirtualization != EGL_DONT_CARE)
159 {
160 displayAttributes.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
161 displayAttributes.push_back(params.contextVirtualization);
162 }
163
164 if (params.platformMethods)
165 {
166 static_assert(sizeof(EGLAttrib) == sizeof(params.platformMethods),
167 "Unexpected pointer size");
168 displayAttributes.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
169 displayAttributes.push_back(reinterpret_cast<EGLAttrib>(params.platformMethods));
170 }
171
172 displayAttributes.push_back(EGL_NONE);
173
174 mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
175 reinterpret_cast<void *>(osWindow->getNativeDisplay()),
176 &displayAttributes[0]);
177 if (mDisplay == EGL_NO_DISPLAY)
178 {
179 destroyGL();
180 return false;
181 }
182
183 if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
184 {
185 destroyGL();
186 return false;
187 }
188
189 mPlatform = params;
190 return true;
191 }
192
initializeSurface(OSWindow * osWindow,angle::Library * glWindowingLibrary,const ConfigParameters & params)193 bool EGLWindow::initializeSurface(OSWindow *osWindow,
194 angle::Library *glWindowingLibrary,
195 const ConfigParameters ¶ms)
196 {
197 mConfigParams = params;
198 const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
199
200 std::vector<EGLint> configAttributes = {
201 EGL_RED_SIZE,
202 (mConfigParams.redBits >= 0) ? mConfigParams.redBits : EGL_DONT_CARE,
203 EGL_GREEN_SIZE,
204 (mConfigParams.greenBits >= 0) ? mConfigParams.greenBits : EGL_DONT_CARE,
205 EGL_BLUE_SIZE,
206 (mConfigParams.blueBits >= 0) ? mConfigParams.blueBits : EGL_DONT_CARE,
207 EGL_ALPHA_SIZE,
208 (mConfigParams.alphaBits >= 0) ? mConfigParams.alphaBits : EGL_DONT_CARE,
209 EGL_DEPTH_SIZE,
210 (mConfigParams.depthBits >= 0) ? mConfigParams.depthBits : EGL_DONT_CARE,
211 EGL_STENCIL_SIZE,
212 (mConfigParams.stencilBits >= 0) ? mConfigParams.stencilBits : EGL_DONT_CARE,
213 EGL_SAMPLE_BUFFERS,
214 mConfigParams.multisample ? 1 : 0,
215 EGL_SAMPLES,
216 (mConfigParams.samples >= 0) ? mConfigParams.samples : EGL_DONT_CARE,
217 };
218
219 // Add dynamic attributes
220 bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
221 if (!hasPixelFormatFloat && mConfigParams.componentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
222 {
223 destroyGL();
224 return false;
225 }
226 if (hasPixelFormatFloat)
227 {
228 configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
229 configAttributes.push_back(mConfigParams.componentType);
230 }
231
232 // Finish the attribute list
233 configAttributes.push_back(EGL_NONE);
234
235 if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
236 {
237 std::cout << "Could not find a suitable EGL config!" << std::endl;
238 destroyGL();
239 return false;
240 }
241
242 eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mConfigParams.redBits);
243 eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mConfigParams.greenBits);
244 eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mConfigParams.blueBits);
245 eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mConfigParams.alphaBits);
246 eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mConfigParams.depthBits);
247 eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mConfigParams.stencilBits);
248 eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mConfigParams.samples);
249
250 std::vector<EGLint> surfaceAttributes;
251 if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
252 {
253 surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
254 surfaceAttributes.push_back(EGL_TRUE);
255 }
256
257 bool hasRobustResourceInit =
258 strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
259 if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
260 {
261 surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
262 surfaceAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
263 : EGL_FALSE);
264 }
265
266 surfaceAttributes.push_back(EGL_NONE);
267
268 osWindow->resetNativeWindow();
269
270 mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
271 &surfaceAttributes[0]);
272 if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
273 {
274 destroyGL();
275 return false;
276 }
277
278 #if defined(ANGLE_USE_UTIL_LOADER)
279 angle::LoadGLES(eglGetProcAddress);
280 #endif // defined(ANGLE_USE_UTIL_LOADER)
281
282 return true;
283 }
284
createContext(EGLContext share) const285 EGLContext EGLWindow::createContext(EGLContext share) const
286 {
287 const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
288
289 // EGL_KHR_create_context is required to request a ES3+ context.
290 bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
291 if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
292 !hasKHRCreateContext)
293 {
294 std::cerr << "EGL_KHR_create_context incompatibility.\n";
295 return EGL_NO_CONTEXT;
296 }
297
298 bool hasWebGLCompatibility =
299 strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
300 if (mConfigParams.webGLCompatibility.valid() && !hasWebGLCompatibility)
301 {
302 std::cerr << "EGL_ANGLE_create_context_webgl_compatibility missing.\n";
303 return EGL_NO_CONTEXT;
304 }
305
306 bool hasCreateContextExtensionsEnabled =
307 strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
308 if (mConfigParams.extensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
309 {
310 std::cerr << "EGL_ANGLE_create_context_extensions_enabled missing.\n";
311 return EGL_NO_CONTEXT;
312 }
313
314 bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
315 if ((mConfigParams.robustAccess ||
316 mConfigParams.resetStrategy != EGL_NO_RESET_NOTIFICATION_EXT) &&
317 !hasRobustness)
318 {
319 std::cerr << "EGL_EXT_create_context_robustness missing.\n";
320 return EGL_NO_CONTEXT;
321 }
322
323 bool hasBindGeneratesResource =
324 strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
325 if (!mConfigParams.bindGeneratesResource && !hasBindGeneratesResource)
326 {
327 std::cerr << "EGL_CHROMIUM_create_context_bind_generates_resource missing.\n";
328 return EGL_NO_CONTEXT;
329 }
330
331 bool hasClientArraysExtension =
332 strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
333 if (!mConfigParams.clientArraysEnabled && !hasClientArraysExtension)
334 {
335 // Non-default state requested without the extension present
336 std::cerr << "EGL_ANGLE_create_context_client_arrays missing.\n";
337 return EGL_NO_CONTEXT;
338 }
339
340 bool hasProgramCacheControlExtension =
341 strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
342 if (mConfigParams.contextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
343 {
344 std::cerr << "EGL_ANGLE_program_cache_control missing.\n";
345 return EGL_NO_CONTEXT;
346 }
347
348 bool hasBackwardsCompatibleContextExtension =
349 strstr(displayExtensions, "EGL_ANGLE_create_context_backwards_compatible") != nullptr;
350 if (!hasProgramCacheControlExtension)
351 {
352 std::cerr << "EGL_ANGLE_create_context_backwards_compatible missing.\n";
353 return EGL_NO_CONTEXT;
354 }
355
356 eglBindAPI(EGL_OPENGL_ES_API);
357 if (eglGetError() != EGL_SUCCESS)
358 {
359 std::cerr << "Error on eglBindAPI.\n";
360 return EGL_NO_CONTEXT;
361 }
362
363 std::vector<EGLint> contextAttributes;
364 if (hasKHRCreateContext)
365 {
366 contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
367 contextAttributes.push_back(mClientMajorVersion);
368
369 contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
370 contextAttributes.push_back(mClientMinorVersion);
371
372 contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
373 contextAttributes.push_back(mConfigParams.debug ? EGL_TRUE : EGL_FALSE);
374
375 // TODO(jmadill): Check for the extension string.
376 // bool hasKHRCreateContextNoError = strstr(displayExtensions,
377 // "EGL_KHR_create_context_no_error") != nullptr;
378
379 contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
380 contextAttributes.push_back(mConfigParams.noError ? EGL_TRUE : EGL_FALSE);
381
382 if (mConfigParams.webGLCompatibility.valid())
383 {
384 contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
385 contextAttributes.push_back(mConfigParams.webGLCompatibility.value() ? EGL_TRUE
386 : EGL_FALSE);
387 }
388
389 if (mConfigParams.extensionsEnabled.valid())
390 {
391 contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
392 contextAttributes.push_back(mConfigParams.extensionsEnabled.value() ? EGL_TRUE
393 : EGL_FALSE);
394 }
395
396 if (hasRobustness)
397 {
398 contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
399 contextAttributes.push_back(mConfigParams.robustAccess ? EGL_TRUE : EGL_FALSE);
400
401 contextAttributes.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
402 contextAttributes.push_back(mConfigParams.resetStrategy);
403 }
404
405 if (hasBindGeneratesResource)
406 {
407 contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
408 contextAttributes.push_back(mConfigParams.bindGeneratesResource ? EGL_TRUE : EGL_FALSE);
409 }
410
411 if (hasClientArraysExtension)
412 {
413 contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
414 contextAttributes.push_back(mConfigParams.clientArraysEnabled ? EGL_TRUE : EGL_FALSE);
415 }
416
417 if (mConfigParams.contextProgramCacheEnabled.valid())
418 {
419 contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
420 contextAttributes.push_back(
421 mConfigParams.contextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
422 }
423
424 if (hasBackwardsCompatibleContextExtension)
425 {
426 // Always request the exact context version that the config wants
427 contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
428 contextAttributes.push_back(EGL_FALSE);
429 }
430
431 bool hasRobustResourceInit =
432 strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
433 if (hasRobustResourceInit && mConfigParams.robustResourceInit.valid())
434 {
435 contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
436 contextAttributes.push_back(mConfigParams.robustResourceInit.value() ? EGL_TRUE
437 : EGL_FALSE);
438 }
439 }
440 contextAttributes.push_back(EGL_NONE);
441
442 EGLContext context = eglCreateContext(mDisplay, mConfig, nullptr, &contextAttributes[0]);
443 if (eglGetError() != EGL_SUCCESS)
444 {
445 std::cerr << "Error on eglCreateContext.\n";
446 return EGL_NO_CONTEXT;
447 }
448
449 return context;
450 }
451
initializeContext()452 bool EGLWindow::initializeContext()
453 {
454 mContext = createContext(EGL_NO_CONTEXT);
455 if (mContext == EGL_NO_CONTEXT)
456 {
457 destroyGL();
458 return false;
459 }
460
461 if (!makeCurrent())
462 {
463 destroyGL();
464 return false;
465 }
466
467 return true;
468 }
469
destroyGL()470 void EGLWindow::destroyGL()
471 {
472 destroyContext();
473 destroySurface();
474
475 if (mDisplay != EGL_NO_DISPLAY)
476 {
477 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
478 eglTerminate(mDisplay);
479 mDisplay = EGL_NO_DISPLAY;
480 }
481 }
482
destroySurface()483 void EGLWindow::destroySurface()
484 {
485 if (mSurface != EGL_NO_SURFACE)
486 {
487 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
488 assert(mDisplay != EGL_NO_DISPLAY);
489 eglDestroySurface(mDisplay, mSurface);
490 mSurface = EGL_NO_SURFACE;
491 }
492 }
493
destroyContext()494 void EGLWindow::destroyContext()
495 {
496 if (mContext != EGL_NO_CONTEXT)
497 {
498 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
499 assert(mDisplay != EGL_NO_DISPLAY);
500 eglDestroyContext(mDisplay, mContext);
501 mContext = EGL_NO_CONTEXT;
502 }
503 }
504
isGLInitialized() const505 bool EGLWindow::isGLInitialized() const
506 {
507 return mSurface != EGL_NO_SURFACE && mContext != EGL_NO_CONTEXT && mDisplay != EGL_NO_DISPLAY;
508 }
509
510 // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
511 // the EGLConfig is found. This indicates that the EGLConfig is not supported.
FindEGLConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * config)512 EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
513 {
514 EGLint numConfigs = 0;
515 eglGetConfigs(dpy, nullptr, 0, &numConfigs);
516 std::vector<EGLConfig> allConfigs(numConfigs);
517 eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
518
519 for (size_t i = 0; i < allConfigs.size(); i++)
520 {
521 bool matchFound = true;
522 for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
523 {
524 if (curAttrib[1] == EGL_DONT_CARE)
525 {
526 continue;
527 }
528
529 EGLint actualValue = EGL_DONT_CARE;
530 eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
531 if (curAttrib[1] != actualValue)
532 {
533 matchFound = false;
534 break;
535 }
536 }
537
538 if (matchFound)
539 {
540 *config = allConfigs[i];
541 return EGL_TRUE;
542 }
543 }
544
545 return EGL_FALSE;
546 }
547
makeCurrent()548 bool EGLWindow::makeCurrent()
549 {
550 if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE ||
551 eglGetError() != EGL_SUCCESS)
552 {
553 std::cerr << "Error during eglMakeCurrent.\n";
554 return false;
555 }
556
557 return true;
558 }
559
setSwapInterval(EGLint swapInterval)560 bool EGLWindow::setSwapInterval(EGLint swapInterval)
561 {
562 if (eglSwapInterval(mDisplay, swapInterval) == EGL_FALSE || eglGetError() != EGL_SUCCESS)
563 {
564 std::cerr << "Error during eglSwapInterval.\n";
565 return false;
566 }
567
568 return true;
569 }
570
hasError() const571 bool EGLWindow::hasError() const
572 {
573 return eglGetError() != EGL_SUCCESS;
574 }
575
CheckExtensionExists(const char * allExtensions,const std::string & extName)576 bool CheckExtensionExists(const char *allExtensions, const std::string &extName)
577 {
578 const std::string paddedExtensions = std::string(" ") + allExtensions + std::string(" ");
579 return paddedExtensions.find(std::string(" ") + extName + std::string(" ")) !=
580 std::string::npos;
581 }
582
583 // static
Delete(GLWindowBase ** window)584 void GLWindowBase::Delete(GLWindowBase **window)
585 {
586 delete *window;
587 *window = nullptr;
588 }
589
590 // static
New(EGLint glesMajorVersion,EGLint glesMinorVersion)591 EGLWindow *EGLWindow::New(EGLint glesMajorVersion, EGLint glesMinorVersion)
592 {
593 return new EGLWindow(glesMajorVersion, glesMinorVersion);
594 }
595
596 // static
Delete(EGLWindow ** window)597 void EGLWindow::Delete(EGLWindow **window)
598 {
599 delete *window;
600 *window = nullptr;
601 }
602