core: introduce drmRenderNodeFD() (#193)

make a getter for drmRenderNodeFD() so we can create sync timelines on
the rendernode on devices not supporting fences on the card* device
directly.
This commit is contained in:
Tom Englund 2025-07-21 20:57:00 +02:00 committed by GitHub
parent 141a991678
commit f0db9b7eed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 120 additions and 2 deletions

View file

@ -88,8 +88,9 @@ namespace Aquamarine {
virtual bool createOutput(const std::string& name = "") = 0; // "" means auto
virtual Hyprutils::Memory::CSharedPointer<IAllocator> preferredAllocator() = 0;
virtual std::vector<SDRMFormat> getRenderableFormats(); // empty = use getRenderFormats
virtual std::vector<Hyprutils::Memory::CSharedPointer<IAllocator>> getAllocators() = 0;
virtual Hyprutils::Memory::CWeakPointer<IBackendImplementation> getPrimary() = 0;
virtual std::vector<Hyprutils::Memory::CSharedPointer<IAllocator>> getAllocators() = 0;
virtual Hyprutils::Memory::CWeakPointer<IBackendImplementation> getPrimary() = 0;
virtual int drmRenderNodeFD() = 0;
};
class CBackend {
@ -148,6 +149,9 @@ namespace Aquamarine {
bool ready = false;
Hyprutils::Memory::CSharedPointer<CSession> session;
/* Get the primary DRM RenderNode */
int drmRenderNodeFD();
private:
CBackend();

View file

@ -379,6 +379,7 @@ namespace Aquamarine {
std::vector<FIdleCallback> idleCallbacks;
std::string gpuName;
virtual int drmRenderNodeFD();
private:
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);

View file

@ -52,6 +52,7 @@ namespace Aquamarine {
virtual Hyprutils::Memory::CWeakPointer<IBackendImplementation> getPrimary();
Hyprutils::Memory::CWeakPointer<CHeadlessBackend> self;
virtual int drmRenderNodeFD();
private:
CHeadlessBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend_);

View file

@ -29,6 +29,7 @@ namespace Aquamarine {
static Hyprutils::Memory::CSharedPointer<CSessionDevice> openIfKMS(Hyprutils::Memory::CSharedPointer<CSession> session_, const std::string& path_);
bool supportsKMS();
void resolveMatchingRenderNode(udev_device* cardDevice);
int fd = -1;
int deviceID = -1;
@ -53,6 +54,8 @@ namespace Aquamarine {
Hyprutils::Signal::CSignalT<> remove;
} events;
int renderNodeFd = -1;
private:
Hyprutils::Memory::CWeakPointer<CSession> session;
};

View file

@ -139,6 +139,7 @@ namespace Aquamarine {
virtual Hyprutils::Memory::CWeakPointer<IBackendImplementation> getPrimary();
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
virtual int drmRenderNodeFD();
private:
CWaylandBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);

View file

@ -210,6 +210,17 @@ int Aquamarine::CBackend::drmFD() {
return -1;
}
int Aquamarine::CBackend::drmRenderNodeFD() {
for (auto const& i : implementations) {
int fd = i->drmRenderNodeFD();
if (fd < 0)
continue;
return fd;
}
return -1;
}
bool Aquamarine::CBackend::hasSession() {
return session;
}

View file

@ -102,6 +102,10 @@ int Aquamarine::CHeadlessBackend::drmFD() {
return -1;
}
int Aquamarine::CHeadlessBackend::drmRenderNodeFD() {
return -1;
}
bool Aquamarine::CHeadlessBackend::dispatchEvents() {
return true;
}

View file

@ -1,4 +1,5 @@
#include <aquamarine/backend/Backend.hpp>
#include <fcntl.h>
extern "C" {
#include <libseat.h>
@ -141,6 +142,9 @@ Aquamarine::CSessionDevice::~CSessionDevice() {
session->backend->log(AQ_LOG_ERROR, std::format("libseat: Couldn't close device at {}", path));
if (fd >= 0)
close(fd);
if (renderNodeFd)
close(renderNodeFd);
}
bool Aquamarine::CSessionDevice::supportsKMS() {
@ -157,6 +161,84 @@ bool Aquamarine::CSessionDevice::supportsKMS() {
return kms;
}
void Aquamarine::CSessionDevice::resolveMatchingRenderNode(udev_device* cardDevice) {
if (!cardDevice)
return;
auto pciParent = udev_device_get_parent_with_subsystem_devtype(cardDevice, "pci", nullptr);
const auto* pciSyspath = pciParent ? udev_device_get_syspath(pciParent) : nullptr;
auto* enumerate = udev_enumerate_new(session->udevHandle);
if (!enumerate)
return;
udev_enumerate_add_match_subsystem(enumerate, "drm");
udev_enumerate_scan_devices(enumerate);
auto* devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry* entry = nullptr;
bool matched = false;
udev_list_entry_foreach(entry, devices) {
const auto* path = udev_list_entry_get_name(entry);
auto dev = udev_device_new_from_syspath(session->udevHandle, path);
if (!dev)
continue;
const auto* devnode = udev_device_get_devnode(dev);
const auto* devtype = udev_device_get_devtype(dev);
if (!devnode || !devtype || strcmp(devtype, "drm_minor") != 0 || !strstr(devnode, "renderD")) {
udev_device_unref(dev);
continue;
}
auto devParent = udev_device_get_parent_with_subsystem_devtype(dev, "pci", nullptr);
if (devParent && pciSyspath && strcmp(udev_device_get_syspath(devParent), pciSyspath) == 0) {
renderNodeFd = open(devnode, O_RDWR | O_CLOEXEC);
if (renderNodeFd < 0)
session->backend->log(AQ_LOG_WARNING, std::format("drm: Failed to open matching render node {}", devnode));
else
matched = true;
udev_device_unref(dev);
break;
}
udev_device_unref(dev);
}
if (!matched) {
// fallback to the first render node
udev_list_entry_foreach(entry, devices) {
const auto* path = udev_list_entry_get_name(entry);
auto dev = udev_device_new_from_syspath(session->udevHandle, path);
if (!dev)
continue;
const auto* devnode = udev_device_get_devnode(dev);
const auto* devtype = udev_device_get_devtype(dev);
if (!devnode || !devtype || strcmp(devtype, "drm_minor") != 0 || !strstr(devnode, "renderD")) {
udev_device_unref(dev);
continue;
}
renderNodeFd = open(devnode, O_RDWR | O_CLOEXEC);
if (renderNodeFd >= 0) {
session->backend->log(AQ_LOG_WARNING, std::format("drm: No matching render node for {}, falling back to {}", path, devnode));
udev_device_unref(dev);
break;
}
udev_device_unref(dev);
}
}
udev_enumerate_unref(enumerate);
}
SP<CSessionDevice> Aquamarine::CSessionDevice::openIfKMS(SP<CSession> session_, const std::string& path_) {
auto dev = makeShared<CSessionDevice>(session_, path_);
if (!dev->supportsKMS())

View file

@ -139,6 +139,11 @@ int Aquamarine::CWaylandBackend::drmFD() {
return drmState.fd;
}
int Aquamarine::CWaylandBackend::drmRenderNodeFD() {
// creation already attempts to use the rendernode, so just return same fd as drmFD().
return drmState.fd;
}
bool Aquamarine::CWaylandBackend::createOutput(const std::string& szName) {
auto o = outputs.emplace_back(SP<CWaylandOutput>(new CWaylandOutput(szName.empty() ? std::format("WAYLAND-{}", ++lastOutputID) : szName, self)));
o->self = o;

View file

@ -150,6 +150,8 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
continue;
}
sessionDevice->resolveMatchingRenderNode(device);
udev_device_unref(device);
if (isBootVGA)
@ -906,6 +908,10 @@ int Aquamarine::CDRMBackend::drmFD() {
return gpu->fd;
}
int Aquamarine::CDRMBackend::drmRenderNodeFD() {
return gpu->renderNodeFd;
}
static void handlePF(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, unsigned crtc_id, void* data) {
auto pageFlip = (SDRMPageFlip*)data;