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"
31 #include "OGLShaderProgram.h"
34 #include "GLContext.h"
35 #include "GLContextProvider.h"
36 #include "GLLibraryLoader.h"
37 #include "GLReadTexImageHelper.h"
38 #include "ScopedGLHelpers.h"
40 # include "mozilla/WidgetUtilsGtk.h"
41 # include "mozilla/widget/DMABufLibWrapper.h"
43 # include "mozilla/widget/nsWaylandDisplay.h"
44 # endif // MOZ_WIDGET_GTK
48 #include <mutex> // for call_once
53 StaticMutex
GLLibraryEGL::sMutex
;
54 StaticRefPtr
<GLLibraryEGL
> GLLibraryEGL::sInstance
;
56 // should match the order of EGLExtensions, and be null-terminated.
57 static const char* sEGLLibraryExtensionNames
[] = {
58 "EGL_ANDROID_get_native_client_buffer",
59 "EGL_ANGLE_device_creation",
60 "EGL_ANGLE_device_creation_d3d11",
61 "EGL_ANGLE_platform_angle",
62 "EGL_ANGLE_platform_angle_d3d",
63 "EGL_EXT_device_enumeration",
64 "EGL_EXT_device_query",
65 "EGL_EXT_platform_device",
66 "EGL_MESA_platform_surfaceless"};
68 // should match the order of EGLExtensions, and be null-terminated.
69 static const char* sEGLExtensionNames
[] = {
71 "EGL_KHR_image_pixmap",
72 "EGL_KHR_gl_texture_2D_image",
73 "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
74 "EGL_EXT_create_context_robustness",
78 "EGL_ANDROID_native_fence_sync",
79 "EGL_ANDROID_image_crop",
80 "EGL_ANGLE_d3d_share_handle_client_buffer",
81 "EGL_KHR_create_context",
83 "EGL_KHR_stream_consumer_gltexture",
84 "EGL_NV_stream_consumer_gltexture_yuv",
85 "EGL_ANGLE_stream_producer_d3d_texture",
86 "EGL_KHR_surfaceless_context",
87 "EGL_KHR_create_context_no_error",
88 "EGL_MOZ_create_context_provoking_vertex_dont_care",
89 "EGL_EXT_swap_buffers_with_damage",
90 "EGL_KHR_swap_buffers_with_damage",
92 "EGL_KHR_partial_update",
93 "EGL_NV_robustness_video_memory_purge",
94 "EGL_EXT_image_dma_buf_import",
95 "EGL_EXT_image_dma_buf_import_modifiers",
96 "EGL_MESA_image_dma_buf_export",
97 "EGL_KHR_no_config_context",
100 PRLibrary
* LoadApitraceLibrary() {
101 const char* path
= nullptr;
104 // We only need to explicitly dlopen egltrace
105 // on android as we can use LD_PRELOAD or other tricks
106 // on other platforms. We look for it in /data/local
107 // as that's writeable by all users.
108 path
= "/data/local/tmp/egltrace.so";
110 if (!path
) return nullptr;
112 // Initialization of gfx prefs here is only needed during the unit tests...
113 if (!StaticPrefs::gfx_apitrace_enabled_AtStartup()) {
117 static PRLibrary
* sApitraceLibrary
= nullptr;
118 if (sApitraceLibrary
) return sApitraceLibrary
;
120 nsAutoCString logFile
;
121 Preferences::GetCString("gfx.apitrace.logfile", logFile
);
122 if (logFile
.IsEmpty()) {
123 logFile
= "firefox.trace";
126 // The firefox process can't write to /data/local, but it can write
128 nsAutoCString logPath
;
129 logPath
.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile
.get());
131 #ifndef XP_WIN // Windows is missing setenv and forbids PR_LoadLibrary.
132 // apitrace uses the TRACE_FILE environment variable to determine where
133 // to log trace output to
134 printf_stderr("Logging GL tracing output to %s", logPath
.get());
135 setenv("TRACE_FILE", logPath
.get(), false);
137 printf_stderr("Attempting load of %s\n", path
);
138 sApitraceLibrary
= PR_LoadLibrary(path
);
141 return sApitraceLibrary
;
145 // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
146 static PRLibrary
* LoadLibraryForEGLOnWindows(const nsAString
& filename
) {
147 nsAutoString
path(gfx::gfxVars::GREDirectory());
148 path
.Append(PR_GetDirectorySeparator());
149 path
.Append(filename
);
152 lspec
.type
= PR_LibSpec_PathnameU
;
153 lspec
.value
.pathname_u
= path
.get();
154 PRLibrary
* lib
= PR_LoadLibraryWithFlags(lspec
, PR_LD_LAZY
| PR_LD_LOCAL
);
156 gfxCriticalNote
<< "Failed to load " << path
.get() << " " << PR_GetError()
157 << " " << PR_GetOSError();
164 static std::shared_ptr
<EglDisplay
> GetAndInitDisplay(
165 GLLibraryEGL
& egl
, void* displayType
,
166 const StaticMutexAutoLock
& aProofOfLock
) {
167 const auto display
= egl
.fGetDisplay(displayType
);
168 if (!display
) return nullptr;
169 return EglDisplay::Create(egl
, display
, false, aProofOfLock
);
172 #ifdef MOZ_WIDGET_GTK
173 static std::shared_ptr
<EglDisplay
> GetAndInitDeviceDisplay(
174 GLLibraryEGL
& egl
, const StaticMutexAutoLock
& aProofOfLock
) {
175 nsAutoCString
drmRenderDevice(gfx::gfxVars::DrmRenderDevice());
176 if (drmRenderDevice
.IsEmpty() ||
177 !egl
.IsExtensionSupported(EGLLibExtension::EXT_platform_device
) ||
178 !egl
.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration
)) {
183 if (!egl
.fQueryDevicesEXT(0, nullptr, &maxDevices
)) {
187 std::vector
<EGLDeviceEXT
> devices(maxDevices
);
189 if (!egl
.fQueryDevicesEXT(devices
.size(), devices
.data(), &numDevices
)) {
192 devices
.resize(numDevices
);
194 EGLDisplay display
= EGL_NO_DISPLAY
;
195 for (const auto& device
: devices
) {
196 const char* renderNodeString
=
197 egl
.fQueryDeviceStringEXT(device
, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT
);
198 if (renderNodeString
&&
199 strcmp(renderNodeString
, drmRenderDevice
.get()) == 0) {
200 const EGLAttrib attrib_list
[] = {LOCAL_EGL_NONE
};
201 display
= egl
.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT
, device
,
210 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
213 static std::shared_ptr
<EglDisplay
> GetAndInitSoftwareDisplay(
214 GLLibraryEGL
& egl
, const StaticMutexAutoLock
& aProofOfLock
) {
215 if (!egl
.IsExtensionSupported(EGLLibExtension::EXT_platform_device
) ||
216 !egl
.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration
)) {
221 if (!egl
.fQueryDevicesEXT(0, nullptr, &maxDevices
)) {
225 std::vector
<EGLDeviceEXT
> devices(maxDevices
);
227 if (!egl
.fQueryDevicesEXT(devices
.size(), devices
.data(), &numDevices
)) {
230 devices
.resize(numDevices
);
232 EGLDisplay display
= EGL_NO_DISPLAY
;
233 for (const auto& device
: devices
) {
234 const char* renderNodeString
=
235 egl
.fQueryDeviceStringEXT(device
, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT
);
236 // We are looking for a device with no file
237 if (!renderNodeString
|| *renderNodeString
== 0) {
238 const EGLAttrib attrib_list
[] = {LOCAL_EGL_NONE
};
239 display
= egl
.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT
, device
,
248 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
251 static std::shared_ptr
<EglDisplay
> GetAndInitSurfacelessDisplay(
252 GLLibraryEGL
& egl
, const StaticMutexAutoLock
& aProofOfLock
) {
253 if (!egl
.IsExtensionSupported(EGLLibExtension::MESA_platform_surfaceless
)) {
257 const EGLAttrib attrib_list
[] = {LOCAL_EGL_NONE
};
258 const EGLDisplay display
= egl
.fGetPlatformDisplay(
259 LOCAL_EGL_PLATFORM_SURFACELESS_MESA
, EGL_DEFAULT_DISPLAY
, attrib_list
);
260 if (display
== EGL_NO_DISPLAY
) {
263 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
267 static auto EglDebugLayersEnabled() {
268 EGLAttrib ret
= LOCAL_EGL_FALSE
;
269 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) {
270 ret
= LOCAL_EGL_TRUE
;
275 static std::shared_ptr
<EglDisplay
> GetAndInitWARPDisplay(
276 GLLibraryEGL
& egl
, void* displayType
,
277 const StaticMutexAutoLock
& aProofOfLock
) {
278 const EGLAttrib attrib_list
[] = {
279 LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE
,
280 LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE
,
281 LOCAL_EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE
,
282 EglDebugLayersEnabled(),
284 LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE
,
285 LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
, LOCAL_EGL_NONE
};
286 const EGLDisplay display
= egl
.fGetPlatformDisplay(
287 LOCAL_EGL_PLATFORM_ANGLE_ANGLE
, displayType
, attrib_list
);
289 if (display
== EGL_NO_DISPLAY
) {
290 const EGLint err
= egl
.fGetError();
291 if (err
!= LOCAL_EGL_SUCCESS
) {
292 gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err
);
293 MOZ_CRASH("GFX: Unexpected GL error.");
298 return EglDisplay::Create(egl
, display
, true, aProofOfLock
);
301 std::shared_ptr
<EglDisplay
> GLLibraryEGL::CreateDisplay(
302 ID3D11Device
* const d3d11Device
) {
303 StaticMutexAutoLock
lock(sMutex
);
304 EGLDeviceEXT eglDevice
=
305 fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE
, d3d11Device
, nullptr);
307 gfxCriticalNote
<< "Failed to get EGLDeviceEXT of D3D11Device";
310 const char* features
[] = {"allowES3OnFL10_0", nullptr};
311 // Create an EGLDisplay using the EGLDevice
312 const EGLAttrib attrib_list
[] = {LOCAL_EGL_FEATURE_OVERRIDES_ENABLED_ANGLE
,
313 reinterpret_cast<EGLAttrib
>(features
),
315 const auto display
= fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT
,
316 eglDevice
, attrib_list
);
318 gfxCriticalNote
<< "Failed to get EGLDisplay of D3D11Device";
323 const EGLint err
= fGetError();
324 if (err
!= LOCAL_EGL_SUCCESS
) {
325 gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err
);
326 MOZ_CRASH("GFX: Unexpected GL error.");
331 const auto ret
= EglDisplay::Create(*this, display
, false, lock
);
334 const EGLint err
= fGetError();
335 if (err
!= LOCAL_EGL_SUCCESS
) {
337 << "Failed to initialize EGLDisplay for WebRender error: "
345 static bool IsAccelAngleSupported(nsACString
* const out_failureId
) {
346 if (!gfx::gfxVars::AllowWebglAccelAngle()) {
347 if (out_failureId
->IsEmpty()) {
348 *out_failureId
= "FEATURE_FAILURE_ACCL_ANGLE_NOT_OK"_ns
;
355 class AngleErrorReporting
{
357 AngleErrorReporting() : mFailureId(nullptr) {
358 // No static constructor
361 void SetFailureId(nsACString
* const aFailureId
) { mFailureId
= aFailureId
; }
363 void logError(const char* errorMessage
) {
368 nsCString
str(errorMessage
);
369 Tokenizer
tokenizer(str
);
371 // Parse "ANGLE Display::initialize error " << error.getID() << ": "
372 // << error.getMessage()
374 Tokenizer::Token intToken
;
375 if (tokenizer
.CheckWord("ANGLE") && tokenizer
.CheckWhite() &&
376 tokenizer
.CheckWord("Display") && tokenizer
.CheckChar(':') &&
377 tokenizer
.CheckChar(':') && tokenizer
.CheckWord("initialize") &&
378 tokenizer
.CheckWhite() && tokenizer
.CheckWord("error") &&
379 tokenizer
.CheckWhite() &&
380 tokenizer
.Check(Tokenizer::TOKEN_INTEGER
, intToken
)) {
381 *mFailureId
= "FAILURE_ID_ANGLE_ID_";
382 mFailureId
->AppendPrintf("%" PRIu64
, intToken
.AsInteger());
384 *mFailureId
= "FAILURE_ID_ANGLE_UNKNOWN";
389 nsACString
* mFailureId
;
392 AngleErrorReporting gAngleErrorReporter
;
394 static std::shared_ptr
<EglDisplay
> GetAndInitDisplayForAccelANGLE(
395 GLLibraryEGL
& egl
, nsACString
* const out_failureId
,
396 const StaticMutexAutoLock
& aProofOfLock
) {
397 gfx::FeatureState
& d3d11ANGLE
=
398 gfx::gfxConfig::GetFeature(gfx::Feature::D3D11_HW_ANGLE
);
400 if (!StaticPrefs::webgl_angle_try_d3d11()) {
401 d3d11ANGLE
.UserDisable("User disabled D3D11 ANGLE by pref",
402 "FAILURE_ID_ANGLE_PREF"_ns
);
404 if (StaticPrefs::webgl_angle_force_d3d11()) {
405 d3d11ANGLE
.UserForceEnable(
406 "User force-enabled D3D11 ANGLE on disabled hardware");
408 gAngleErrorReporter
.SetFailureId(out_failureId
);
410 auto guardShutdown
= mozilla::MakeScopeExit([&] {
411 gAngleErrorReporter
.SetFailureId(nullptr);
412 // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the
413 // ANGLE display is destroyed. However gAngleErrorReporter
414 // will live longer than the ANGLE display so we're fine.
417 if (gfx::gfxConfig::IsForcedOnByUser(gfx::Feature::D3D11_HW_ANGLE
)) {
418 return GetAndInitDisplay(egl
, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE
,
422 std::shared_ptr
<EglDisplay
> ret
;
423 if (d3d11ANGLE
.IsEnabled()) {
424 ret
= GetAndInitDisplay(egl
, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE
,
429 ret
= GetAndInitDisplay(egl
, EGL_DEFAULT_DISPLAY
, aProofOfLock
);
432 if (!ret
&& out_failureId
->IsEmpty()) {
433 *out_failureId
= "FEATURE_FAILURE_ACCL_ANGLE_NO_DISP"_ns
;
442 # define GLES2_LIB "libGLESv2.so"
443 # define GLES2_LIB2 "libGLESv2.so.2"
444 # define GL_LIB "libGL.so"
445 # define GL_LIB2 "libGL.so.1"
446 #elif defined(XP_WIN)
447 # define GLES2_LIB "libGLESv2.dll"
449 # error "Platform not recognized"
452 Maybe
<SymbolLoader
> GLLibraryEGL::GetSymbolLoader() const {
453 auto ret
= SymbolLoader(mSymbols
.fGetProcAddress
);
454 ret
.mLib
= mGLLibrary
;
461 RefPtr
<GLLibraryEGL
> GLLibraryEGL::Get(nsACString
* const out_failureId
) {
462 StaticMutexAutoLock
lock(sMutex
);
464 sInstance
= new GLLibraryEGL
;
465 if (NS_WARN_IF(!sInstance
->Init(out_failureId
))) {
472 /* static */ void GLLibraryEGL::Shutdown() {
473 StaticMutexAutoLock
lock(sMutex
);
477 bool GLLibraryEGL::Init(nsACString
* const out_failureId
) {
478 MOZ_RELEASE_ASSERT(!mSymbols
.fTerminate
);
480 mozilla::ScopedGfxFeatureReporter
reporter("EGL");
484 // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul
485 // and we should look for them there. We have to load the libs in this
486 // order, because libEGL.dll depends on libGLESv2.dll which depends on the
487 // DXSDK libraries. This matters especially for WebRT apps which are in a
488 // different directory. See bug 760323 and bug 749459
490 // Also note that we intentionally leak the libs we load.
493 // Windows 8.1+ has d3dcompiler_47.dll in the system directory.
494 if (LoadLibrarySystem32(L
"d3dcompiler_47.dll")) break;
496 MOZ_ASSERT(false, "d3dcompiler DLL loading failed.");
499 mGLLibrary
= LoadLibraryForEGLOnWindows(u
"libGLESv2.dll"_ns
);
501 mEGLLibrary
= LoadLibraryForEGLOnWindows(u
"libEGL.dll"_ns
);
506 // On non-Windows (Android) we use system copies of libEGL. We look for
507 // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
509 # if defined(ANDROID)
510 if (!mEGLLibrary
) mEGLLibrary
= LoadApitraceLibrary();
514 mEGLLibrary
= PR_LoadLibrary("libEGL.so");
516 # if defined(XP_UNIX)
518 mEGLLibrary
= PR_LoadLibrary("libEGL.so.1");
524 mGLLibrary
= PR_LoadLibrary(APITRACE_LIB
);
530 mGLLibrary
= PR_LoadLibrary(GL_LIB
);
536 mGLLibrary
= PR_LoadLibrary(GL_LIB2
);
541 mGLLibrary
= PR_LoadLibrary(GLES2_LIB
);
546 mGLLibrary
= PR_LoadLibrary(GLES2_LIB2
);
552 if (!mEGLLibrary
|| !mGLLibrary
) {
553 NS_WARNING("Couldn't load EGL LIB.");
554 *out_failureId
= "FEATURE_FAILURE_EGL_LOAD_3"_ns
;
560 (PRFuncPtr*)&mSymbols.f##X, { \
564 #define END_OF_SYMBOLS \
569 SymLoadStruct earlySymbols
[] = {SYMBOL(GetDisplay
),
571 SYMBOL(GetCurrentSurface
),
572 SYMBOL(GetCurrentContext
),
574 SYMBOL(DestroyContext
),
575 SYMBOL(CreateContext
),
576 SYMBOL(DestroySurface
),
577 SYMBOL(CreateWindowSurface
),
578 SYMBOL(CreatePbufferSurface
),
579 SYMBOL(CreatePbufferFromClientBuffer
),
580 SYMBOL(CreatePixmapSurface
),
583 SYMBOL(ChooseConfig
),
586 SYMBOL(GetConfigAttrib
),
588 SYMBOL(GetProcAddress
),
592 SYMBOL(QueryContext
),
593 SYMBOL(BindTexImage
),
594 SYMBOL(ReleaseTexImage
),
595 SYMBOL(SwapInterval
),
596 SYMBOL(QuerySurface
),
600 const SymbolLoader
libLoader(*mEGLLibrary
);
601 if (!libLoader
.LoadSymbols(earlySymbols
)) {
603 "Couldn't find required entry points in EGL library (early init)");
604 *out_failureId
= "FEATURE_FAILURE_EGL_SYM"_ns
;
610 const char internalFuncName
[] =
611 "_Z35eglQueryStringImplementationANDROIDPvi";
612 const auto& internalFunc
=
613 PR_FindFunctionSymbol(mEGLLibrary
, internalFuncName
);
615 *(PRFuncPtr
*)&mSymbols
.fQueryString
= internalFunc
;
623 const SymbolLoader
pfnLoader(mSymbols
.fGetProcAddress
);
625 const auto fnLoadSymbols
= [&](const SymLoadStruct
* symbols
) {
626 const bool shouldWarn
= gfxEnv::MOZ_GL_SPEW();
627 if (pfnLoader
.LoadSymbols(symbols
, shouldWarn
)) return true;
629 ClearSymbols(symbols
);
633 // Check the ANGLE support the system has
634 mIsANGLE
= IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle
);
636 // Client exts are ready. (But not display exts!)
639 MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d
));
640 const SymLoadStruct angleSymbols
[] = {SYMBOL(GetPlatformDisplay
),
642 if (!fnLoadSymbols(angleSymbols
)) {
643 gfxCriticalError() << "Failed to load ANGLE symbols!";
646 MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d
));
647 const SymLoadStruct createDeviceSymbols
[] = {
648 SYMBOL(CreateDeviceANGLE
), SYMBOL(ReleaseDeviceANGLE
), END_OF_SYMBOLS
};
649 if (!fnLoadSymbols(createDeviceSymbols
)) {
651 "EGL supports ANGLE_device_creation without exposing its functions!");
652 MarkExtensionUnsupported(EGLLibExtension::ANGLE_device_creation
);
656 // ANDROID_get_native_client_buffer isn't necessarily enumerated in lib exts,
659 const SymLoadStruct symbols
[] = {SYMBOL(GetNativeClientBufferANDROID
),
661 if (fnLoadSymbols(symbols
)) {
662 mAvailableExtensions
[UnderlyingValue(
663 EGLLibExtension::ANDROID_get_native_client_buffer
)] = true;
668 // Load possible display ext symbols.
671 const SymLoadStruct symbols
[] = {SYMBOL(QuerySurfacePointerANGLE
),
673 (void)fnLoadSymbols(symbols
);
676 const SymLoadStruct symbols
[] = {
677 SYMBOL(CreateSyncKHR
), SYMBOL(DestroySyncKHR
),
678 SYMBOL(ClientWaitSyncKHR
), SYMBOL(GetSyncAttribKHR
), END_OF_SYMBOLS
};
679 (void)fnLoadSymbols(symbols
);
682 const SymLoadStruct symbols
[] = {SYMBOL(CreateImageKHR
),
683 SYMBOL(DestroyImageKHR
), END_OF_SYMBOLS
};
684 (void)fnLoadSymbols(symbols
);
687 const SymLoadStruct symbols
[] = {SYMBOL(WaitSyncKHR
), END_OF_SYMBOLS
};
688 (void)fnLoadSymbols(symbols
);
691 const SymLoadStruct symbols
[] = {SYMBOL(DupNativeFenceFDANDROID
),
693 (void)fnLoadSymbols(symbols
);
696 const SymLoadStruct symbols
[] = {SYMBOL(CreateStreamKHR
),
697 SYMBOL(DestroyStreamKHR
),
698 SYMBOL(QueryStreamKHR
), END_OF_SYMBOLS
};
699 (void)fnLoadSymbols(symbols
);
702 const SymLoadStruct symbols
[] = {SYMBOL(StreamConsumerGLTextureExternalKHR
),
703 SYMBOL(StreamConsumerAcquireKHR
),
704 SYMBOL(StreamConsumerReleaseKHR
),
706 (void)fnLoadSymbols(symbols
);
709 const SymLoadStruct symbols
[] = {
710 SYMBOL(QueryDisplayAttribEXT
), SYMBOL(QueryDeviceAttribEXT
),
711 SYMBOL(QueryDeviceStringEXT
), END_OF_SYMBOLS
};
712 (void)fnLoadSymbols(symbols
);
715 const SymLoadStruct symbols
[] = {
716 SYMBOL(StreamConsumerGLTextureExternalAttribsNV
), END_OF_SYMBOLS
};
717 (void)fnLoadSymbols(symbols
);
720 const SymLoadStruct symbols
[] = {
721 SYMBOL(CreateStreamProducerD3DTextureANGLE
),
722 SYMBOL(StreamPostD3DTextureANGLE
), END_OF_SYMBOLS
};
723 (void)fnLoadSymbols(symbols
);
726 const SymLoadStruct symbols
[] = {
727 {(PRFuncPtr
*)&mSymbols
.fSwapBuffersWithDamage
,
728 {{"eglSwapBuffersWithDamageEXT"}}},
730 (void)fnLoadSymbols(symbols
);
733 const SymLoadStruct symbols
[] = {
734 {(PRFuncPtr
*)&mSymbols
.fSwapBuffersWithDamage
,
735 {{"eglSwapBuffersWithDamageKHR"}}},
737 (void)fnLoadSymbols(symbols
);
740 const SymLoadStruct symbols
[] = {
741 {(PRFuncPtr
*)&mSymbols
.fSetDamageRegion
, {{"eglSetDamageRegionKHR"}}},
743 (void)fnLoadSymbols(symbols
);
746 const SymLoadStruct symbols
[] = {SYMBOL(GetPlatformDisplay
),
748 (void)fnLoadSymbols(symbols
);
751 const SymLoadStruct symbols
[] = {SYMBOL(ExportDMABUFImageQueryMESA
),
752 SYMBOL(ExportDMABUFImageMESA
),
754 (void)fnLoadSymbols(symbols
);
757 const SymLoadStruct symbols
[] = {SYMBOL(QueryDevicesEXT
), END_OF_SYMBOLS
};
758 (void)fnLoadSymbols(symbols
);
767 static void MarkExtensions(const char* rawExtString
, bool shouldDumpExts
,
768 const char* extType
, const char* const (&names
)[N
],
769 std::bitset
<N
>* const out
) {
770 MOZ_ASSERT(rawExtString
);
772 const nsDependentCString
extString(rawExtString
);
774 std::vector
<nsCString
> extList
;
775 SplitByChar(extString
, ' ', &extList
);
777 if (shouldDumpExts
) {
778 printf_stderr("%u EGL %s extensions: (*: recognized)\n",
779 (uint32_t)extList
.size(), extType
);
782 MarkBitfieldByStrings(extList
, shouldDumpExts
, names
, out
);
788 std::shared_ptr
<EglDisplay
> EglDisplay::Create(
789 GLLibraryEGL
& lib
, const EGLDisplay display
, const bool isWarp
,
790 const StaticMutexAutoLock
& aProofOfLock
) {
791 // Retrieve the EglDisplay if it already exists
793 const auto itr
= lib
.mActiveDisplays
.find(display
);
794 if (itr
!= lib
.mActiveDisplays
.end()) {
795 const auto ret
= itr
->second
.lock();
802 if (!lib
.fInitialize(display
, nullptr, nullptr)) {
806 static std::once_flag sMesaLeakFlag
;
807 std::call_once(sMesaLeakFlag
, MesaMemoryLeakWorkaround
);
810 std::make_shared
<EglDisplay
>(PrivateUseOnly
{}, lib
, display
, isWarp
);
811 lib
.mActiveDisplays
.insert({display
, ret
});
815 EglDisplay::EglDisplay(const PrivateUseOnly
&, GLLibraryEGL
& lib
,
816 const EGLDisplay disp
, const bool isWarp
)
817 : mLib(&lib
), mDisplay(disp
), mIsWARP(isWarp
) {
818 const bool shouldDumpExts
= GLContext::ShouldDumpExts();
821 (const char*)mLib
->fQueryString(mDisplay
, LOCAL_EGL_EXTENSIONS
);
823 NS_WARNING("Failed to query EGL display extensions!.");
826 MarkExtensions(rawExtString
, shouldDumpExts
, "display", sEGLExtensionNames
,
827 &mAvailableExtensions
);
831 if (!HasKHRImageBase()) {
832 MarkExtensionUnsupported(EGLExtension::KHR_image_pixmap
);
835 if (IsExtensionSupported(EGLExtension::KHR_surfaceless_context
)) {
837 (const char*)mLib
->fQueryString(mDisplay
, LOCAL_EGL_VENDOR
);
839 // Bug 1464610: Mali T720 (Amazon Fire 8 HD) claims to support this
840 // extension, but if you actually eglMakeCurrent() with EGL_NO_SURFACE, it
841 // fails to render anything when a real surface is provided later on. We
842 // only have the EGL vendor available here, so just avoid using this
843 // extension on all Mali devices.
844 if (vendor
&& (strcmp(vendor
, "ARM") == 0)) {
845 MarkExtensionUnsupported(EGLExtension::KHR_surfaceless_context
);
849 // ANDROID_native_fence_sync isn't necessarily enumerated in display ext,
851 if (mLib
->mSymbols
.fDupNativeFenceFDANDROID
) {
852 mAvailableExtensions
[UnderlyingValue(
853 EGLExtension::ANDROID_native_fence_sync
)] = true;
857 EglDisplay::~EglDisplay() {
858 StaticMutexAutoLock
lock(GLLibraryEGL::sMutex
);
860 mLib
->mActiveDisplays
.erase(mDisplay
);
865 std::shared_ptr
<EglDisplay
> GLLibraryEGL::DefaultDisplay(
866 nsACString
* const out_failureId
) {
867 StaticMutexAutoLock
lock(sMutex
);
868 auto ret
= mDefaultDisplay
.lock();
871 ret
= CreateDisplayLocked(false, out_failureId
, lock
);
872 mDefaultDisplay
= ret
;
876 std::shared_ptr
<EglDisplay
> GLLibraryEGL::CreateDisplay(
877 const bool forceAccel
, nsACString
* const out_failureId
) {
878 StaticMutexAutoLock
lock(sMutex
);
879 return CreateDisplayLocked(forceAccel
, out_failureId
, lock
);
882 std::shared_ptr
<EglDisplay
> GLLibraryEGL::CreateDisplayLocked(
883 const bool forceAccel
, nsACString
* const out_failureId
,
884 const StaticMutexAutoLock
& aProofOfLock
) {
885 std::shared_ptr
<EglDisplay
> ret
;
887 if (IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d
)) {
888 nsCString accelAngleFailureId
;
889 bool accelAngleSupport
= IsAccelAngleSupported(&accelAngleFailureId
);
890 bool shouldTryAccel
= forceAccel
|| accelAngleSupport
;
891 bool shouldTryWARP
= !forceAccel
; // Only if ANGLE not supported or fails
893 // If WARP preferred, will override ANGLE support
894 if (StaticPrefs::webgl_angle_force_warp()) {
895 shouldTryWARP
= true;
896 shouldTryAccel
= false;
897 if (accelAngleFailureId
.IsEmpty()) {
898 accelAngleFailureId
= "FEATURE_FAILURE_FORCE_WARP"_ns
;
902 // Hardware accelerated ANGLE path (supported or force accel)
903 if (shouldTryAccel
) {
904 ret
= GetAndInitDisplayForAccelANGLE(*this, out_failureId
, aProofOfLock
);
907 // Report the acceleration status to telemetry
909 if (accelAngleFailureId
.IsEmpty()) {
910 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID
,
911 "FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"_ns
);
913 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID
,
914 accelAngleFailureId
);
917 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID
,
921 // Fallback to a WARP display if ANGLE fails, or if WARP is forced
922 if (!ret
&& shouldTryWARP
) {
923 ret
= GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY
, aProofOfLock
);
925 if (out_failureId
->IsEmpty()) {
926 *out_failureId
= "FEATURE_FAILURE_WARP_FALLBACK"_ns
;
928 NS_ERROR("Fallback WARP context failed to initialize.");
933 void* nativeDisplay
= EGL_DEFAULT_DISPLAY
;
934 #ifdef MOZ_WIDGET_GTK
935 if (!ret
&& !gfx::gfxVars::WebglUseHardware()) {
936 // Initialize a swrast egl device such as llvmpipe
937 ret
= GetAndInitSoftwareDisplay(*this, aProofOfLock
);
939 // Initialize the display the normal way
940 if (!ret
&& !gdk_display_get_default()) {
941 ret
= GetAndInitDeviceDisplay(*this, aProofOfLock
);
943 ret
= GetAndInitSurfacelessDisplay(*this, aProofOfLock
);
947 else if (!ret
&& widget::GdkIsWaylandDisplay()) {
948 // Wayland does not support EGL_DEFAULT_DISPLAY
949 nativeDisplay
= widget::WaylandDisplayGetWLDisplay();
950 if (!nativeDisplay
) {
951 NS_WARNING("Failed to get wl_display.");
958 ret
= GetAndInitDisplay(*this, nativeDisplay
, aProofOfLock
);
963 if (out_failureId
->IsEmpty()) {
964 *out_failureId
= "FEATURE_FAILURE_NO_DISPLAY"_ns
;
966 NS_WARNING("Failed to initialize a display.");
973 void GLLibraryEGL::InitLibExtensions() {
974 const bool shouldDumpExts
= GLContext::ShouldDumpExts();
976 const char* rawExtString
= nullptr;
979 // Bug 1209612: Crashes on a number of android drivers.
980 // Ideally we would only blocklist this there, but for now we don't need the
981 // client extension list on ANDROID (we mostly need it on ANGLE), and we'd
983 rawExtString
= (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS
);
987 if (shouldDumpExts
) {
988 printf_stderr("No EGL lib extensions.\n");
993 MarkExtensions(rawExtString
, shouldDumpExts
, "lib", sEGLLibraryExtensionNames
,
994 &mAvailableExtensions
);
997 void EglDisplay::DumpEGLConfig(EGLConfig cfg
) const {
1001 mLib->fGetConfigAttrib(mDisplay, cfg, LOCAL_EGL_##_x, &attrval); \
1002 const auto err = mLib->fGetError(); \
1003 if (err != 0x3000) { \
1004 printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \
1006 printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \
1010 printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg
, cfg
);
1019 ATTR(CONFIG_CAVEAT
);
1022 ATTR(MAX_PBUFFER_HEIGHT
);
1023 ATTR(MAX_PBUFFER_PIXELS
);
1024 ATTR(MAX_PBUFFER_WIDTH
);
1025 ATTR(NATIVE_RENDERABLE
);
1026 ATTR(NATIVE_VISUAL_ID
);
1027 ATTR(NATIVE_VISUAL_TYPE
);
1028 ATTR(PRESERVED_RESOURCES
);
1030 ATTR(SAMPLE_BUFFERS
);
1032 ATTR(TRANSPARENT_TYPE
);
1033 ATTR(TRANSPARENT_RED_VALUE
);
1034 ATTR(TRANSPARENT_GREEN_VALUE
);
1035 ATTR(TRANSPARENT_BLUE_VALUE
);
1036 ATTR(BIND_TO_TEXTURE_RGB
);
1037 ATTR(BIND_TO_TEXTURE_RGBA
);
1038 ATTR(MIN_SWAP_INTERVAL
);
1039 ATTR(MAX_SWAP_INTERVAL
);
1040 ATTR(LUMINANCE_SIZE
);
1041 ATTR(ALPHA_MASK_SIZE
);
1042 ATTR(COLOR_BUFFER_TYPE
);
1043 ATTR(RENDERABLE_TYPE
);
1049 void EglDisplay::DumpEGLConfigs() const {
1051 mLib
->fGetConfigs(mDisplay
, nullptr, 0, &nc
);
1052 std::vector
<EGLConfig
> ec(nc
);
1053 mLib
->fGetConfigs(mDisplay
, ec
.data(), ec
.size(), &nc
);
1055 for (int i
= 0; i
< nc
; ++i
) {
1056 printf_stderr("========= EGL Config %d ========\n", i
);
1057 DumpEGLConfig(ec
[i
]);
1061 static bool ShouldTrace() {
1062 static bool ret
= gfxEnv::MOZ_GL_DEBUG_VERBOSE();
1066 void BeforeEGLCall(const char* glFunction
) {
1067 if (ShouldTrace()) {
1068 printf_stderr("[egl] > %s\n", glFunction
);
1072 void AfterEGLCall(const char* glFunction
) {
1073 if (ShouldTrace()) {
1074 printf_stderr("[egl] < %s\n", glFunction
);
1078 } /* namespace gl */
1079 } /* namespace mozilla */