Bug 1703443 - pt 6. Move RunNextCollectorTimer() into CCGCScheduler r=smaug
[gecko.git] / gfx / gl / GLContextProviderEGL.cpp
blob33e63b1bc453f18f89ffd18637396bf10fcc4bf6
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 "gfxASurface.h"
55 #include "gfxCrashReporterUtils.h"
56 #include "gfxFailure.h"
57 #include "gfxPlatform.h"
58 #include "gfxUtils.h"
59 #include "GLBlitHelper.h"
60 #include "GLContextEGL.h"
61 #include "GLContextProvider.h"
62 #include "GLLibraryEGL.h"
63 #include "GLLibraryLoader.h"
64 #include "mozilla/ArrayUtils.h"
65 #include "mozilla/Preferences.h"
66 #include "mozilla/Services.h"
67 #include "mozilla/StaticPrefs_gfx.h"
68 #include "mozilla/gfx/gfxVars.h"
69 #include "mozilla/gfx/BuildConstants.h"
70 #include "mozilla/gfx/Logging.h"
71 #include "mozilla/layers/CompositorOptions.h"
72 #include "mozilla/widget/CompositorWidget.h"
73 #include "nsDebug.h"
74 #include "nsIWidget.h"
75 #include "nsThreadUtils.h"
76 #include "ScopedGLHelpers.h"
78 #if defined(MOZ_WIDGET_GTK)
79 # include "mozilla/widget/GtkCompositorWidget.h"
80 # include "mozilla/WidgetUtilsGtk.h"
81 # if defined(MOZ_WAYLAND)
82 # include <gdk/gdkwayland.h>
83 # include <wayland-egl.h>
84 # define MOZ_GTK_WAYLAND 1
85 # endif
86 #endif
88 struct wl_egl_window;
90 using namespace mozilla::gfx;
92 namespace mozilla {
93 namespace gl {
95 using namespace mozilla::widget;
97 #if defined(MOZ_WAYLAND)
98 class WaylandGLSurface {
99 public:
100 WaylandGLSurface(struct wl_surface* aWaylandSurface,
101 struct wl_egl_window* aEGLWindow);
102 ~WaylandGLSurface();
104 private:
105 struct wl_surface* mWaylandSurface;
106 struct wl_egl_window* mEGLWindow;
109 static nsTHashMap<nsPtrHashKey<void>, WaylandGLSurface*> sWaylandGLSurface;
111 void DeleteWaylandGLSurface(EGLSurface surface) {
112 # ifdef MOZ_GTK_WAYLAND
113 // We're running on Wayland which means our EGLSurface may
114 // have attached Wayland backend data which must be released.
115 if (GdkIsWaylandDisplay()) {
116 auto entry = sWaylandGLSurface.Lookup(surface);
117 if (entry) {
118 delete entry.Data();
119 entry.Remove();
122 # endif
124 #endif
126 static bool CreateConfigScreen(EglDisplay&, EGLConfig* const aConfig,
127 const bool aEnableDepthBuffer,
128 const bool aUseGles, int aVisual = 0);
130 // append three zeros at the end of attribs list to work around
131 // EGL implementation bugs that iterate until they find 0, instead of
132 // EGL_NONE. See bug 948406.
133 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
134 LOCAL_EGL_NONE, 0, 0, 0
136 static EGLint kTerminationAttribs[] = {
137 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS};
139 static int next_power_of_two(int v) {
140 v--;
141 v |= v >> 1;
142 v |= v >> 2;
143 v |= v >> 4;
144 v |= v >> 8;
145 v |= v >> 16;
146 v++;
148 return v;
151 static bool is_power_of_two(int v) {
152 NS_ASSERTION(v >= 0, "bad value");
154 if (v == 0) return true;
156 return (v & (v - 1)) == 0;
159 static void DestroySurface(EglDisplay& egl, const EGLSurface oldSurface) {
160 if (oldSurface != EGL_NO_SURFACE) {
161 // TODO: This breaks TLS MakeCurrent caching.
162 egl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
163 egl.fDestroySurface(oldSurface);
164 #if defined(MOZ_WAYLAND)
165 DeleteWaylandGLSurface(oldSurface);
166 #endif
170 static EGLSurface CreateFallbackSurface(EglDisplay& egl,
171 const EGLConfig& config) {
172 if (egl.IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
173 // We don't need a PBuffer surface in this case
174 return EGL_NO_SURFACE;
177 std::vector<EGLint> pbattrs;
178 pbattrs.push_back(LOCAL_EGL_WIDTH);
179 pbattrs.push_back(1);
180 pbattrs.push_back(LOCAL_EGL_HEIGHT);
181 pbattrs.push_back(1);
183 for (const auto& cur : kTerminationAttribs) {
184 pbattrs.push_back(cur);
187 EGLSurface surface = egl.fCreatePbufferSurface(config, pbattrs.data());
188 if (!surface) {
189 MOZ_CRASH("Failed to create fallback EGLSurface");
192 return surface;
195 static EGLSurface CreateSurfaceFromNativeWindow(
196 EglDisplay& egl, const EGLNativeWindowType window, const EGLConfig config) {
197 MOZ_ASSERT(window);
198 EGLSurface newSurface = EGL_NO_SURFACE;
200 #ifdef MOZ_WIDGET_ANDROID
201 JNIEnv* const env = jni::GetEnvForThread();
202 ANativeWindow* const nativeWindow =
203 ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
204 if (!nativeWindow) {
205 return EGL_NO_SURFACE;
207 const auto& display = egl.mLib->fGetDisplay(EGL_DEFAULT_DISPLAY);
208 newSurface = egl.mLib->fCreateWindowSurface(display, config, nativeWindow, 0);
209 ANativeWindow_release(nativeWindow);
210 #else
211 newSurface = egl.fCreateWindowSurface(config, window, 0);
212 if (!newSurface) {
213 const auto err = egl.mLib->fGetError();
214 gfxCriticalNote << "Failed to create EGLSurface!: " << gfx::hexa(err);
216 #endif
217 return newSurface;
220 /* GLContextEGLFactory class was added as a friend of GLContextEGL
221 * so that it could access GLContextEGL::CreateGLContext. This was
222 * done so that a new function would not need to be added to the shared
223 * GLContextProvider interface.
225 class GLContextEGLFactory {
226 public:
227 static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow,
228 bool aHardwareWebRender);
229 static already_AddRefed<GLContext> CreateImpl(EGLNativeWindowType aWindow,
230 bool aHardwareWebRender,
231 bool aUseGles);
233 private:
234 GLContextEGLFactory() = default;
235 ~GLContextEGLFactory() = default;
238 already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
239 EGLNativeWindowType aWindow, bool aHardwareWebRender, bool aUseGles) {
240 nsCString failureId;
241 const auto lib = gl::DefaultEglLibrary(&failureId);
242 if (!lib) {
243 gfxCriticalNote << "Failed[3] to load EGL library: " << failureId.get();
244 return nullptr;
246 const auto egl = lib->CreateDisplay(true, &failureId);
247 if (!egl) {
248 gfxCriticalNote << "Failed[3] to create EGL library display: "
249 << failureId.get();
250 return nullptr;
253 int visualID = 0;
254 #ifdef MOZ_X11
255 GdkDisplay* gdkDisplay = gdk_display_get_default();
256 if (GdkIsX11Display(gdkDisplay) && aWindow) {
257 auto* display = GDK_DISPLAY_XDISPLAY(gdkDisplay);
258 if (display) {
259 XWindowAttributes windowAttrs;
260 if (!XGetWindowAttributes(display, (Window)aWindow, &windowAttrs)) {
261 NS_WARNING("[EGL] XGetWindowAttributes() failed");
262 return nullptr;
264 visualID = XVisualIDFromVisual(windowAttrs.visual);
267 #endif
269 bool doubleBuffered = true;
271 EGLConfig config;
272 if (aHardwareWebRender && egl->mLib->IsANGLE()) {
273 // Force enable alpha channel to make sure ANGLE use correct framebuffer
274 // formart
275 const int bpp = 32;
276 if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
277 gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!";
278 return nullptr;
280 } else if (aHardwareWebRender && (kIsWayland || kIsX11)) {
281 const int bpp = 32;
282 const bool enableDepthBuffer = gfx::gfxVars::UseWebRenderCompositor();
283 if (!CreateConfig(*egl, &config, bpp, enableDepthBuffer, aUseGles,
284 visualID)) {
285 gfxCriticalNote << "Failed to create EGLConfig for WebRender!";
286 return nullptr;
288 } else {
289 if (!CreateConfigScreen(*egl, &config,
290 /* aEnableDepthBuffer */ false, aUseGles,
291 visualID)) {
292 gfxCriticalNote << "Failed to create EGLConfig!";
293 return nullptr;
297 EGLSurface surface = EGL_NO_SURFACE;
298 if (aWindow) {
299 surface = mozilla::gl::CreateSurfaceFromNativeWindow(*egl, aWindow, config);
300 if (!surface) {
301 return nullptr;
305 CreateContextFlags flags = CreateContextFlags::NONE;
306 if (aHardwareWebRender &&
307 StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
308 flags |= CreateContextFlags::PREFER_ROBUSTNESS;
310 if (aHardwareWebRender && aUseGles) {
311 flags |= CreateContextFlags::PREFER_ES3;
313 if (!aHardwareWebRender) {
314 flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
317 const auto desc = GLContextDesc{{flags}, false};
318 RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
319 egl, desc, config, surface, aUseGles, &failureId);
320 if (!gl) {
321 const auto err = egl->mLib->fGetError();
322 gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err);
323 mozilla::gl::DestroySurface(*egl, surface);
324 return nullptr;
327 gl->MakeCurrent();
328 gl->SetIsDoubleBuffered(doubleBuffered);
330 #ifdef MOZ_GTK_WAYLAND
331 if (surface && GdkIsWaylandDisplay()) {
332 // Make eglSwapBuffers() non-blocking on wayland
333 egl->fSwapInterval(0);
335 #endif
336 if (aHardwareWebRender && egl->mLib->IsANGLE()) {
337 MOZ_ASSERT(doubleBuffered);
338 egl->fSwapInterval(0);
340 return gl.forget();
343 already_AddRefed<GLContext> GLContextEGLFactory::Create(
344 EGLNativeWindowType aWindow, bool aHardwareWebRender) {
345 RefPtr<GLContext> glContext;
346 #if !defined(MOZ_WIDGET_ANDROID)
347 glContext = CreateImpl(aWindow, aHardwareWebRender, /* aUseGles */ false);
348 #endif // !defined(MOZ_WIDGET_ANDROID)
350 if (!glContext) {
351 glContext = CreateImpl(aWindow, aHardwareWebRender, /* aUseGles */ true);
353 return glContext.forget();
356 /* static */
357 EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
358 widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig) {
359 nsCString discardFailureId;
360 const auto egl = DefaultEglDisplay(&discardFailureId);
361 if (!egl) {
362 gfxCriticalNote << "Failed to load EGL library 6!";
363 return EGL_NO_SURFACE;
366 MOZ_ASSERT(aCompositorWidget);
367 EGLNativeWindowType window =
368 GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
369 if (!window) {
370 gfxCriticalNote << "window is null";
371 return EGL_NO_SURFACE;
374 return mozilla::gl::CreateSurfaceFromNativeWindow(*egl, window, aConfig);
377 GLContextEGL::GLContextEGL(const std::shared_ptr<EglDisplay> egl,
378 const GLContextDesc& desc, EGLConfig config,
379 EGLSurface surface, EGLContext context)
380 : GLContext(desc, nullptr, false),
381 mEgl(egl),
382 mConfig(config),
383 mContext(context),
384 mSurface(surface),
385 mFallbackSurface(CreateFallbackSurface(*mEgl, mConfig)) {
386 #ifdef DEBUG
387 printf_stderr("Initializing context %p surface %p on display %p\n", mContext,
388 mSurface, mEgl->mDisplay);
389 #endif
392 void GLContextEGL::OnMarkDestroyed() {
393 if (mSurfaceOverride != EGL_NO_SURFACE) {
394 SetEGLSurfaceOverride(EGL_NO_SURFACE);
398 GLContextEGL::~GLContextEGL() {
399 MarkDestroyed();
401 // Wrapped context should not destroy eglContext/Surface
402 if (!mOwnsContext) {
403 return;
406 #ifdef DEBUG
407 printf_stderr("Destroying context %p surface %p on display %p\n", mContext,
408 mSurface, mEgl->mDisplay);
409 #endif
411 mEgl->fDestroyContext(mContext);
413 mozilla::gl::DestroySurface(*mEgl, mSurface);
414 mozilla::gl::DestroySurface(*mEgl, mFallbackSurface);
417 bool GLContextEGL::Init() {
418 if (!GLContext::Init()) return false;
420 bool current = MakeCurrent();
421 if (!current) {
422 gfx::LogFailure("Couldn't get device attachments for device."_ns);
423 return false;
426 mShareWithEGLImage =
427 mEgl->HasKHRImageBase() &&
428 mEgl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) &&
429 IsExtensionSupported(OES_EGL_image);
431 return true;
434 bool GLContextEGL::BindTexImage() {
435 if (!mSurface) return false;
437 if (mBound && !ReleaseTexImage()) return false;
439 EGLBoolean success =
440 mEgl->fBindTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
441 if (success == LOCAL_EGL_FALSE) return false;
443 mBound = true;
444 return true;
447 bool GLContextEGL::ReleaseTexImage() {
448 if (!mBound) return true;
450 if (!mSurface) return false;
452 EGLBoolean success;
453 success = mEgl->fReleaseTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
454 if (success == LOCAL_EGL_FALSE) return false;
456 mBound = false;
457 return true;
460 void GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
461 mSurfaceOverride = surf;
462 DebugOnly<bool> ok = MakeCurrent(true);
463 MOZ_ASSERT(ok);
466 bool GLContextEGL::MakeCurrentImpl() const {
467 EGLSurface surface =
468 (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride : mSurface;
469 if (!surface) {
470 surface = mFallbackSurface;
473 const bool succeeded = mEgl->fMakeCurrent(surface, surface, mContext);
474 if (!succeeded) {
475 const auto eglError = mEgl->mLib->fGetError();
476 if (eglError == LOCAL_EGL_CONTEXT_LOST) {
477 OnContextLostError();
478 } else {
479 NS_WARNING("Failed to make GL context current!");
480 #ifdef DEBUG
481 printf_stderr("EGL Error: 0x%04x\n", eglError);
482 #endif
486 return succeeded;
489 bool GLContextEGL::IsCurrentImpl() const {
490 return mEgl->mLib->fGetCurrentContext() == mContext;
493 bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
494 if (!mOwnsContext) {
495 return false;
497 // unconditionally release the surface and create a new one. Don't try to
498 // optimize this away. If we get here, then by definition we know that we want
499 // to get a new surface.
500 ReleaseSurface();
501 MOZ_ASSERT(aWidget);
503 EGLNativeWindowType nativeWindow =
504 GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
505 if (nativeWindow) {
506 mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(*mEgl, nativeWindow,
507 mConfig);
508 if (!mSurface) {
509 NS_WARNING("Failed to create EGLSurface from native window");
510 return false;
513 const bool ok = MakeCurrent(true);
514 MOZ_ASSERT(ok);
515 #ifdef MOZ_GTK_WAYLAND
516 if (mSurface && GdkIsWaylandDisplay()) {
517 // Make eglSwapBuffers() non-blocking on wayland
518 mEgl->fSwapInterval(0);
520 #endif
521 return ok;
524 void GLContextEGL::ReleaseSurface() {
525 if (mOwnsContext) {
526 mozilla::gl::DestroySurface(*mEgl, mSurface);
528 if (mSurface == mSurfaceOverride) {
529 mSurfaceOverride = EGL_NO_SURFACE;
531 mSurface = EGL_NO_SURFACE;
534 Maybe<SymbolLoader> GLContextEGL::GetSymbolLoader() const {
535 return mEgl->mLib->GetSymbolLoader();
538 bool GLContextEGL::SwapBuffers() {
539 EGLSurface surface =
540 mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
541 if (surface) {
542 if ((mEgl->IsExtensionSupported(
543 EGLExtension::EXT_swap_buffers_with_damage) ||
544 mEgl->IsExtensionSupported(
545 EGLExtension::KHR_swap_buffers_with_damage))) {
546 std::vector<EGLint> rects;
547 for (auto iter = mDamageRegion.RectIter(); !iter.Done(); iter.Next()) {
548 const IntRect& r = iter.Get();
549 rects.push_back(r.X());
550 rects.push_back(r.Y());
551 rects.push_back(r.Width());
552 rects.push_back(r.Height());
554 mDamageRegion.SetEmpty();
555 return mEgl->fSwapBuffersWithDamage(surface, rects.data(),
556 rects.size() / 4);
558 return mEgl->fSwapBuffers(surface);
559 } else {
560 return false;
564 void GLContextEGL::SetDamage(const nsIntRegion& aDamageRegion) {
565 mDamageRegion = aDamageRegion;
568 void GLContextEGL::GetWSIInfo(nsCString* const out) const {
569 out->AppendLiteral("EGL_VENDOR: ");
570 out->Append(
571 (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VENDOR));
573 out->AppendLiteral("\nEGL_VERSION: ");
574 out->Append(
575 (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VERSION));
577 out->AppendLiteral("\nEGL_EXTENSIONS: ");
578 out->Append((const char*)mEgl->mLib->fQueryString(mEgl->mDisplay,
579 LOCAL_EGL_EXTENSIONS));
581 #ifndef ANDROID // This query will crash some old android.
582 out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
583 out->Append(
584 (const char*)mEgl->mLib->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
585 #endif
588 // hold a reference to the given surface
589 // for the lifetime of this context.
590 void GLContextEGL::HoldSurface(gfxASurface* aSurf) { mThebesSurface = aSurf; }
592 bool GLContextEGL::HasExtBufferAge() const {
593 return mEgl->IsExtensionSupported(EGLExtension::EXT_buffer_age);
596 bool GLContextEGL::HasKhrPartialUpdate() const {
597 return mEgl->IsExtensionSupported(EGLExtension::KHR_partial_update);
600 GLint GLContextEGL::GetBufferAge() const {
601 EGLSurface surface =
602 mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
604 if (surface && (HasExtBufferAge() || HasKhrPartialUpdate())) {
605 EGLint result;
606 mEgl->fQuerySurface(surface, LOCAL_EGL_BUFFER_AGE_EXT, &result);
607 return result;
610 return 0;
613 #define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
615 RefPtr<GLContextEGL> GLContextEGL::CreateGLContext(
616 const std::shared_ptr<EglDisplay> egl, const GLContextDesc& desc,
617 EGLConfig config, EGLSurface surface, const bool useGles,
618 nsACString* const out_failureId) {
619 const auto& flags = desc.flags;
621 std::vector<EGLint> required_attribs;
623 if (useGles) {
624 // TODO: This fBindAPI could be more thread-safe
625 if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
626 *out_failureId = "FEATURE_FAILURE_EGL_ES"_ns;
627 NS_WARNING("Failed to bind API to GLES!");
628 return nullptr;
630 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
631 if (flags & CreateContextFlags::PREFER_ES3) {
632 required_attribs.push_back(3);
633 } else {
634 required_attribs.push_back(2);
636 } else {
637 if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_API) == LOCAL_EGL_FALSE) {
638 *out_failureId = "FEATURE_FAILURE_EGL"_ns;
639 NS_WARNING("Failed to bind API to GL!");
640 return nullptr;
642 if (flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE) {
643 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
644 required_attribs.push_back(
645 LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
646 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
647 required_attribs.push_back(2);
648 } else {
649 // !REQUIRE_COMPAT_PROFILE means core profle.
650 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
651 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
652 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
653 required_attribs.push_back(3);
654 required_attribs.push_back(LOCAL_EGL_CONTEXT_MINOR_VERSION);
655 required_attribs.push_back(2);
659 if ((flags & CreateContextFlags::PREFER_EXACT_VERSION) &&
660 egl->mLib->IsANGLE()) {
661 required_attribs.push_back(
662 LOCAL_EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
663 required_attribs.push_back(LOCAL_EGL_FALSE);
666 const auto debugFlags = GLContext::ChooseDebugFlags(flags);
667 if (!debugFlags && flags & CreateContextFlags::NO_VALIDATION &&
668 egl->IsExtensionSupported(EGLExtension::KHR_create_context_no_error)) {
669 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
670 required_attribs.push_back(LOCAL_EGL_TRUE);
673 if (flags & CreateContextFlags::PROVOKING_VERTEX_DONT_CARE &&
674 egl->IsExtensionSupported(
675 EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
676 required_attribs.push_back(
677 LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ);
678 required_attribs.push_back(LOCAL_EGL_TRUE);
681 std::vector<EGLint> ext_robustness_attribs;
682 std::vector<EGLint> ext_rbab_attribs; // RBAB: Robust Buffer Access Behavior
683 std::vector<EGLint> khr_robustness_attribs;
684 std::vector<EGLint> khr_rbab_attribs; // RBAB: Robust Buffer Access Behavior
685 if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
686 std::vector<EGLint> base_robustness_attribs = required_attribs;
687 if (egl->IsExtensionSupported(
688 EGLExtension::NV_robustness_video_memory_purge)) {
689 base_robustness_attribs.push_back(
690 LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
691 base_robustness_attribs.push_back(LOCAL_EGL_TRUE);
694 if (egl->IsExtensionSupported(
695 EGLExtension::EXT_create_context_robustness)) {
696 ext_robustness_attribs = base_robustness_attribs;
697 ext_robustness_attribs.push_back(
698 LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
699 ext_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
701 if (gfxVars::AllowEglRbab()) {
702 ext_rbab_attribs = ext_robustness_attribs;
703 ext_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
704 ext_rbab_attribs.push_back(LOCAL_EGL_TRUE);
708 if (egl->IsExtensionSupported(EGLExtension::KHR_create_context)) {
709 khr_robustness_attribs = base_robustness_attribs;
710 khr_robustness_attribs.push_back(
711 LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
712 khr_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
714 khr_rbab_attribs = khr_robustness_attribs;
715 khr_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
716 khr_rbab_attribs.push_back(
717 LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
721 const auto fnCreate = [&](const std::vector<EGLint>& attribs) {
722 auto terminated_attribs = attribs;
724 for (const auto& cur : kTerminationAttribs) {
725 terminated_attribs.push_back(cur);
728 return egl->fCreateContext(config, EGL_NO_CONTEXT,
729 terminated_attribs.data());
732 EGLContext context;
733 do {
734 if (!khr_rbab_attribs.empty()) {
735 context = fnCreate(khr_rbab_attribs);
736 if (context) break;
737 NS_WARNING("Failed to create EGLContext with khr_rbab_attribs");
740 if (!ext_rbab_attribs.empty()) {
741 context = fnCreate(ext_rbab_attribs);
742 if (context) break;
743 NS_WARNING("Failed to create EGLContext with ext_rbab_attribs");
746 if (!khr_robustness_attribs.empty()) {
747 context = fnCreate(khr_robustness_attribs);
748 if (context) break;
749 NS_WARNING("Failed to create EGLContext with khr_robustness_attribs");
752 if (!ext_robustness_attribs.empty()) {
753 context = fnCreate(ext_robustness_attribs);
754 if (context) break;
755 NS_WARNING("Failed to create EGLContext with ext_robustness_attribs");
758 context = fnCreate(required_attribs);
759 if (context) break;
760 NS_WARNING("Failed to create EGLContext with required_attribs");
762 *out_failureId = "FEATURE_FAILURE_EGL_CREATE"_ns;
763 return nullptr;
764 } while (false);
765 MOZ_ASSERT(context);
767 RefPtr<GLContextEGL> glContext =
768 new GLContextEGL(egl, desc, config, surface, context);
769 if (!glContext->Init()) {
770 *out_failureId = "FEATURE_FAILURE_EGL_INIT"_ns;
771 return nullptr;
774 if (GLContext::ShouldSpew()) {
775 printf_stderr("new GLContextEGL %p on EGLDisplay %p\n", glContext.get(),
776 egl->mDisplay);
779 return glContext;
782 // static
783 EGLSurface GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
784 EglDisplay& egl, EGLConfig config, EGLenum bindToTextureFormat,
785 mozilla::gfx::IntSize& pbsize) {
786 nsTArray<EGLint> pbattrs(16);
787 EGLSurface surface = nullptr;
789 TRY_AGAIN_POWER_OF_TWO:
790 pbattrs.Clear();
791 pbattrs.AppendElement(LOCAL_EGL_WIDTH);
792 pbattrs.AppendElement(pbsize.width);
793 pbattrs.AppendElement(LOCAL_EGL_HEIGHT);
794 pbattrs.AppendElement(pbsize.height);
796 if (bindToTextureFormat != LOCAL_EGL_NONE) {
797 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
798 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
800 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
801 pbattrs.AppendElement(bindToTextureFormat);
804 for (const auto& cur : kTerminationAttribs) {
805 pbattrs.AppendElement(cur);
808 surface = egl.fCreatePbufferSurface(config, &pbattrs[0]);
809 if (!surface) {
810 if (!is_power_of_two(pbsize.width) || !is_power_of_two(pbsize.height)) {
811 if (!is_power_of_two(pbsize.width))
812 pbsize.width = next_power_of_two(pbsize.width);
813 if (!is_power_of_two(pbsize.height))
814 pbsize.height = next_power_of_two(pbsize.height);
816 NS_WARNING("Failed to create pbuffer, trying power of two dims");
817 goto TRY_AGAIN_POWER_OF_TWO;
820 NS_WARNING("Failed to create pbuffer surface");
821 return nullptr;
824 return surface;
827 #if defined(MOZ_WAYLAND)
828 WaylandGLSurface::WaylandGLSurface(struct wl_surface* aWaylandSurface,
829 struct wl_egl_window* aEGLWindow)
830 : mWaylandSurface(aWaylandSurface), mEGLWindow(aEGLWindow) {}
832 WaylandGLSurface::~WaylandGLSurface() {
833 wl_egl_window_destroy(mEGLWindow);
834 wl_surface_destroy(mWaylandSurface);
836 #endif
838 // static
839 EGLSurface GLContextEGL::CreateWaylandBufferSurface(
840 EglDisplay& egl, EGLConfig config, mozilla::gfx::IntSize& pbsize) {
841 wl_egl_window* eglwindow = nullptr;
843 #ifdef MOZ_GTK_WAYLAND
844 struct wl_compositor* compositor =
845 gdk_wayland_display_get_wl_compositor(gdk_display_get_default());
846 struct wl_surface* wlsurface = wl_compositor_create_surface(compositor);
847 eglwindow = wl_egl_window_create(wlsurface, pbsize.width, pbsize.height);
848 #endif
849 if (!eglwindow) return nullptr;
851 const auto surface = egl.fCreateWindowSurface(
852 config, reinterpret_cast<EGLNativeWindowType>(eglwindow), 0);
853 if (surface) {
854 #ifdef MOZ_GTK_WAYLAND
855 MOZ_ASSERT(!sWaylandGLSurface.Contains(surface));
856 sWaylandGLSurface.LookupOrInsert(
857 surface, new WaylandGLSurface(wlsurface, eglwindow));
858 #endif
861 return surface;
864 static const EGLint kEGLConfigAttribsRGB16[] = {
865 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
866 LOCAL_EGL_RED_SIZE, 5,
867 LOCAL_EGL_GREEN_SIZE, 6,
868 LOCAL_EGL_BLUE_SIZE, 5,
869 LOCAL_EGL_ALPHA_SIZE, 0};
871 static const EGLint kEGLConfigAttribsRGB24[] = {
872 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
873 LOCAL_EGL_RED_SIZE, 8,
874 LOCAL_EGL_GREEN_SIZE, 8,
875 LOCAL_EGL_BLUE_SIZE, 8,
876 LOCAL_EGL_ALPHA_SIZE, 0};
878 static const EGLint kEGLConfigAttribsRGBA32[] = {
879 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
880 LOCAL_EGL_RED_SIZE, 8,
881 LOCAL_EGL_GREEN_SIZE, 8,
882 LOCAL_EGL_BLUE_SIZE, 8,
883 LOCAL_EGL_ALPHA_SIZE, 8};
885 bool CreateConfig(EglDisplay& egl, EGLConfig* aConfig, int32_t depth,
886 bool aEnableDepthBuffer, bool aUseGles, int aVisual) {
887 EGLConfig configs[64];
888 std::vector<EGLint> attribs;
889 EGLint ncfg = ArrayLength(configs);
891 switch (depth) {
892 case 16:
893 for (const auto& cur : kEGLConfigAttribsRGB16) {
894 attribs.push_back(cur);
896 break;
897 case 24:
898 for (const auto& cur : kEGLConfigAttribsRGB24) {
899 attribs.push_back(cur);
901 break;
902 case 32:
903 for (const auto& cur : kEGLConfigAttribsRGBA32) {
904 attribs.push_back(cur);
906 break;
907 default:
908 NS_ERROR("Unknown pixel depth");
909 return false;
912 if (aUseGles) {
913 attribs.push_back(LOCAL_EGL_RENDERABLE_TYPE);
914 attribs.push_back(LOCAL_EGL_OPENGL_ES2_BIT);
916 for (const auto& cur : kTerminationAttribs) {
917 attribs.push_back(cur);
920 if (!egl.fChooseConfig(attribs.data(), configs, ncfg, &ncfg) || ncfg < 1) {
921 return false;
924 Maybe<EGLConfig> fallbackConfig;
926 for (int j = 0; j < ncfg; ++j) {
927 EGLConfig config = configs[j];
928 EGLint r, g, b, a;
929 if (egl.fGetConfigAttrib(config, LOCAL_EGL_RED_SIZE, &r) &&
930 egl.fGetConfigAttrib(config, LOCAL_EGL_GREEN_SIZE, &g) &&
931 egl.fGetConfigAttrib(config, LOCAL_EGL_BLUE_SIZE, &b) &&
932 egl.fGetConfigAttrib(config, LOCAL_EGL_ALPHA_SIZE, &a) &&
933 ((depth == 16 && r == 5 && g == 6 && b == 5) ||
934 (depth == 24 && r == 8 && g == 8 && b == 8) ||
935 (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) {
936 EGLint z;
937 if (aEnableDepthBuffer) {
938 if (!egl.fGetConfigAttrib(config, LOCAL_EGL_DEPTH_SIZE, &z) ||
939 z != 24) {
940 continue;
943 if (kIsX11 && aVisual) {
944 int vis;
945 if (!egl.fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, &vis) ||
946 aVisual != vis) {
947 if (!fallbackConfig) {
948 fallbackConfig = Some(config);
950 continue;
953 *aConfig = config;
954 return true;
958 // We don't have a frame buffer X11 visual which matches the EGL visual
959 // from GLContextEGL::FindVisual(). Let's try to use the fallback one and hope
960 // we're not on NVIDIA (Bug 1478454) as it causes X11 BadMatch error there.
961 if (kIsX11 && 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 // aVisual is used in Linux only.
975 static bool CreateConfigScreen(EglDisplay& egl, EGLConfig* const aConfig,
976 const bool aEnableDepthBuffer,
977 const bool aUseGles, int aVisual) {
978 int32_t depth = gfxVars::ScreenDepth();
979 if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles,
980 aVisual)) {
981 return true;
983 #ifdef MOZ_WIDGET_ANDROID
984 // Bug 736005
985 // Android doesn't always support 16 bit so also try 24 bit
986 if (depth == 16) {
987 return CreateConfig(egl, aConfig, 24, aEnableDepthBuffer, aUseGles);
989 // Bug 970096
990 // Some devices that have 24 bit screens only support 16 bit OpenGL?
991 if (depth == 24) {
992 return CreateConfig(egl, aConfig, 16, aEnableDepthBuffer, aUseGles);
994 #endif
995 return false;
998 already_AddRefed<GLContext> GLContextProviderEGL::CreateForCompositorWidget(
999 CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
1000 bool /*aForceAccelerated*/) {
1001 EGLNativeWindowType window = nullptr;
1002 if (aCompositorWidget) {
1003 window = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
1005 return GLContextEGLFactory::Create(window, aHardwareWebRender);
1008 EGLSurface GLContextEGL::CreateCompatibleSurface(void* aWindow) const {
1009 MOZ_ASSERT(aWindow);
1010 if (mConfig == EGL_NO_CONFIG) {
1011 MOZ_CRASH("GFX: Failed with invalid EGLConfig 2!");
1014 const auto fnCreate = [&](const bool useGles) -> EGLSurface {
1015 // NOTE: aWindow is an ANativeWindow
1016 auto config = mConfig;
1017 if (!config && !CreateConfigScreen(*mEgl, &config,
1018 /* aEnableDepthBuffer */ false,
1019 /* useGles */ useGles)) {
1020 return nullptr;
1023 return mEgl->fCreateWindowSurface(
1024 config, reinterpret_cast<EGLNativeWindowType>(aWindow), 0);
1027 auto surface = fnCreate(false);
1028 if (!surface) {
1029 surface = fnCreate(true);
1031 if (!surface) {
1032 MOZ_CRASH("GFX: Failed to create EGLSurface 2!");
1034 return surface;
1037 static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
1038 out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
1039 #ifdef MOZ_GTK_WAYLAND
1040 if (GdkIsWaylandDisplay()) {
1041 // Wayland on desktop does not support PBuffer or FBO.
1042 // We create a dummy wl_egl_window instead.
1043 out->AppendElement(LOCAL_EGL_WINDOW_BIT);
1044 } else
1045 #endif
1047 out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
1050 if (useGles) {
1051 out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE);
1052 if (es3) {
1053 out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR);
1054 } else {
1055 out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
1059 out->AppendElement(LOCAL_EGL_RED_SIZE);
1060 out->AppendElement(8);
1062 out->AppendElement(LOCAL_EGL_GREEN_SIZE);
1063 out->AppendElement(8);
1065 out->AppendElement(LOCAL_EGL_BLUE_SIZE);
1066 out->AppendElement(8);
1068 out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
1069 out->AppendElement(8);
1071 out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
1072 out->AppendElement(0);
1074 out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
1075 out->AppendElement(0);
1077 // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
1078 out->AppendElement(LOCAL_EGL_NONE);
1079 out->AppendElement(0);
1081 out->AppendElement(0);
1082 out->AppendElement(0);
1086 /// Useful for debugging, but normally unused.
1087 static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) {
1088 EGLint bits = 0;
1089 egl->fGetConfigAttrib(config, attrib, &bits);
1090 MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
1092 return bits;
1096 static EGLConfig ChooseConfig(EglDisplay& egl, const GLContextCreateDesc& desc,
1097 const bool useGles) {
1098 nsTArray<EGLint> configAttribList;
1099 FillContextAttribs(bool(desc.flags & CreateContextFlags::PREFER_ES3), useGles,
1100 &configAttribList);
1102 const EGLint* configAttribs = configAttribList.Elements();
1104 // The sorting dictated by the spec for eglChooseConfig reasonably assures
1105 // that a reasonable 'best' config is on top.
1106 const EGLint kMaxConfigs = 1;
1107 EGLConfig configs[kMaxConfigs];
1108 EGLint foundConfigs = 0;
1109 if (!egl.fChooseConfig(configAttribs, configs, kMaxConfigs, &foundConfigs) ||
1110 foundConfigs == 0) {
1111 return EGL_NO_CONFIG;
1114 EGLConfig config = configs[0];
1115 return config;
1118 #ifdef MOZ_X11
1119 /* static */
1120 bool GLContextEGL::FindVisual(bool aUseWebRender, bool useAlpha,
1121 int* const out_visualId) {
1122 nsCString discardFailureId;
1123 const auto egl = DefaultEglDisplay(&discardFailureId);
1124 if (!egl) {
1125 gfxCriticalNote
1126 << "GLContextEGL::FindVisual(): Failed to load EGL library!";
1127 return false;
1130 EGLConfig config;
1131 const int bpp = useAlpha ? 32 : 24;
1132 if (!CreateConfig(*egl, &config, bpp, aUseWebRender, /* aUseGles */ false)) {
1133 gfxCriticalNote
1134 << "GLContextEGL::FindVisual(): Failed to create EGLConfig!";
1135 return false;
1137 if (egl->fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, out_visualId)) {
1138 return true;
1140 return false;
1142 #endif
1144 /*static*/
1145 RefPtr<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContextImpl(
1146 const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc,
1147 const mozilla::gfx::IntSize& size, const bool useGles,
1148 nsACString* const out_failureId) {
1149 const EGLConfig config = ChooseConfig(*egl, desc, useGles);
1150 if (config == EGL_NO_CONFIG) {
1151 *out_failureId = "FEATURE_FAILURE_EGL_NO_CONFIG"_ns;
1152 NS_WARNING("Failed to find a compatible config.");
1153 return nullptr;
1156 if (GLContext::ShouldSpew()) {
1157 egl->DumpEGLConfig(config);
1160 mozilla::gfx::IntSize pbSize(size);
1161 EGLSurface surface = nullptr;
1162 #ifdef MOZ_GTK_WAYLAND
1163 if (GdkIsWaylandDisplay()) {
1164 surface = GLContextEGL::CreateWaylandBufferSurface(*egl, config, pbSize);
1165 } else
1166 #endif
1168 surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
1169 *egl, config, LOCAL_EGL_NONE, pbSize);
1171 if (!surface) {
1172 *out_failureId = "FEATURE_FAILURE_EGL_POT"_ns;
1173 NS_WARNING("Failed to create PBuffer for context!");
1174 return nullptr;
1177 auto fullDesc = GLContextDesc{desc};
1178 fullDesc.isOffscreen = true;
1179 RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
1180 egl, fullDesc, config, surface, useGles, out_failureId);
1181 if (!gl) {
1182 NS_WARNING("Failed to create GLContext from PBuffer");
1183 egl->fDestroySurface(surface);
1184 #if defined(MOZ_WAYLAND)
1185 DeleteWaylandGLSurface(surface);
1186 #endif
1187 return nullptr;
1190 return gl;
1193 /*static*/
1194 RefPtr<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContext(
1195 const std::shared_ptr<EglDisplay> display, const GLContextCreateDesc& desc,
1196 const mozilla::gfx::IntSize& size, nsACString* const out_failureId) {
1197 RefPtr<GLContextEGL> gl = CreateEGLPBufferOffscreenContextImpl(
1198 display, desc, size, /* useGles */ false, out_failureId);
1199 if (!gl) {
1200 gl = CreateEGLPBufferOffscreenContextImpl(
1201 display, desc, size, /* useGles */ true, out_failureId);
1203 return gl;
1206 /*static*/
1207 already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless(
1208 const GLContextCreateDesc& desc, nsACString* const out_failureId) {
1209 const auto display = DefaultEglDisplay(out_failureId);
1210 if (!display) {
1211 return nullptr;
1213 mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
1214 auto ret = GLContextEGL::CreateEGLPBufferOffscreenContext(
1215 display, desc, dummySize, out_failureId);
1216 return ret.forget();
1219 // Don't want a global context on Android as 1) share groups across 2 threads
1220 // fail on many Tegra drivers (bug 759225) and 2) some mobile devices have a
1221 // very strict limit on global number of GL contexts (bug 754257) and 3) each
1222 // EGL context eats 750k on B2G (bug 813783)
1223 /*static*/
1224 GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; }
1226 // -
1228 static StaticMutex sMutex;
1229 static StaticRefPtr<GLLibraryEGL> gDefaultEglLibrary;
1231 RefPtr<GLLibraryEGL> DefaultEglLibrary(nsACString* const out_failureId) {
1232 StaticMutexAutoLock lock(sMutex);
1233 if (!gDefaultEglLibrary) {
1234 gDefaultEglLibrary = GLLibraryEGL::Create(out_failureId);
1235 if (!gDefaultEglLibrary) {
1236 NS_WARNING("GLLibraryEGL::Create failed");
1239 return gDefaultEglLibrary.get();
1242 // -
1244 /*static*/
1245 void GLContextProviderEGL::Shutdown() {
1246 StaticMutexAutoLock lock(sMutex);
1247 if (!gDefaultEglLibrary) {
1248 return;
1250 gDefaultEglLibrary = nullptr;
1253 } /* namespace gl */
1254 } /* namespace mozilla */
1256 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS