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/. */
5
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
28
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
35
36 # define GLES2_LIB "libGLESv2.so"
37 # define GLES2_LIB2 "libGLESv2.so.2"
38
39 #elif defined(XP_WIN)
40 # include "mozilla/widget/WinCompositorWidget.h"
41 # include "nsIFile.h"
42
43 # define GLES2_LIB "libGLESv2.dll"
44
45 # ifndef WIN32_LEAN_AND_MEAN
46 # define WIN32_LEAN_AND_MEAN 1
47 # endif
48
49 # include <windows.h>
50 #else
51 # error "Platform not recognized"
52 #endif
53
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"
76
77 #if defined(MOZ_WIDGET_GTK)
78 # include "mozilla/widget/GtkCompositorWidget.h"
79 # include "mozilla/WidgetUtilsGtk.h"
80 # if defined(MOZ_WAYLAND)
81 # include <gdk/gdkwayland.h>
82 # include <wayland-egl.h>
83 # define MOZ_GTK_WAYLAND 1
84 # endif
85 #endif
86
87 struct wl_egl_window;
88
89 using namespace mozilla::gfx;
90
91 namespace mozilla {
92 namespace gl {
93
94 using namespace mozilla::widget;
95
96 #if defined(MOZ_WAYLAND)
97 class WaylandGLSurface {
98 public:
99 WaylandGLSurface(struct wl_surface* aWaylandSurface,
100 struct wl_egl_window* aEGLWindow);
101 ~WaylandGLSurface();
102
103 private:
104 struct wl_surface* mWaylandSurface;
105 struct wl_egl_window* mEGLWindow;
106 };
107
108 static nsTHashMap<nsPtrHashKey<void>, WaylandGLSurface*> sWaylandGLSurface;
109
DeleteWaylandGLSurface(EGLSurface surface)110 void DeleteWaylandGLSurface(EGLSurface surface) {
111 # ifdef MOZ_GTK_WAYLAND
112 // We're running on Wayland which means our EGLSurface may
113 // have attached Wayland backend data which must be released.
114 if (GdkIsWaylandDisplay()) {
115 auto entry = sWaylandGLSurface.Lookup(surface);
116 if (entry) {
117 delete entry.Data();
118 entry.Remove();
119 }
120 }
121 # endif
122 }
123 #endif
124
125 static bool CreateConfigScreen(EglDisplay&, EGLConfig* const aConfig,
126 const bool aEnableDepthBuffer,
127 const bool aUseGles);
128
129 // append three zeros at the end of attribs list to work around
130 // EGL implementation bugs that iterate until they find 0, instead of
131 // EGL_NONE. See bug 948406.
132 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
133 LOCAL_EGL_NONE, 0, 0, 0
134
135 static EGLint kTerminationAttribs[] = {
136 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS};
137
next_power_of_two(int v)138 static int next_power_of_two(int v) {
139 v--;
140 v |= v >> 1;
141 v |= v >> 2;
142 v |= v >> 4;
143 v |= v >> 8;
144 v |= v >> 16;
145 v++;
146
147 return v;
148 }
149
is_power_of_two(int v)150 static bool is_power_of_two(int v) {
151 NS_ASSERTION(v >= 0, "bad value");
152
153 if (v == 0) return true;
154
155 return (v & (v - 1)) == 0;
156 }
157
DestroySurface(EglDisplay & egl,const EGLSurface oldSurface)158 static void DestroySurface(EglDisplay& egl, const EGLSurface oldSurface) {
159 if (oldSurface != EGL_NO_SURFACE) {
160 // TODO: This breaks TLS MakeCurrent caching.
161 egl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
162 egl.fDestroySurface(oldSurface);
163 #if defined(MOZ_WAYLAND)
164 DeleteWaylandGLSurface(oldSurface);
165 #endif
166 }
167 }
168
CreateFallbackSurface(EglDisplay & egl,const EGLConfig & config)169 static EGLSurface CreateFallbackSurface(EglDisplay& egl,
170 const EGLConfig& config) {
171 if (egl.IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
172 // We don't need a PBuffer surface in this case
173 return EGL_NO_SURFACE;
174 }
175
176 std::vector<EGLint> pbattrs;
177 pbattrs.push_back(LOCAL_EGL_WIDTH);
178 pbattrs.push_back(1);
179 pbattrs.push_back(LOCAL_EGL_HEIGHT);
180 pbattrs.push_back(1);
181
182 for (const auto& cur : kTerminationAttribs) {
183 pbattrs.push_back(cur);
184 }
185
186 EGLSurface surface = egl.fCreatePbufferSurface(config, pbattrs.data());
187 if (!surface) {
188 MOZ_CRASH("Failed to create fallback EGLSurface");
189 }
190
191 return surface;
192 }
193
CreateSurfaceFromNativeWindow(EglDisplay & egl,const EGLNativeWindowType window,const EGLConfig config)194 static EGLSurface CreateSurfaceFromNativeWindow(
195 EglDisplay& egl, const EGLNativeWindowType window, const EGLConfig config) {
196 MOZ_ASSERT(window);
197 EGLSurface newSurface = EGL_NO_SURFACE;
198
199 #ifdef MOZ_WIDGET_ANDROID
200 JNIEnv* const env = jni::GetEnvForThread();
201 ANativeWindow* const nativeWindow =
202 ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
203 if (!nativeWindow) {
204 return EGL_NO_SURFACE;
205 }
206 const auto& display = egl.mLib->fGetDisplay(EGL_DEFAULT_DISPLAY);
207 newSurface = egl.mLib->fCreateWindowSurface(display, config, nativeWindow, 0);
208 ANativeWindow_release(nativeWindow);
209 #else
210 newSurface = egl.fCreateWindowSurface(config, window, 0);
211 if (!newSurface) {
212 const auto err = egl.mLib->fGetError();
213 gfxCriticalNote << "Failed to create EGLSurface!: " << gfx::hexa(err);
214 }
215 #endif
216 return newSurface;
217 }
218
219 /* GLContextEGLFactory class was added as a friend of GLContextEGL
220 * so that it could access GLContextEGL::CreateGLContext. This was
221 * done so that a new function would not need to be added to the shared
222 * GLContextProvider interface.
223 */
224 class GLContextEGLFactory {
225 public:
226 static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow,
227 bool aHardwareWebRender);
228 static already_AddRefed<GLContext> CreateImpl(EGLNativeWindowType aWindow,
229 bool aHardwareWebRender,
230 bool aUseGles);
231
232 private:
233 GLContextEGLFactory() = default;
234 ~GLContextEGLFactory() = default;
235 };
236
CreateImpl(EGLNativeWindowType aWindow,bool aHardwareWebRender,bool aUseGles)237 already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
238 EGLNativeWindowType aWindow, bool aHardwareWebRender, bool aUseGles) {
239 nsCString failureId;
240 const auto lib = gl::DefaultEglLibrary(&failureId);
241 if (!lib) {
242 gfxCriticalNote << "Failed[3] to load EGL library: " << failureId.get();
243 return nullptr;
244 }
245 const auto egl = lib->CreateDisplay(true, &failureId);
246 if (!egl) {
247 gfxCriticalNote << "Failed[3] to create EGL library display: "
248 << failureId.get();
249 return nullptr;
250 }
251
252 bool doubleBuffered = true;
253
254 EGLConfig config;
255 if (aHardwareWebRender && egl->mLib->IsANGLE()) {
256 // Force enable alpha channel to make sure ANGLE use correct framebuffer
257 // formart
258 const int bpp = 32;
259 if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
260 gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!";
261 return nullptr;
262 }
263 } else if (kIsWayland || kIsX11) {
264 const int bpp = 32;
265 if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
266 gfxCriticalNote << "Failed to create EGLConfig for WebRender!";
267 return nullptr;
268 }
269 } else {
270 if (!CreateConfigScreen(*egl, &config,
271 /* aEnableDepthBuffer */ false, aUseGles)) {
272 gfxCriticalNote << "Failed to create EGLConfig!";
273 return nullptr;
274 }
275 }
276
277 EGLSurface surface = EGL_NO_SURFACE;
278 if (aWindow) {
279 surface = mozilla::gl::CreateSurfaceFromNativeWindow(*egl, aWindow, config);
280 if (!surface) {
281 return nullptr;
282 }
283 }
284
285 CreateContextFlags flags = CreateContextFlags::NONE;
286 if (aHardwareWebRender &&
287 StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
288 flags |= CreateContextFlags::PREFER_ROBUSTNESS;
289 }
290 if (aHardwareWebRender && aUseGles) {
291 flags |= CreateContextFlags::PREFER_ES3;
292 }
293 if (!aHardwareWebRender) {
294 flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
295 }
296
297 const auto desc = GLContextDesc{{flags}, false};
298 RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
299 egl, desc, config, surface, aUseGles, &failureId);
300 if (!gl) {
301 const auto err = egl->mLib->fGetError();
302 gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err);
303 mozilla::gl::DestroySurface(*egl, surface);
304 return nullptr;
305 }
306
307 gl->MakeCurrent();
308 gl->SetIsDoubleBuffered(doubleBuffered);
309
310 #ifdef MOZ_WIDGET_GTK
311 if (surface) {
312 const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
313 egl->fSwapInterval(interval);
314 }
315 #endif
316 if (aHardwareWebRender && egl->mLib->IsANGLE()) {
317 MOZ_ASSERT(doubleBuffered);
318 const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
319 egl->fSwapInterval(interval);
320 }
321 return gl.forget();
322 }
323
Create(EGLNativeWindowType aWindow,bool aHardwareWebRender)324 already_AddRefed<GLContext> GLContextEGLFactory::Create(
325 EGLNativeWindowType aWindow, bool aHardwareWebRender) {
326 bool preferGles;
327 #if defined(MOZ_WIDGET_ANDROID)
328 preferGles = true;
329 #else
330 preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup();
331 #endif // defined(MOZ_WIDGET_ANDROID)
332
333 RefPtr<GLContext> glContext =
334 CreateImpl(aWindow, aHardwareWebRender, preferGles);
335 #if !defined(MOZ_WIDGET_ANDROID)
336 if (!glContext) {
337 glContext = CreateImpl(aWindow, aHardwareWebRender, !preferGles);
338 }
339 #endif // !defined(MOZ_WIDGET_ANDROID)
340 return glContext.forget();
341 }
342
343 /* static */
CreateEGLSurfaceForCompositorWidget(widget::CompositorWidget * aCompositorWidget,const EGLConfig aConfig)344 EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
345 widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig) {
346 nsCString discardFailureId;
347 const auto egl = DefaultEglDisplay(&discardFailureId);
348 if (!egl) {
349 gfxCriticalNote << "Failed to load EGL library 6!";
350 return EGL_NO_SURFACE;
351 }
352
353 MOZ_ASSERT(aCompositorWidget);
354 EGLNativeWindowType window =
355 GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
356 if (!window) {
357 gfxCriticalNote << "window is null";
358 return EGL_NO_SURFACE;
359 }
360
361 return mozilla::gl::CreateSurfaceFromNativeWindow(*egl, window, aConfig);
362 }
363
GLContextEGL(const std::shared_ptr<EglDisplay> egl,const GLContextDesc & desc,EGLConfig config,EGLSurface surface,EGLContext context)364 GLContextEGL::GLContextEGL(const std::shared_ptr<EglDisplay> egl,
365 const GLContextDesc& desc, EGLConfig config,
366 EGLSurface surface, EGLContext context)
367 : GLContext(desc, nullptr, false),
368 mEgl(egl),
369 mConfig(config),
370 mContext(context),
371 mSurface(surface),
372 mFallbackSurface(CreateFallbackSurface(*mEgl, mConfig)) {
373 #ifdef DEBUG
374 printf_stderr("Initializing context %p surface %p on display %p\n", mContext,
375 mSurface, mEgl->mDisplay);
376 #endif
377 }
378
OnMarkDestroyed()379 void GLContextEGL::OnMarkDestroyed() {
380 if (mSurfaceOverride != EGL_NO_SURFACE) {
381 SetEGLSurfaceOverride(EGL_NO_SURFACE);
382 }
383 }
384
~GLContextEGL()385 GLContextEGL::~GLContextEGL() {
386 MarkDestroyed();
387
388 // Wrapped context should not destroy eglContext/Surface
389 if (!mOwnsContext) {
390 return;
391 }
392
393 #ifdef DEBUG
394 printf_stderr("Destroying context %p surface %p on display %p\n", mContext,
395 mSurface, mEgl->mDisplay);
396 #endif
397
398 mEgl->fDestroyContext(mContext);
399
400 mozilla::gl::DestroySurface(*mEgl, mSurface);
401 mozilla::gl::DestroySurface(*mEgl, mFallbackSurface);
402 }
403
Init()404 bool GLContextEGL::Init() {
405 if (!GLContext::Init()) return false;
406
407 bool current = MakeCurrent();
408 if (!current) {
409 gfx::LogFailure("Couldn't get device attachments for device."_ns);
410 return false;
411 }
412
413 mShareWithEGLImage =
414 mEgl->HasKHRImageBase() &&
415 mEgl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) &&
416 IsExtensionSupported(OES_EGL_image);
417
418 return true;
419 }
420
BindTexImage()421 bool GLContextEGL::BindTexImage() {
422 if (!mSurface) return false;
423
424 if (mBound && !ReleaseTexImage()) return false;
425
426 EGLBoolean success =
427 mEgl->fBindTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
428 if (success == LOCAL_EGL_FALSE) return false;
429
430 mBound = true;
431 return true;
432 }
433
ReleaseTexImage()434 bool GLContextEGL::ReleaseTexImage() {
435 if (!mBound) return true;
436
437 if (!mSurface) return false;
438
439 EGLBoolean success;
440 success = mEgl->fReleaseTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
441 if (success == LOCAL_EGL_FALSE) return false;
442
443 mBound = false;
444 return true;
445 }
446
SetEGLSurfaceOverride(EGLSurface surf)447 void GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
448 mSurfaceOverride = surf;
449 DebugOnly<bool> ok = MakeCurrent(true);
450 MOZ_ASSERT(ok);
451 }
452
MakeCurrentImpl() const453 bool GLContextEGL::MakeCurrentImpl() const {
454 EGLSurface surface =
455 (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride : mSurface;
456 if (!surface) {
457 surface = mFallbackSurface;
458 }
459
460 const bool succeeded = mEgl->fMakeCurrent(surface, surface, mContext);
461 if (!succeeded) {
462 const auto eglError = mEgl->mLib->fGetError();
463 if (eglError == LOCAL_EGL_CONTEXT_LOST) {
464 OnContextLostError();
465 } else {
466 NS_WARNING("Failed to make GL context current!");
467 #ifdef DEBUG
468 printf_stderr("EGL Error: 0x%04x\n", eglError);
469 #endif
470 }
471 }
472
473 return succeeded;
474 }
475
IsCurrentImpl() const476 bool GLContextEGL::IsCurrentImpl() const {
477 return mEgl->mLib->fGetCurrentContext() == mContext;
478 }
479
RenewSurface(CompositorWidget * aWidget)480 bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
481 if (!mOwnsContext) {
482 return false;
483 }
484 // unconditionally release the surface and create a new one. Don't try to
485 // optimize this away. If we get here, then by definition we know that we want
486 // to get a new surface.
487 ReleaseSurface();
488 MOZ_ASSERT(aWidget);
489
490 EGLNativeWindowType nativeWindow =
491 GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
492 if (nativeWindow) {
493 mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(*mEgl, nativeWindow,
494 mConfig);
495 if (!mSurface) {
496 NS_WARNING("Failed to create EGLSurface from native window");
497 return false;
498 }
499 }
500 const bool ok = MakeCurrent(true);
501 MOZ_ASSERT(ok);
502 #ifdef MOZ_WIDGET_GTK
503 if (mSurface) {
504 const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
505 mEgl->fSwapInterval(interval);
506 }
507 #endif
508 return ok;
509 }
510
ReleaseSurface()511 void GLContextEGL::ReleaseSurface() {
512 if (mOwnsContext) {
513 mozilla::gl::DestroySurface(*mEgl, mSurface);
514 }
515 if (mSurface == mSurfaceOverride) {
516 mSurfaceOverride = EGL_NO_SURFACE;
517 }
518 mSurface = EGL_NO_SURFACE;
519 }
520
GetSymbolLoader() const521 Maybe<SymbolLoader> GLContextEGL::GetSymbolLoader() const {
522 return mEgl->mLib->GetSymbolLoader();
523 }
524
SwapBuffers()525 bool GLContextEGL::SwapBuffers() {
526 EGLSurface surface =
527 mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
528 if (surface) {
529 if ((mEgl->IsExtensionSupported(
530 EGLExtension::EXT_swap_buffers_with_damage) ||
531 mEgl->IsExtensionSupported(
532 EGLExtension::KHR_swap_buffers_with_damage))) {
533 std::vector<EGLint> rects;
534 for (auto iter = mDamageRegion.RectIter(); !iter.Done(); iter.Next()) {
535 const IntRect& r = iter.Get();
536 rects.push_back(r.X());
537 rects.push_back(r.Y());
538 rects.push_back(r.Width());
539 rects.push_back(r.Height());
540 }
541 mDamageRegion.SetEmpty();
542 return mEgl->fSwapBuffersWithDamage(surface, rects.data(),
543 rects.size() / 4);
544 }
545 return mEgl->fSwapBuffers(surface);
546 } else {
547 return false;
548 }
549 }
550
SetDamage(const nsIntRegion & aDamageRegion)551 void GLContextEGL::SetDamage(const nsIntRegion& aDamageRegion) {
552 mDamageRegion = aDamageRegion;
553 }
554
GetWSIInfo(nsCString * const out) const555 void GLContextEGL::GetWSIInfo(nsCString* const out) const {
556 out->AppendLiteral("EGL_VENDOR: ");
557 out->Append(
558 (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VENDOR));
559
560 out->AppendLiteral("\nEGL_VERSION: ");
561 out->Append(
562 (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VERSION));
563
564 out->AppendLiteral("\nEGL_EXTENSIONS: ");
565 out->Append((const char*)mEgl->mLib->fQueryString(mEgl->mDisplay,
566 LOCAL_EGL_EXTENSIONS));
567
568 #ifndef ANDROID // This query will crash some old android.
569 out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
570 out->Append(
571 (const char*)mEgl->mLib->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
572 #endif
573 }
574
HasExtBufferAge() const575 bool GLContextEGL::HasExtBufferAge() const {
576 return mEgl->IsExtensionSupported(EGLExtension::EXT_buffer_age);
577 }
578
HasKhrPartialUpdate() const579 bool GLContextEGL::HasKhrPartialUpdate() const {
580 return mEgl->IsExtensionSupported(EGLExtension::KHR_partial_update);
581 }
582
GetBufferAge() const583 GLint GLContextEGL::GetBufferAge() const {
584 EGLSurface surface =
585 mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
586
587 if (surface && (HasExtBufferAge() || HasKhrPartialUpdate())) {
588 EGLint result;
589 mEgl->fQuerySurface(surface, LOCAL_EGL_BUFFER_AGE_EXT, &result);
590 return result;
591 }
592
593 return 0;
594 }
595
596 #define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
597
CreateGLContext(const std::shared_ptr<EglDisplay> egl,const GLContextDesc & desc,EGLConfig config,EGLSurface surface,const bool useGles,nsACString * const out_failureId)598 RefPtr<GLContextEGL> GLContextEGL::CreateGLContext(
599 const std::shared_ptr<EglDisplay> egl, const GLContextDesc& desc,
600 EGLConfig config, EGLSurface surface, const bool useGles,
601 nsACString* const out_failureId) {
602 const auto& flags = desc.flags;
603
604 std::vector<EGLint> required_attribs;
605
606 if (useGles) {
607 // TODO: This fBindAPI could be more thread-safe
608 if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
609 *out_failureId = "FEATURE_FAILURE_EGL_ES"_ns;
610 NS_WARNING("Failed to bind API to GLES!");
611 return nullptr;
612 }
613 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
614 if (flags & CreateContextFlags::PREFER_ES3) {
615 required_attribs.push_back(3);
616 } else {
617 required_attribs.push_back(2);
618 }
619 } else {
620 if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_API) == LOCAL_EGL_FALSE) {
621 *out_failureId = "FEATURE_FAILURE_EGL"_ns;
622 NS_WARNING("Failed to bind API to GL!");
623 return nullptr;
624 }
625 if (flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE) {
626 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
627 required_attribs.push_back(
628 LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
629 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
630 required_attribs.push_back(2);
631 } else {
632 // !REQUIRE_COMPAT_PROFILE means core profle.
633 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
634 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
635 required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
636 required_attribs.push_back(3);
637 required_attribs.push_back(LOCAL_EGL_CONTEXT_MINOR_VERSION);
638 required_attribs.push_back(2);
639 }
640 }
641
642 if ((flags & CreateContextFlags::PREFER_EXACT_VERSION) &&
643 egl->mLib->IsANGLE()) {
644 required_attribs.push_back(
645 LOCAL_EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
646 required_attribs.push_back(LOCAL_EGL_FALSE);
647 }
648
649 const auto debugFlags = GLContext::ChooseDebugFlags(flags);
650 if (!debugFlags && flags & CreateContextFlags::NO_VALIDATION &&
651 egl->IsExtensionSupported(EGLExtension::KHR_create_context_no_error)) {
652 required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
653 required_attribs.push_back(LOCAL_EGL_TRUE);
654 }
655
656 if (flags & CreateContextFlags::PROVOKING_VERTEX_DONT_CARE &&
657 egl->IsExtensionSupported(
658 EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
659 required_attribs.push_back(
660 LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ);
661 required_attribs.push_back(LOCAL_EGL_TRUE);
662 }
663
664 std::vector<EGLint> ext_robustness_attribs;
665 std::vector<EGLint> ext_rbab_attribs; // RBAB: Robust Buffer Access Behavior
666 std::vector<EGLint> khr_robustness_attribs;
667 std::vector<EGLint> khr_rbab_attribs; // RBAB: Robust Buffer Access Behavior
668 if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
669 std::vector<EGLint> base_robustness_attribs = required_attribs;
670 if (egl->IsExtensionSupported(
671 EGLExtension::NV_robustness_video_memory_purge)) {
672 base_robustness_attribs.push_back(
673 LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
674 base_robustness_attribs.push_back(LOCAL_EGL_TRUE);
675 }
676
677 if (egl->IsExtensionSupported(
678 EGLExtension::EXT_create_context_robustness)) {
679 ext_robustness_attribs = base_robustness_attribs;
680 ext_robustness_attribs.push_back(
681 LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
682 ext_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
683
684 if (gfxVars::AllowEglRbab()) {
685 ext_rbab_attribs = ext_robustness_attribs;
686 ext_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
687 ext_rbab_attribs.push_back(LOCAL_EGL_TRUE);
688 }
689 }
690
691 if (egl->IsExtensionSupported(EGLExtension::KHR_create_context)) {
692 khr_robustness_attribs = base_robustness_attribs;
693 khr_robustness_attribs.push_back(
694 LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
695 khr_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
696
697 khr_rbab_attribs = khr_robustness_attribs;
698 khr_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
699 khr_rbab_attribs.push_back(
700 LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
701 }
702 }
703
704 const auto fnCreate = [&](const std::vector<EGLint>& attribs) {
705 auto terminated_attribs = attribs;
706
707 for (const auto& cur : kTerminationAttribs) {
708 terminated_attribs.push_back(cur);
709 }
710
711 return egl->fCreateContext(config, EGL_NO_CONTEXT,
712 terminated_attribs.data());
713 };
714
715 EGLContext context;
716 do {
717 if (!khr_rbab_attribs.empty()) {
718 context = fnCreate(khr_rbab_attribs);
719 if (context) break;
720 NS_WARNING("Failed to create EGLContext with khr_rbab_attribs");
721 }
722
723 if (!ext_rbab_attribs.empty()) {
724 context = fnCreate(ext_rbab_attribs);
725 if (context) break;
726 NS_WARNING("Failed to create EGLContext with ext_rbab_attribs");
727 }
728
729 if (!khr_robustness_attribs.empty()) {
730 context = fnCreate(khr_robustness_attribs);
731 if (context) break;
732 NS_WARNING("Failed to create EGLContext with khr_robustness_attribs");
733 }
734
735 if (!ext_robustness_attribs.empty()) {
736 context = fnCreate(ext_robustness_attribs);
737 if (context) break;
738 NS_WARNING("Failed to create EGLContext with ext_robustness_attribs");
739 }
740
741 context = fnCreate(required_attribs);
742 if (context) break;
743 NS_WARNING("Failed to create EGLContext with required_attribs");
744
745 *out_failureId = "FEATURE_FAILURE_EGL_CREATE"_ns;
746 return nullptr;
747 } while (false);
748 MOZ_ASSERT(context);
749
750 RefPtr<GLContextEGL> glContext =
751 new GLContextEGL(egl, desc, config, surface, context);
752 if (!glContext->Init()) {
753 *out_failureId = "FEATURE_FAILURE_EGL_INIT"_ns;
754 return nullptr;
755 }
756
757 if (GLContext::ShouldSpew()) {
758 printf_stderr("new GLContextEGL %p on EGLDisplay %p\n", glContext.get(),
759 egl->mDisplay);
760 }
761
762 return glContext;
763 }
764
765 // static
CreatePBufferSurfaceTryingPowerOfTwo(EglDisplay & egl,EGLConfig config,EGLenum bindToTextureFormat,mozilla::gfx::IntSize & pbsize)766 EGLSurface GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
767 EglDisplay& egl, EGLConfig config, EGLenum bindToTextureFormat,
768 mozilla::gfx::IntSize& pbsize) {
769 nsTArray<EGLint> pbattrs(16);
770 EGLSurface surface = nullptr;
771
772 TRY_AGAIN_POWER_OF_TWO:
773 pbattrs.Clear();
774 pbattrs.AppendElement(LOCAL_EGL_WIDTH);
775 pbattrs.AppendElement(pbsize.width);
776 pbattrs.AppendElement(LOCAL_EGL_HEIGHT);
777 pbattrs.AppendElement(pbsize.height);
778
779 if (bindToTextureFormat != LOCAL_EGL_NONE) {
780 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
781 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
782
783 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
784 pbattrs.AppendElement(bindToTextureFormat);
785 }
786
787 for (const auto& cur : kTerminationAttribs) {
788 pbattrs.AppendElement(cur);
789 }
790
791 surface = egl.fCreatePbufferSurface(config, &pbattrs[0]);
792 if (!surface) {
793 if (!is_power_of_two(pbsize.width) || !is_power_of_two(pbsize.height)) {
794 if (!is_power_of_two(pbsize.width))
795 pbsize.width = next_power_of_two(pbsize.width);
796 if (!is_power_of_two(pbsize.height))
797 pbsize.height = next_power_of_two(pbsize.height);
798
799 NS_WARNING("Failed to create pbuffer, trying power of two dims");
800 goto TRY_AGAIN_POWER_OF_TWO;
801 }
802
803 NS_WARNING("Failed to create pbuffer surface");
804 return nullptr;
805 }
806
807 return surface;
808 }
809
810 #if defined(MOZ_WAYLAND)
WaylandGLSurface(struct wl_surface * aWaylandSurface,struct wl_egl_window * aEGLWindow)811 WaylandGLSurface::WaylandGLSurface(struct wl_surface* aWaylandSurface,
812 struct wl_egl_window* aEGLWindow)
813 : mWaylandSurface(aWaylandSurface), mEGLWindow(aEGLWindow) {}
814
~WaylandGLSurface()815 WaylandGLSurface::~WaylandGLSurface() {
816 wl_egl_window_destroy(mEGLWindow);
817 wl_surface_destroy(mWaylandSurface);
818 }
819 #endif
820
821 // static
CreateWaylandBufferSurface(EglDisplay & egl,EGLConfig config,mozilla::gfx::IntSize & pbsize)822 EGLSurface GLContextEGL::CreateWaylandBufferSurface(
823 EglDisplay& egl, EGLConfig config, mozilla::gfx::IntSize& pbsize) {
824 wl_egl_window* eglwindow = nullptr;
825
826 #ifdef MOZ_GTK_WAYLAND
827 struct wl_compositor* compositor =
828 gdk_wayland_display_get_wl_compositor(gdk_display_get_default());
829 struct wl_surface* wlsurface = wl_compositor_create_surface(compositor);
830 eglwindow = wl_egl_window_create(wlsurface, pbsize.width, pbsize.height);
831 #endif
832 if (!eglwindow) return nullptr;
833
834 const auto surface = egl.fCreateWindowSurface(
835 config, reinterpret_cast<EGLNativeWindowType>(eglwindow), 0);
836 if (surface) {
837 #ifdef MOZ_GTK_WAYLAND
838 MOZ_ASSERT(!sWaylandGLSurface.Contains(surface));
839 sWaylandGLSurface.LookupOrInsert(
840 surface, new WaylandGLSurface(wlsurface, eglwindow));
841 #endif
842 }
843
844 return surface;
845 }
846
847 static const EGLint kEGLConfigAttribsRGB16[] = {
848 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
849 LOCAL_EGL_RED_SIZE, 5,
850 LOCAL_EGL_GREEN_SIZE, 6,
851 LOCAL_EGL_BLUE_SIZE, 5,
852 LOCAL_EGL_ALPHA_SIZE, 0};
853
854 static const EGLint kEGLConfigAttribsRGB24[] = {
855 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
856 LOCAL_EGL_RED_SIZE, 8,
857 LOCAL_EGL_GREEN_SIZE, 8,
858 LOCAL_EGL_BLUE_SIZE, 8,
859 LOCAL_EGL_ALPHA_SIZE, 0};
860
861 static const EGLint kEGLConfigAttribsRGBA32[] = {
862 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
863 LOCAL_EGL_RED_SIZE, 8,
864 LOCAL_EGL_GREEN_SIZE, 8,
865 LOCAL_EGL_BLUE_SIZE, 8,
866 LOCAL_EGL_ALPHA_SIZE, 8};
867
CreateConfig(EglDisplay & aEgl,EGLConfig * aConfig,int32_t aDepth,bool aEnableDepthBuffer,bool aUseGles,bool aAllowFallback)868 bool CreateConfig(EglDisplay& aEgl, EGLConfig* aConfig, int32_t aDepth,
869 bool aEnableDepthBuffer, bool aUseGles, bool aAllowFallback) {
870 EGLConfig configs[64];
871 std::vector<EGLint> attribs;
872 EGLint ncfg = ArrayLength(configs);
873
874 switch (aDepth) {
875 case 16:
876 for (const auto& cur : kEGLConfigAttribsRGB16) {
877 attribs.push_back(cur);
878 }
879 break;
880 case 24:
881 for (const auto& cur : kEGLConfigAttribsRGB24) {
882 attribs.push_back(cur);
883 }
884 break;
885 case 32:
886 for (const auto& cur : kEGLConfigAttribsRGBA32) {
887 attribs.push_back(cur);
888 }
889 break;
890 default:
891 NS_ERROR("Unknown pixel depth");
892 return false;
893 }
894
895 if (aUseGles) {
896 attribs.push_back(LOCAL_EGL_RENDERABLE_TYPE);
897 attribs.push_back(LOCAL_EGL_OPENGL_ES2_BIT);
898 }
899 for (const auto& cur : kTerminationAttribs) {
900 attribs.push_back(cur);
901 }
902
903 if (!aEgl.fChooseConfig(attribs.data(), configs, ncfg, &ncfg) || ncfg < 1) {
904 return false;
905 }
906
907 Maybe<EGLConfig> fallbackConfig;
908
909 for (int j = 0; j < ncfg; ++j) {
910 EGLConfig config = configs[j];
911 EGLint r, g, b, a;
912 if (aEgl.fGetConfigAttrib(config, LOCAL_EGL_RED_SIZE, &r) &&
913 aEgl.fGetConfigAttrib(config, LOCAL_EGL_GREEN_SIZE, &g) &&
914 aEgl.fGetConfigAttrib(config, LOCAL_EGL_BLUE_SIZE, &b) &&
915 aEgl.fGetConfigAttrib(config, LOCAL_EGL_ALPHA_SIZE, &a) &&
916 ((aDepth == 16 && r == 5 && g == 6 && b == 5) ||
917 (aDepth == 24 && r == 8 && g == 8 && b == 8) ||
918 (aDepth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) {
919 EGLint z;
920 if (aEnableDepthBuffer) {
921 if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_DEPTH_SIZE, &z) ||
922 z != 24) {
923 continue;
924 }
925 }
926 #ifdef MOZ_X11
927 if (GdkIsX11Display()) {
928 int configVisualID;
929 if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID,
930 &configVisualID)) {
931 continue;
932 }
933
934 XVisualInfo visual_info_template, *visual_info;
935 int num_visuals;
936
937 visual_info_template.visualid = configVisualID;
938 visual_info =
939 XGetVisualInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
940 VisualIDMask, &visual_info_template, &num_visuals);
941
942 if (!visual_info || visual_info->depth != aDepth) {
943 if (aAllowFallback && !fallbackConfig) {
944 fallbackConfig = Some(config);
945 }
946 continue;
947 }
948 }
949 #endif
950 *aConfig = config;
951 return true;
952 }
953 }
954
955 if (kIsX11 && fallbackConfig) {
956 *aConfig = fallbackConfig.value();
957 return true;
958 }
959
960 return false;
961 }
962
963 // Return true if a suitable EGLConfig was found and pass it out
964 // through aConfig. Return false otherwise.
965 //
966 // NB: It's entirely legal for the returned EGLConfig to be valid yet
967 // have the value null.
CreateConfigScreen(EglDisplay & egl,EGLConfig * const aConfig,const bool aEnableDepthBuffer,const bool aUseGles)968 static bool CreateConfigScreen(EglDisplay& egl, EGLConfig* const aConfig,
969 const bool aEnableDepthBuffer,
970 const bool aUseGles) {
971 int32_t depth = gfxVars::ScreenDepth();
972 if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles)) {
973 return true;
974 }
975 #ifdef MOZ_WIDGET_ANDROID
976 // Bug 736005
977 // Android doesn't always support 16 bit so also try 24 bit
978 if (depth == 16) {
979 return CreateConfig(egl, aConfig, 24, aEnableDepthBuffer, aUseGles);
980 }
981 // Bug 970096
982 // Some devices that have 24 bit screens only support 16 bit OpenGL?
983 if (depth == 24) {
984 return CreateConfig(egl, aConfig, 16, aEnableDepthBuffer, aUseGles);
985 }
986 #endif
987 return false;
988 }
989
CreateForCompositorWidget(CompositorWidget * aCompositorWidget,bool aHardwareWebRender,bool)990 already_AddRefed<GLContext> GLContextProviderEGL::CreateForCompositorWidget(
991 CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
992 bool /*aForceAccelerated*/) {
993 EGLNativeWindowType window = nullptr;
994 if (aCompositorWidget) {
995 window = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
996 }
997 return GLContextEGLFactory::Create(window, aHardwareWebRender);
998 }
999
CreateCompatibleSurface(void * aWindow) const1000 EGLSurface GLContextEGL::CreateCompatibleSurface(void* aWindow) const {
1001 MOZ_ASSERT(aWindow);
1002 MOZ_RELEASE_ASSERT(mConfig != EGL_NO_CONFIG);
1003
1004 // NOTE: aWindow is an ANativeWindow
1005 EGLSurface surface = mEgl->fCreateWindowSurface(
1006 mConfig, reinterpret_cast<EGLNativeWindowType>(aWindow), nullptr);
1007 if (!surface) {
1008 gfxCriticalError() << "CreateCompatibleSurface failed: "
1009 << hexa(GetError());
1010 }
1011 return surface;
1012 }
1013
FillContextAttribs(bool es3,bool useGles,nsTArray<EGLint> * out)1014 static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
1015 out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
1016 #ifdef MOZ_GTK_WAYLAND
1017 if (GdkIsWaylandDisplay()) {
1018 // Wayland on desktop does not support PBuffer or FBO.
1019 // We create a dummy wl_egl_window instead.
1020 out->AppendElement(LOCAL_EGL_WINDOW_BIT);
1021 } else
1022 #endif
1023 {
1024 out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
1025 }
1026
1027 if (useGles) {
1028 out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE);
1029 if (es3) {
1030 out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR);
1031 } else {
1032 out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
1033 }
1034 }
1035
1036 out->AppendElement(LOCAL_EGL_RED_SIZE);
1037 out->AppendElement(8);
1038
1039 out->AppendElement(LOCAL_EGL_GREEN_SIZE);
1040 out->AppendElement(8);
1041
1042 out->AppendElement(LOCAL_EGL_BLUE_SIZE);
1043 out->AppendElement(8);
1044
1045 out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
1046 out->AppendElement(8);
1047
1048 out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
1049 out->AppendElement(0);
1050
1051 out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
1052 out->AppendElement(0);
1053
1054 // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
1055 out->AppendElement(LOCAL_EGL_NONE);
1056 out->AppendElement(0);
1057
1058 out->AppendElement(0);
1059 out->AppendElement(0);
1060 }
1061
1062 /*
1063 /// Useful for debugging, but normally unused.
1064 static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) {
1065 EGLint bits = 0;
1066 egl->fGetConfigAttrib(config, attrib, &bits);
1067 MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
1068
1069 return bits;
1070 }
1071 */
1072
ChooseConfig(EglDisplay & egl,const GLContextCreateDesc & desc,const bool useGles)1073 static EGLConfig ChooseConfig(EglDisplay& egl, const GLContextCreateDesc& desc,
1074 const bool useGles) {
1075 nsTArray<EGLint> configAttribList;
1076 FillContextAttribs(bool(desc.flags & CreateContextFlags::PREFER_ES3), useGles,
1077 &configAttribList);
1078
1079 const EGLint* configAttribs = configAttribList.Elements();
1080
1081 // The sorting dictated by the spec for eglChooseConfig reasonably assures
1082 // that a reasonable 'best' config is on top.
1083 const EGLint kMaxConfigs = 1;
1084 EGLConfig configs[kMaxConfigs];
1085 EGLint foundConfigs = 0;
1086 if (!egl.fChooseConfig(configAttribs, configs, kMaxConfigs, &foundConfigs) ||
1087 foundConfigs == 0) {
1088 return EGL_NO_CONFIG;
1089 }
1090
1091 EGLConfig config = configs[0];
1092 return config;
1093 }
1094
1095 #ifdef MOZ_X11
1096 /* static */
FindVisual(int * const out_visualId)1097 bool GLContextEGL::FindVisual(int* const out_visualId) {
1098 nsCString discardFailureId;
1099 const auto egl = DefaultEglDisplay(&discardFailureId);
1100 if (!egl) {
1101 gfxCriticalNote
1102 << "GLContextEGL::FindVisual(): Failed to load EGL library!";
1103 return false;
1104 }
1105
1106 EGLConfig config;
1107 const int bpp = 32;
1108 if (!CreateConfig(*egl, &config, bpp, /* aEnableDepthBuffer */ false,
1109 /* aUseGles */ false, /* aAllowFallback */ false)) {
1110 // We are on a buggy driver. Do not return a visual so a fallback path can
1111 // be used. See https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
1112 return false;
1113 }
1114 if (egl->fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, out_visualId)) {
1115 return true;
1116 }
1117 return false;
1118 }
1119 #endif
1120
1121 /*static*/
CreateEGLPBufferOffscreenContextImpl(const std::shared_ptr<EglDisplay> egl,const GLContextCreateDesc & desc,const mozilla::gfx::IntSize & size,const bool useGles,nsACString * const out_failureId)1122 RefPtr<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContextImpl(
1123 const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc,
1124 const mozilla::gfx::IntSize& size, const bool useGles,
1125 nsACString* const out_failureId) {
1126 const EGLConfig config = ChooseConfig(*egl, desc, useGles);
1127 if (config == EGL_NO_CONFIG) {
1128 *out_failureId = "FEATURE_FAILURE_EGL_NO_CONFIG"_ns;
1129 NS_WARNING("Failed to find a compatible config.");
1130 return nullptr;
1131 }
1132
1133 if (GLContext::ShouldSpew()) {
1134 egl->DumpEGLConfig(config);
1135 }
1136
1137 mozilla::gfx::IntSize pbSize(size);
1138 EGLSurface surface = nullptr;
1139 #ifdef MOZ_GTK_WAYLAND
1140 if (GdkIsWaylandDisplay()) {
1141 surface = GLContextEGL::CreateWaylandBufferSurface(*egl, config, pbSize);
1142 } else
1143 #endif
1144 {
1145 surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
1146 *egl, config, LOCAL_EGL_NONE, pbSize);
1147 }
1148 if (!surface) {
1149 *out_failureId = "FEATURE_FAILURE_EGL_POT"_ns;
1150 NS_WARNING("Failed to create PBuffer for context!");
1151 return nullptr;
1152 }
1153
1154 auto fullDesc = GLContextDesc{desc};
1155 fullDesc.isOffscreen = true;
1156 RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
1157 egl, fullDesc, config, surface, useGles, out_failureId);
1158 if (!gl) {
1159 NS_WARNING("Failed to create GLContext from PBuffer");
1160 egl->fDestroySurface(surface);
1161 #if defined(MOZ_WAYLAND)
1162 DeleteWaylandGLSurface(surface);
1163 #endif
1164 return nullptr;
1165 }
1166
1167 return gl;
1168 }
1169
1170 /*static*/
CreateEGLPBufferOffscreenContext(const std::shared_ptr<EglDisplay> display,const GLContextCreateDesc & desc,const mozilla::gfx::IntSize & size,nsACString * const out_failureId)1171 RefPtr<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContext(
1172 const std::shared_ptr<EglDisplay> display, const GLContextCreateDesc& desc,
1173 const mozilla::gfx::IntSize& size, nsACString* const out_failureId) {
1174 bool preferGles;
1175 #if defined(MOZ_WIDGET_ANDROID)
1176 preferGles = true;
1177 #else
1178 preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup();
1179 #endif // defined(MOZ_WIDGET_ANDROID)
1180
1181 RefPtr<GLContextEGL> gl = CreateEGLPBufferOffscreenContextImpl(
1182 display, desc, size, preferGles, out_failureId);
1183 #if !defined(MOZ_WIDGET_ANDROID)
1184 if (!gl) {
1185 gl = CreateEGLPBufferOffscreenContextImpl(display, desc, size, !preferGles,
1186 out_failureId);
1187 }
1188 #endif // !defined(MOZ_WIDGET_ANDROID)
1189 return gl;
1190 }
1191
1192 /*static*/
CreateHeadless(const GLContextCreateDesc & desc,nsACString * const out_failureId)1193 already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless(
1194 const GLContextCreateDesc& desc, nsACString* const out_failureId) {
1195 const auto display = DefaultEglDisplay(out_failureId);
1196 if (!display) {
1197 return nullptr;
1198 }
1199 mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
1200 auto ret = GLContextEGL::CreateEGLPBufferOffscreenContext(
1201 display, desc, dummySize, out_failureId);
1202 return ret.forget();
1203 }
1204
1205 // Don't want a global context on Android as 1) share groups across 2 threads
1206 // fail on many Tegra drivers (bug 759225) and 2) some mobile devices have a
1207 // very strict limit on global number of GL contexts (bug 754257) and 3) each
1208 // EGL context eats 750k on B2G (bug 813783)
1209 /*static*/
GetGlobalContext()1210 GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; }
1211
1212 // -
1213
1214 static StaticMutex sMutex;
1215 static StaticRefPtr<GLLibraryEGL> gDefaultEglLibrary;
1216
DefaultEglLibrary(nsACString * const out_failureId)1217 RefPtr<GLLibraryEGL> DefaultEglLibrary(nsACString* const out_failureId) {
1218 StaticMutexAutoLock lock(sMutex);
1219 if (!gDefaultEglLibrary) {
1220 gDefaultEglLibrary = GLLibraryEGL::Create(out_failureId);
1221 if (!gDefaultEglLibrary) {
1222 NS_WARNING("GLLibraryEGL::Create failed");
1223 }
1224 }
1225 return gDefaultEglLibrary.get();
1226 }
1227
1228 // -
1229
1230 /*static*/
Shutdown()1231 void GLContextProviderEGL::Shutdown() {
1232 StaticMutexAutoLock lock(sMutex);
1233 if (!gDefaultEglLibrary) {
1234 return;
1235 }
1236 gDefaultEglLibrary = nullptr;
1237 }
1238
1239 } /* namespace gl */
1240 } /* namespace mozilla */
1241
1242 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
1243