diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /widget/gtk/DMABufLibWrapper.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget/gtk/DMABufLibWrapper.cpp')
-rw-r--r-- | widget/gtk/DMABufLibWrapper.cpp | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/widget/gtk/DMABufLibWrapper.cpp b/widget/gtk/DMABufLibWrapper.cpp new file mode 100644 index 0000000000..7a9ae98ff8 --- /dev/null +++ b/widget/gtk/DMABufLibWrapper.cpp @@ -0,0 +1,300 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=4: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsWaylandDisplay.h" +#include "DMABufLibWrapper.h" +#include "mozilla/StaticPrefs_widget.h" +#include "mozilla/StaticPrefs_media.h" +#include "mozilla/gfx/gfxVars.h" + +#include <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dlfcn.h> + +namespace mozilla { +namespace widget { + +#define GBMLIB_NAME "libgbm.so.1" +#define DRMLIB_NAME "libdrm.so.2" + +void* nsGbmLib::sGbmLibHandle = nullptr; +void* nsGbmLib::sXf86DrmLibHandle = nullptr; +bool nsGbmLib::sLibLoaded = false; +CreateDeviceFunc nsGbmLib::sCreateDevice; +CreateFunc nsGbmLib::sCreate; +CreateWithModifiersFunc nsGbmLib::sCreateWithModifiers; +GetModifierFunc nsGbmLib::sGetModifier; +GetStrideFunc nsGbmLib::sGetStride; +GetFdFunc nsGbmLib::sGetFd; +DestroyFunc nsGbmLib::sDestroy; +MapFunc nsGbmLib::sMap; +UnmapFunc nsGbmLib::sUnmap; +GetPlaneCountFunc nsGbmLib::sGetPlaneCount; +GetHandleForPlaneFunc nsGbmLib::sGetHandleForPlane; +GetStrideForPlaneFunc nsGbmLib::sGetStrideForPlane; +GetOffsetFunc nsGbmLib::sGetOffset; +DeviceIsFormatSupportedFunc nsGbmLib::sDeviceIsFormatSupported; +DrmPrimeHandleToFDFunc nsGbmLib::sDrmPrimeHandleToFD; + +bool nsGbmLib::IsLoaded() { + return sCreateDevice != nullptr && sCreate != nullptr && + sCreateWithModifiers != nullptr && sGetModifier != nullptr && + sGetStride != nullptr && sGetFd != nullptr && sDestroy != nullptr && + sMap != nullptr && sUnmap != nullptr && sGetPlaneCount != nullptr && + sGetHandleForPlane != nullptr && sGetStrideForPlane != nullptr && + sGetOffset != nullptr && sDeviceIsFormatSupported != nullptr && + sDrmPrimeHandleToFD != nullptr; +} + +bool nsGbmLib::IsAvailable() { + if (!Load()) { + return false; + } + return IsLoaded(); +} + +bool nsGbmLib::Load() { + if (!sGbmLibHandle && !sLibLoaded) { + sLibLoaded = true; + + sGbmLibHandle = dlopen(GBMLIB_NAME, RTLD_LAZY | RTLD_LOCAL); + if (!sGbmLibHandle) { + LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", GBMLIB_NAME)); + return false; + } + + sCreateDevice = (CreateDeviceFunc)dlsym(sGbmLibHandle, "gbm_create_device"); + sCreate = (CreateFunc)dlsym(sGbmLibHandle, "gbm_bo_create"); + sCreateWithModifiers = (CreateWithModifiersFunc)dlsym( + sGbmLibHandle, "gbm_bo_create_with_modifiers"); + sGetModifier = (GetModifierFunc)dlsym(sGbmLibHandle, "gbm_bo_get_modifier"); + sGetStride = (GetStrideFunc)dlsym(sGbmLibHandle, "gbm_bo_get_stride"); + sGetFd = (GetFdFunc)dlsym(sGbmLibHandle, "gbm_bo_get_fd"); + sDestroy = (DestroyFunc)dlsym(sGbmLibHandle, "gbm_bo_destroy"); + sMap = (MapFunc)dlsym(sGbmLibHandle, "gbm_bo_map"); + sUnmap = (UnmapFunc)dlsym(sGbmLibHandle, "gbm_bo_unmap"); + sGetPlaneCount = + (GetPlaneCountFunc)dlsym(sGbmLibHandle, "gbm_bo_get_plane_count"); + sGetHandleForPlane = (GetHandleForPlaneFunc)dlsym( + sGbmLibHandle, "gbm_bo_get_handle_for_plane"); + sGetStrideForPlane = (GetStrideForPlaneFunc)dlsym( + sGbmLibHandle, "gbm_bo_get_stride_for_plane"); + sGetOffset = (GetOffsetFunc)dlsym(sGbmLibHandle, "gbm_bo_get_offset"); + sDeviceIsFormatSupported = (DeviceIsFormatSupportedFunc)dlsym( + sGbmLibHandle, "gbm_device_is_format_supported"); + + sXf86DrmLibHandle = dlopen(DRMLIB_NAME, RTLD_LAZY | RTLD_LOCAL); + if (!sXf86DrmLibHandle) { + LOGDMABUF(("Failed to load %s, dmabuf isn't available.\n", DRMLIB_NAME)); + return false; + } + sDrmPrimeHandleToFD = + (DrmPrimeHandleToFDFunc)dlsym(sXf86DrmLibHandle, "drmPrimeHandleToFD"); + if (!IsLoaded()) { + LOGDMABUF(("Failed to load all symbols from %s\n", GBMLIB_NAME)); + } + } + + return sGbmLibHandle; +} + +gbm_device* nsDMABufDevice::GetGbmDevice() { + return IsDMABufEnabled() ? mGbmDevice : nullptr; +} + +int nsDMABufDevice::GetGbmDeviceFd() { return IsDMABufEnabled() ? mGbmFd : -1; } + +static void dmabuf_modifiers(void* data, + struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf, + uint32_t format, uint32_t modifier_hi, + uint32_t modifier_lo) { + auto* device = static_cast<nsDMABufDevice*>(data); + switch (format) { + case GBM_FORMAT_ARGB8888: + device->AddFormatModifier(true, format, modifier_hi, modifier_lo); + break; + case GBM_FORMAT_XRGB8888: + device->AddFormatModifier(false, format, modifier_hi, modifier_lo); + break; + default: + break; + } +} + +static void dmabuf_format(void* data, + struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf, + uint32_t format) { + // XXX: deprecated +} + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { + dmabuf_format, dmabuf_modifiers}; + +static void global_registry_handler(void* data, wl_registry* registry, + uint32_t id, const char* interface, + uint32_t version) { + auto* device = static_cast<nsDMABufDevice*>(data); + if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version > 2) { + auto* dmabuf = WaylandRegistryBind<zwp_linux_dmabuf_v1>( + registry, id, &zwp_linux_dmabuf_v1_interface, 3); + LOGDMABUF(("zwp_linux_dmabuf_v1 is available.")); + device->ResetFormatsModifiers(); + zwp_linux_dmabuf_v1_add_listener(dmabuf, &dmabuf_listener, data); + } else if (strcmp(interface, "wl_drm") == 0) { + LOGDMABUF(("wl_drm is available.")); + } +} + +static void global_registry_remover(void* data, wl_registry* registry, + uint32_t id) {} + +static const struct wl_registry_listener registry_listener = { + global_registry_handler, global_registry_remover}; + +nsDMABufDevice::nsDMABufDevice() + : mXRGBFormat({true, false, GBM_FORMAT_XRGB8888, nullptr, 0}), + mARGBFormat({true, true, GBM_FORMAT_ARGB8888, nullptr, 0}), + mGbmDevice(nullptr), + mGbmFd(-1) { + if (gdk_display_get_default() && + !GDK_IS_X11_DISPLAY(gdk_display_get_default())) { + wl_display* display = WaylandDisplayGetWLDisplay(); + mRegistry = (void*)wl_display_get_registry(display); + wl_registry_add_listener((wl_registry*)mRegistry, ®istry_listener, this); + wl_display_roundtrip(display); + wl_display_roundtrip(display); + } +} + +nsDMABufDevice::~nsDMABufDevice() { + if (mRegistry) { + wl_registry_destroy((wl_registry*)mRegistry); + mRegistry = nullptr; + } +} + +bool nsDMABufDevice::Configure() { + bool isDMABufUsed = ( +#ifdef NIGHTLY_BUILD + StaticPrefs::widget_dmabuf_textures_enabled() || +#endif + StaticPrefs::widget_dmabuf_webgl_enabled() || + StaticPrefs::media_ffmpeg_vaapi_enabled() || + StaticPrefs::media_ffmpeg_vaapi_drm_display_enabled()); + + if (!isDMABufUsed) { + // Disabled by user, just quit. + LOGDMABUF(("IsDMABufEnabled(): Disabled by preferences.")); + return false; + } + + if (!nsGbmLib::IsAvailable()) { + LOGDMABUF(("nsGbmLib is not available!")); + return false; + } + + nsAutoCString drm_render_node(getenv("MOZ_WAYLAND_DRM_DEVICE")); + if (drm_render_node.IsEmpty()) { + drm_render_node.Assign(gfx::gfxVars::DrmRenderDevice()); + if (drm_render_node.IsEmpty()) { + return false; + } + } + + mGbmFd = open(drm_render_node.get(), O_RDWR); + if (mGbmFd < 0) { + LOGDMABUF(("Failed to open drm render node %s\n", drm_render_node.get())); + return false; + } + + mGbmDevice = nsGbmLib::CreateDevice(mGbmFd); + if (!mGbmDevice) { + LOGDMABUF( + ("Failed to create drm render device %s\n", drm_render_node.get())); + close(mGbmFd); + mGbmFd = -1; + return false; + } + + LOGDMABUF(("GBM device initialized")); + return true; +} + +bool nsDMABufDevice::IsDMABufEnabled() { + static bool isDMABufEnabled = Configure(); + return isDMABufEnabled; +} + +#ifdef NIGHTLY_BUILD +bool nsDMABufDevice::IsDMABufTexturesEnabled() { + return gfx::gfxVars::UseEGL() && IsDMABufEnabled() && + StaticPrefs::widget_dmabuf_textures_enabled(); +} +#else +bool nsDMABufDevice::IsDMABufTexturesEnabled() { return false; } +#endif +bool nsDMABufDevice::IsDMABufVAAPIEnabled() { + return gfx::gfxVars::UseEGL() && IsDMABufEnabled() && + StaticPrefs::media_ffmpeg_vaapi_enabled() && + gfx::gfxVars::CanUseHardwareVideoDecoding() && !XRE_IsRDDProcess(); +} +bool nsDMABufDevice::IsDMABufWebGLEnabled() { + return gfx::gfxVars::UseEGL() && IsDMABufEnabled() && + StaticPrefs::widget_dmabuf_webgl_enabled(); +} + +GbmFormat* nsDMABufDevice::GetGbmFormat(bool aHasAlpha) { + GbmFormat* format = aHasAlpha ? &mARGBFormat : &mXRGBFormat; + return format->mIsSupported ? format : nullptr; +} + +GbmFormat* nsDMABufDevice::GetExactGbmFormat(int aFormat) { + if (aFormat == mARGBFormat.mFormat) { + return &mARGBFormat; + } else if (aFormat == mXRGBFormat.mFormat) { + return &mXRGBFormat; + } + + return nullptr; +} + +void nsDMABufDevice::AddFormatModifier(bool aHasAlpha, int aFormat, + uint32_t mModifierHi, + uint32_t mModifierLo) { + GbmFormat* format = aHasAlpha ? &mARGBFormat : &mXRGBFormat; + format->mIsSupported = true; + format->mHasAlpha = aHasAlpha; + format->mFormat = aFormat; + format->mModifiersCount++; + format->mModifiers = + (uint64_t*)realloc(format->mModifiers, + format->mModifiersCount * sizeof(*format->mModifiers)); + format->mModifiers[format->mModifiersCount - 1] = + ((uint64_t)mModifierHi << 32) | mModifierLo; +} + +void nsDMABufDevice::ResetFormatsModifiers() { + mARGBFormat.mModifiersCount = 0; + free(mARGBFormat.mModifiers); + mARGBFormat.mModifiers = nullptr; + + mXRGBFormat.mModifiersCount = 0; + free(mXRGBFormat.mModifiers); + mXRGBFormat.mModifiers = nullptr; +} + +nsDMABufDevice* GetDMABufDevice() { + static nsDMABufDevice dmaBufDevice; + return &dmaBufDevice; +} + +} // namespace widget +} // namespace mozilla |