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