Skip to content

Commit

Permalink
handle monitor hotplugs and fix a few bugs that it revealed
Browse files Browse the repository at this point in the history
  • Loading branch information
ikalco committed Jul 15, 2024
1 parent ad8261b commit 4e1d430
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 46 deletions.
2 changes: 1 addition & 1 deletion include/aquamarine/backend/DRM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ namespace Aquamarine {
SDRMPageFlip pendingPageFlip;
bool frameEventScheduled = false;

drmModeModeInfo fallbackModeInfo;
Hyprutils::Memory::CSharedPointer<SOutputMode> fallbackMode;

struct {
bool vrrEnabled = false;
Expand Down
75 changes: 38 additions & 37 deletions src/backend/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,46 +303,47 @@ void Aquamarine::CSession::dispatchUdevEvents() {
return;
}

dev_t deviceNum = udev_device_get_devnum(device);
SP<CSessionDevice> sessionDevice;
for (auto& sDev : sessionDevices) {
if (sDev->dev == deviceNum)
sessionDevice = sDev;
}

if (!sessionDevice) {
udev_device_unref(device);
return;
}

if (action == std::string{"add"})
events.addDrmCard.emit(SAddDrmCardEvent{.path = devnode});
else if (action == std::string{"change"} || action == std::string{"remove"}) {
dev_t deviceNum = udev_device_get_devnum(device);

for (auto& d : sessionDevices) {
if (d->dev != deviceNum)
continue;

if (action == std::string{"change"}) {
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} changed", sysname ? sysname : "unknown"));

CSessionDevice::SChangeEvent event;

auto prop = udev_device_get_property_value(device, "HOTPLUG");
if (prop && prop == std::string{"1"}) {
event.type = CSessionDevice::AQ_SESSION_EVENT_CHANGE_HOTPLUG;

prop = udev_device_get_property_value(device, "CONNECTOR");
if (prop)
event.hotplug.connectorID = std::stoull(prop);

prop = udev_device_get_property_value(device, "PROPERTY");
if (prop)
event.hotplug.propID = std::stoull(prop);
} else if (prop = udev_device_get_property_value(device, "LEASE"); prop && prop == std::string{"1"}) {
event.type = CSessionDevice::AQ_SESSION_EVENT_CHANGE_LEASE;
} else {
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} change event unrecognized", sysname ? sysname : "unknown"));
break;
}

d->events.change.emit(event);
} else if (action == std::string{"remove"}) {
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} removed", sysname ? sysname : "unknown"));
d->events.remove.emit();
}

break;
else if (action == std::string{"change"}) {
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} changed", sysname ? sysname : "unknown"));

CSessionDevice::SChangeEvent event;

//
auto prop = udev_device_get_property_value(device, "HOTPLUG");
if (prop && prop == std::string{"1"}) {
event.type = CSessionDevice::AQ_SESSION_EVENT_CHANGE_HOTPLUG;

prop = udev_device_get_property_value(device, "CONNECTOR");
if (prop)
event.hotplug.connectorID = std::stoull(prop);

prop = udev_device_get_property_value(device, "PROPERTY");
if (prop)
event.hotplug.propID = std::stoull(prop);
} else if (prop = udev_device_get_property_value(device, "LEASE"); prop && prop == std::string{"1"}) {
event.type = CSessionDevice::AQ_SESSION_EVENT_CHANGE_LEASE;
} else {
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} change event unrecognized", sysname ? sysname : "unknown"));
}

sessionDevice->events.change.emit(event);
} else if (action == std::string{"remove"}) {
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} removed", sysname ? sysname : "unknown"));
sessionDevice->events.remove.emit();
}

udev_device_unref(device);
Expand Down
29 changes: 21 additions & 8 deletions src/backend/drm/DRM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backe
}

backends.emplace_back(drmBackend);

// so that session can handle udev change/remove events for this gpu
backend->session->sessionDevices.push_back(gpu);
}

return backends;
Expand Down Expand Up @@ -793,6 +796,7 @@ void Aquamarine::CDRMBackend::onReady() {
// swapchain has to be created here because allocator is absent in connect if not ready
c->output->swapchain = CSwapchain::create(backend->primaryAllocator, self.lock());
c->output->swapchain->reconfigure(SSwapchainOptions{.length = 0, .scanout = true, .multigpu = !!primary}); // mark the swapchain for scanout
c->output->setCursor(nullptr, {});
c->output->needsFrame = true;

backend->events.newOutput.emit(SP<IOutput>(c->output));
Expand Down Expand Up @@ -1024,7 +1028,6 @@ drmModeModeInfo* Aquamarine::SDRMConnector::getCurrentMode() {
if (crtc->props.mode_id) {
size_t size = 0;
return (drmModeModeInfo*)getDRMPropBlob(backend->gpu->fd, crtc->id, crtc->props.mode_id, &size);
;
}

auto drmCrtc = drmModeGetCrtc(backend->gpu->fd, crtc->id);
Expand Down Expand Up @@ -1095,15 +1098,15 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
continue;
}

if (i == 1)
fallbackModeInfo = drmMode;

auto aqMode = makeShared<SOutputMode>();
aqMode->pixelSize = {drmMode.hdisplay, drmMode.vdisplay};
aqMode->refreshRate = calculateRefresh(drmMode);
aqMode->preferred = (drmMode.type & DRM_MODE_TYPE_PREFERRED);
aqMode->modeInfo = drmMode;

if (i == 1)
fallbackMode = aqMode;

output->modes.emplace_back(aqMode);

if (currentModeInfo && std::memcmp(&drmMode, currentModeInfo, sizeof(drmModeModeInfo))) {
Expand All @@ -1120,6 +1123,11 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
aqMode->preferred ? " (preferred)" : ""));
}

if (!currentModeInfo) {
output->state->setMode(fallbackMode);
crtc->refresh = calculateRefresh(fallbackMode->modeInfo.value());
}

output->physicalSize = {(double)connector->mmWidth, (double)connector->mmHeight};

backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Physical size {} (mm)", output->physicalSize));
Expand Down Expand Up @@ -1181,7 +1189,8 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
return;

output->swapchain = CSwapchain::create(backend->backend->primaryAllocator, backend->self.lock());
backend->backend->events.newOutput.emit(output);
output->setCursor(nullptr, {});
backend->backend->events.newOutput.emit(SP<IOutput>(output));
output->scheduleFrame(IOutput::AQ_SCHEDULE_NEW_CONNECTOR);
}

Expand Down Expand Up @@ -1395,7 +1404,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
else
data.cursorFB = connector->crtc->cursor->front;

if (data.cursorFB) {
if (data.cursorFB && data.cursorFB->buffer) {
// verify cursor format. This might be wrong on NVIDIA where linear buffers
// fail to be created from gbm
// TODO: add an API to detect this and request drm_dumb linear buffers. Or do something,
Expand Down Expand Up @@ -1439,9 +1448,13 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
return false;
}

if (!buffer)
if (!buffer) {
connector->crtc->pendingCursor.reset();
connector->crtc->cursor->front.reset();
connector->crtc->cursor->back.reset();
connector->crtc->cursor->last.reset();
setCursorVisible(false);
else {
} else {
SP<CDRMFB> fb;

if (backend->primary) {
Expand Down

0 comments on commit 4e1d430

Please sign in to comment.