mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 20:39:49 +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 */
|
/* remove an idle event from the queue */
|
||||||
void removeIdleEvent(Hyprutils::Memory::CSharedPointer<std::function<void(void)>> pfn);
|
void removeIdleEvent(Hyprutils::Memory::CSharedPointer<std::function<void(void)>> pfn);
|
||||||
|
|
||||||
|
// utils
|
||||||
|
int reopenDRMNode(int drmFD, bool allowRenderNode = true);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Hyprutils::Signal::CSignal newOutput;
|
Hyprutils::Signal::CSignal newOutput;
|
||||||
Hyprutils::Signal::CSignal newPointer;
|
Hyprutils::Signal::CSignal newPointer;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
using namespace Hyprutils::Memory;
|
using namespace Hyprutils::Memory;
|
||||||
using namespace Aquamarine;
|
using namespace Aquamarine;
|
||||||
|
@ -144,7 +146,13 @@ bool Aquamarine::CBackend::start() {
|
||||||
// TODO: obviously change this when (if) we add different allocators.
|
// TODO: obviously change this when (if) we add different allocators.
|
||||||
for (auto& b : implementations) {
|
for (auto& b : implementations) {
|
||||||
if (b->drmFD() >= 0) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,3 +266,64 @@ void Aquamarine::CBackend::dispatchIdle() {
|
||||||
|
|
||||||
updateIdleTimer();
|
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)));
|
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?
|
// FIXME: why does this implode when it doesnt on wlroots or kwin?
|
||||||
// closeHandles();
|
closeHandles();
|
||||||
|
|
||||||
listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) {
|
listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) {
|
||||||
drop();
|
drop();
|
||||||
|
|
Loading…
Reference in a new issue