mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 10:29:48 +01:00
drm: reopen DRM node to avoid KMS refcounting issues
This commit is contained in:
parent
59fc21940d
commit
05219d5287
3 changed files with 74 additions and 2 deletions
|
@ -112,6 +112,9 @@ namespace Aquamarine {
|
|||
/* remove an idle event from the queue */
|
||||
void removeIdleEvent(Hyprutils::Memory::CSharedPointer<std::function<void(void)>> pfn);
|
||||
|
||||
// utils
|
||||
int reopenDRMNode(int drmFD, bool allowRenderNode = true);
|
||||
|
||||
struct {
|
||||
Hyprutils::Signal::CSignal newOutput;
|
||||
Hyprutils::Signal::CSignal newPointer;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <sys/timerfd.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <xf86drm.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
using namespace Hyprutils::Memory;
|
||||
using namespace Aquamarine;
|
||||
|
@ -144,7 +146,13 @@ bool Aquamarine::CBackend::start() {
|
|||
// TODO: obviously change this when (if) we add different allocators.
|
||||
for (auto& b : implementations) {
|
||||
if (b->drmFD() >= 0) {
|
||||
primaryAllocator = CGBMAllocator::create(b->drmFD(), self);
|
||||
auto fd = reopenDRMNode(b->drmFD());
|
||||
if (fd < 0) {
|
||||
// this is critical, we cannot create an allocator properly
|
||||
log(AQ_LOG_CRITICAL, "Failed to create an allocator (reopenDRMNode failed)");
|
||||
return false;
|
||||
}
|
||||
primaryAllocator = CGBMAllocator::create(fd, self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -258,3 +266,64 @@ void Aquamarine::CBackend::dispatchIdle() {
|
|||
|
||||
updateIdleTimer();
|
||||
}
|
||||
|
||||
// Yoinked from wlroots, render/allocator/allocator.c
|
||||
// Ref-counting reasons, see https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/110
|
||||
int Aquamarine::CBackend::reopenDRMNode(int drmFD, bool allowRenderNode) {
|
||||
|
||||
if (drmIsMaster(drmFD)) {
|
||||
// Only recent kernels support empty leases
|
||||
uint32_t lesseeID = 0;
|
||||
int leaseFD = drmModeCreateLease(drmFD, nullptr, 0, O_CLOEXEC, &lesseeID);
|
||||
if (leaseFD >= 0) {
|
||||
return leaseFD;
|
||||
} else if (leaseFD != -EINVAL && leaseFD != -EOPNOTSUPP) {
|
||||
log(AQ_LOG_ERROR, "reopenDRMNode: drmModeCreateLease failed");
|
||||
return -1;
|
||||
}
|
||||
log(AQ_LOG_DEBUG, "reopenDRMNode: drmModeCreateLease failed, falling back to open");
|
||||
}
|
||||
|
||||
char* name = nullptr;
|
||||
if (allowRenderNode)
|
||||
name = drmGetRenderDeviceNameFromFd(drmFD);
|
||||
|
||||
if (!name) {
|
||||
// primary node or no name
|
||||
name = drmGetDeviceNameFromFd2(drmFD);
|
||||
|
||||
if (!name) {
|
||||
log(AQ_LOG_ERROR, "reopenDRMNode: drmGetDeviceNameFromFd2 failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
log(AQ_LOG_DEBUG, std::format("reopenDRMNode: opening node {}", name));
|
||||
|
||||
int newFD = open(name, O_RDWR | O_CLOEXEC);
|
||||
if (newFD < 0) {
|
||||
log(AQ_LOG_ERROR, std::format("reopenDRMNode: failed to open node {}", name));
|
||||
free(name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(name);
|
||||
|
||||
// We need to authenticate if we are using a DRM primary node and are the master
|
||||
if (drmIsMaster(drmFD) && drmGetNodeTypeFromFd(drmFD) == DRM_NODE_PRIMARY) {
|
||||
drm_magic_t magic;
|
||||
if (int ret = drmGetMagic(newFD, &magic); ret < 0) {
|
||||
log(AQ_LOG_ERROR, std::format("reopenDRMNode: drmGetMagic failed: {}", strerror(-ret)));
|
||||
close(newFD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (int ret = drmAuthMagic(newFD, magic); ret < 0) {
|
||||
log(AQ_LOG_ERROR, std::format("reopenDRMNode: drmAuthMagic failed: {}", strerror(-ret)));
|
||||
close(newFD);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return newFD;
|
||||
}
|
||||
|
|
|
@ -1617,7 +1617,7 @@ void Aquamarine::CDRMFB::import() {
|
|||
TRACE(backend->backend->log(AQ_LOG_TRACE, std::format("drm: new buffer {}", id)));
|
||||
|
||||
// FIXME: why does this implode when it doesnt on wlroots or kwin?
|
||||
// closeHandles();
|
||||
closeHandles();
|
||||
|
||||
listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) {
|
||||
drop();
|
||||
|
|
Loading…
Reference in a new issue