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"
12 #include "base/message_loop.h" // for MessageLoop
13 #include "mozilla/StaticPrefs_widget.h"
14 #include "mozilla/StaticPrefs_media.h"
15 #include "mozilla/gfx/gfxVars.h"
16 #include "WidgetUtilsGtk.h"
17 #include "gfxConfig.h"
18 #include "nsIGfxInfo.h"
19 #include "mozilla/Components.h"
20 #include "mozilla/ClearOnShutdown.h"
22 #include <sys/types.h>
30 using namespace mozilla::gfx
;
35 bool sUseWebGLDmabufBackend
= true;
37 #define GBMLIB_NAME "libgbm.so.1"
38 #define DRMLIB_NAME "libdrm.so.2"
40 // Use static lock to protect dri operation as
41 // gbm_dri.c is not thread safe.
42 // https://gitlab.freedesktop.org/mesa/mesa/-/issues/4422
43 mozilla::StaticMutex
GbmLib::sDRILock MOZ_UNANNOTATED
;
45 bool GbmLib::sLoaded
= false;
46 void* GbmLib::sGbmLibHandle
= nullptr;
47 void* GbmLib::sXf86DrmLibHandle
= nullptr;
48 CreateDeviceFunc
GbmLib::sCreateDevice
;
49 DestroyDeviceFunc
GbmLib::sDestroyDevice
;
50 CreateFunc
GbmLib::sCreate
;
51 CreateWithModifiersFunc
GbmLib::sCreateWithModifiers
;
52 GetModifierFunc
GbmLib::sGetModifier
;
53 GetStrideFunc
GbmLib::sGetStride
;
54 GetFdFunc
GbmLib::sGetFd
;
55 DestroyFunc
GbmLib::sDestroy
;
57 UnmapFunc
GbmLib::sUnmap
;
58 GetPlaneCountFunc
GbmLib::sGetPlaneCount
;
59 GetHandleForPlaneFunc
GbmLib::sGetHandleForPlane
;
60 GetStrideForPlaneFunc
GbmLib::sGetStrideForPlane
;
61 GetOffsetFunc
GbmLib::sGetOffset
;
62 DeviceIsFormatSupportedFunc
GbmLib::sDeviceIsFormatSupported
;
63 DrmPrimeHandleToFDFunc
GbmLib::sDrmPrimeHandleToFD
;
64 CreateSurfaceFunc
GbmLib::sCreateSurface
;
65 DestroySurfaceFunc
GbmLib::sDestroySurface
;
67 bool GbmLib::IsLoaded() {
68 return sCreateDevice
!= nullptr && sDestroyDevice
!= nullptr &&
69 sCreate
!= nullptr && sCreateWithModifiers
!= nullptr &&
70 sGetModifier
!= nullptr && sGetStride
!= nullptr &&
71 sGetFd
!= nullptr && sDestroy
!= nullptr && sMap
!= nullptr &&
72 sUnmap
!= nullptr && sGetPlaneCount
!= nullptr &&
73 sGetHandleForPlane
!= nullptr && sGetStrideForPlane
!= nullptr &&
74 sGetOffset
!= nullptr && sDeviceIsFormatSupported
!= nullptr &&
75 sDrmPrimeHandleToFD
!= nullptr && sCreateSurface
!= nullptr &&
76 sDestroySurface
!= nullptr;
80 static bool sTriedToLoad
= false;
87 MOZ_ASSERT(!sGbmLibHandle
);
90 LOGDMABUF(("Loading DMABuf system library %s ...\n", GBMLIB_NAME
));
92 sGbmLibHandle
= dlopen(GBMLIB_NAME
, RTLD_LAZY
| RTLD_LOCAL
);
94 LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", GBMLIB_NAME
));
98 sCreateDevice
= (CreateDeviceFunc
)dlsym(sGbmLibHandle
, "gbm_create_device");
100 (DestroyDeviceFunc
)dlsym(sGbmLibHandle
, "gbm_device_destroy");
101 sCreate
= (CreateFunc
)dlsym(sGbmLibHandle
, "gbm_bo_create");
102 sCreateWithModifiers
= (CreateWithModifiersFunc
)dlsym(
103 sGbmLibHandle
, "gbm_bo_create_with_modifiers");
104 sGetModifier
= (GetModifierFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_modifier");
105 sGetStride
= (GetStrideFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_stride");
106 sGetFd
= (GetFdFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_fd");
107 sDestroy
= (DestroyFunc
)dlsym(sGbmLibHandle
, "gbm_bo_destroy");
108 sMap
= (MapFunc
)dlsym(sGbmLibHandle
, "gbm_bo_map");
109 sUnmap
= (UnmapFunc
)dlsym(sGbmLibHandle
, "gbm_bo_unmap");
111 (GetPlaneCountFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_plane_count");
112 sGetHandleForPlane
= (GetHandleForPlaneFunc
)dlsym(
113 sGbmLibHandle
, "gbm_bo_get_handle_for_plane");
114 sGetStrideForPlane
= (GetStrideForPlaneFunc
)dlsym(
115 sGbmLibHandle
, "gbm_bo_get_stride_for_plane");
116 sGetOffset
= (GetOffsetFunc
)dlsym(sGbmLibHandle
, "gbm_bo_get_offset");
117 sDeviceIsFormatSupported
= (DeviceIsFormatSupportedFunc
)dlsym(
118 sGbmLibHandle
, "gbm_device_is_format_supported");
120 (CreateSurfaceFunc
)dlsym(sGbmLibHandle
, "gbm_surface_create");
122 (DestroySurfaceFunc
)dlsym(sGbmLibHandle
, "gbm_surface_destroy");
124 sXf86DrmLibHandle
= dlopen(DRMLIB_NAME
, RTLD_LAZY
| RTLD_LOCAL
);
125 if (!sXf86DrmLibHandle
) {
126 LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", DRMLIB_NAME
));
129 sDrmPrimeHandleToFD
=
130 (DrmPrimeHandleToFDFunc
)dlsym(sXf86DrmLibHandle
, "drmPrimeHandleToFD");
131 sLoaded
= IsLoaded();
133 LOGDMABUF(("Failed to load all symbols from %s\n", GBMLIB_NAME
));
138 int DMABufDevice::GetDmabufFD(uint32_t aGEMHandle
) {
140 return GbmLib::DrmPrimeHandleToFD(mDRMFd
, aGEMHandle
, 0, &fd
) < 0 ? -1 : fd
;
143 gbm_device
* DMABufDevice::GetGbmDevice() {
144 std::call_once(mFlagGbmDevice
, [&] {
145 mGbmDevice
= (mDRMFd
!= -1) ? GbmLib::CreateDevice(mDRMFd
) : nullptr;
150 int DMABufDevice::OpenDRMFd() { return open(mDrmRenderNode
.get(), O_RDWR
); }
152 bool DMABufDevice::IsEnabled(nsACString
& aFailureId
) {
154 aFailureId
= mFailureId
;
159 DMABufDevice::DMABufDevice()
160 : mXRGBFormat({true, false, GBM_FORMAT_XRGB8888
, {}}),
161 mARGBFormat({true, true, GBM_FORMAT_ARGB8888
, {}}) {
165 DMABufDevice::~DMABufDevice() {
167 GbmLib::DestroyDevice(mGbmDevice
);
168 mGbmDevice
= nullptr;
176 void DMABufDevice::Configure() {
177 LOGDMABUF(("DMABufDevice::Configure()"));
179 if (!GbmLib::IsAvailable()) {
180 LOGDMABUF(("GbmLib is not available!"));
181 mFailureId
= "FEATURE_FAILURE_NO_LIBGBM";
185 mDrmRenderNode
= nsAutoCString(getenv("MOZ_DRM_DEVICE"));
186 if (mDrmRenderNode
.IsEmpty()) {
187 mDrmRenderNode
.Assign(gfx::gfxVars::DrmRenderDevice());
189 if (mDrmRenderNode
.IsEmpty()) {
190 LOGDMABUF(("We're missing DRM render device!\n"));
191 mFailureId
= "FEATURE_FAILURE_NO_DRM_DEVICE";
195 LOGDMABUF(("Using DRM device %s", mDrmRenderNode
.get()));
196 mDRMFd
= open(mDrmRenderNode
.get(), O_RDWR
);
198 LOGDMABUF(("Failed to open drm render node %s error %s\n",
199 mDrmRenderNode
.get(), strerror(errno
)));
200 mFailureId
= "FEATURE_FAILURE_NO_DRM_DEVICE";
205 LoadFormatModifiers();
208 LOGDMABUF(("DMABuf is enabled"));
212 bool DMABufDevice::IsDMABufTexturesEnabled() {
213 return gfx::gfxVars::UseDMABuf() &&
214 StaticPrefs::widget_dmabuf_textures_enabled();
217 bool DMABufDevice::IsDMABufTexturesEnabled() { return false; }
219 bool DMABufDevice::IsDMABufWebGLEnabled() {
221 ("DMABufDevice::IsDMABufWebGLEnabled: UseDMABuf %d "
222 "sUseWebGLDmabufBackend %d "
223 "widget_dmabuf_webgl_enabled %d\n",
224 gfx::gfxVars::UseDMABuf(), sUseWebGLDmabufBackend
,
225 StaticPrefs::widget_dmabuf_webgl_enabled()));
226 return gfx::gfxVars::UseDMABuf() && sUseWebGLDmabufBackend
&&
227 StaticPrefs::widget_dmabuf_webgl_enabled();
231 void DMABufDevice::SetModifiersToGfxVars() {
232 gfxVars::SetDMABufModifiersXRGB(mXRGBFormat
.mModifiers
);
233 gfxVars::SetDMABufModifiersARGB(mARGBFormat
.mModifiers
);
236 void DMABufDevice::GetModifiersFromGfxVars() {
237 mXRGBFormat
.mModifiers
= gfxVars::DMABufModifiersXRGB().Clone();
238 mARGBFormat
.mModifiers
= gfxVars::DMABufModifiersARGB().Clone();
242 void DMABufDevice::DisableDMABufWebGL() { sUseWebGLDmabufBackend
= false; }
244 GbmFormat
* DMABufDevice::GetGbmFormat(bool aHasAlpha
) {
245 GbmFormat
* format
= aHasAlpha
? &mARGBFormat
: &mXRGBFormat
;
246 return format
->mIsSupported
? format
: nullptr;
250 void DMABufDevice::AddFormatModifier(bool aHasAlpha
, int aFormat
,
251 uint32_t mModifierHi
,
252 uint32_t mModifierLo
) {
253 GbmFormat
* format
= aHasAlpha
? &mARGBFormat
: &mXRGBFormat
;
254 format
->mIsSupported
= true;
255 format
->mHasAlpha
= aHasAlpha
;
256 format
->mFormat
= aFormat
;
257 format
->mModifiers
.AppendElement(((uint64_t)mModifierHi
<< 32) | mModifierLo
);
260 static void dmabuf_modifiers(void* data
,
261 struct zwp_linux_dmabuf_v1
* zwp_linux_dmabuf
,
262 uint32_t format
, uint32_t modifier_hi
,
263 uint32_t modifier_lo
) {
264 // skip modifiers marked as invalid
265 if (modifier_hi
== (DRM_FORMAT_MOD_INVALID
>> 32) &&
266 modifier_lo
== (DRM_FORMAT_MOD_INVALID
& 0xffffffff)) {
270 auto* device
= static_cast<DMABufDevice
*>(data
);
272 case GBM_FORMAT_ARGB8888
:
273 device
->AddFormatModifier(true, format
, modifier_hi
, modifier_lo
);
275 case GBM_FORMAT_XRGB8888
:
276 device
->AddFormatModifier(false, format
, modifier_hi
, modifier_lo
);
283 static void dmabuf_format(void* data
,
284 struct zwp_linux_dmabuf_v1
* zwp_linux_dmabuf
,
289 static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener
= {
290 dmabuf_format
, dmabuf_modifiers
};
292 static void global_registry_handler(void* data
, wl_registry
* registry
,
293 uint32_t id
, const char* interface
,
295 if (strcmp(interface
, "zwp_linux_dmabuf_v1") == 0 && version
> 2) {
296 auto* dmabuf
= WaylandRegistryBind
<zwp_linux_dmabuf_v1
>(
297 registry
, id
, &zwp_linux_dmabuf_v1_interface
, 3);
298 LOGDMABUF(("zwp_linux_dmabuf_v1 is available."));
299 zwp_linux_dmabuf_v1_add_listener(dmabuf
, &dmabuf_listener
, data
);
300 } else if (strcmp(interface
, "wl_drm") == 0) {
301 LOGDMABUF(("wl_drm is available."));
305 static void global_registry_remover(void* data
, wl_registry
* registry
,
308 static const struct wl_registry_listener registry_listener
= {
309 global_registry_handler
, global_registry_remover
};
311 void DMABufDevice::LoadFormatModifiers() {
312 if (!GdkIsWaylandDisplay()) {
315 if (XRE_IsParentProcess()) {
316 MOZ_ASSERT(NS_IsMainThread());
317 wl_display
* display
= WaylandDisplayGetWLDisplay();
318 wl_registry
* registry
= wl_display_get_registry(display
);
319 wl_registry_add_listener(registry
, ®istry_listener
, this);
320 wl_display_roundtrip(display
);
321 wl_display_roundtrip(display
);
322 wl_registry_destroy(registry
);
323 SetModifiersToGfxVars();
325 GetModifiersFromGfxVars();
330 DMABufDevice
* GetDMABufDevice() {
331 static StaticAutoPtr
<DMABufDevice
> sDmaBufDevice
;
332 static std::once_flag onceFlag
;
333 std::call_once(onceFlag
, [] {
334 sDmaBufDevice
= new DMABufDevice();
335 if (NS_IsMainThread()) {
336 ClearOnShutdown(&sDmaBufDevice
);
338 NS_DispatchToMainThread(NS_NewRunnableFunction(
339 "ClearDmaBufDevice", [] { ClearOnShutdown(&sDmaBufDevice
); }));
342 return sDmaBufDevice
.get();
345 } // namespace widget
346 } // namespace mozilla