Bug 1728955: part 6) Log result of Windows' `OleSetClipboardResult`. r=masayuki
[gecko.git] / gfx / gl / GLLibraryEGL.cpp
blob94371ec92234574ca11c9883914ba4bb005121d2
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "GLLibraryEGL.h"
7 #include "gfxConfig.h"
8 #include "gfxCrashReporterUtils.h"
9 #include "gfxEnv.h"
10 #include "gfxUtils.h"
11 #include "mozilla/Preferences.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/gfx/gfxVars.h"
14 #include "mozilla/gfx/Logging.h"
15 #include "mozilla/Telemetry.h"
16 #include "mozilla/Tokenizer.h"
17 #include "mozilla/ScopeExit.h"
18 #include "mozilla/StaticPrefs_gfx.h"
19 #include "mozilla/StaticPrefs_webgl.h"
20 #include "mozilla/Unused.h"
21 #include "mozilla/webrender/RenderThread.h"
22 #include "nsDirectoryServiceDefs.h"
23 #include "nsDirectoryServiceUtils.h"
24 #include "nsPrintfCString.h"
25 #ifdef XP_WIN
26 # include "mozilla/gfx/DeviceManagerDx.h"
27 # include "nsWindowsHelpers.h"
29 # include <d3d11.h>
30 #endif
31 #include "OGLShaderProgram.h"
32 #include "prenv.h"
33 #include "prsystem.h"
34 #include "GLContext.h"
35 #include "GLContextProvider.h"
36 #include "GLLibraryLoader.h"
37 #include "GLReadTexImageHelper.h"
38 #include "ScopedGLHelpers.h"
39 #ifdef MOZ_WIDGET_GTK
40 # include "mozilla/WidgetUtilsGtk.h"
41 # ifdef MOZ_WAYLAND
42 # include "mozilla/widget/nsWaylandDisplay.h"
43 # endif // MOZ_WIDGET_GTK
44 # include <gdk/gdk.h>
45 #endif // MOZ_WAYLAND
47 #include <mutex> // for call_once
49 namespace mozilla {
50 namespace gl {
52 // should match the order of EGLExtensions, and be null-terminated.
53 static const char* sEGLLibraryExtensionNames[] = {
54 "EGL_ANDROID_get_native_client_buffer", "EGL_ANGLE_device_creation",
55 "EGL_ANGLE_device_creation_d3d11", "EGL_ANGLE_platform_angle",
56 "EGL_ANGLE_platform_angle_d3d"};
58 // should match the order of EGLExtensions, and be null-terminated.
59 static const char* sEGLExtensionNames[] = {
60 "EGL_KHR_image_base",
61 "EGL_KHR_image_pixmap",
62 "EGL_KHR_gl_texture_2D_image",
63 "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
64 "EGL_EXT_create_context_robustness",
65 "EGL_KHR_image",
66 "EGL_KHR_fence_sync",
67 "EGL_KHR_wait_sync",
68 "EGL_ANDROID_native_fence_sync",
69 "EGL_ANDROID_image_crop",
70 "EGL_ANGLE_d3d_share_handle_client_buffer",
71 "EGL_KHR_create_context",
72 "EGL_KHR_stream",
73 "EGL_KHR_stream_consumer_gltexture",
74 "EGL_EXT_device_query",
75 "EGL_NV_stream_consumer_gltexture_yuv",
76 "EGL_ANGLE_stream_producer_d3d_texture",
77 "EGL_KHR_surfaceless_context",
78 "EGL_KHR_create_context_no_error",
79 "EGL_MOZ_create_context_provoking_vertex_dont_care",
80 "EGL_EXT_swap_buffers_with_damage",
81 "EGL_KHR_swap_buffers_with_damage",
82 "EGL_EXT_buffer_age",
83 "EGL_KHR_partial_update",
84 "EGL_NV_robustness_video_memory_purge"};
86 PRLibrary* LoadApitraceLibrary() {
87 const char* path = nullptr;
89 #ifdef ANDROID
90 // We only need to explicitly dlopen egltrace
91 // on android as we can use LD_PRELOAD or other tricks
92 // on other platforms. We look for it in /data/local
93 // as that's writeable by all users.
94 path = "/data/local/tmp/egltrace.so";
95 #endif
96 if (!path) return nullptr;
98 // Initialization of gfx prefs here is only needed during the unit tests...
99 if (!StaticPrefs::gfx_apitrace_enabled_AtStartup()) {
100 return nullptr;
103 static PRLibrary* sApitraceLibrary = nullptr;
104 if (sApitraceLibrary) return sApitraceLibrary;
106 nsAutoCString logFile;
107 Preferences::GetCString("gfx.apitrace.logfile", logFile);
108 if (logFile.IsEmpty()) {
109 logFile = "firefox.trace";
112 // The firefox process can't write to /data/local, but it can write
113 // to $GRE_HOME/
114 nsAutoCString logPath;
115 logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get());
117 #ifndef XP_WIN // Windows is missing setenv and forbids PR_LoadLibrary.
118 // apitrace uses the TRACE_FILE environment variable to determine where
119 // to log trace output to
120 printf_stderr("Logging GL tracing output to %s", logPath.get());
121 setenv("TRACE_FILE", logPath.get(), false);
123 printf_stderr("Attempting load of %s\n", path);
124 sApitraceLibrary = PR_LoadLibrary(path);
125 #endif
127 return sApitraceLibrary;
130 #ifdef XP_WIN
131 // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
132 static PRLibrary* LoadLibraryForEGLOnWindows(const nsAString& filename) {
133 nsAutoString path(gfx::gfxVars::GREDirectory());
134 path.Append(PR_GetDirectorySeparator());
135 path.Append(filename);
137 PRLibSpec lspec;
138 lspec.type = PR_LibSpec_PathnameU;
139 lspec.value.pathname_u = path.get();
140 return PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
143 #endif // XP_WIN
145 static std::shared_ptr<EglDisplay> GetAndInitDisplay(GLLibraryEGL& egl,
146 void* displayType) {
147 const auto display = egl.fGetDisplay(displayType);
148 if (!display) return nullptr;
149 return EglDisplay::Create(egl, display, false);
152 static std::shared_ptr<EglDisplay> GetAndInitWARPDisplay(GLLibraryEGL& egl,
153 void* displayType) {
154 const EGLAttrib attrib_list[] = {
155 LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
156 LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
157 // Requires:
158 LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
159 LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, LOCAL_EGL_NONE};
160 const EGLDisplay display = egl.fGetPlatformDisplay(
161 LOCAL_EGL_PLATFORM_ANGLE_ANGLE, displayType, attrib_list);
163 if (display == EGL_NO_DISPLAY) {
164 const EGLint err = egl.fGetError();
165 if (err != LOCAL_EGL_SUCCESS) {
166 gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
167 MOZ_CRASH("GFX: Unexpected GL error.");
169 return nullptr;
172 return EglDisplay::Create(egl, display, true);
175 std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
176 ID3D11Device* const d3d11Device) {
177 EGLDeviceEXT eglDevice =
178 fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE, d3d11Device, nullptr);
179 if (!eglDevice) {
180 gfxCriticalNote << "Failed to get EGLDeviceEXT of D3D11Device";
181 return nullptr;
183 const char* features[] = {"allowES3OnFL10_0", nullptr};
184 // Create an EGLDisplay using the EGLDevice
185 const EGLAttrib attrib_list[] = {LOCAL_EGL_FEATURE_OVERRIDES_ENABLED_ANGLE,
186 reinterpret_cast<EGLAttrib>(features),
187 LOCAL_EGL_NONE};
188 const auto display = fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT,
189 eglDevice, attrib_list);
190 if (!display) {
191 gfxCriticalNote << "Failed to get EGLDisplay of D3D11Device";
192 return nullptr;
195 if (!display) {
196 const EGLint err = fGetError();
197 if (err != LOCAL_EGL_SUCCESS) {
198 gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
199 MOZ_CRASH("GFX: Unexpected GL error.");
201 return nullptr;
204 const auto ret = EglDisplay::Create(*this, display, false);
206 if (!ret) {
207 const EGLint err = fGetError();
208 if (err != LOCAL_EGL_SUCCESS) {
209 gfxCriticalError()
210 << "Failed to initialize EGLDisplay for WebRender error: "
211 << gfx::hexa(err);
213 return nullptr;
215 return ret;
218 static bool IsAccelAngleSupported(nsACString* const out_failureId) {
219 if (wr::RenderThread::IsInRenderThread()) {
220 // We can only enter here with WebRender, so assert that this is a
221 // WebRender-enabled build.
222 return true;
224 if (!gfx::gfxVars::AllowWebglAccelAngle()) {
225 if (out_failureId->IsEmpty()) {
226 *out_failureId = "FEATURE_FAILURE_ACCL_ANGLE_NOT_OK"_ns;
228 return false;
230 return true;
233 class AngleErrorReporting {
234 public:
235 AngleErrorReporting() : mFailureId(nullptr) {
236 // No static constructor
239 void SetFailureId(nsACString* const aFailureId) { mFailureId = aFailureId; }
241 void logError(const char* errorMessage) {
242 if (!mFailureId) {
243 return;
246 nsCString str(errorMessage);
247 Tokenizer tokenizer(str);
249 // Parse "ANGLE Display::initialize error " << error.getID() << ": "
250 // << error.getMessage()
251 nsCString currWord;
252 Tokenizer::Token intToken;
253 if (tokenizer.CheckWord("ANGLE") && tokenizer.CheckWhite() &&
254 tokenizer.CheckWord("Display") && tokenizer.CheckChar(':') &&
255 tokenizer.CheckChar(':') && tokenizer.CheckWord("initialize") &&
256 tokenizer.CheckWhite() && tokenizer.CheckWord("error") &&
257 tokenizer.CheckWhite() &&
258 tokenizer.Check(Tokenizer::TOKEN_INTEGER, intToken)) {
259 *mFailureId = "FAILURE_ID_ANGLE_ID_";
260 mFailureId->AppendPrintf("%" PRIu64, intToken.AsInteger());
261 } else {
262 *mFailureId = "FAILURE_ID_ANGLE_UNKNOWN";
266 private:
267 nsACString* mFailureId;
270 AngleErrorReporting gAngleErrorReporter;
272 static std::shared_ptr<EglDisplay> GetAndInitDisplayForAccelANGLE(
273 GLLibraryEGL& egl, nsACString* const out_failureId) {
274 MOZ_RELEASE_ASSERT(!wr::RenderThread::IsInRenderThread());
276 gfx::FeatureState& d3d11ANGLE =
277 gfx::gfxConfig::GetFeature(gfx::Feature::D3D11_HW_ANGLE);
279 if (!StaticPrefs::webgl_angle_try_d3d11()) {
280 d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref",
281 "FAILURE_ID_ANGLE_PREF"_ns);
283 if (StaticPrefs::webgl_angle_force_d3d11()) {
284 d3d11ANGLE.UserForceEnable(
285 "User force-enabled D3D11 ANGLE on disabled hardware");
287 gAngleErrorReporter.SetFailureId(out_failureId);
289 auto guardShutdown = mozilla::MakeScopeExit([&] {
290 gAngleErrorReporter.SetFailureId(nullptr);
291 // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the
292 // ANGLE display is destroyed. However gAngleErrorReporter
293 // will live longer than the ANGLE display so we're fine.
296 if (gfx::gfxConfig::IsForcedOnByUser(gfx::Feature::D3D11_HW_ANGLE)) {
297 return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
300 std::shared_ptr<EglDisplay> ret;
301 if (d3d11ANGLE.IsEnabled()) {
302 ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
305 if (!ret) {
306 ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY);
309 if (!ret && out_failureId->IsEmpty()) {
310 *out_failureId = "FEATURE_FAILURE_ACCL_ANGLE_NO_DISP"_ns;
313 return ret;
316 // -
318 #if defined(XP_UNIX)
319 # define GLES2_LIB "libGLESv2.so"
320 # define GLES2_LIB2 "libGLESv2.so.2"
321 # define GL_LIB "libGL.so"
322 # define GL_LIB2 "libGL.so.1"
323 #elif defined(XP_WIN)
324 # define GLES2_LIB "libGLESv2.dll"
325 #else
326 # error "Platform not recognized"
327 #endif
329 Maybe<SymbolLoader> GLLibraryEGL::GetSymbolLoader() const {
330 auto ret = SymbolLoader(mSymbols.fGetProcAddress);
331 ret.mLib = mGLLibrary;
332 return Some(ret);
335 // -
337 /* static */
338 RefPtr<GLLibraryEGL> GLLibraryEGL::Create(nsACString* const out_failureId) {
339 RefPtr<GLLibraryEGL> ret = new GLLibraryEGL;
340 if (!ret->Init(out_failureId)) {
341 return nullptr;
343 return ret;
346 bool GLLibraryEGL::Init(nsACString* const out_failureId) {
347 MOZ_RELEASE_ASSERT(!mSymbols.fTerminate);
349 mozilla::ScopedGfxFeatureReporter reporter("EGL");
351 #ifdef XP_WIN
352 if (!mEGLLibrary) {
353 // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul
354 // and we should look for them there. We have to load the libs in this
355 // order, because libEGL.dll depends on libGLESv2.dll which depends on the
356 // DXSDK libraries. This matters especially for WebRT apps which are in a
357 // different directory. See bug 760323 and bug 749459
359 // Also note that we intentionally leak the libs we load.
361 do {
362 // Windows 8.1+ has d3dcompiler_47.dll in the system directory.
363 // Try it first. Note that _46 will never be in the system
364 // directory. So there is no point trying _46 in the system
365 // directory.
367 if (LoadLibrarySystem32(L"d3dcompiler_47.dll")) break;
369 # ifdef MOZ_D3DCOMPILER_VISTA_DLL
370 if (LoadLibraryForEGLOnWindows(NS_LITERAL_STRING_FROM_CSTRING(
371 MOZ_STRINGIFY(MOZ_D3DCOMPILER_VISTA_DLL))))
372 break;
373 # endif
375 MOZ_ASSERT(false, "d3dcompiler DLL loading failed.");
376 } while (false);
378 mGLLibrary = LoadLibraryForEGLOnWindows(u"libGLESv2.dll"_ns);
380 mEGLLibrary = LoadLibraryForEGLOnWindows(u"libEGL.dll"_ns);
383 #else // !Windows
385 // On non-Windows (Android) we use system copies of libEGL. We look for
386 // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
388 # if defined(ANDROID)
389 if (!mEGLLibrary) mEGLLibrary = LoadApitraceLibrary();
390 # endif
392 if (!mEGLLibrary) {
393 mEGLLibrary = PR_LoadLibrary("libEGL.so");
395 # if defined(XP_UNIX)
396 if (!mEGLLibrary) {
397 mEGLLibrary = PR_LoadLibrary("libEGL.so.1");
399 # endif
401 # ifdef APITRACE_LIB
402 if (!mGLLibrary) {
403 mGLLibrary = PR_LoadLibrary(APITRACE_LIB);
405 # endif
407 # ifdef GL_LIB
408 if (!mGLLibrary) {
409 mGLLibrary = PR_LoadLibrary(GL_LIB);
411 # endif
413 # ifdef GL_LIB2
414 if (!mGLLibrary) {
415 mGLLibrary = PR_LoadLibrary(GL_LIB2);
417 # endif
419 if (!mGLLibrary) {
420 mGLLibrary = PR_LoadLibrary(GLES2_LIB);
423 # ifdef GLES2_LIB2
424 if (!mGLLibrary) {
425 mGLLibrary = PR_LoadLibrary(GLES2_LIB2);
427 # endif
429 #endif // !Windows
431 if (!mEGLLibrary || !mGLLibrary) {
432 NS_WARNING("Couldn't load EGL LIB.");
433 *out_failureId = "FEATURE_FAILURE_EGL_LOAD_3"_ns;
434 return false;
437 #define SYMBOL(X) \
439 (PRFuncPtr*)&mSymbols.f##X, { \
440 { "egl" #X } \
443 #define END_OF_SYMBOLS \
445 nullptr, {} \
448 SymLoadStruct earlySymbols[] = {SYMBOL(GetDisplay),
449 SYMBOL(Terminate),
450 SYMBOL(GetCurrentSurface),
451 SYMBOL(GetCurrentContext),
452 SYMBOL(MakeCurrent),
453 SYMBOL(DestroyContext),
454 SYMBOL(CreateContext),
455 SYMBOL(DestroySurface),
456 SYMBOL(CreateWindowSurface),
457 SYMBOL(CreatePbufferSurface),
458 SYMBOL(CreatePbufferFromClientBuffer),
459 SYMBOL(CreatePixmapSurface),
460 SYMBOL(BindAPI),
461 SYMBOL(Initialize),
462 SYMBOL(ChooseConfig),
463 SYMBOL(GetError),
464 SYMBOL(GetConfigs),
465 SYMBOL(GetConfigAttrib),
466 SYMBOL(WaitNative),
467 SYMBOL(GetProcAddress),
468 SYMBOL(SwapBuffers),
469 SYMBOL(CopyBuffers),
470 SYMBOL(QueryString),
471 SYMBOL(QueryContext),
472 SYMBOL(BindTexImage),
473 SYMBOL(ReleaseTexImage),
474 SYMBOL(SwapInterval),
475 SYMBOL(QuerySurface),
476 END_OF_SYMBOLS};
479 const SymbolLoader libLoader(*mEGLLibrary);
480 if (!libLoader.LoadSymbols(earlySymbols)) {
481 NS_WARNING(
482 "Couldn't find required entry points in EGL library (early init)");
483 *out_failureId = "FEATURE_FAILURE_EGL_SYM"_ns;
484 return false;
489 const char internalFuncName[] =
490 "_Z35eglQueryStringImplementationANDROIDPvi";
491 const auto& internalFunc =
492 PR_FindFunctionSymbol(mEGLLibrary, internalFuncName);
493 if (internalFunc) {
494 *(PRFuncPtr*)&mSymbols.fQueryString = internalFunc;
498 // -
500 InitLibExtensions();
502 const SymbolLoader pfnLoader(mSymbols.fGetProcAddress);
504 const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) {
505 const bool shouldWarn = gfxEnv::GlSpew();
506 if (pfnLoader.LoadSymbols(symbols, shouldWarn)) return true;
508 ClearSymbols(symbols);
509 return false;
512 // Check the ANGLE support the system has
513 mIsANGLE = IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle);
515 // Client exts are ready. (But not display exts!)
517 if (mIsANGLE) {
518 MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d));
519 const SymLoadStruct angleSymbols[] = {SYMBOL(GetPlatformDisplay),
520 END_OF_SYMBOLS};
521 if (!fnLoadSymbols(angleSymbols)) {
522 gfxCriticalError() << "Failed to load ANGLE symbols!";
523 return false;
525 MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d));
526 const SymLoadStruct createDeviceSymbols[] = {
527 SYMBOL(CreateDeviceANGLE), SYMBOL(ReleaseDeviceANGLE), END_OF_SYMBOLS};
528 if (!fnLoadSymbols(createDeviceSymbols)) {
529 NS_ERROR(
530 "EGL supports ANGLE_device_creation without exposing its functions!");
531 MarkExtensionUnsupported(EGLLibExtension::ANGLE_device_creation);
535 // ANDROID_get_native_client_buffer isn't necessarily enumerated in lib exts,
536 // but it is one.
538 const SymLoadStruct symbols[] = {SYMBOL(GetNativeClientBufferANDROID),
539 END_OF_SYMBOLS};
540 if (fnLoadSymbols(symbols)) {
541 mAvailableExtensions[UnderlyingValue(
542 EGLLibExtension::ANDROID_get_native_client_buffer)] = true;
546 // -
547 // Load possible display ext symbols.
550 const SymLoadStruct symbols[] = {SYMBOL(QuerySurfacePointerANGLE),
551 END_OF_SYMBOLS};
552 (void)fnLoadSymbols(symbols);
555 const SymLoadStruct symbols[] = {
556 SYMBOL(CreateSyncKHR), SYMBOL(DestroySyncKHR),
557 SYMBOL(ClientWaitSyncKHR), SYMBOL(GetSyncAttribKHR), END_OF_SYMBOLS};
558 (void)fnLoadSymbols(symbols);
561 const SymLoadStruct symbols[] = {SYMBOL(CreateImageKHR),
562 SYMBOL(DestroyImageKHR), END_OF_SYMBOLS};
563 (void)fnLoadSymbols(symbols);
566 const SymLoadStruct symbols[] = {SYMBOL(WaitSyncKHR), END_OF_SYMBOLS};
567 (void)fnLoadSymbols(symbols);
570 const SymLoadStruct symbols[] = {SYMBOL(DupNativeFenceFDANDROID),
571 END_OF_SYMBOLS};
572 (void)fnLoadSymbols(symbols);
575 const SymLoadStruct symbols[] = {SYMBOL(CreateStreamKHR),
576 SYMBOL(DestroyStreamKHR),
577 SYMBOL(QueryStreamKHR), END_OF_SYMBOLS};
578 (void)fnLoadSymbols(symbols);
581 const SymLoadStruct symbols[] = {SYMBOL(StreamConsumerGLTextureExternalKHR),
582 SYMBOL(StreamConsumerAcquireKHR),
583 SYMBOL(StreamConsumerReleaseKHR),
584 END_OF_SYMBOLS};
585 (void)fnLoadSymbols(symbols);
588 const SymLoadStruct symbols[] = {SYMBOL(QueryDisplayAttribEXT),
589 SYMBOL(QueryDeviceAttribEXT),
590 END_OF_SYMBOLS};
591 (void)fnLoadSymbols(symbols);
594 const SymLoadStruct symbols[] = {
595 SYMBOL(StreamConsumerGLTextureExternalAttribsNV), END_OF_SYMBOLS};
596 (void)fnLoadSymbols(symbols);
599 const SymLoadStruct symbols[] = {
600 SYMBOL(CreateStreamProducerD3DTextureANGLE),
601 SYMBOL(StreamPostD3DTextureANGLE), END_OF_SYMBOLS};
602 (void)fnLoadSymbols(symbols);
605 const SymLoadStruct symbols[] = {
606 {(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage,
607 {{"eglSwapBuffersWithDamageEXT"}}},
608 END_OF_SYMBOLS};
609 (void)fnLoadSymbols(symbols);
612 const SymLoadStruct symbols[] = {
613 {(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage,
614 {{"eglSwapBuffersWithDamageKHR"}}},
615 END_OF_SYMBOLS};
616 (void)fnLoadSymbols(symbols);
619 const SymLoadStruct symbols[] = {
620 {(PRFuncPtr*)&mSymbols.fSetDamageRegion, {{"eglSetDamageRegionKHR"}}},
621 END_OF_SYMBOLS};
622 (void)fnLoadSymbols(symbols);
625 return true;
628 // -
630 template <size_t N>
631 static void MarkExtensions(const char* rawExtString, bool shouldDumpExts,
632 const char* extType, const char* const (&names)[N],
633 std::bitset<N>* const out) {
634 MOZ_ASSERT(rawExtString);
636 const nsDependentCString extString(rawExtString);
638 std::vector<nsCString> extList;
639 SplitByChar(extString, ' ', &extList);
641 if (shouldDumpExts) {
642 printf_stderr("%u EGL %s extensions: (*: recognized)\n",
643 (uint32_t)extList.size(), extType);
646 MarkBitfieldByStrings(extList, shouldDumpExts, names, out);
649 // -
651 // static
652 std::shared_ptr<EglDisplay> EglDisplay::Create(GLLibraryEGL& lib,
653 const EGLDisplay display,
654 const bool isWarp) {
655 // Retrieve the EglDisplay if it already exists
657 const auto itr = lib.mActiveDisplays.find(display);
658 if (itr != lib.mActiveDisplays.end()) {
659 const auto ret = itr->second.lock();
660 if (ret) {
661 return ret;
666 if (!lib.fInitialize(display, nullptr, nullptr)) {
667 return nullptr;
670 static std::once_flag sMesaLeakFlag;
671 std::call_once(sMesaLeakFlag, MesaMemoryLeakWorkaround);
673 const auto ret =
674 std::make_shared<EglDisplay>(PrivateUseOnly{}, lib, display, isWarp);
675 lib.mActiveDisplays.insert({display, ret});
676 return ret;
679 EglDisplay::EglDisplay(const PrivateUseOnly&, GLLibraryEGL& lib,
680 const EGLDisplay disp, const bool isWarp)
681 : mLib(&lib), mDisplay(disp), mIsWARP(isWarp) {
682 const bool shouldDumpExts = GLContext::ShouldDumpExts();
684 auto rawExtString =
685 (const char*)mLib->fQueryString(mDisplay, LOCAL_EGL_EXTENSIONS);
686 if (!rawExtString) {
687 NS_WARNING("Failed to query EGL display extensions!.");
688 rawExtString = "";
690 MarkExtensions(rawExtString, shouldDumpExts, "display", sEGLExtensionNames,
691 &mAvailableExtensions);
693 // -
695 if (!HasKHRImageBase()) {
696 MarkExtensionUnsupported(EGLExtension::KHR_image_pixmap);
699 if (IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
700 const auto vendor =
701 (const char*)mLib->fQueryString(mDisplay, LOCAL_EGL_VENDOR);
703 // Bug 1464610: Mali T720 (Amazon Fire 8 HD) claims to support this
704 // extension, but if you actually eglMakeCurrent() with EGL_NO_SURFACE, it
705 // fails to render anything when a real surface is provided later on. We
706 // only have the EGL vendor available here, so just avoid using this
707 // extension on all Mali devices.
708 if (strcmp(vendor, "ARM") == 0) {
709 MarkExtensionUnsupported(EGLExtension::KHR_surfaceless_context);
713 // ANDROID_native_fence_sync isn't necessarily enumerated in display ext,
714 // but it is one.
715 if (mLib->mSymbols.fDupNativeFenceFDANDROID) {
716 mAvailableExtensions[UnderlyingValue(
717 EGLExtension::ANDROID_native_fence_sync)] = true;
721 EglDisplay::~EglDisplay() {
722 fTerminate();
723 mLib->mActiveDisplays.erase(mDisplay);
726 // -
728 std::shared_ptr<EglDisplay> GLLibraryEGL::DefaultDisplay(
729 nsACString* const out_failureId) {
730 auto ret = mDefaultDisplay.lock();
731 if (ret) return ret;
733 ret = CreateDisplay(false, out_failureId);
734 mDefaultDisplay = ret;
735 return ret;
738 std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
739 const bool forceAccel, nsACString* const out_failureId) {
740 std::shared_ptr<EglDisplay> ret;
742 if (IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d)) {
743 nsCString accelAngleFailureId;
744 bool accelAngleSupport = IsAccelAngleSupported(&accelAngleFailureId);
745 bool shouldTryAccel = forceAccel || accelAngleSupport;
746 bool shouldTryWARP = !forceAccel; // Only if ANGLE not supported or fails
748 // If WARP preferred, will override ANGLE support
749 if (StaticPrefs::webgl_angle_force_warp()) {
750 shouldTryWARP = true;
751 shouldTryAccel = false;
752 if (accelAngleFailureId.IsEmpty()) {
753 accelAngleFailureId = "FEATURE_FAILURE_FORCE_WARP"_ns;
757 // Hardware accelerated ANGLE path (supported or force accel)
758 if (shouldTryAccel) {
759 ret = GetAndInitDisplayForAccelANGLE(*this, out_failureId);
762 // Report the acceleration status to telemetry
763 if (!ret) {
764 if (accelAngleFailureId.IsEmpty()) {
765 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
766 "FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"_ns);
767 } else {
768 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
769 accelAngleFailureId);
771 } else {
772 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
773 "SUCCESS"_ns);
776 // Fallback to a WARP display if ANGLE fails, or if WARP is forced
777 if (!ret && shouldTryWARP) {
778 ret = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY);
779 if (!ret) {
780 if (out_failureId->IsEmpty()) {
781 *out_failureId = "FEATURE_FAILURE_WARP_FALLBACK"_ns;
783 NS_ERROR("Fallback WARP context failed to initialize.");
784 return nullptr;
787 } else {
788 void* nativeDisplay = EGL_DEFAULT_DISPLAY;
789 #ifdef MOZ_WAYLAND
790 // Some drivers doesn't support EGL_DEFAULT_DISPLAY
791 GdkDisplay* gdkDisplay = gdk_display_get_default();
792 if (widget::GdkIsWaylandDisplay(gdkDisplay)) {
793 nativeDisplay = widget::WaylandDisplayGetWLDisplay(gdkDisplay);
794 if (!nativeDisplay) {
795 NS_WARNING("Failed to get wl_display.");
796 return nullptr;
799 #endif
800 ret = GetAndInitDisplay(*this, nativeDisplay);
803 if (!ret) {
804 if (out_failureId->IsEmpty()) {
805 *out_failureId = "FEATURE_FAILURE_NO_DISPLAY"_ns;
807 NS_WARNING("Failed to initialize a display.");
808 return nullptr;
811 return ret;
814 void GLLibraryEGL::InitLibExtensions() {
815 const bool shouldDumpExts = GLContext::ShouldDumpExts();
817 const char* rawExtString = nullptr;
819 #ifndef ANDROID
820 // Bug 1209612: Crashes on a number of android drivers.
821 // Ideally we would only blocklist this there, but for now we don't need the
822 // client extension list on ANDROID (we mostly need it on ANGLE), and we'd
823 // rather not crash.
824 rawExtString = (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS);
825 #endif
827 if (!rawExtString) {
828 if (shouldDumpExts) {
829 printf_stderr("No EGL lib extensions.\n");
831 return;
834 MarkExtensions(rawExtString, shouldDumpExts, "lib", sEGLLibraryExtensionNames,
835 &mAvailableExtensions);
838 void EglDisplay::DumpEGLConfig(EGLConfig cfg) const {
839 #define ATTR(_x) \
840 do { \
841 int attrval = 0; \
842 mLib->fGetConfigAttrib(mDisplay, cfg, LOCAL_EGL_##_x, &attrval); \
843 const auto err = mLib->fGetError(); \
844 if (err != 0x3000) { \
845 printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \
846 } else { \
847 printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \
849 } while (0)
851 printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg);
853 ATTR(BUFFER_SIZE);
854 ATTR(ALPHA_SIZE);
855 ATTR(BLUE_SIZE);
856 ATTR(GREEN_SIZE);
857 ATTR(RED_SIZE);
858 ATTR(DEPTH_SIZE);
859 ATTR(STENCIL_SIZE);
860 ATTR(CONFIG_CAVEAT);
861 ATTR(CONFIG_ID);
862 ATTR(LEVEL);
863 ATTR(MAX_PBUFFER_HEIGHT);
864 ATTR(MAX_PBUFFER_PIXELS);
865 ATTR(MAX_PBUFFER_WIDTH);
866 ATTR(NATIVE_RENDERABLE);
867 ATTR(NATIVE_VISUAL_ID);
868 ATTR(NATIVE_VISUAL_TYPE);
869 ATTR(PRESERVED_RESOURCES);
870 ATTR(SAMPLES);
871 ATTR(SAMPLE_BUFFERS);
872 ATTR(SURFACE_TYPE);
873 ATTR(TRANSPARENT_TYPE);
874 ATTR(TRANSPARENT_RED_VALUE);
875 ATTR(TRANSPARENT_GREEN_VALUE);
876 ATTR(TRANSPARENT_BLUE_VALUE);
877 ATTR(BIND_TO_TEXTURE_RGB);
878 ATTR(BIND_TO_TEXTURE_RGBA);
879 ATTR(MIN_SWAP_INTERVAL);
880 ATTR(MAX_SWAP_INTERVAL);
881 ATTR(LUMINANCE_SIZE);
882 ATTR(ALPHA_MASK_SIZE);
883 ATTR(COLOR_BUFFER_TYPE);
884 ATTR(RENDERABLE_TYPE);
885 ATTR(CONFORMANT);
887 #undef ATTR
890 void EglDisplay::DumpEGLConfigs() const {
891 int nc = 0;
892 mLib->fGetConfigs(mDisplay, nullptr, 0, &nc);
893 std::vector<EGLConfig> ec(nc);
894 mLib->fGetConfigs(mDisplay, ec.data(), ec.size(), &nc);
896 for (int i = 0; i < nc; ++i) {
897 printf_stderr("========= EGL Config %d ========\n", i);
898 DumpEGLConfig(ec[i]);
902 static bool ShouldTrace() {
903 static bool ret = gfxEnv::GlDebugVerbose();
904 return ret;
907 void BeforeEGLCall(const char* glFunction) {
908 if (ShouldTrace()) {
909 printf_stderr("[egl] > %s\n", glFunction);
913 void AfterEGLCall(const char* glFunction) {
914 if (ShouldTrace()) {
915 printf_stderr("[egl] < %s\n", glFunction);
919 } /* namespace gl */
920 } /* namespace mozilla */