diff --git a/include/aquamarine/allocator/Allocator.hpp b/include/aquamarine/allocator/Allocator.hpp index 02552f2..2dc1ee5 100644 --- a/include/aquamarine/allocator/Allocator.hpp +++ b/include/aquamarine/allocator/Allocator.hpp @@ -26,5 +26,6 @@ namespace Aquamarine { virtual Hyprutils::Memory::CSharedPointer getBackend() = 0; virtual int drmFD() = 0; virtual eAllocatorType type() = 0; + virtual void destroyBuffers(); }; }; diff --git a/include/aquamarine/allocator/GBM.hpp b/include/aquamarine/allocator/GBM.hpp index 6e95c5b..09e6cb9 100644 --- a/include/aquamarine/allocator/GBM.hpp +++ b/include/aquamarine/allocator/GBM.hpp @@ -46,6 +46,7 @@ namespace Aquamarine { virtual Hyprutils::Memory::CSharedPointer getBackend(); virtual int drmFD(); virtual eAllocatorType type(); + virtual void destroyBuffers(); // Hyprutils::Memory::CWeakPointer self; diff --git a/include/aquamarine/backend/Backend.hpp b/include/aquamarine/backend/Backend.hpp index 2dd039c..7da8039 100644 --- a/include/aquamarine/backend/Backend.hpp +++ b/include/aquamarine/backend/Backend.hpp @@ -117,6 +117,9 @@ namespace Aquamarine { // utils int reopenDRMNode(int drmFD, bool allowRenderNode = true); + // called when a new DRM card is hotplugged + void onNewGpu(std::string path); + struct { Hyprutils::Signal::CSignal newOutput; Hyprutils::Signal::CSignal newPointer; @@ -126,6 +129,8 @@ namespace Aquamarine { Hyprutils::Signal::CSignal newTablet; Hyprutils::Signal::CSignal newTabletTool; Hyprutils::Signal::CSignal newTabletPad; + + Hyprutils::Signal::CSignal pollFDsChanged; } events; Hyprutils::Memory::CSharedPointer primaryAllocator; @@ -159,5 +164,7 @@ namespace Aquamarine { std::mutex loopRequestMutex; std::mutex eventLock; } m_sEventLoopInternals; + + friend class CDRMBackend; }; }; diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index cc03904..9f7f718 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -389,6 +389,9 @@ namespace Aquamarine { CDRMBackend(Hyprutils::Memory::CSharedPointer backend); static std::vector> attempt(Hyprutils::Memory::CSharedPointer backend); + static Hyprutils::Memory::CSharedPointer fromGpu(std::string path, Hyprutils::Memory::CSharedPointer backend, + Hyprutils::Memory::CSharedPointer primary); + bool registerGPU(Hyprutils::Memory::CSharedPointer gpu_, Hyprutils::Memory::CSharedPointer primary_ = {}); bool checkFeatures(); bool initResources(); diff --git a/src/allocator/Allocator.cpp b/src/allocator/Allocator.cpp new file mode 100644 index 0000000..740450f --- /dev/null +++ b/src/allocator/Allocator.cpp @@ -0,0 +1,3 @@ +#include + +void Aquamarine::IAllocator::destroyBuffers() {} diff --git a/src/allocator/GBM.cpp b/src/allocator/GBM.cpp index 3e2eb38..a061111 100644 --- a/src/allocator/GBM.cpp +++ b/src/allocator/GBM.cpp @@ -228,14 +228,16 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti } Aquamarine::CGBMBuffer::~CGBMBuffer() { + for (size_t i = 0; i < (size_t)attrs.planes; i++) { + close(attrs.fds.at(i)); + } + events.destroy.emit(); if (bo) { if (gboMapping) gbm_bo_unmap(bo, gboMapping); // FIXME: is it needed before destroy? gbm_bo_destroy(bo); } - for (size_t i = 0; i < (size_t)attrs.planes; i++) - close(attrs.fds.at(i)); } eBufferCapability Aquamarine::CGBMBuffer::caps() { @@ -280,9 +282,23 @@ void Aquamarine::CGBMBuffer::endDataPtr() { } } +void CGBMAllocator::destroyBuffers() { + for (auto& buf : buffers) { + buf.reset(); + } +} + CGBMAllocator::~CGBMAllocator() { - if (gbmDevice) - gbm_device_destroy(gbmDevice); + if (!gbmDevice) + return; + + int fd = gbm_device_get_fd(gbmDevice); + gbm_device_destroy(gbmDevice); + + if (fd < 0) + return; + + close(fd); } SP Aquamarine::CGBMAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer backend_) { diff --git a/src/backend/Backend.cpp b/src/backend/Backend.cpp index 32651ac..675f905 100644 --- a/src/backend/Backend.cpp +++ b/src/backend/Backend.cpp @@ -271,6 +271,27 @@ void Aquamarine::CBackend::dispatchIdle() { updateIdleTimer(); } +void Aquamarine::CBackend::onNewGpu(std::string path) { + const auto primary = std::ranges::find_if(implementations, [](SP value) { return value->type() == Aquamarine::AQ_BACKEND_DRM; }); + const auto primaryDrm = primary != implementations.end() ? ((Aquamarine::CDRMBackend*)(*primary).get())->self.lock() : nullptr; + + auto ref = CDRMBackend::fromGpu(path, self.lock(), primaryDrm); + if (!ref) { + log(AQ_LOG_ERROR, std::format("DRM Backend failed for device {}", path)); + return; + } + if (!ref->start()) { + log(AQ_LOG_ERROR, std::format("Couldn't start DRM Backend for device {}", path)); + return; + } + + implementations.emplace_back(ref); + events.pollFDsChanged.emit(); + + ref->onReady(); // Renderer created here + ref->recheckOutputs(); // Now we can recheck outputs +} + // 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) { diff --git a/src/backend/Session.cpp b/src/backend/Session.cpp index 6d47aaa..b2d37a2 100644 --- a/src/backend/Session.cpp +++ b/src/backend/Session.cpp @@ -296,6 +296,12 @@ void Aquamarine::CSession::dispatchUdevEvents() { } } + if (!sessionDevice && action == std::string{"add"}) { + backend->onNewGpu(devnode); + udev_device_unref(device); + return; + } + if (!sessionDevice) { udev_device_unref(device); return; @@ -330,6 +336,7 @@ void Aquamarine::CSession::dispatchUdevEvents() { } else if (action == std::string{"remove"}) { backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} removed", sysname ? sysname : "unknown")); sessionDevice->events.remove.emit(); + std::erase_if(sessionDevices, [sessionDevice](const auto& sd) { return sd == sessionDevice; }); } udev_device_unref(device); diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 816d1c2..38222b4 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -181,6 +181,43 @@ static std::vector> scanGPUs(SP backend) { return vecDevices; } +SP Aquamarine::CDRMBackend::fromGpu(std::string path, SP backend, SP primary) { + auto gpu = CSessionDevice::openIfKMS(backend->session, path); + if (!gpu) { + return nullptr; + } + + auto drmBackend = SP(new CDRMBackend(backend)); + drmBackend->self = drmBackend; + + if (!drmBackend->registerGPU(gpu, primary)) { + backend->log(AQ_LOG_ERROR, std::format("drm: Failed to register gpu {}", gpu->path)); + return nullptr; + } else + backend->log(AQ_LOG_DEBUG, std::format("drm: Registered gpu {}", gpu->path)); + + if (!drmBackend->checkFeatures()) { + backend->log(AQ_LOG_ERROR, "drm: Failed checking features"); + return nullptr; + } + + if (!drmBackend->initResources()) { + backend->log(AQ_LOG_ERROR, "drm: Failed initializing resources"); + return nullptr; + } + + backend->log(AQ_LOG_DEBUG, std::format("drm: Basic init pass for gpu {}", gpu->path)); + + drmBackend->grabFormats(); + + drmBackend->dumbAllocator = CDRMDumbAllocator::create(gpu->fd, backend); + + // so that session can handle udev change/remove events for this gpu + backend->session->sessionDevices.push_back(gpu); + + return drmBackend; +} + std::vector> Aquamarine::CDRMBackend::attempt(SP backend) { if (!backend->session) backend->session = CSession::attempt(backend); @@ -269,7 +306,15 @@ std::vector> Aquamarine::CDRMBackend::attempt(SP backe } Aquamarine::CDRMBackend::~CDRMBackend() { - ; + for (auto conn : connectors) { + conn->disconnect(); + conn.reset(); + } + + rendererState.allocator->destroyBuffers(); + + rendererState.renderer.reset(); + rendererState.allocator.reset(); } void Aquamarine::CDRMBackend::log(eBackendLogLevel l, const std::string& s) { @@ -663,8 +708,10 @@ bool Aquamarine::CDRMBackend::registerGPU(SP gpu_, SPevents.remove.registerListener( - [this](std::any d) { backend->log(AQ_LOG_ERROR, std::format("drm: !!!!FIXME: Got a remove event for {}, this is not handled properly!!!!!", gpuName)); }); + listeners.gpuRemove = gpu->events.remove.registerListener([this](std::any d) { + std::erase_if(backend->implementations, [this](const auto& impl) { return impl->drmFD() == this->drmFD(); }); + backend->events.pollFDsChanged.emit(); + }); return true; } diff --git a/src/backend/drm/Renderer.cpp b/src/backend/drm/Renderer.cpp index a1683d8..7d4d7d8 100644 --- a/src/backend/drm/Renderer.cpp +++ b/src/backend/drm/Renderer.cpp @@ -197,6 +197,15 @@ bool CDRMRenderer::initDRMFormats() { return true; } +Aquamarine::CDRMRenderer::~CDRMRenderer() { + eglMakeCurrent(egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(egl.display, egl.context); + + eglTerminate(egl.display); + + eglReleaseThread(); +} + SP CDRMRenderer::attempt(Hyprutils::Memory::CSharedPointer allocator_, SP backend_) { SP renderer = SP(new CDRMRenderer()); renderer->drmFD = allocator_->drmFD(); diff --git a/src/backend/drm/Renderer.hpp b/src/backend/drm/Renderer.hpp index 3819c5e..5749754 100644 --- a/src/backend/drm/Renderer.hpp +++ b/src/backend/drm/Renderer.hpp @@ -42,6 +42,7 @@ namespace Aquamarine { class CDRMRenderer { public: + ~CDRMRenderer(); static Hyprutils::Memory::CSharedPointer attempt(Hyprutils::Memory::CSharedPointer allocator_, Hyprutils::Memory::CSharedPointer backend_);