mirror of
https://github.com/hyprwm/aquamarine.git
synced 2025-01-25 00:29:49 +01:00
core: GPU hotplug support (#130)
This commit is contained in:
parent
c2369bc3ab
commit
03677f8561
11 changed files with 123 additions and 7 deletions
|
@ -26,5 +26,6 @@ namespace Aquamarine {
|
|||
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
|
||||
virtual int drmFD() = 0;
|
||||
virtual eAllocatorType type() = 0;
|
||||
virtual void destroyBuffers();
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<IAllocator> primaryAllocator;
|
||||
|
@ -159,5 +164,7 @@ namespace Aquamarine {
|
|||
std::mutex loopRequestMutex;
|
||||
std::mutex eventLock;
|
||||
} m_sEventLoopInternals;
|
||||
|
||||
friend class CDRMBackend;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
3
src/allocator/Allocator.cpp
Normal file
3
src/allocator/Allocator.cpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include <aquamarine/allocator/Allocator.hpp>
|
||||
|
||||
void Aquamarine::IAllocator::destroyBuffers() {}
|
|
@ -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<CGBMAllocator> Aquamarine::CGBMAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer<CBackend> backend_) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_);
|
||||
|
||||
|
|
Loading…
Reference in a new issue