1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "DMABufLibWrapper.h"
10 # include "nsWaylandDisplay.h"
11 # include "DMABufFormats.h"
13 #include "base/message_loop.h" // for MessageLoop
14 #include "mozilla/gfx/Logging.h" // for gfxCriticalNote
15 #include "mozilla/StaticPrefs_widget.h"
16 #include "mozilla/StaticPrefs_media.h"
17 #include "mozilla/gfx/gfxVars.h"
18 #include "WidgetUtilsGtk.h"
19 #include "gfxConfig.h"
20 #include "nsIGfxInfo.h"
22 #include "mozilla/Components.h"
23 #include "mozilla/ClearOnShutdown.h"
25 #include <sys/types.h>
33 using namespace mozilla::gfx
;
38 bool sUseWebGLDmabufBackend
= true;
40 #define GBMLIB_NAME "libgbm.so.1"
41 #define DRMLIB_NAME "libdrm.so.2"
43 // Use static lock to protect dri operation as
44 // gbm_dri.c is not thread safe.
45 // https://gitlab.freedesktop.org/mesa/mesa/-/issues/4422
46 mozilla::StaticMutex
GbmLib::sDRILock MOZ_UNANNOTATED
;
48 bool GbmLib::sLoaded
= false;
49 void* GbmLib::sGbmLibHandle
= nullptr;
50 void* GbmLib::sXf86DrmLibHandle
= nullptr;
51 CreateDeviceFunc
GbmLib::sCreateDevice
;
52 DestroyDeviceFunc
GbmLib::sDestroyDevice
;
53 CreateFunc
GbmLib::sCreate
;
54 CreateWithModifiersFunc
GbmLib::sCreateWithModifiers
;
55 CreateWithModifiers2Func
GbmLib::sCreateWithModifiers2
;
56 GetModifierFunc
GbmLib::sGetModifier
;
57 GetStrideFunc
GbmLib::sGetStride
;
58 GetFdFunc
GbmLib::sGetFd
;
59 DestroyFunc
GbmLib::sDestroy
;
61 UnmapFunc
GbmLib::sUnmap
;
62 GetPlaneCountFunc
GbmLib::sGetPlaneCount
;
63 GetHandleForPlaneFunc
GbmLib::sGetHandleForPlane
;
64 GetStrideForPlaneFunc
GbmLib::sGetStrideForPlane
;
65 GetOffsetFunc
GbmLib::sGetOffset
;
66 DeviceIsFormatSupportedFunc
GbmLib::sDeviceIsFormatSupported
;
67 DrmPrimeHandleToFDFunc
GbmLib::sDrmPrimeHandleToFD
;
68 CreateSurfaceFunc
GbmLib::sCreateSurface
;
69 DestroySurfaceFunc
GbmLib::sDestroySurface
;
71 bool GbmLib::IsLoaded() {
72 return sCreateDevice
!= nullptr && sDestroyDevice
!= nullptr &&
73 sCreate
!= nullptr && sCreateWithModifiers
!= nullptr &&
74 sGetModifier
!= nullptr && sGetStride
!= nullptr &&
75 sGetFd
!= nullptr && sDestroy
!= nullptr && sMap
!= nullptr &&
76 sUnmap
!= nullptr && sGetPlaneCount
!= nullptr &&
77 sGetHandleForPlane
!= nullptr && sGetStrideForPlane
!= nullptr &&
78 sGetOffset
!= nullptr && sDeviceIsFormatSupported
!= nullptr &&
79 sDrmPrimeHandleToFD
!= nullptr && sCreateSurface
!= nullptr &&
80 sDestroySurface
!= nullptr;
84 static bool sTriedToLoad
= false;
91 MOZ_ASSERT(!sGbmLibHandle
);
94 LOGDMABUF(("Loading DMABuf system library %s ...\n", GBMLIB_NAME
));
96 sGbmLibHandle
= dlopen(GBMLIB_NAME
, RTLD_LAZY
| RTLD_LOCAL
);
98 LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", GBMLIB_NAME
));
102 sCreateDevice
= (CreateDeviceFunc
)dlsym(sGbmLibHandle
, "gbm_create_device");
104 (DestroyDeviceFunc
)dlsym(sGbmLibHandle
, "gbm_device_destroy");
105 sCreate
= (CreateFunc
)dlsym(sGbmLibHandle
, "gbm_bo_create");
106 sCreateWithModifiers
= (CreateWithModifiersFunc
)dlsym(
107 sGbmLibHandle
, "gbm_bo_create_with_modifiers");
108 sCreateWithModifiers2
= (CreateWithModifiers2Func
)dlsym(
109 sGbmLibHandle
, "gbm_bo_create_with_modifiers2");
110 sGetModifier
= (GetModifierFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_modifier");
111 sGetStride
= (GetStrideFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_stride");
112 sGetFd
= (GetFdFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_fd");
113 sDestroy
= (DestroyFunc
)dlsym(sGbmLibHandle
, "gbm_bo_destroy");
114 sMap
= (MapFunc
)dlsym(sGbmLibHandle
, "gbm_bo_map");
115 sUnmap
= (UnmapFunc
)dlsym(sGbmLibHandle
, "gbm_bo_unmap");
117 (GetPlaneCountFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_plane_count");
118 sGetHandleForPlane
= (GetHandleForPlaneFunc
)dlsym(
119 sGbmLibHandle
, "gbm_bo_get_handle_for_plane");
120 sGetStrideForPlane
= (GetStrideForPlaneFunc
)dlsym(
121 sGbmLibHandle
, "gbm_bo_get_stride_for_plane");
122 sGetOffset
= (GetOffsetFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_offset");
123 sDeviceIsFormatSupported
= (DeviceIsFormatSupportedFunc
)dlsym(
124 sGbmLibHandle
, "gbm_device_is_format_supported");
126 (CreateSurfaceFunc
)dlsym(sGbmLibHandle
, "gbm_surface_create");
128 (DestroySurfaceFunc
)dlsym(sGbmLibHandle
, "gbm_surface_destroy");
130 sXf86DrmLibHandle
= dlopen(DRMLIB_NAME
, RTLD_LAZY
| RTLD_LOCAL
);
131 if (!sXf86DrmLibHandle
) {
132 LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", DRMLIB_NAME
));
135 sDrmPrimeHandleToFD
=
136 (DrmPrimeHandleToFDFunc
)dlsym(sXf86DrmLibHandle
, "drmPrimeHandleToFD");
137 sLoaded
= IsLoaded();
139 LOGDMABUF(("Failed to load all symbols from %s\n", GBMLIB_NAME
));
144 int DMABufDevice::GetDmabufFD(uint32_t aGEMHandle
) {
146 return GbmLib::DrmPrimeHandleToFD(mDRMFd
, aGEMHandle
, 0, &fd
) < 0 ? -1 : fd
;
149 gbm_device
* DMABufDevice::GetGbmDevice() {
150 std::call_once(mFlagGbmDevice
, [&] {
151 mGbmDevice
= (mDRMFd
!= -1) ? GbmLib::CreateDevice(mDRMFd
) : nullptr;
156 int DMABufDevice::OpenDRMFd() { return open(mDrmRenderNode
.get(), O_RDWR
); }
158 bool DMABufDevice::IsEnabled(nsACString
& aFailureId
) {
160 aFailureId
= mFailureId
;
165 DMABufDevice::DMABufDevice() { Configure(); }
167 DMABufDevice::~DMABufDevice() {
169 GbmLib::DestroyDevice(mGbmDevice
);
170 mGbmDevice
= nullptr;
178 void DMABufDevice::Configure() {
179 LOGDMABUF(("DMABufDevice::Configure()"));
181 if (!GbmLib::IsAvailable()) {
182 LOGDMABUF(("GbmLib is not available!"));
183 mFailureId
= "FEATURE_FAILURE_NO_LIBGBM";
187 // See Bug 1865747 for details.
188 if (XRE_IsParentProcess()) {
189 if (auto* gbmBackend
= getenv("GBM_BACKEND")) {
190 const nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
191 nsAutoString vendorID
;
192 gfxInfo
->GetAdapterVendorID(vendorID
);
193 if (vendorID
!= GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA
)) {
194 if (strstr(gbmBackend
, "nvidia")) {
195 unsetenv("GBM_BACKEND");
201 mDrmRenderNode
= nsAutoCString(getenv("MOZ_DRM_DEVICE"));
202 if (mDrmRenderNode
.IsEmpty()) {
203 mDrmRenderNode
.Assign(gfx::gfxVars::DrmRenderDevice());
205 if (mDrmRenderNode
.IsEmpty()) {
206 LOGDMABUF(("We're missing DRM render device!\n"));
207 mFailureId
= "FEATURE_FAILURE_NO_DRM_DEVICE";
211 LOGDMABUF(("Using DRM device %s", mDrmRenderNode
.get()));
212 mDRMFd
= open(mDrmRenderNode
.get(), O_RDWR
);
214 LOGDMABUF(("Failed to open drm render node %s error %s\n",
215 mDrmRenderNode
.get(), strerror(errno
)));
216 mFailureId
= "FEATURE_FAILURE_NO_DRM_DEVICE";
221 LoadFormatModifiers();
224 LOGDMABUF(("DMABuf is enabled"));
228 bool DMABufDevice::IsDMABufTexturesEnabled() {
229 return gfx::gfxVars::UseDMABuf() &&
230 StaticPrefs::widget_dmabuf_textures_enabled();
233 bool DMABufDevice::IsDMABufTexturesEnabled() { return false; }
235 bool DMABufDevice::IsDMABufWebGLEnabled() {
237 ("DMABufDevice::IsDMABufWebGLEnabled: UseDMABuf %d "
238 "sUseWebGLDmabufBackend %d "
239 "UseDMABufWebGL %d\n",
240 gfx::gfxVars::UseDMABuf(), sUseWebGLDmabufBackend
,
241 gfx::gfxVars::UseDMABufWebGL()));
242 return gfx::gfxVars::UseDMABuf() && sUseWebGLDmabufBackend
&&
243 gfx::gfxVars::UseDMABufWebGL();
247 void DMABufDevice::SetModifiersToGfxVars() {
248 RefPtr
<DMABufFormats
> formats
= WaylandDisplayGet()->GetDMABufFormats();
252 if (DRMFormat
* format
= formats
->GetFormat(GBM_FORMAT_XRGB8888
)) {
253 mFormatRGBX
= new DRMFormat(*format
);
254 gfxVars::SetDMABufModifiersXRGB(*format
->GetModifiers());
256 if (DRMFormat
* format
= formats
->GetFormat(GBM_FORMAT_ARGB8888
)) {
257 mFormatRGBA
= new DRMFormat(*format
);
258 gfxVars::SetDMABufModifiersARGB(*format
->GetModifiers());
262 void DMABufDevice::GetModifiersFromGfxVars() {
264 new DRMFormat(GBM_FORMAT_XRGB8888
, gfxVars::DMABufModifiersXRGB());
266 new DRMFormat(GBM_FORMAT_ARGB8888
, gfxVars::DMABufModifiersARGB());
270 void DMABufDevice::DisableDMABufWebGL() { sUseWebGLDmabufBackend
= false; }
272 RefPtr
<DRMFormat
> DMABufDevice::GetDRMFormat(int32_t aFOURCCFormat
) {
273 switch (aFOURCCFormat
) {
274 case GBM_FORMAT_XRGB8888
:
276 case GBM_FORMAT_ARGB8888
:
279 gfxCriticalNoteOnce
<< "DMABufDevice::GetDRMFormat() unknow format: "
286 void DMABufDevice::LoadFormatModifiers() {
287 if (!GdkIsWaylandDisplay()) {
290 if (XRE_IsParentProcess()) {
291 MOZ_ASSERT(NS_IsMainThread());
292 SetModifiersToGfxVars();
294 GetModifiersFromGfxVars();
299 DMABufDevice
* GetDMABufDevice() {
300 static StaticAutoPtr
<DMABufDevice
> sDmaBufDevice
;
301 static std::once_flag onceFlag
;
302 std::call_once(onceFlag
, [] {
303 sDmaBufDevice
= new DMABufDevice();
304 if (NS_IsMainThread()) {
305 ClearOnShutdown(&sDmaBufDevice
);
307 NS_DispatchToMainThread(NS_NewRunnableFunction(
308 "ClearDmaBufDevice", [] { ClearOnShutdown(&sDmaBufDevice
); }));
311 return sDmaBufDevice
.get();
314 } // namespace widget
315 } // namespace mozilla