protocols/dmabuf: fix DMA-BUF checks and events (#12965)

This commit is contained in:
UjinT34 2026-02-07 15:40:08 +03:00 committed by GitHub
parent 9f9dbb0dc5
commit 60f1c61323
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 55 additions and 12 deletions

View file

@ -2047,5 +2047,11 @@ inline static const std::vector<SConfigOptionDescription> 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},
},
};

View file

@ -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"});

View file

@ -26,6 +26,8 @@ static std::optional<dev_t> devIDFromFD(int fd) {
CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector<std::pair<PHLMONITORREF, SDMABUFTranche>> tranches_) :
m_rendererTranche(_rendererTranche), m_monitorTranches(tranches_) {
static const auto PSKIP_NON_KMS = CConfigValue<Hyprlang::INT>("quirks:skip_non_kms_dmabuf_formats");
std::vector<SDMABUFFormatTableEntry> formatsVec;
std::set<std::pair<uint32_t, uint64_t>> 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<PHLMONITORREF, SDMABUFTranche>& 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<CZwpLinuxBufferParamsV
return;
}
const uint64_t modifier = (sc<uint64_t>(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<uint64_t>(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(UP<CZwpLinuxBufferParamsV
return;
}
if (m_resource->version() >= 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<CZwpLinuxDmabufV1>&& 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<PHLMONITORREF, SDMABUFTranche> 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<Hyprlang::INT>("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<CDMABUFFormatTable>(eglTranche, tches);