From 60f1c6132340eebe8fe54864e4e6137ecca4e752 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sat, 7 Feb 2026 15:40:08 +0300 Subject: [PATCH] protocols/dmabuf: fix DMA-BUF checks and events (#12965) --- src/config/ConfigDescriptions.hpp | 6 ++++ src/config/ConfigManager.cpp | 1 + src/protocols/LinuxDMABUF.cpp | 60 ++++++++++++++++++++++++------- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 0a1e37d5..fa1ad35b 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -2047,5 +2047,11 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 2}, }, + SConfigOptionDescription{ + .value = "quirks:skip_non_kms_dmabuf_formats", + .description = "Do not report dmabuf formats which cannot be imported into KMS", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 09ec4456..61ba9dd3 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -791,6 +791,7 @@ CConfigManager::CConfigManager() { registerConfigVar("ecosystem:enforce_permissions", Hyprlang::INT{0}); registerConfigVar("quirks:prefer_hdr", Hyprlang::INT{0}); + registerConfigVar("quirks:skip_non_kms_dmabuf_formats", Hyprlang::INT{0}); // devices m_config->addSpecialCategory("device", {"name"}); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 4f59e4b3..296a27ed 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -26,6 +26,8 @@ static std::optional devIDFromFD(int fd) { CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector> tranches_) : m_rendererTranche(_rendererTranche), m_monitorTranches(tranches_) { + static const auto PSKIP_NON_KMS = CConfigValue("quirks:skip_non_kms_dmabuf_formats"); + std::vector formatsVec; std::set> formats; @@ -35,6 +37,17 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec m_rendererTranche.indices.clear(); for (auto const& fmt : m_rendererTranche.formats) { for (auto const& mod : fmt.modifiers) { + LOGM(Log::TRACE, "Render format 0x{:x} ({}) with mod 0x{:x} ({})", fmt.drmFormat, NFormatUtils::drmFormatName(fmt.drmFormat), mod, NFormatUtils::drmModifierName(mod)); + if (*PSKIP_NON_KMS && !m_monitorTranches.empty()) { + if (std::ranges::none_of(m_monitorTranches, [fmt, mod](const std::pair& pair) { + return std::ranges::any_of(pair.second.formats, [fmt, mod](const SDRMFormat& format) { + return format.drmFormat == fmt.drmFormat && std::ranges::any_of(format.modifiers, [mod](uint64_t modifier) { return mod == modifier; }); + }); + })) { + LOGM(Log::TRACE, " skipped"); + continue; + } + } auto format = std::make_pair<>(fmt.drmFormat, mod); auto [_, inserted] = formats.insert(format); if (inserted) { @@ -56,6 +69,9 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec tranche.indices.clear(); for (auto const& fmt : tranche.formats) { for (auto const& mod : fmt.modifiers) { + LOGM(Log::TRACE, "[DMA] Monitor format 0x{:x} ({}) with mod 0x{:x} ({})", fmt.drmFormat, NFormatUtils::drmFormatName(fmt.drmFormat), mod, + NFormatUtils::drmModifierName(mod)); + // FIXME: recheck this. DRM_FORMAT_MOD_INVALID is allowed by the proto "For legacy support". DRM_FORMAT_MOD_LINEAR should be the most compatible mod // apparently these can implode on planes, so don't use them if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) continue; @@ -147,10 +163,17 @@ CLinuxDMABUFParamsResource::CLinuxDMABUFParamsResource(UP(modHi) << 32) | modLo; + + if (m_resource->version() >= 5 && m_attrs->modifier && m_attrs->modifier != modifier) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "planes have different modifiers"); + return; + } + m_attrs->fds[plane] = fd; m_attrs->strides[plane] = stride; m_attrs->offsets[plane] = offset; - m_attrs->modifier = (sc(modHi) << 32) | modLo; + m_attrs->modifier = modifier; }); m_resource->setCreate([this](CZwpLinuxBufferParamsV1* r, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) { @@ -165,6 +188,13 @@ CLinuxDMABUFParamsResource::CLinuxDMABUFParamsResource(UPversion() >= 4 && std::ranges::none_of(PROTO::linuxDma->m_formatTable->m_rendererTranche.formats, [this, fmt](const auto format) { + return format.drmFormat == fmt && std::ranges::any_of(format.modifiers, [this](const auto mod) { return !mod || mod == m_attrs->modifier; }); + })) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "format + modifier pair is not supported"); + return; + } + m_attrs->size = {w, h}; m_attrs->format = fmt; m_attrs->planes = 4 - std::ranges::count(m_attrs->fds, -1); @@ -382,8 +412,7 @@ CLinuxDMABUFResource::CLinuxDMABUFResource(UP&& resource_) : } }); - if (m_resource->version() < 4) - sendMods(); + sendMods(); } bool CLinuxDMABUFResource::good() { @@ -392,16 +421,14 @@ bool CLinuxDMABUFResource::good() { void CLinuxDMABUFResource::sendMods() { for (auto const& fmt : PROTO::linuxDma->m_formatTable->m_rendererTranche.formats) { - for (auto const& mod : fmt.modifiers) { - if (m_resource->version() < 3) { - if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) - m_resource->sendFormat(fmt.drmFormat); - continue; + m_resource->sendFormat(fmt.drmFormat); + + if (m_resource->version() == 3) { + for (auto const& mod : fmt.modifiers) { + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + + m_resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF); } - - // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 - - m_resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF); } } } @@ -456,6 +483,15 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const std::erase_if(m_formatTable->m_monitorTranches, [pMonitor](std::pair pair) { return pair.first == pMonitor; }); resetFormatTable(); }); + + static auto configReloaded = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { + static const auto PSKIP_NON_KMS = CConfigValue("quirks:skip_non_kms_dmabuf_formats"); + static auto prev = *PSKIP_NON_KMS; + if (prev != *PSKIP_NON_KMS) { + prev = *PSKIP_NON_KMS; + resetFormatTable(); + } + }); } m_formatTable = makeUnique(eglTranche, tches);