Skip to content

Commit

Permalink
core: GPU hotplug support (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
maround95 authored Jan 10, 2025
1 parent c2369bc commit 03677f8
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/aquamarine/allocator/Allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ namespace Aquamarine {
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
virtual int drmFD() = 0;
virtual eAllocatorType type() = 0;
virtual void destroyBuffers();
};
};
1 change: 1 addition & 0 deletions include/aquamarine/allocator/GBM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace Aquamarine {
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
virtual int drmFD();
virtual eAllocatorType type();
virtual void destroyBuffers();

//
Hyprutils::Memory::CWeakPointer<CGBMAllocator> self;
Expand Down
7 changes: 7 additions & 0 deletions include/aquamarine/backend/Backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<IAllocator> primaryAllocator;
Expand Down Expand Up @@ -159,5 +164,7 @@ namespace Aquamarine {
std::mutex loopRequestMutex;
std::mutex eventLock;
} m_sEventLoopInternals;

friend class CDRMBackend;
};
};
3 changes: 3 additions & 0 deletions include/aquamarine/backend/DRM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ namespace Aquamarine {
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);

static std::vector<Hyprutils::Memory::CSharedPointer<CDRMBackend>> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend);
static Hyprutils::Memory::CSharedPointer<CDRMBackend> fromGpu(std::string path, Hyprutils::Memory::CSharedPointer<CBackend> backend,
Hyprutils::Memory::CSharedPointer<CDRMBackend> primary);

bool registerGPU(Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu_, Hyprutils::Memory::CSharedPointer<CDRMBackend> primary_ = {});
bool checkFeatures();
bool initResources();
Expand Down
3 changes: 3 additions & 0 deletions src/allocator/Allocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <aquamarine/allocator/Allocator.hpp>

void Aquamarine::IAllocator::destroyBuffers() {}
24 changes: 20 additions & 4 deletions src/allocator/GBM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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<CGBMAllocator> Aquamarine::CGBMAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer<CBackend> backend_) {
Expand Down
21 changes: 21 additions & 0 deletions src/backend/Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<IBackendImplementation> 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) {
Expand Down
7 changes: 7 additions & 0 deletions src/backend/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
53 changes: 50 additions & 3 deletions src/backend/drm/DRM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,43 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
return vecDevices;
}

SP<CDRMBackend> Aquamarine::CDRMBackend::fromGpu(std::string path, SP<CBackend> backend, SP<CDRMBackend> primary) {
auto gpu = CSessionDevice::openIfKMS(backend->session, path);
if (!gpu) {
return nullptr;
}

auto drmBackend = SP<CDRMBackend>(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<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
if (!backend->session)
backend->session = CSession::attempt(backend);
Expand Down Expand Up @@ -269,7 +306,15 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> 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) {
Expand Down Expand Up @@ -663,8 +708,10 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
}
});

listeners.gpuRemove = gpu->events.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;
}
Expand Down
9 changes: 9 additions & 0 deletions src/backend/drm/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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> CDRMRenderer::attempt(Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_, SP<CBackend> backend_) {
SP<CDRMRenderer> renderer = SP<CDRMRenderer>(new CDRMRenderer());
renderer->drmFD = allocator_->drmFD();
Expand Down
1 change: 1 addition & 0 deletions src/backend/drm/Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace Aquamarine {

class CDRMRenderer {
public:
~CDRMRenderer();
static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_,
Hyprutils::Memory::CSharedPointer<CBackend> backend_);

Expand Down

0 comments on commit 03677f8

Please sign in to comment.