Bug 1883287 - Don't wait for the hidden window to be created on Linux to load the...
[gecko.git] / gfx / gl / GLContextProviderEGL.cpp
blobcb47e285a50c2dd8c557d4d213f72e11eb9709b7
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #if defined(MOZ_WIDGET_GTK)
7 # define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
8 ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_EGL_WINDOW))
9 # define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
10 (aWidget->AsGTK()->GetEGLNativeWindow())
11 #elif defined(MOZ_WIDGET_ANDROID)
12 # define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
13 ((EGLNativeWindowType)aWidget->GetNativeData(NS_JAVA_SURFACE))
14 # define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
15 (aWidget->AsAndroid()->GetEGLNativeWindow())
16 #elif defined(XP_WIN)
17 # define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
18 ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
19 # define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
20 ((EGLNativeWindowType)aWidget->AsWindows()->GetHwnd())
21 #else
22 # define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
23 ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
24 # define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
25 ((EGLNativeWindowType)aWidget->RealWidget()->GetNativeData( \
26 NS_NATIVE_WINDOW))
27 #endif
29 #if defined(XP_UNIX)
30 # ifdef MOZ_WIDGET_ANDROID
31 # include <android/native_window.h>
32 # include <android/native_window_jni.h>
33 # include "mozilla/widget/AndroidCompositorWidget.h"
34 # endif
36 # define GLES2_LIB "libGLESv2.so"
37 # define GLES2_LIB2 "libGLESv2.so.2"
39 #elif defined(XP_WIN)
40 # include "mozilla/widget/WinCompositorWidget.h"
41 # include "nsIFile.h"
43 # define GLES2_LIB "libGLESv2.dll"
45 # ifndef WIN32_LEAN_AND_MEAN
46 # define WIN32_LEAN_AND_MEAN 1
47 # endif
49 # include <windows.h>
50 #else
51 # error "Platform not recognized"
52 #endif
54 #include "gfxCrashReporterUtils.h"
55 #include "gfxFailure.h"
56 #include "gfxPlatform.h"
57 #include "gfxUtils.h"
58 #include "GLBlitHelper.h"
59 #include "GLContextEGL.h"
60 #include "GLContextProvider.h"
61 #include "GLLibraryEGL.h"
62 #include "GLLibraryLoader.h"
63 #include "mozilla/ArrayUtils.h"
64 #include "mozilla/Preferences.h"
65 #include "mozilla/Services.h"
66 #include "mozilla/StaticPrefs_gfx.h"
67 #include "mozilla/gfx/gfxVars.h"
68 #include "mozilla/gfx/BuildConstants.h"
69 #include "mozilla/gfx/Logging.h"
70 #include "mozilla/layers/CompositorOptions.h"
71 #include "mozilla/widget/CompositorWidget.h"
72 #include "nsDebug.h"
73 #include "nsIWidget.h"
74 #include "nsThreadUtils.h"
75 #include "ScopedGLHelpers.h"
77 #if defined(MOZ_WIDGET_GTK)
78 # include "mozilla/widget/GtkCompositorWidget.h"
79 # if defined(MOZ_WAYLAND)
80 # include <gdk/gdkwayland.h>
81 # include <wayland-egl.h>
82 # include "mozilla/WidgetUtilsGtk.h"
83 # include "mozilla/widget/nsWaylandDisplay.h"
84 # endif
85 #endif
87 struct wl_egl_window;
89 using namespace mozilla::gfx;
91 namespace mozilla {
92 namespace gl {
94 using namespace mozilla::widget;
96 #if defined(MOZ_WAYLAND)
97 class WaylandOffscreenGLSurface {
98 public:
99 WaylandOffscreenGLSurface(struct wl_surface* aWaylandSurface,
100 struct wl_egl_window* aEGLWindow);
101 ~WaylandOffscreenGLSurface();
103 private:
104 struct wl_surface* mWaylandSurface = nullptr;
105 struct wl_egl_window* mEGLWindow = nullptr;
108 static nsTHashMap<nsPtrHashKey<void>, WaylandOffscreenGLSurface*>
109 sWaylandOffscreenGLSurfaces;
111 void DeleteWaylandOffscreenGLSurface(EGLSurface surface) {
112 auto entry = sWaylandOffscreenGLSurfaces.Lookup(surface);
113 if (entry) {
114 delete entry.Data();
115 entry.Remove();
118 #endif
120 static bool CreateConfigScreen(EglDisplay&, EGLConfig* const aConfig,
121 const bool aEnableDepthBuffer,
122 const bool aUseGles);
124 // append three zeros at the end of attribs list to work around
125 // EGL implementation bugs that iterate until they find 0, instead of
126 // EGL_NONE. See bug 948406.
127 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
128 LOCAL_EGL_NONE, 0, 0, 0
130 static EGLint kTerminationAttribs[] = {
131 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS};
133 static int next_power_of_two(int v) {
134 v--;
135 v |= v >> 1;
136 v |= v >> 2;
137 v |= v >> 4;
138 v |= v >> 8;
139 v |= v >> 16;
140 v++;
142 return v;
145 static bool is_power_of_two(int v) {
146 NS_ASSERTION(v >= 0, "bad value");
148 if (v == 0) return true;
150 return (v & (v - 1)) == 0;
153 static EGLSurface CreateFallbackSurface(EglDisplay& egl,
154 const EGLConfig& config) {
155 if (egl.IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
156 // We don't need a PBuffer surface in this case
157 return EGL_NO_SURFACE;
160 std::vector<EGLint> pbattrs;
161 pbattrs.push_back(LOCAL_EGL_WIDTH);
162 pbattrs.push_back(1);
163 pbattrs.push_back(LOCAL_EGL_HEIGHT);
164 pbattrs.push_back(1);
166 for (const auto& cur : kTerminationAttribs) {
167 pbattrs.push_back(cur);
170 EGLSurface surface = egl.fCreatePbufferSurface(config, pbattrs.data());
171 if (!surface) {
172 MOZ_CRASH("Failed to create fallback EGLSurface");
175 return surface;
178 static EGLSurface CreateSurfaceFromNativeWindow(
179 EglDisplay& egl, const EGLNativeWindowType window, const EGLConfig config) {
180 MOZ_ASSERT(window);
181 EGLSurface newSurface = EGL_NO_SURFACE;
183 #ifdef MOZ_WIDGET_ANDROID
184 JNIEnv* const env = jni::GetEnvForThread();
185 ANativeWindow* const nativeWindow =
186 ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
187 if (!nativeWindow) {
188 gfxCriticalNote << "Failed to obtain native window from Surface";
189 return EGL_NO_SURFACE;
191 const auto& display = egl.mLib->fGetDisplay(EGL_DEFAULT_DISPLAY);
192 newSurface = egl.mLib->fCreateWindowSurface(display, config, nativeWindow, 0);
193 ANativeWindow_release(nativeWindow);
194 #else
195 newSurface = egl.fCreateWindowSurface(config, window, 0);
196 #endif
197 if (!newSurface) {
198 const auto err = egl.mLib->fGetError();
199 gfxCriticalNote << "Failed to create EGLSurface!: " << gfx::hexa(err);
201 return newSurface;
204 /* GLContextEGLFactory class was added as a friend of GLContextEGL
205 * so that it could access GLContextEGL::CreateGLContext. This was
206 * done so that a new function would not need to be added to the shared
207 * GLContextProvider interface.
209 class GLContextEGLFactory {
210 public:
211 static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow,
212 bool aHardwareWebRender);
213 static already_AddRefed<GLContext> CreateImpl(EGLNativeWindowType aWindow,
214 bool aHardwareWebRender,
215 bool aUseGles);
217 private:
218 GLContextEGLFactory() = default;
219 ~GLContextEGLFactory() = default;
222 already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
223 EGLNativeWindowType aWindow, bool aHardwareWebRender, bool aUseGles) {
224 nsCString failureId;
225 const auto lib = GLLibraryEGL::Get(&failureId);
226 if (!lib) {
227 gfxCriticalNote << "Failed[3] to load EGL library: " << failureId.get();
228 return nullptr;
230 const auto egl = lib->CreateDisplay(true, &failureId);
231 if (!egl) {
232 gfxCriticalNote << "Failed[3] to create EGL library display: "
233 << failureId.get();
234 return nullptr;
237 bool doubleBuffered = true;
239 EGLConfig config;
240 if (aHardwareWebRender && egl->mLib->IsANGLE()) {
241 // Force enable alpha channel to make sure ANGLE use correct framebuffer
242 // formart
243 const int bpp = 32;
244 if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
245 gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!";
246 return nullptr;
248 } else if (kIsLinux) {
249 const int bpp = 32;
250 if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
251 gfxCriticalNote << "Failed to create EGLConfig for WebRender!";
252 return nullptr;
254 } else {
255 if (!CreateConfigScreen(*egl, &config,
256 /* aEnableDepthBuffer */ false, aUseGles)) {
257 gfxCriticalNote << "Failed to create EGLConfig!";
258 return nullptr;
262 EGLSurface surface = EGL_NO_SURFACE;
263 if (aWindow) {
264 surface = mozilla::gl::CreateSurfaceFromNativeWindow(*egl, aWindow, config);
265 if (!surface) {
266 return nullptr;
270 CreateContextFlags flags = CreateContextFlags::NONE;
271 if (aHardwareWebRender &&
272 StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
273 flags |= CreateContextFlags::PREFER_ROBUSTNESS;
275 if (aHardwareWebRender && aUseGles) {
276 flags |= CreateContextFlags::PREFER_ES3;
278 if (!aHardwareWebRender) {
279 flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
282 const auto desc = GLContextDesc{{flags}, false};
283 RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
284 egl, desc, config, surface, aUseGles, config, &failureId);
285 if (!gl) {
286 const auto err = egl->mLib->fGetError();
287 gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err);
288 GLContextEGL::DestroySurface(*egl, surface);
289 return nullptr;
292 gl->MakeCurrent();
293 gl->SetIsDoubleBuffered(doubleBuffered);
295 #ifdef MOZ_WIDGET_GTK
296 if (surface) {
297 const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
298 egl->fSwapInterval(interval);
300 #endif
301 if (aHardwareWebRender && egl->mLib->IsANGLE()) {
302 MOZ_ASSERT(doubleBuffered);
303 const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
304 egl->fSwapInterval(interval);
306 return gl.forget();
309 already_AddRefed<GLContext> GLContextEGLFactory::Create(
310 EGLNativeWindowType aWindow, bool aHardwareWebRender) {
311 bool preferGles;
312 #if defined(MOZ_WIDGET_ANDROID)
313 preferGles = true;
314 #else
315 preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup();
316 #endif // defined(MOZ_WIDGET_ANDROID)
318 RefPtr<GLContext> glContext =
319 CreateImpl(aWindow, aHardwareWebRender, preferGles);
320 #if !defined(MOZ_WIDGET_ANDROID)
321 if (!glContext) {
322 glContext = CreateImpl(aWindow, aHardwareWebRender, !preferGles);
324 #endif // !defined(MOZ_WIDGET_ANDROID)
325 return glContext.forget();
328 /* static */
329 EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
330 widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig) {
331 nsCString discardFailureId;
332 const auto egl = DefaultEglDisplay(&discardFailureId);
333 if (!egl) {
334 gfxCriticalNote << "Failed to load EGL library 6!";
335 return EGL_NO_SURFACE;
338 MOZ_ASSERT(aCompositorWidget);
339 #ifdef MOZ_WAYLAND
340 // RenderCompositorEGL does not like EGL_NO_SURFACE as it fallbacks
341 // to SW rendering or claims itself as paused.
342 // In case we're missing valid native window because aCompositorWidget hidden,
343 // just create a fallback EGLSurface.
344 // Actual EGLSurface will be created by widget code later when
345 // aCompositorWidget becomes visible.
346 if (widget::GdkIsWaylandDisplay() && aCompositorWidget->IsHidden()) {
347 mozilla::gfx::IntSize pbSize(16, 16);
348 return CreateWaylandOffscreenSurface(*egl, aConfig, pbSize);
350 #endif
351 EGLNativeWindowType window =
352 GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
353 if (!window) {
354 gfxCriticalNote << "window is null";
355 return EGL_NO_SURFACE;
358 return mozilla::gl::CreateSurfaceFromNativeWindow(*egl, window, aConfig);
361 GLContextEGL::GLContextEGL(const std::shared_ptr<EglDisplay> egl,
362 const GLContextDesc& desc, EGLConfig surfaceConfig,
363 EGLSurface surface, EGLContext context)
364 : GLContext(desc, nullptr, false),
365 mEgl(egl),
366 mSurfaceConfig(surfaceConfig),
367 mContext(context),
368 mSurface(surface),
369 mFallbackSurface(CreateFallbackSurface(*mEgl, mSurfaceConfig)) {
370 #ifdef DEBUG
371 printf_stderr("Initializing context %p surface %p on display %p\n", mContext,
372 mSurface, mEgl->mDisplay);
373 #endif
376 void GLContextEGL::OnMarkDestroyed() {
377 if (mSurfaceOverride != EGL_NO_SURFACE) {
378 SetEGLSurfaceOverride(EGL_NO_SURFACE);
382 GLContextEGL::~GLContextEGL() {
383 MarkDestroyed();
385 // Wrapped context should not destroy eglContext/Surface
386 if (!mOwnsContext) {
387 return;
390 #ifdef DEBUG
391 printf_stderr("Destroying context %p surface %p on display %p\n", mContext,
392 mSurface, mEgl->mDisplay);
393 #endif
395 mEgl->fDestroyContext(mContext);
397 DestroySurface(*mEgl, mSurface);
398 DestroySurface(*mEgl, mFallbackSurface);
401 bool GLContextEGL::Init() {
402 if (!GLContext::Init()) return false;
404 bool current = MakeCurrent();
405 if (!current) {
406 gfx::LogFailure("Couldn't get device attachments for device."_ns);
407 return false;
410 mShareWithEGLImage =
411 mEgl->HasKHRImageBase() &&
412 mEgl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) &&
413 IsExtensionSupported(OES_EGL_image);
415 return true;
418 bool GLContextEGL::BindTexImage() {
419 if (!mSurface) return false;
421 if (mBound && !ReleaseTexImage()) return false;
423 EGLBoolean success =
424 mEgl->fBindTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
425 if (success == LOCAL_EGL_FALSE) return false;
427 mBound = true;
428 return true;
431 bool GLContextEGL::ReleaseTexImage() {
432 if (!mBound) return true;
434 if (!mSurface) return false;
436 EGLBoolean success;
437 success = mEgl->fReleaseTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
438 if (success == LOCAL_EGL_FALSE) return false;
440 mBound = false;
441 return true;
444 void GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
445 mSurfaceOverride = surf;
446 DebugOnly<bool> ok = MakeCurrent(true);
447 MOZ_ASSERT(ok);
450 bool GLContextEGL::MakeCurrentImpl() const {
451 EGLSurface surface =
452 (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride : mSurface;
453 if (!surface) {
454 surface = mFallbackSurface;
457 const bool succeeded = mEgl->fMakeCurrent(surface, surface, mContext);
458 if (!succeeded) {
459 const auto eglError = mEgl->mLib->fGetError();
460 if (eglError == LOCAL_EGL_CONTEXT_LOST) {
461 OnContextLostError();
462 } else {
463 NS_WARNING("Failed to make GL context current!");
464 #ifdef DEBUG
465 printf_stderr("EGL Error: 0x%04x\n", eglError);
466 #endif
470 return succeeded;
473 bool GLContextEGL::IsCurrentImpl() const {
474 return mEgl->mLib->fGetCurrentContext() == mContext;
477 bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
478 if (!mOwnsContext) {
479 return false;
481 // unconditionally release the surface and create a new one. Don't try to
482 // optimize this away. If we get here, then by definition we know that we want
483 // to get a new surface.
484 ReleaseSurface();
485 MOZ_ASSERT(aWidget);
487 EGLNativeWindowType nativeWindow =
488 GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
489 #ifdef MOZ_WAYLAND
490 // In case we're missing native window on Wayland CompositorWidget is hidden.
491 // Don't create a fallback EGL surface but fails here.
492 // We need to repeat RenewSurface() when native window is available
493 // (CompositorWidget becomes visible).
494 if (GdkIsWaylandDisplay()) {
495 NS_WARNING("Failed to get native window");
496 return false;
498 #endif
499 if (nativeWindow) {
500 mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(*mEgl, nativeWindow,
501 mSurfaceConfig);
502 if (!mSurface) {
503 NS_WARNING("Failed to create EGLSurface from native window");
504 return false;
507 const bool ok = MakeCurrent(true);
508 MOZ_ASSERT(ok);
509 #ifdef MOZ_WIDGET_GTK
510 if (mSurface) {
511 const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
512 mEgl->fSwapInterval(interval);
514 #endif
515 return ok;
518 void GLContextEGL::ReleaseSurface() {
519 if (mOwnsContext) {
520 DestroySurface(*mEgl, mSurface);
522 if (mSurface == mSurfaceOverride) {
523 mSurfaceOverride = EGL_NO_SURFACE;
525 mSurface = EGL_NO_SURFACE;
528 Maybe<SymbolLoader> GLContextEGL::GetSymbolLoader() const {
529 return mEgl->mLib->GetSymbolLoader();
532 bool GLContextEGL::SwapBuffers() {
533 EGLSurface surface =
534 mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
535 if (surface) {
536 if ((mEgl->IsExtensionSupported(
537 EGLExtension::EXT_swap_buffers_with_damage) ||
538 mEgl->IsExtensionSupported(
539 EGLExtension::KHR_swap_buffers_with_damage))) {
540 std::vector<EGLint> rects;
541 for (auto iter = mDamageRegion.RectIter(); !iter.Done(); iter.Next()) {
542 const IntRect& r = iter.Get();
543 rects.push_back(r.X());
544 rects.push_back(r.Y());
545 rects.push_back(r.Width());
546 rects.push_back(r.Height());
548 mDamageRegion.SetEmpty();
549 return mEgl->fSwapBuffersWithDamage(surface, rects.data(),
550 rects.size() / 4);
552 return mEgl->fSwapBuffers(surface);
553 } else {
554 return false;
558 void GLContextEGL::SetDamage(const nsIntRegion& aDamageRegion) {
559 mDamageRegion = aDamageRegion;
562 void GLContextEGL::GetWSIInfo(nsCString* const out) const {
563 out->AppendLiteral("EGL_VENDOR: ");
564 out->Append(
565 (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VENDOR));
567 out->AppendLiteral("\nEGL_VERSION: ");
568 out->Append(
569 (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VERSION));
571 out->AppendLiteral("\nEGL_EXTENSIONS: ");
572 out->Append((const char*)mEgl->mLib->fQueryString(mEgl->mDisplay,
573 LOCAL_EGL_EXTENSIONS));
575 #ifndef ANDROID // This query will crash some old android.
576 out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
577 out->Append(
578 (const char*)mEgl->mLib->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
579 #endif
582 bool GLContextEGL::HasExtBufferAge() const {
583 return mEgl->IsExtensionSupported(EGLExtension::EXT_buffer_age);
586 bool GLContextEGL::HasKhrPartialUpdate() const {
587 return mEgl->IsExtensionSupported(EGLExtension::KHR_partial_update);
590 GLint GLContextEGL::GetBufferAge() const {
591 EGLSurface surface =
592 mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
594 if (surface && (HasExtBufferAge() || HasKhrPartialUpdate())) {
595 EGLint result;
596 mEgl->fQuerySurface(surface, LOCAL_EGL_BUFFER_AGE_EXT, &result);
597 return result;
600 return 0;
603 #define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
605 RefPtr<GLContextEGL> GLContextEGL::CreateGLContext(
606 const std::shared_ptr<EglDisplay> egl, const GLContextDesc& desc,
607 EGLConfig surfaceConfig, EGLSurface surface, const bool useGles,
608 EGLConfig contextConfig, nsACString* const out_failureId) {
609 const auto& flags = desc.flags;
611 std::vector<EGLint> required_attribs;
613 if (useGles) {
614 // TODO: This fBindAPI could be more thread-safe
615 if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
616 *out_failureId = "FEATURE_FAILURE_EGL_ES"_ns;
617 NS_WARNING("Failed to bind API to GLES!");
618 return nullptr;
620 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
621 if (flags & CreateContextFlags::PREFER_ES3) {
622 required_attribs.push_back(3);
623 } else {
624 required_attribs.push_back(2);
626 } else {
627 if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_API) == LOCAL_EGL_FALSE) {
628 *out_failureId = "FEATURE_FAILURE_EGL"_ns;
629 NS_WARNING("Failed to bind API to GL!");
630 return nullptr;
632 if (flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE) {
633 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
634 required_attribs.push_back(
635 LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
636 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
637 required_attribs.push_back(2);
638 } else {
639 // !REQUIRE_COMPAT_PROFILE means core profle.
640 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
641 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
642 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
643 required_attribs.push_back(3);
644 required_attribs.push_back(LOCAL_EGL_CONTEXT_MINOR_VERSION);
645 required_attribs.push_back(2);
649 if ((flags & CreateContextFlags::PREFER_EXACT_VERSION) &&
650 egl->mLib->IsANGLE()) {
651 required_attribs.push_back(
652 LOCAL_EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
653 required_attribs.push_back(LOCAL_EGL_FALSE);
656 const auto debugFlags = GLContext::ChooseDebugFlags(flags);
657 if (!debugFlags && flags & CreateContextFlags::NO_VALIDATION &&
658 egl->IsExtensionSupported(EGLExtension::KHR_create_context_no_error)) {
659 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
660 required_attribs.push_back(LOCAL_EGL_TRUE);
663 if (flags & CreateContextFlags::PROVOKING_VERTEX_DONT_CARE &&
664 egl->IsExtensionSupported(
665 EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
666 required_attribs.push_back(
667 LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ);
668 required_attribs.push_back(LOCAL_EGL_TRUE);
671 std::vector<EGLint> ext_robustness_attribs;
672 std::vector<EGLint> ext_rbab_attribs; // RBAB: Robust Buffer Access Behavior
673 std::vector<EGLint> khr_robustness_attribs;
674 std::vector<EGLint> khr_rbab_attribs; // RBAB: Robust Buffer Access Behavior
675 if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
676 std::vector<EGLint> base_robustness_attribs = required_attribs;
677 if (egl->IsExtensionSupported(
678 EGLExtension::NV_robustness_video_memory_purge)) {
679 base_robustness_attribs.push_back(
680 LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
681 base_robustness_attribs.push_back(LOCAL_EGL_TRUE);
684 if (egl->IsExtensionSupported(
685 EGLExtension::EXT_create_context_robustness)) {
686 ext_robustness_attribs = base_robustness_attribs;
687 ext_robustness_attribs.push_back(
688 LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
689 ext_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
691 if (gfxVars::AllowEglRbab()) {
692 ext_rbab_attribs = ext_robustness_attribs;
693 ext_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
694 ext_rbab_attribs.push_back(LOCAL_EGL_TRUE);
698 if (egl->IsExtensionSupported(EGLExtension::KHR_create_context)) {
699 khr_robustness_attribs = base_robustness_attribs;
700 khr_robustness_attribs.push_back(
701 LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
702 khr_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
704 khr_rbab_attribs = khr_robustness_attribs;
705 khr_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
706 khr_rbab_attribs.push_back(
707 LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
711 const auto fnCreate = [&](const std::vector<EGLint>& attribs) {
712 auto terminated_attribs = attribs;
714 for (const auto& cur : kTerminationAttribs) {
715 terminated_attribs.push_back(cur);
718 return egl->fCreateContext(contextConfig, EGL_NO_CONTEXT,
719 terminated_attribs.data());
722 EGLContext context;
723 do {
724 if (!khr_rbab_attribs.empty()) {
725 context = fnCreate(khr_rbab_attribs);
726 if (context) break;
727 NS_WARNING("Failed to create EGLContext with khr_rbab_attribs");
730 if (!ext_rbab_attribs.empty()) {
731 context = fnCreate(ext_rbab_attribs);
732 if (context) break;
733 NS_WARNING("Failed to create EGLContext with ext_rbab_attribs");
736 if (!khr_robustness_attribs.empty()) {
737 context = fnCreate(khr_robustness_attribs);
738 if (context) break;
739 NS_WARNING("Failed to create EGLContext with khr_robustness_attribs");
742 if (!ext_robustness_attribs.empty()) {
743 context = fnCreate(ext_robustness_attribs);
744 if (context) break;
745 NS_WARNING("Failed to create EGLContext with ext_robustness_attribs");
748 context = fnCreate(required_attribs);
749 if (context) break;
750 NS_WARNING("Failed to create EGLContext with required_attribs");
752 *out_failureId = "FEATURE_FAILURE_EGL_CREATE"_ns;
753 return nullptr;
754 } while (false);
755 MOZ_ASSERT(context);
757 RefPtr<GLContextEGL> glContext =
758 new GLContextEGL(egl, desc, surfaceConfig, surface, context);
759 if (!glContext->Init()) {
760 *out_failureId = "FEATURE_FAILURE_EGL_INIT"_ns;
761 return nullptr;
764 if (GLContext::ShouldSpew()) {
765 printf_stderr("new GLContextEGL %p on EGLDisplay %p\n", glContext.get(),
766 egl->mDisplay);
769 return glContext;
772 // static
773 EGLSurface GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
774 EglDisplay& egl, EGLConfig config, EGLenum bindToTextureFormat,
775 mozilla::gfx::IntSize& pbsize) {
776 nsTArray<EGLint> pbattrs(16);
777 EGLSurface surface = nullptr;
779 TRY_AGAIN_POWER_OF_TWO:
780 pbattrs.Clear();
781 pbattrs.AppendElement(LOCAL_EGL_WIDTH);
782 pbattrs.AppendElement(pbsize.width);
783 pbattrs.AppendElement(LOCAL_EGL_HEIGHT);
784 pbattrs.AppendElement(pbsize.height);
786 if (bindToTextureFormat != LOCAL_EGL_NONE) {
787 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
788 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
790 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
791 pbattrs.AppendElement(bindToTextureFormat);
794 for (const auto& cur : kTerminationAttribs) {
795 pbattrs.AppendElement(cur);
798 surface = egl.fCreatePbufferSurface(config, &pbattrs[0]);
799 if (!surface) {
800 if (!is_power_of_two(pbsize.width) || !is_power_of_two(pbsize.height)) {
801 if (!is_power_of_two(pbsize.width))
802 pbsize.width = next_power_of_two(pbsize.width);
803 if (!is_power_of_two(pbsize.height))
804 pbsize.height = next_power_of_two(pbsize.height);
806 NS_WARNING("Failed to create pbuffer, trying power of two dims");
807 goto TRY_AGAIN_POWER_OF_TWO;
810 NS_WARNING("Failed to create pbuffer surface");
811 return nullptr;
814 return surface;
817 #if defined(MOZ_WAYLAND)
818 WaylandOffscreenGLSurface::WaylandOffscreenGLSurface(
819 struct wl_surface* aWaylandSurface, struct wl_egl_window* aEGLWindow)
820 : mWaylandSurface(aWaylandSurface), mEGLWindow(aEGLWindow) {}
822 WaylandOffscreenGLSurface::~WaylandOffscreenGLSurface() {
823 if (mEGLWindow) {
824 wl_egl_window_destroy(mEGLWindow);
826 if (mWaylandSurface) {
827 wl_surface_destroy(mWaylandSurface);
831 // static
832 EGLSurface GLContextEGL::CreateWaylandOffscreenSurface(
833 EglDisplay& egl, EGLConfig config, mozilla::gfx::IntSize& pbsize) {
834 wl_egl_window* eglwindow = nullptr;
836 struct wl_compositor* compositor =
837 gdk_wayland_display_get_wl_compositor(gdk_display_get_default());
838 struct wl_surface* wlsurface = wl_compositor_create_surface(compositor);
839 eglwindow = wl_egl_window_create(wlsurface, pbsize.width, pbsize.height);
840 if (!eglwindow) return nullptr;
842 const auto surface = egl.fCreateWindowSurface(
843 config, reinterpret_cast<EGLNativeWindowType>(eglwindow), 0);
844 if (surface) {
845 MOZ_DIAGNOSTIC_ASSERT(!sWaylandOffscreenGLSurfaces.Contains(surface));
846 sWaylandOffscreenGLSurfaces.LookupOrInsert(
847 surface, new WaylandOffscreenGLSurface(wlsurface, eglwindow));
849 return surface;
851 #endif
853 static const EGLint kEGLConfigAttribsRGB16[] = {
854 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
855 LOCAL_EGL_RED_SIZE, 5,
856 LOCAL_EGL_GREEN_SIZE, 6,
857 LOCAL_EGL_BLUE_SIZE, 5,
858 LOCAL_EGL_ALPHA_SIZE, 0};
860 static const EGLint kEGLConfigAttribsRGB24[] = {
861 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
862 LOCAL_EGL_RED_SIZE, 8,
863 LOCAL_EGL_GREEN_SIZE, 8,
864 LOCAL_EGL_BLUE_SIZE, 8,
865 LOCAL_EGL_ALPHA_SIZE, 0};
867 static const EGLint kEGLConfigAttribsRGBA32[] = {
868 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
869 LOCAL_EGL_RED_SIZE, 8,
870 LOCAL_EGL_GREEN_SIZE, 8,
871 LOCAL_EGL_BLUE_SIZE, 8,
872 LOCAL_EGL_ALPHA_SIZE, 8};
874 bool CreateConfig(EglDisplay& aEgl, EGLConfig* aConfig, int32_t aDepth,
875 bool aEnableDepthBuffer, bool aUseGles, bool aAllowFallback) {
876 EGLConfig configs[64];
877 std::vector<EGLint> attribs;
878 EGLint ncfg = ArrayLength(configs);
880 switch (aDepth) {
881 case 16:
882 for (const auto& cur : kEGLConfigAttribsRGB16) {
883 attribs.push_back(cur);
885 break;
886 case 24:
887 for (const auto& cur : kEGLConfigAttribsRGB24) {
888 attribs.push_back(cur);
890 break;
891 case 32:
892 for (const auto& cur : kEGLConfigAttribsRGBA32) {
893 attribs.push_back(cur);
895 break;
896 default:
897 NS_ERROR("Unknown pixel depth");
898 return false;
901 if (aUseGles) {
902 attribs.push_back(LOCAL_EGL_RENDERABLE_TYPE);
903 attribs.push_back(LOCAL_EGL_OPENGL_ES2_BIT);
905 for (const auto& cur : kTerminationAttribs) {
906 attribs.push_back(cur);
909 if (!aEgl.fChooseConfig(attribs.data(), configs, ncfg, &ncfg) || ncfg < 1) {
910 return false;
913 Maybe<EGLConfig> fallbackConfig;
915 for (int j = 0; j < ncfg; ++j) {
916 EGLConfig config = configs[j];
917 EGLint r, g, b, a;
918 if (aEgl.fGetConfigAttrib(config, LOCAL_EGL_RED_SIZE, &r) &&
919 aEgl.fGetConfigAttrib(config, LOCAL_EGL_GREEN_SIZE, &g) &&
920 aEgl.fGetConfigAttrib(config, LOCAL_EGL_BLUE_SIZE, &b) &&
921 aEgl.fGetConfigAttrib(config, LOCAL_EGL_ALPHA_SIZE, &a) &&
922 ((aDepth == 16 && r == 5 && g == 6 && b == 5) ||
923 (aDepth == 24 && r == 8 && g == 8 && b == 8) ||
924 (aDepth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) {
925 EGLint z;
926 if (aEnableDepthBuffer) {
927 if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_DEPTH_SIZE, &z) ||
928 z != 24) {
929 continue;
932 #ifdef MOZ_X11
933 if (GdkIsX11Display()) {
934 int configVisualID;
935 if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID,
936 &configVisualID)) {
937 continue;
940 XVisualInfo visual_info_template, *visual_info;
941 int num_visuals;
943 visual_info_template.visualid = configVisualID;
944 visual_info =
945 XGetVisualInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
946 VisualIDMask, &visual_info_template, &num_visuals);
948 if (!visual_info || visual_info->depth != aDepth) {
949 if (aAllowFallback && !fallbackConfig) {
950 fallbackConfig = Some(config);
952 continue;
955 #endif
956 *aConfig = config;
957 return true;
961 if (kIsLinux && fallbackConfig) {
962 *aConfig = fallbackConfig.value();
963 return true;
966 return false;
969 // Return true if a suitable EGLConfig was found and pass it out
970 // through aConfig. Return false otherwise.
972 // NB: It's entirely legal for the returned EGLConfig to be valid yet
973 // have the value null.
974 static bool CreateConfigScreen(EglDisplay& egl, EGLConfig* const aConfig,
975 const bool aEnableDepthBuffer,
976 const bool aUseGles) {
977 int32_t depth = gfxVars::ScreenDepth();
978 if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles)) {
979 return true;
981 #ifdef MOZ_WIDGET_ANDROID
982 // Bug 736005
983 // Android doesn't always support 16 bit so also try 24 bit
984 if (depth == 16) {
985 return CreateConfig(egl, aConfig, 24, aEnableDepthBuffer, aUseGles);
987 // Bug 970096
988 // Some devices that have 24 bit screens only support 16 bit OpenGL?
989 if (depth == 24) {
990 return CreateConfig(egl, aConfig, 16, aEnableDepthBuffer, aUseGles);
992 #endif
993 return false;
996 already_AddRefed<GLContext> GLContextProviderEGL::CreateForCompositorWidget(
997 CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
998 bool /*aForceAccelerated*/) {
999 EGLNativeWindowType window = nullptr;
1000 if (aCompositorWidget) {
1001 window = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
1003 return GLContextEGLFactory::Create(window, aHardwareWebRender);
1006 EGLSurface GLContextEGL::CreateCompatibleSurface(void* aWindow) const {
1007 MOZ_ASSERT(aWindow);
1008 MOZ_RELEASE_ASSERT(mSurfaceConfig != EGL_NO_CONFIG);
1010 // NOTE: aWindow is an ANativeWindow
1011 EGLSurface surface = mEgl->fCreateWindowSurface(
1012 mSurfaceConfig, reinterpret_cast<EGLNativeWindowType>(aWindow), nullptr);
1013 if (!surface) {
1014 gfxCriticalError() << "CreateCompatibleSurface failed: "
1015 << hexa(GetError());
1017 return surface;
1020 static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
1021 out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
1022 #ifdef MOZ_WAYLAND
1023 if (GdkIsWaylandDisplay()) {
1024 // Wayland on desktop does not support PBuffer or FBO.
1025 // We create a dummy wl_egl_window instead.
1026 out->AppendElement(LOCAL_EGL_WINDOW_BIT);
1027 } else
1028 #endif
1030 out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
1033 if (useGles) {
1034 out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE);
1035 if (es3) {
1036 out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR);
1037 } else {
1038 out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
1042 out->AppendElement(LOCAL_EGL_RED_SIZE);
1043 out->AppendElement(8);
1045 out->AppendElement(LOCAL_EGL_GREEN_SIZE);
1046 out->AppendElement(8);
1048 out->AppendElement(LOCAL_EGL_BLUE_SIZE);
1049 out->AppendElement(8);
1051 out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
1052 out->AppendElement(8);
1054 out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
1055 out->AppendElement(0);
1057 out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
1058 out->AppendElement(0);
1060 // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
1061 out->AppendElement(LOCAL_EGL_NONE);
1062 out->AppendElement(0);
1064 out->AppendElement(0);
1065 out->AppendElement(0);
1069 /// Useful for debugging, but normally unused.
1070 static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) {
1071 EGLint bits = 0;
1072 egl->fGetConfigAttrib(config, attrib, &bits);
1073 MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
1075 return bits;
1079 static EGLConfig ChooseConfig(EglDisplay& egl, const GLContextCreateDesc& desc,
1080 const bool useGles) {
1081 nsTArray<EGLint> configAttribList;
1082 FillContextAttribs(bool(desc.flags & CreateContextFlags::PREFER_ES3), useGles,
1083 &configAttribList);
1085 const EGLint* configAttribs = configAttribList.Elements();
1087 // The sorting dictated by the spec for eglChooseConfig reasonably assures
1088 // that a reasonable 'best' config is on top.
1089 const EGLint kMaxConfigs = 1;
1090 EGLConfig configs[kMaxConfigs];
1091 EGLint foundConfigs = 0;
1092 if (!egl.fChooseConfig(configAttribs, configs, kMaxConfigs, &foundConfigs) ||
1093 foundConfigs == 0) {
1094 return EGL_NO_CONFIG;
1097 EGLConfig config = configs[0];
1098 return config;
1101 #ifdef MOZ_X11
1102 /* static */
1103 bool GLContextEGL::FindVisual(int* const out_visualId) {
1104 nsCString discardFailureId;
1105 const auto egl = DefaultEglDisplay(&discardFailureId);
1106 if (!egl) {
1107 gfxCriticalNote
1108 << "GLContextEGL::FindVisual(): Failed to load EGL library!";
1109 return false;
1112 EGLConfig config;
1113 const int bpp = 32;
1114 if (!CreateConfig(*egl, &config, bpp, /* aEnableDepthBuffer */ false,
1115 /* aUseGles */ false, /* aAllowFallback */ false)) {
1116 // We are on a buggy driver. Do not return a visual so a fallback path can
1117 // be used. See https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
1118 return false;
1120 if (egl->fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, out_visualId)) {
1121 return true;
1123 return false;
1125 #endif
1127 /*static*/
1128 RefPtr<GLContextEGL> GLContextEGL::CreateWithoutSurface(
1129 const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc,
1130 nsACString* const out_failureId) {
1131 const auto WithUseGles = [&](const bool useGles) -> RefPtr<GLContextEGL> {
1132 #ifdef MOZ_WIDGET_GTK
1133 // First try creating a context with no config and no surface, this is what
1134 // we really want, and seems to be the only way to make selecting software
1135 // Mesa init properly when it's not the first device.
1136 if (egl->IsExtensionSupported(EGLExtension::KHR_no_config_context) &&
1137 egl->IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
1138 // These extensions have been supported by mesa and nvidia drivers
1139 // since 2014 or earlier, this is the preferred code path
1140 auto fullDesc = GLContextDesc{desc};
1141 fullDesc.isOffscreen = true;
1142 RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
1143 egl, fullDesc, EGL_NO_CONFIG, EGL_NO_SURFACE, useGles, EGL_NO_CONFIG,
1144 out_failureId);
1145 if (gl) {
1146 return gl;
1148 NS_WARNING(
1149 "Failed to create GLContext with no config and no surface, will try "
1150 "ChooseConfig");
1152 #endif
1154 const EGLConfig surfaceConfig = ChooseConfig(*egl, desc, useGles);
1155 if (surfaceConfig == EGL_NO_CONFIG) {
1156 *out_failureId = "FEATURE_FAILURE_EGL_NO_CONFIG"_ns;
1157 NS_WARNING("Failed to find a compatible config.");
1158 return nullptr;
1161 if (GLContext::ShouldSpew()) {
1162 egl->DumpEGLConfig(surfaceConfig);
1164 const EGLConfig contextConfig =
1165 egl->IsExtensionSupported(EGLExtension::KHR_no_config_context)
1166 ? nullptr
1167 : surfaceConfig;
1169 auto dummySize = mozilla::gfx::IntSize{16, 16};
1170 EGLSurface surface = nullptr;
1171 #ifdef MOZ_WAYLAND
1172 if (GdkIsWaylandDisplay()) {
1173 surface = GLContextEGL::CreateWaylandOffscreenSurface(*egl, surfaceConfig,
1174 dummySize);
1175 } else
1176 #endif
1178 surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
1179 *egl, surfaceConfig, LOCAL_EGL_NONE, dummySize);
1181 if (!surface) {
1182 *out_failureId = "FEATURE_FAILURE_EGL_POT"_ns;
1183 NS_WARNING("Failed to create PBuffer for context!");
1184 return nullptr;
1187 auto fullDesc = GLContextDesc{desc};
1188 fullDesc.isOffscreen = true;
1189 RefPtr<GLContextEGL> gl =
1190 GLContextEGL::CreateGLContext(egl, fullDesc, surfaceConfig, surface,
1191 useGles, contextConfig, out_failureId);
1192 if (!gl) {
1193 NS_WARNING("Failed to create GLContext from PBuffer");
1194 egl->fDestroySurface(surface);
1195 #if defined(MOZ_WAYLAND)
1196 DeleteWaylandOffscreenGLSurface(surface);
1197 #endif
1198 return nullptr;
1201 return gl;
1204 bool preferGles;
1205 #if defined(MOZ_WIDGET_ANDROID)
1206 preferGles = true;
1207 #else
1208 preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup();
1209 #endif // defined(MOZ_WIDGET_ANDROID)
1210 RefPtr<GLContextEGL> gl = WithUseGles(preferGles);
1211 #if !defined(MOZ_WIDGET_ANDROID)
1212 if (!gl) {
1213 gl = WithUseGles(!preferGles);
1215 #endif // !defined(MOZ_WIDGET_ANDROID)
1216 return gl;
1219 /*static*/
1220 void GLContextEGL::DestroySurface(EglDisplay& aEgl, const EGLSurface aSurface) {
1221 if (aSurface != EGL_NO_SURFACE) {
1222 if (!aEgl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
1223 const EGLint err = aEgl.mLib->fGetError();
1224 gfxCriticalNote << "Error in eglMakeCurrent: " << gfx::hexa(err);
1226 if (!aEgl.fDestroySurface(aSurface)) {
1227 const EGLint err = aEgl.mLib->fGetError();
1228 gfxCriticalNote << "Error in eglDestroySurface: " << gfx::hexa(err);
1230 #if defined(MOZ_WAYLAND)
1231 DeleteWaylandOffscreenGLSurface(aSurface);
1232 #endif
1236 /*static*/
1237 already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless(
1238 const GLContextCreateDesc& desc, nsACString* const out_failureId) {
1239 const auto display = DefaultEglDisplay(out_failureId);
1240 if (!display) {
1241 return nullptr;
1243 auto ret = GLContextEGL::CreateWithoutSurface(display, desc, out_failureId);
1244 return ret.forget();
1247 // Don't want a global context on Android as 1) share groups across 2 threads
1248 // fail on many Tegra drivers (bug 759225) and 2) some mobile devices have a
1249 // very strict limit on global number of GL contexts (bug 754257) and 3) each
1250 // EGL context eats 750k on B2G (bug 813783)
1251 /*static*/
1252 GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; }
1254 // -
1256 /*static*/ void GLContextProviderEGL::Shutdown() { GLLibraryEGL::Shutdown(); }
1258 } /* namespace gl */
1259 } /* namespace mozilla */
1261 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS