fix(linux/kms): count CRTCs not planes when assigning monitor index
Some checks failed
Top issues / Top issues (push) Has been cancelled

kms_display_names() and display_t::init() each independently counted
every active, non-cursor plane as one "monitor" when building/matching
the display index. A CRTC with more than one simultaneously-active
plane (e.g. gamescope's base + overlay layers) was counted twice by
both passes, throwing their indices out of sync with each other and
producing duplicate/misnumbered display names.

Track counted CRTCs per card in both passes so a CRTC contributes to
the index exactly once, regardless of how many active planes it has.
This commit is contained in:
2026-08-19 00:11:34 -06:00
parent 25c06d79b5
commit bbf3cf0031

View File

@@ -7,6 +7,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <filesystem> #include <filesystem>
#include <ranges> #include <ranges>
#include <set>
#include <thread> #include <thread>
#include <unistd.h> #include <unistd.h>
@@ -932,6 +933,7 @@ namespace platf {
continue; continue;
} }
std::set<std::uint32_t> counted_crtcs;
auto end = std::end(card); auto end = std::end(card);
for (auto plane = std::begin(card); plane != end; ++plane) { for (auto plane = std::begin(card); plane != end; ++plane) {
// Skip unused planes // Skip unused planes
@@ -943,8 +945,15 @@ namespace platf {
continue; continue;
} }
// A CRTC can have more than one simultaneously-active plane (e.g. gamescope's
// base + overlay layers). Count each CRTC once so this matches kms_display_names().
if (counted_crtcs.count(plane->crtc_id)) {
continue;
}
if (monitor != monitor_index) { if (monitor != monitor_index) {
++monitor; ++monitor;
counted_crtcs.insert(plane->crtc_id);
continue; continue;
} }
@@ -2075,6 +2084,7 @@ namespace platf {
} }
auto crtc_to_monitor = kms::map_crtc_to_monitor(card.monitors(conn_type_count)); auto crtc_to_monitor = kms::map_crtc_to_monitor(card.monitors(conn_type_count));
std::set<std::uint32_t> counted_crtcs;
auto end = std::end(card); auto end = std::end(card);
for (auto plane = std::begin(card); plane != end; ++plane) { for (auto plane = std::begin(card); plane != end; ++plane) {
@@ -2087,6 +2097,12 @@ namespace platf {
continue; continue;
} }
// A CRTC can have more than one simultaneously-active plane (e.g. gamescope's
// base + overlay layers). Count each CRTC once, not once per active plane.
if (counted_crtcs.count(plane->crtc_id)) {
continue;
}
auto fb = card.fb(plane.get()); auto fb = card.fb(plane.get());
if (!fb) { if (!fb) {
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno); BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
@@ -2126,6 +2142,7 @@ namespace platf {
kms::print(plane.get(), fb.get(), crtc.get()); kms::print(plane.get(), fb.get(), crtc.get());
display_names.emplace_back(std::format("{}-{}", drmModeGetConnectorTypeName(it->second.type), it->second.index)); display_names.emplace_back(std::format("{}-{}", drmModeGetConnectorTypeName(it->second.type), it->second.index));
count++; count++;
counted_crtcs.insert(plane->crtc_id);
} }
cds.emplace_back(kms::card_descriptor_t { cds.emplace_back(kms::card_descriptor_t {