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"
8 #include "gfxCrashReporterUtils.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 "nsDirectoryServiceDefs.h"
22 #include "nsDirectoryServiceUtils.h"
23 #include "nsPrintfCString.h"
25 # include "mozilla/gfx/DeviceManagerDx.h"
26 # include "nsWindowsHelpers.h"
30 #include "OGLShaderProgram.h"
33 #include "GLContext.h"
34 #include "GLContextProvider.h"
35 #include "GLLibraryLoader.h"
36 #include "GLReadTexImageHelper.h"
37 #include "ScopedGLHelpers.h"
39 # include "mozilla/WidgetUtilsGtk.h"
41 # include "mozilla/widget/nsWaylandDisplay.h"
42 # include "mozilla/widget/DMABufLibWrapper.h"
43 # endif // MOZ_WIDGET_GTK
47 #include <mutex> // for call_once
52 StaticMutex
GLLibraryEGL::sMutex
;
53 StaticRefPtr
<GLLibraryEGL
> GLLibraryEGL::sInstance
;
55 // should match the order of EGLExtensions, and be null-terminated.
56 static const char* sEGLLibraryExtensionNames
[] = {
57 "EGL_ANDROID_get_native_client_buffer",
58 "EGL_ANGLE_device_creation",
59 "EGL_ANGLE_device_creation_d3d11",
60 "EGL_ANGLE_platform_angle",
61 "EGL_ANGLE_platform_angle_d3d",
62 "EGL_EXT_device_enumeration",
63 "EGL_EXT_device_query",
64 "EGL_EXT_platform_device",
65 "EGL_MESA_platform_surfaceless"};
67 // should match the order of EGLExtensions, and be null-terminated.
68 static const char* sEGLExtensionNames
[] = {
70 "EGL_KHR_image_pixmap",
71 "EGL_KHR_gl_texture_2D_image",
72 "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
73 "EGL_EXT_create_context_robustness",
77 "EGL_ANDROID_native_fence_sync",
78 "EGL_ANDROID_image_crop",
79 "EGL_ANGLE_d3d_share_handle_client_buffer",
80 "EGL_KHR_create_context",
82 "EGL_KHR_stream_consumer_gltexture",
83 "EGL_NV_stream_consumer_gltexture_yuv",
84 "EGL_ANGLE_stream_producer_d3d_texture",
85 "EGL_KHR_surfaceless_context",
86 "EGL_KHR_create_context_no_error",
87 "EGL_MOZ_create_context_provoking_vertex_dont_care",
88 "EGL_EXT_swap_buffers_with_damage",
89 "EGL_KHR_swap_buffers_with_damage",
91 "EGL_KHR_partial_update",
92 "EGL_NV_robustness_video_memory_purge",
93 "EGL_EXT_image_dma_buf_import",
94 "EGL_EXT_image_dma_buf_import_modifiers",
95 "EGL_MESA_image_dma_buf_export"};
97 PRLibrary
* LoadApitraceLibrary() {
98 const char* path
= nullptr;
101 // We only need to explicitly dlopen egltrace
102 // on android as we can use LD_PRELOAD or other tricks
103 // on other platforms. We look for it in /data/local
104 // as that's writeable by all users.
105 path
= "/data/local/tmp/egltrace.so";
107 if (!path
) return nullptr;
109 // Initialization of gfx prefs here is only needed during the unit tests...
110 if (!StaticPrefs::gfx_apitrace_enabled_AtStartup()) {
114 static PRLibrary
* sApitraceLibrary
= nullptr;
115 if (sApitraceLibrary
) return sApitraceLibrary
;
117 nsAutoCString logFile
;
118 Preferences::GetCString("gfx.apitrace.logfile", logFile
);
119 if (logFile
.IsEmpty()) {
120 logFile
= "firefox.trace";
123 // The firefox process can't write to /data/local, but it can write
125 nsAutoCString logPath
;
126 logPath
.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile
.get());
128 #ifndef XP_WIN // Windows is missing setenv and forbids PR_LoadLibrary.
129 // apitrace uses the TRACE_FILE environment variable to determine where
130 // to log trace output to
131 printf_stderr("Logging GL tracing output to %s", logPath
.get());
132 setenv("TRACE_FILE", logPath
.get(), false);
134 printf_stderr("Attempting load of %s\n", path
);
135 sApitraceLibrary
= PR_LoadLibrary(path
);
138 return sApitraceLibrary
;
142 // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
143 static PRLibrary
* LoadLibraryForEGLOnWindows(const nsAString
& filename
) {
144 nsAutoString
path(gfx::gfxVars::GREDirectory());
145 path
.Append(PR_GetDirectorySeparator());
146 path
.Append(filename
);
149 lspec
.type
= PR_LibSpec_PathnameU
;
150 lspec
.value
.pathname_u
= path
.get();
151 return PR_LoadLibraryWithFlags(lspec
, PR_LD_LAZY
| PR_LD_LOCAL
);
156 static std::shared_ptr
<EglDisplay
> GetAndInitDisplay(
157 GLLibraryEGL
& egl
, void* displayType
,
158 const StaticMutexAutoLock
& aProofOfLock
) {
159 const auto display
= egl
.fGetDisplay(displayType
);
160 if (!display
) return nullptr;
161 return EglDisplay::Create(egl
, display
, false, aProofOfLock
);
165 static std::shared_ptr
<EglDisplay
> GetAndInitDeviceDisplay(
166 GLLibraryEGL
& egl
, const StaticMutexAutoLock
& aProofOfLock
) {
167 nsAutoCString
drmRenderDevice(gfx::gfxVars::DrmRenderDevice());
168 if (drmRenderDevice
.IsEmpty() ||
169 !egl
.IsExtensionSupported(EGLLibExtension::EXT_platform_device
) ||
170 !egl
.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration
)) {
175 if (!egl
.fQueryDevicesEXT(0, nullptr, &maxDevices
)) {
179 std::vector
<EGLDeviceEXT
> devices(maxDevices
);
181 if (!egl
.fQueryDevicesEXT(devices
.size(), devices
.data(), &numDevices
)) {
184 devices
.resize(numDevices
);
186 EGLDisplay display
= EGL_NO_DISPLAY
;
187 for (const auto& device
: devices
) {
188 const char* renderNodeString
=
189 egl
.fQueryDeviceStringEXT(device
, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT
);
190 if (renderNodeString
&&
191 strcmp(renderNodeString
, drmRenderDevice
.get()) == 0) {
192 const EGLAttrib attrib_list
[] = {LOCAL_EGL_NONE
};
193 display
= egl
.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT
, device
,
202 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
205 static std::shared_ptr
<EglDisplay
> GetAndInitSurfacelessDisplay(
206 GLLibraryEGL
& egl
, const StaticMutexAutoLock
& aProofOfLock
) {
207 if (!egl
.IsExtensionSupported(EGLLibExtension::MESA_platform_surfaceless
)) {
211 const EGLAttrib attrib_list
[] = {LOCAL_EGL_NONE
};
212 const EGLDisplay display
= egl
.fGetPlatformDisplay(
213 LOCAL_EGL_PLATFORM_SURFACELESS_MESA
, EGL_DEFAULT_DISPLAY
, attrib_list
);
214 if (display
== EGL_NO_DISPLAY
) {
217 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
221 static std::shared_ptr
<EglDisplay
> GetAndInitWARPDisplay(
222 GLLibraryEGL
& egl
, void* displayType
,
223 const StaticMutexAutoLock
& aProofOfLock
) {
224 const EGLAttrib attrib_list
[] = {
225 LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE
,
226 LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE
,
228 LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE
,
229 LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
, LOCAL_EGL_NONE
};
230 const EGLDisplay display
= egl
.fGetPlatformDisplay(
231 LOCAL_EGL_PLATFORM_ANGLE_ANGLE
, displayType
, attrib_list
);
233 if (display
== EGL_NO_DISPLAY
) {
234 const EGLint err
= egl
.fGetError();
235 if (err
!= LOCAL_EGL_SUCCESS
) {
236 gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err
);
237 MOZ_CRASH("GFX: Unexpected GL error.");
242 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
245 std::shared_ptr
<EglDisplay
> GLLibraryEGL::CreateDisplay(
246 ID3D11Device
* const d3d11Device
) {
247 StaticMutexAutoLock
lock(sMutex
);
248 EGLDeviceEXT eglDevice
=
249 fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE
, d3d11Device
, nullptr);
251 gfxCriticalNote
<< "Failed to get EGLDeviceEXT of D3D11Device";
254 const char* features
[] = {"allowES3OnFL10_0", nullptr};
255 // Create an EGLDisplay using the EGLDevice
256 const EGLAttrib attrib_list
[] = {LOCAL_EGL_FEATURE_OVERRIDES_ENABLED_ANGLE
,
257 reinterpret_cast<EGLAttrib
>(features
),
259 const auto display
= fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT
,
260 eglDevice
, attrib_list
);
262 gfxCriticalNote
<< "Failed to get EGLDisplay of D3D11Device";
267 const EGLint err
= fGetError();
268 if (err
!= LOCAL_EGL_SUCCESS
) {
269 gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err
);
270 MOZ_CRASH("GFX: Unexpected GL error.");
275 const auto ret
= EglDisplay::Create(*this, display
, false, lock
);
278 const EGLint err
= fGetError();
279 if (err
!= LOCAL_EGL_SUCCESS
) {
281 << "Failed to initialize EGLDisplay for WebRender error: "
289 static bool IsAccelAngleSupported(nsACString
* const out_failureId
) {
290 if (!gfx::gfxVars::AllowWebglAccelAngle()) {
291 if (out_failureId
->IsEmpty()) {
292 *out_failureId
= "FEATURE_FAILURE_ACCL_ANGLE_NOT_OK"_ns
;
299 class AngleErrorReporting
{
301 AngleErrorReporting() : mFailureId(nullptr) {
302 // No static constructor
305 void SetFailureId(nsACString
* const aFailureId
) { mFailureId
= aFailureId
; }
307 void logError(const char* errorMessage
) {
312 nsCString
str(errorMessage
);
313 Tokenizer
tokenizer(str
);
315 // Parse "ANGLE Display::initialize error " << error.getID() << ": "
316 // << error.getMessage()
318 Tokenizer::Token intToken
;
319 if (tokenizer
.CheckWord("ANGLE") && tokenizer
.CheckWhite() &&
320 tokenizer
.CheckWord("Display") && tokenizer
.CheckChar(':') &&
321 tokenizer
.CheckChar(':') && tokenizer
.CheckWord("initialize") &&
322 tokenizer
.CheckWhite() && tokenizer
.CheckWord("error") &&
323 tokenizer
.CheckWhite() &&
324 tokenizer
.Check(Tokenizer::TOKEN_INTEGER
, intToken
)) {
325 *mFailureId
= "FAILURE_ID_ANGLE_ID_";
326 mFailureId
->AppendPrintf("%" PRIu64
, intToken
.AsInteger());
328 *mFailureId
= "FAILURE_ID_ANGLE_UNKNOWN";
333 nsACString
* mFailureId
;
336 AngleErrorReporting gAngleErrorReporter
;
338 static std::shared_ptr
<EglDisplay
> GetAndInitDisplayForAccelANGLE(
339 GLLibraryEGL
& egl
, nsACString
* const out_failureId
,
340 const StaticMutexAutoLock
& aProofOfLock
) {
341 gfx::FeatureState
& d3d11ANGLE
=
342 gfx::gfxConfig::GetFeature(gfx::Feature::D3D11_HW_ANGLE
);
344 if (!StaticPrefs::webgl_angle_try_d3d11()) {
345 d3d11ANGLE
.UserDisable("User disabled D3D11 ANGLE by pref",
346 "FAILURE_ID_ANGLE_PREF"_ns
);
348 if (StaticPrefs::webgl_angle_force_d3d11()) {
349 d3d11ANGLE
.UserForceEnable(
350 "User force-enabled D3D11 ANGLE on disabled hardware");
352 gAngleErrorReporter
.SetFailureId(out_failureId
);
354 auto guardShutdown
= mozilla::MakeScopeExit([&] {
355 gAngleErrorReporter
.SetFailureId(nullptr);
356 // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the
357 // ANGLE display is destroyed. However gAngleErrorReporter
358 // will live longer than the ANGLE display so we're fine.
361 if (gfx::gfxConfig::IsForcedOnByUser(gfx::Feature::D3D11_HW_ANGLE
)) {
362 return GetAndInitDisplay(egl
, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE
,
366 std::shared_ptr
<EglDisplay
> ret
;
367 if (d3d11ANGLE
.IsEnabled()) {
368 ret
= GetAndInitDisplay(egl
, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE
,
373 ret
= GetAndInitDisplay(egl
, EGL_DEFAULT_DISPLAY
, aProofOfLock
);
376 if (!ret
&& out_failureId
->IsEmpty()) {
377 *out_failureId
= "FEATURE_FAILURE_ACCL_ANGLE_NO_DISP"_ns
;
386 # define GLES2_LIB "libGLESv2.so"
387 # define GLES2_LIB2 "libGLESv2.so.2"
388 # define GL_LIB "libGL.so"
389 # define GL_LIB2 "libGL.so.1"
390 #elif defined(XP_WIN)
391 # define GLES2_LIB "libGLESv2.dll"
393 # error "Platform not recognized"
396 Maybe
<SymbolLoader
> GLLibraryEGL::GetSymbolLoader() const {
397 auto ret
= SymbolLoader(mSymbols
.fGetProcAddress
);
398 ret
.mLib
= mGLLibrary
;
405 RefPtr
<GLLibraryEGL
> GLLibraryEGL::Get(nsACString
* const out_failureId
) {
406 StaticMutexAutoLock
lock(sMutex
);
408 sInstance
= new GLLibraryEGL
;
409 if (NS_WARN_IF(!sInstance
->Init(out_failureId
))) {
416 /* static */ void GLLibraryEGL::Shutdown() {
417 StaticMutexAutoLock
lock(sMutex
);
421 bool GLLibraryEGL::Init(nsACString
* const out_failureId
) {
422 MOZ_RELEASE_ASSERT(!mSymbols
.fTerminate
);
424 mozilla::ScopedGfxFeatureReporter
reporter("EGL");
428 // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul
429 // and we should look for them there. We have to load the libs in this
430 // order, because libEGL.dll depends on libGLESv2.dll which depends on the
431 // DXSDK libraries. This matters especially for WebRT apps which are in a
432 // different directory. See bug 760323 and bug 749459
434 // Also note that we intentionally leak the libs we load.
437 // Windows 8.1+ has d3dcompiler_47.dll in the system directory.
438 // Try it first. Note that _46 will never be in the system
439 // directory. So there is no point trying _46 in the system
442 if (LoadLibrarySystem32(L
"d3dcompiler_47.dll")) break;
444 # ifdef MOZ_D3DCOMPILER_VISTA_DLL
445 if (LoadLibraryForEGLOnWindows(NS_LITERAL_STRING_FROM_CSTRING(
446 MOZ_STRINGIFY(MOZ_D3DCOMPILER_VISTA_DLL
))))
450 MOZ_ASSERT(false, "d3dcompiler DLL loading failed.");
453 mGLLibrary
= LoadLibraryForEGLOnWindows(u
"libGLESv2.dll"_ns
);
455 mEGLLibrary
= LoadLibraryForEGLOnWindows(u
"libEGL.dll"_ns
);
460 // On non-Windows (Android) we use system copies of libEGL. We look for
461 // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
463 # if defined(ANDROID)
464 if (!mEGLLibrary
) mEGLLibrary
= LoadApitraceLibrary();
468 mEGLLibrary
= PR_LoadLibrary("libEGL.so");
470 # if defined(XP_UNIX)
472 mEGLLibrary
= PR_LoadLibrary("libEGL.so.1");
478 mGLLibrary
= PR_LoadLibrary(APITRACE_LIB
);
484 mGLLibrary
= PR_LoadLibrary(GL_LIB
);
490 mGLLibrary
= PR_LoadLibrary(GL_LIB2
);
495 mGLLibrary
= PR_LoadLibrary(GLES2_LIB
);
500 mGLLibrary
= PR_LoadLibrary(GLES2_LIB2
);
506 if (!mEGLLibrary
|| !mGLLibrary
) {
507 NS_WARNING("Couldn't load EGL LIB.");
508 *out_failureId
= "FEATURE_FAILURE_EGL_LOAD_3"_ns
;
514 (PRFuncPtr*)&mSymbols.f##X, { \
518 #define END_OF_SYMBOLS \
523 SymLoadStruct earlySymbols
[] = {SYMBOL(GetDisplay
),
525 SYMBOL(GetCurrentSurface
),
526 SYMBOL(GetCurrentContext
),
528 SYMBOL(DestroyContext
),
529 SYMBOL(CreateContext
),
530 SYMBOL(DestroySurface
),
531 SYMBOL(CreateWindowSurface
),
532 SYMBOL(CreatePbufferSurface
),
533 SYMBOL(CreatePbufferFromClientBuffer
),
534 SYMBOL(CreatePixmapSurface
),
537 SYMBOL(ChooseConfig
),
540 SYMBOL(GetConfigAttrib
),
542 SYMBOL(GetProcAddress
),
546 SYMBOL(QueryContext
),
547 SYMBOL(BindTexImage
),
548 SYMBOL(ReleaseTexImage
),
549 SYMBOL(SwapInterval
),
550 SYMBOL(QuerySurface
),
554 const SymbolLoader
libLoader(*mEGLLibrary
);
555 if (!libLoader
.LoadSymbols(earlySymbols
)) {
557 "Couldn't find required entry points in EGL library (early init)");
558 *out_failureId
= "FEATURE_FAILURE_EGL_SYM"_ns
;
564 const char internalFuncName
[] =
565 "_Z35eglQueryStringImplementationANDROIDPvi";
566 const auto& internalFunc
=
567 PR_FindFunctionSymbol(mEGLLibrary
, internalFuncName
);
569 *(PRFuncPtr
*)&mSymbols
.fQueryString
= internalFunc
;
577 const SymbolLoader
pfnLoader(mSymbols
.fGetProcAddress
);
579 const auto fnLoadSymbols
= [&](const SymLoadStruct
* symbols
) {
580 const bool shouldWarn
= gfxEnv::GlSpew();
581 if (pfnLoader
.LoadSymbols(symbols
, shouldWarn
)) return true;
583 ClearSymbols(symbols
);
587 // Check the ANGLE support the system has
588 mIsANGLE
= IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle
);
590 // Client exts are ready. (But not display exts!)
593 MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d
));
594 const SymLoadStruct angleSymbols
[] = {SYMBOL(GetPlatformDisplay
),
596 if (!fnLoadSymbols(angleSymbols
)) {
597 gfxCriticalError() << "Failed to load ANGLE symbols!";
600 MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d
));
601 const SymLoadStruct createDeviceSymbols
[] = {
602 SYMBOL(CreateDeviceANGLE
), SYMBOL(ReleaseDeviceANGLE
), END_OF_SYMBOLS
};
603 if (!fnLoadSymbols(createDeviceSymbols
)) {
605 "EGL supports ANGLE_device_creation without exposing its functions!");
606 MarkExtensionUnsupported(EGLLibExtension::ANGLE_device_creation
);
610 // ANDROID_get_native_client_buffer isn't necessarily enumerated in lib exts,
613 const SymLoadStruct symbols
[] = {SYMBOL(GetNativeClientBufferANDROID
),
615 if (fnLoadSymbols(symbols
)) {
616 mAvailableExtensions
[UnderlyingValue(
617 EGLLibExtension::ANDROID_get_native_client_buffer
)] = true;
622 // Load possible display ext symbols.
625 const SymLoadStruct symbols
[] = {SYMBOL(QuerySurfacePointerANGLE
),
627 (void)fnLoadSymbols(symbols
);
630 const SymLoadStruct symbols
[] = {
631 SYMBOL(CreateSyncKHR
), SYMBOL(DestroySyncKHR
),
632 SYMBOL(ClientWaitSyncKHR
), SYMBOL(GetSyncAttribKHR
), END_OF_SYMBOLS
};
633 (void)fnLoadSymbols(symbols
);
636 const SymLoadStruct symbols
[] = {SYMBOL(CreateImageKHR
),
637 SYMBOL(DestroyImageKHR
), END_OF_SYMBOLS
};
638 (void)fnLoadSymbols(symbols
);
641 const SymLoadStruct symbols
[] = {SYMBOL(WaitSyncKHR
), END_OF_SYMBOLS
};
642 (void)fnLoadSymbols(symbols
);
645 const SymLoadStruct symbols
[] = {SYMBOL(DupNativeFenceFDANDROID
),
647 (void)fnLoadSymbols(symbols
);
650 const SymLoadStruct symbols
[] = {SYMBOL(CreateStreamKHR
),
651 SYMBOL(DestroyStreamKHR
),
652 SYMBOL(QueryStreamKHR
), END_OF_SYMBOLS
};
653 (void)fnLoadSymbols(symbols
);
656 const SymLoadStruct symbols
[] = {SYMBOL(StreamConsumerGLTextureExternalKHR
),
657 SYMBOL(StreamConsumerAcquireKHR
),
658 SYMBOL(StreamConsumerReleaseKHR
),
660 (void)fnLoadSymbols(symbols
);
663 const SymLoadStruct symbols
[] = {
664 SYMBOL(QueryDisplayAttribEXT
), SYMBOL(QueryDeviceAttribEXT
),
665 SYMBOL(QueryDeviceStringEXT
), END_OF_SYMBOLS
};
666 (void)fnLoadSymbols(symbols
);
669 const SymLoadStruct symbols
[] = {
670 SYMBOL(StreamConsumerGLTextureExternalAttribsNV
), END_OF_SYMBOLS
};
671 (void)fnLoadSymbols(symbols
);
674 const SymLoadStruct symbols
[] = {
675 SYMBOL(CreateStreamProducerD3DTextureANGLE
),
676 SYMBOL(StreamPostD3DTextureANGLE
), END_OF_SYMBOLS
};
677 (void)fnLoadSymbols(symbols
);
680 const SymLoadStruct symbols
[] = {
681 {(PRFuncPtr
*)&mSymbols
.fSwapBuffersWithDamage
,
682 {{"eglSwapBuffersWithDamageEXT"}}},
684 (void)fnLoadSymbols(symbols
);
687 const SymLoadStruct symbols
[] = {
688 {(PRFuncPtr
*)&mSymbols
.fSwapBuffersWithDamage
,
689 {{"eglSwapBuffersWithDamageKHR"}}},
691 (void)fnLoadSymbols(symbols
);
694 const SymLoadStruct symbols
[] = {
695 {(PRFuncPtr
*)&mSymbols
.fSetDamageRegion
, {{"eglSetDamageRegionKHR"}}},
697 (void)fnLoadSymbols(symbols
);
700 const SymLoadStruct symbols
[] = {SYMBOL(GetPlatformDisplay
),
702 (void)fnLoadSymbols(symbols
);
705 const SymLoadStruct symbols
[] = {SYMBOL(ExportDMABUFImageQueryMESA
),
706 SYMBOL(ExportDMABUFImageMESA
),
708 (void)fnLoadSymbols(symbols
);
711 const SymLoadStruct symbols
[] = {SYMBOL(QueryDevicesEXT
), END_OF_SYMBOLS
};
712 (void)fnLoadSymbols(symbols
);
721 static void MarkExtensions(const char* rawExtString
, bool shouldDumpExts
,
722 const char* extType
, const char* const (&names
)[N
],
723 std::bitset
<N
>* const out
) {
724 MOZ_ASSERT(rawExtString
);
726 const nsDependentCString
extString(rawExtString
);
728 std::vector
<nsCString
> extList
;
729 SplitByChar(extString
, ' ', &extList
);
731 if (shouldDumpExts
) {
732 printf_stderr("%u EGL %s extensions: (*: recognized)\n",
733 (uint32_t)extList
.size(), extType
);
736 MarkBitfieldByStrings(extList
, shouldDumpExts
, names
, out
);
742 std::shared_ptr
<EglDisplay
> EglDisplay::Create(
743 GLLibraryEGL
& lib
, const EGLDisplay display
, const bool isWarp
,
744 const StaticMutexAutoLock
& aProofOfLock
) {
745 // Retrieve the EglDisplay if it already exists
747 const auto itr
= lib
.mActiveDisplays
.find(display
);
748 if (itr
!= lib
.mActiveDisplays
.end()) {
749 const auto ret
= itr
->second
.lock();
756 if (!lib
.fInitialize(display
, nullptr, nullptr)) {
760 static std::once_flag sMesaLeakFlag
;
761 std::call_once(sMesaLeakFlag
, MesaMemoryLeakWorkaround
);
764 std::make_shared
<EglDisplay
>(PrivateUseOnly
{}, lib
, display
, isWarp
);
765 lib
.mActiveDisplays
.insert({display
, ret
});
769 EglDisplay::EglDisplay(const PrivateUseOnly
&, GLLibraryEGL
& lib
,
770 const EGLDisplay disp
, const bool isWarp
)
771 : mLib(&lib
), mDisplay(disp
), mIsWARP(isWarp
) {
772 const bool shouldDumpExts
= GLContext::ShouldDumpExts();
775 (const char*)mLib
->fQueryString(mDisplay
, LOCAL_EGL_EXTENSIONS
);
777 NS_WARNING("Failed to query EGL display extensions!.");
780 MarkExtensions(rawExtString
, shouldDumpExts
, "display", sEGLExtensionNames
,
781 &mAvailableExtensions
);
785 if (!HasKHRImageBase()) {
786 MarkExtensionUnsupported(EGLExtension::KHR_image_pixmap
);
789 if (IsExtensionSupported(EGLExtension::KHR_surfaceless_context
)) {
791 (const char*)mLib
->fQueryString(mDisplay
, LOCAL_EGL_VENDOR
);
793 // Bug 1464610: Mali T720 (Amazon Fire 8 HD) claims to support this
794 // extension, but if you actually eglMakeCurrent() with EGL_NO_SURFACE, it
795 // fails to render anything when a real surface is provided later on. We
796 // only have the EGL vendor available here, so just avoid using this
797 // extension on all Mali devices.
798 if (vendor
&& (strcmp(vendor
, "ARM") == 0)) {
799 MarkExtensionUnsupported(EGLExtension::KHR_surfaceless_context
);
803 // ANDROID_native_fence_sync isn't necessarily enumerated in display ext,
805 if (mLib
->mSymbols
.fDupNativeFenceFDANDROID
) {
806 mAvailableExtensions
[UnderlyingValue(
807 EGLExtension::ANDROID_native_fence_sync
)] = true;
811 EglDisplay::~EglDisplay() {
812 StaticMutexAutoLock
lock(GLLibraryEGL::sMutex
);
814 mLib
->mActiveDisplays
.erase(mDisplay
);
819 std::shared_ptr
<EglDisplay
> GLLibraryEGL::DefaultDisplay(
820 nsACString
* const out_failureId
) {
821 StaticMutexAutoLock
lock(sMutex
);
822 auto ret
= mDefaultDisplay
.lock();
825 ret
= CreateDisplayLocked(false, out_failureId
, lock
);
826 mDefaultDisplay
= ret
;
830 std::shared_ptr
<EglDisplay
> GLLibraryEGL::CreateDisplay(
831 const bool forceAccel
, nsACString
* const out_failureId
) {
832 StaticMutexAutoLock
lock(sMutex
);
833 return CreateDisplayLocked(forceAccel
, out_failureId
, lock
);
836 std::shared_ptr
<EglDisplay
> GLLibraryEGL::CreateDisplayLocked(
837 const bool forceAccel
, nsACString
* const out_failureId
,
838 const StaticMutexAutoLock
& aProofOfLock
) {
839 std::shared_ptr
<EglDisplay
> ret
;
841 if (IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d
)) {
842 nsCString accelAngleFailureId
;
843 bool accelAngleSupport
= IsAccelAngleSupported(&accelAngleFailureId
);
844 bool shouldTryAccel
= forceAccel
|| accelAngleSupport
;
845 bool shouldTryWARP
= !forceAccel
; // Only if ANGLE not supported or fails
847 // If WARP preferred, will override ANGLE support
848 if (StaticPrefs::webgl_angle_force_warp()) {
849 shouldTryWARP
= true;
850 shouldTryAccel
= false;
851 if (accelAngleFailureId
.IsEmpty()) {
852 accelAngleFailureId
= "FEATURE_FAILURE_FORCE_WARP"_ns
;
856 // Hardware accelerated ANGLE path (supported or force accel)
857 if (shouldTryAccel
) {
858 ret
= GetAndInitDisplayForAccelANGLE(*this, out_failureId
, aProofOfLock
);
861 // Report the acceleration status to telemetry
863 if (accelAngleFailureId
.IsEmpty()) {
864 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID
,
865 "FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"_ns
);
867 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID
,
868 accelAngleFailureId
);
871 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID
,
875 // Fallback to a WARP display if ANGLE fails, or if WARP is forced
876 if (!ret
&& shouldTryWARP
) {
877 ret
= GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY
, aProofOfLock
);
879 if (out_failureId
->IsEmpty()) {
880 *out_failureId
= "FEATURE_FAILURE_WARP_FALLBACK"_ns
;
882 NS_ERROR("Fallback WARP context failed to initialize.");
887 void* nativeDisplay
= EGL_DEFAULT_DISPLAY
;
889 GdkDisplay
* gdkDisplay
= gdk_display_get_default();
891 ret
= GetAndInitDeviceDisplay(*this, aProofOfLock
);
893 ret
= GetAndInitSurfacelessDisplay(*this, aProofOfLock
);
895 } else if (widget::GdkIsWaylandDisplay(gdkDisplay
)) {
896 // Wayland does not support EGL_DEFAULT_DISPLAY
897 nativeDisplay
= widget::WaylandDisplayGetWLDisplay(gdkDisplay
);
898 if (!nativeDisplay
) {
899 NS_WARNING("Failed to get wl_display.");
905 ret
= GetAndInitDisplay(*this, nativeDisplay
, aProofOfLock
);
910 if (out_failureId
->IsEmpty()) {
911 *out_failureId
= "FEATURE_FAILURE_NO_DISPLAY"_ns
;
913 NS_WARNING("Failed to initialize a display.");
920 void GLLibraryEGL::InitLibExtensions() {
921 const bool shouldDumpExts
= GLContext::ShouldDumpExts();
923 const char* rawExtString
= nullptr;
926 // Bug 1209612: Crashes on a number of android drivers.
927 // Ideally we would only blocklist this there, but for now we don't need the
928 // client extension list on ANDROID (we mostly need it on ANGLE), and we'd
930 rawExtString
= (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS
);
934 if (shouldDumpExts
) {
935 printf_stderr("No EGL lib extensions.\n");
940 MarkExtensions(rawExtString
, shouldDumpExts
, "lib", sEGLLibraryExtensionNames
,
941 &mAvailableExtensions
);
944 void EglDisplay::DumpEGLConfig(EGLConfig cfg
) const {
948 mLib->fGetConfigAttrib(mDisplay, cfg, LOCAL_EGL_##_x, &attrval); \
949 const auto err = mLib->fGetError(); \
950 if (err != 0x3000) { \
951 printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \
953 printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \
957 printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg
, cfg
);
969 ATTR(MAX_PBUFFER_HEIGHT
);
970 ATTR(MAX_PBUFFER_PIXELS
);
971 ATTR(MAX_PBUFFER_WIDTH
);
972 ATTR(NATIVE_RENDERABLE
);
973 ATTR(NATIVE_VISUAL_ID
);
974 ATTR(NATIVE_VISUAL_TYPE
);
975 ATTR(PRESERVED_RESOURCES
);
977 ATTR(SAMPLE_BUFFERS
);
979 ATTR(TRANSPARENT_TYPE
);
980 ATTR(TRANSPARENT_RED_VALUE
);
981 ATTR(TRANSPARENT_GREEN_VALUE
);
982 ATTR(TRANSPARENT_BLUE_VALUE
);
983 ATTR(BIND_TO_TEXTURE_RGB
);
984 ATTR(BIND_TO_TEXTURE_RGBA
);
985 ATTR(MIN_SWAP_INTERVAL
);
986 ATTR(MAX_SWAP_INTERVAL
);
987 ATTR(LUMINANCE_SIZE
);
988 ATTR(ALPHA_MASK_SIZE
);
989 ATTR(COLOR_BUFFER_TYPE
);
990 ATTR(RENDERABLE_TYPE
);
996 void EglDisplay::DumpEGLConfigs() const {
998 mLib
->fGetConfigs(mDisplay
, nullptr, 0, &nc
);
999 std::vector
<EGLConfig
> ec(nc
);
1000 mLib
->fGetConfigs(mDisplay
, ec
.data(), ec
.size(), &nc
);
1002 for (int i
= 0; i
< nc
; ++i
) {
1003 printf_stderr("========= EGL Config %d ========\n", i
);
1004 DumpEGLConfig(ec
[i
]);
1008 static bool ShouldTrace() {
1009 static bool ret
= gfxEnv::GlDebugVerbose();
1013 void BeforeEGLCall(const char* glFunction
) {
1014 if (ShouldTrace()) {
1015 printf_stderr("[egl] > %s\n", glFunction
);
1019 void AfterEGLCall(const char* glFunction
) {
1020 if (ShouldTrace()) {
1021 printf_stderr("[egl] < %s\n", glFunction
);
1025 } /* namespace gl */
1026 } /* namespace mozilla */