Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / widget / gtk / DMABufLibWrapper.cpp
blobdc4c428041cbf70f8d9d63f16eb97d119a5f848a
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
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"
9 #ifdef MOZ_WAYLAND
10 # include "nsWaylandDisplay.h"
11 # include "DMABufFormats.h"
12 #endif
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"
21 #include "GfxInfo.h"
22 #include "mozilla/Components.h"
23 #include "mozilla/ClearOnShutdown.h"
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <dlfcn.h>
29 #include <mutex>
30 #include <unistd.h>
31 #include "gbm.h"
33 using namespace mozilla::gfx;
35 namespace mozilla {
36 namespace widget {
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;
60 MapFunc GbmLib::sMap;
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;
83 bool GbmLib::Load() {
84 static bool sTriedToLoad = false;
85 if (sTriedToLoad) {
86 return sLoaded;
89 sTriedToLoad = true;
91 MOZ_ASSERT(!sGbmLibHandle);
92 MOZ_ASSERT(!sLoaded);
94 LOGDMABUF(("Loading DMABuf system library %s ...\n", GBMLIB_NAME));
96 sGbmLibHandle = dlopen(GBMLIB_NAME, RTLD_LAZY | RTLD_LOCAL);
97 if (!sGbmLibHandle) {
98 LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", GBMLIB_NAME));
99 return false;
102 sCreateDevice = (CreateDeviceFunc)dlsym(sGbmLibHandle, "gbm_create_device");
103 sDestroyDevice =
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");
116 sGetPlaneCount =
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");
125 sCreateSurface =
126 (CreateSurfaceFunc)dlsym(sGbmLibHandle, "gbm_surface_create");
127 sDestroySurface =
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));
133 return false;
135 sDrmPrimeHandleToFD =
136 (DrmPrimeHandleToFDFunc)dlsym(sXf86DrmLibHandle, "drmPrimeHandleToFD");
137 sLoaded = IsLoaded();
138 if (!sLoaded) {
139 LOGDMABUF(("Failed to load all symbols from %s\n", GBMLIB_NAME));
141 return sLoaded;
144 int DMABufDevice::GetDmabufFD(uint32_t aGEMHandle) {
145 int fd;
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;
153 return mGbmDevice;
156 int DMABufDevice::OpenDRMFd() { return open(mDrmRenderNode.get(), O_RDWR); }
158 bool DMABufDevice::IsEnabled(nsACString& aFailureId) {
159 if (mDRMFd == -1) {
160 aFailureId = mFailureId;
162 return mDRMFd != -1;
165 DMABufDevice::DMABufDevice() { Configure(); }
167 DMABufDevice::~DMABufDevice() {
168 if (mGbmDevice) {
169 GbmLib::DestroyDevice(mGbmDevice);
170 mGbmDevice = nullptr;
172 if (mDRMFd != -1) {
173 close(mDRMFd);
174 mDRMFd = -1;
178 void DMABufDevice::Configure() {
179 LOGDMABUF(("DMABufDevice::Configure()"));
181 if (!GbmLib::IsAvailable()) {
182 LOGDMABUF(("GbmLib is not available!"));
183 mFailureId = "FEATURE_FAILURE_NO_LIBGBM";
184 return;
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";
208 return;
211 LOGDMABUF(("Using DRM device %s", mDrmRenderNode.get()));
212 mDRMFd = open(mDrmRenderNode.get(), O_RDWR);
213 if (mDRMFd < 0) {
214 LOGDMABUF(("Failed to open drm render node %s error %s\n",
215 mDrmRenderNode.get(), strerror(errno)));
216 mFailureId = "FEATURE_FAILURE_NO_DRM_DEVICE";
217 return;
220 #ifdef MOZ_WAYLAND
221 LoadFormatModifiers();
222 #endif
224 LOGDMABUF(("DMABuf is enabled"));
227 #ifdef NIGHTLY_BUILD
228 bool DMABufDevice::IsDMABufTexturesEnabled() {
229 return gfx::gfxVars::UseDMABuf() &&
230 StaticPrefs::widget_dmabuf_textures_enabled();
232 #else
233 bool DMABufDevice::IsDMABufTexturesEnabled() { return false; }
234 #endif
235 bool DMABufDevice::IsDMABufWebGLEnabled() {
236 LOGDMABUF(
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();
246 #ifdef MOZ_WAYLAND
247 void DMABufDevice::SetModifiersToGfxVars() {
248 RefPtr<DMABufFormats> formats = WaylandDisplayGet()->GetDMABufFormats();
249 if (!formats) {
250 return;
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() {
263 mFormatRGBX =
264 new DRMFormat(GBM_FORMAT_XRGB8888, gfxVars::DMABufModifiersXRGB());
265 mFormatRGBX =
266 new DRMFormat(GBM_FORMAT_ARGB8888, gfxVars::DMABufModifiersARGB());
268 #endif
270 void DMABufDevice::DisableDMABufWebGL() { sUseWebGLDmabufBackend = false; }
272 RefPtr<DRMFormat> DMABufDevice::GetDRMFormat(int32_t aFOURCCFormat) {
273 switch (aFOURCCFormat) {
274 case GBM_FORMAT_XRGB8888:
275 return mFormatRGBX;
276 case GBM_FORMAT_ARGB8888:
277 return mFormatRGBA;
278 default:
279 gfxCriticalNoteOnce << "DMABufDevice::GetDRMFormat() unknow format: "
280 << aFOURCCFormat;
281 return nullptr;
285 #ifdef MOZ_WAYLAND
286 void DMABufDevice::LoadFormatModifiers() {
287 if (!GdkIsWaylandDisplay()) {
288 return;
290 if (XRE_IsParentProcess()) {
291 MOZ_ASSERT(NS_IsMainThread());
292 SetModifiersToGfxVars();
293 } else {
294 GetModifiersFromGfxVars();
297 #endif
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);
306 } else {
307 NS_DispatchToMainThread(NS_NewRunnableFunction(
308 "ClearDmaBufDevice", [] { ClearOnShutdown(&sDmaBufDevice); }));
311 return sDmaBufDevice.get();
314 } // namespace widget
315 } // namespace mozilla