Skip to content

Commit 03677f8

Browse files
authored
core: GPU hotplug support (#130)
1 parent c2369bc commit 03677f8

File tree

11 files changed

+123
-7
lines changed

11 files changed

+123
-7
lines changed

include/aquamarine/allocator/Allocator.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ namespace Aquamarine {
2626
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
2727
virtual int drmFD() = 0;
2828
virtual eAllocatorType type() = 0;
29+
virtual void destroyBuffers();
2930
};
3031
};

include/aquamarine/allocator/GBM.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace Aquamarine {
4646
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
4747
virtual int drmFD();
4848
virtual eAllocatorType type();
49+
virtual void destroyBuffers();
4950

5051
//
5152
Hyprutils::Memory::CWeakPointer<CGBMAllocator> self;

include/aquamarine/backend/Backend.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ namespace Aquamarine {
117117
// utils
118118
int reopenDRMNode(int drmFD, bool allowRenderNode = true);
119119

120+
// called when a new DRM card is hotplugged
121+
void onNewGpu(std::string path);
122+
120123
struct {
121124
Hyprutils::Signal::CSignal newOutput;
122125
Hyprutils::Signal::CSignal newPointer;
@@ -126,6 +129,8 @@ namespace Aquamarine {
126129
Hyprutils::Signal::CSignal newTablet;
127130
Hyprutils::Signal::CSignal newTabletTool;
128131
Hyprutils::Signal::CSignal newTabletPad;
132+
133+
Hyprutils::Signal::CSignal pollFDsChanged;
129134
} events;
130135

131136
Hyprutils::Memory::CSharedPointer<IAllocator> primaryAllocator;
@@ -159,5 +164,7 @@ namespace Aquamarine {
159164
std::mutex loopRequestMutex;
160165
std::mutex eventLock;
161166
} m_sEventLoopInternals;
167+
168+
friend class CDRMBackend;
162169
};
163170
};

include/aquamarine/backend/DRM.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@ namespace Aquamarine {
389389
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
390390

391391
static std::vector<Hyprutils::Memory::CSharedPointer<CDRMBackend>> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend);
392+
static Hyprutils::Memory::CSharedPointer<CDRMBackend> fromGpu(std::string path, Hyprutils::Memory::CSharedPointer<CBackend> backend,
393+
Hyprutils::Memory::CSharedPointer<CDRMBackend> primary);
394+
392395
bool registerGPU(Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu_, Hyprutils::Memory::CSharedPointer<CDRMBackend> primary_ = {});
393396
bool checkFeatures();
394397
bool initResources();

src/allocator/Allocator.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include <aquamarine/allocator/Allocator.hpp>
2+
3+
void Aquamarine::IAllocator::destroyBuffers() {}

src/allocator/GBM.cpp

+20-4
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,16 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
228228
}
229229

230230
Aquamarine::CGBMBuffer::~CGBMBuffer() {
231+
for (size_t i = 0; i < (size_t)attrs.planes; i++) {
232+
close(attrs.fds.at(i));
233+
}
234+
231235
events.destroy.emit();
232236
if (bo) {
233237
if (gboMapping)
234238
gbm_bo_unmap(bo, gboMapping); // FIXME: is it needed before destroy?
235239
gbm_bo_destroy(bo);
236240
}
237-
for (size_t i = 0; i < (size_t)attrs.planes; i++)
238-
close(attrs.fds.at(i));
239241
}
240242

241243
eBufferCapability Aquamarine::CGBMBuffer::caps() {
@@ -280,9 +282,23 @@ void Aquamarine::CGBMBuffer::endDataPtr() {
280282
}
281283
}
282284

285+
void CGBMAllocator::destroyBuffers() {
286+
for (auto& buf : buffers) {
287+
buf.reset();
288+
}
289+
}
290+
283291
CGBMAllocator::~CGBMAllocator() {
284-
if (gbmDevice)
285-
gbm_device_destroy(gbmDevice);
292+
if (!gbmDevice)
293+
return;
294+
295+
int fd = gbm_device_get_fd(gbmDevice);
296+
gbm_device_destroy(gbmDevice);
297+
298+
if (fd < 0)
299+
return;
300+
301+
close(fd);
286302
}
287303

288304
SP<CGBMAllocator> Aquamarine::CGBMAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer<CBackend> backend_) {

src/backend/Backend.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,27 @@ void Aquamarine::CBackend::dispatchIdle() {
271271
updateIdleTimer();
272272
}
273273

274+
void Aquamarine::CBackend::onNewGpu(std::string path) {
275+
const auto primary = std::ranges::find_if(implementations, [](SP<IBackendImplementation> value) { return value->type() == Aquamarine::AQ_BACKEND_DRM; });
276+
const auto primaryDrm = primary != implementations.end() ? ((Aquamarine::CDRMBackend*)(*primary).get())->self.lock() : nullptr;
277+
278+
auto ref = CDRMBackend::fromGpu(path, self.lock(), primaryDrm);
279+
if (!ref) {
280+
log(AQ_LOG_ERROR, std::format("DRM Backend failed for device {}", path));
281+
return;
282+
}
283+
if (!ref->start()) {
284+
log(AQ_LOG_ERROR, std::format("Couldn't start DRM Backend for device {}", path));
285+
return;
286+
}
287+
288+
implementations.emplace_back(ref);
289+
events.pollFDsChanged.emit();
290+
291+
ref->onReady(); // Renderer created here
292+
ref->recheckOutputs(); // Now we can recheck outputs
293+
}
294+
274295
// Yoinked from wlroots, render/allocator/allocator.c
275296
// Ref-counting reasons, see https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/110
276297
int Aquamarine::CBackend::reopenDRMNode(int drmFD, bool allowRenderNode) {

src/backend/Session.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ void Aquamarine::CSession::dispatchUdevEvents() {
296296
}
297297
}
298298

299+
if (!sessionDevice && action == std::string{"add"}) {
300+
backend->onNewGpu(devnode);
301+
udev_device_unref(device);
302+
return;
303+
}
304+
299305
if (!sessionDevice) {
300306
udev_device_unref(device);
301307
return;
@@ -330,6 +336,7 @@ void Aquamarine::CSession::dispatchUdevEvents() {
330336
} else if (action == std::string{"remove"}) {
331337
backend->log(AQ_LOG_DEBUG, std::format("udev: DRM device {} removed", sysname ? sysname : "unknown"));
332338
sessionDevice->events.remove.emit();
339+
std::erase_if(sessionDevices, [sessionDevice](const auto& sd) { return sd == sessionDevice; });
333340
}
334341

335342
udev_device_unref(device);

src/backend/drm/DRM.cpp

+50-3
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,43 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
181181
return vecDevices;
182182
}
183183

184+
SP<CDRMBackend> Aquamarine::CDRMBackend::fromGpu(std::string path, SP<CBackend> backend, SP<CDRMBackend> primary) {
185+
auto gpu = CSessionDevice::openIfKMS(backend->session, path);
186+
if (!gpu) {
187+
return nullptr;
188+
}
189+
190+
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
191+
drmBackend->self = drmBackend;
192+
193+
if (!drmBackend->registerGPU(gpu, primary)) {
194+
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to register gpu {}", gpu->path));
195+
return nullptr;
196+
} else
197+
backend->log(AQ_LOG_DEBUG, std::format("drm: Registered gpu {}", gpu->path));
198+
199+
if (!drmBackend->checkFeatures()) {
200+
backend->log(AQ_LOG_ERROR, "drm: Failed checking features");
201+
return nullptr;
202+
}
203+
204+
if (!drmBackend->initResources()) {
205+
backend->log(AQ_LOG_ERROR, "drm: Failed initializing resources");
206+
return nullptr;
207+
}
208+
209+
backend->log(AQ_LOG_DEBUG, std::format("drm: Basic init pass for gpu {}", gpu->path));
210+
211+
drmBackend->grabFormats();
212+
213+
drmBackend->dumbAllocator = CDRMDumbAllocator::create(gpu->fd, backend);
214+
215+
// so that session can handle udev change/remove events for this gpu
216+
backend->session->sessionDevices.push_back(gpu);
217+
218+
return drmBackend;
219+
}
220+
184221
std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
185222
if (!backend->session)
186223
backend->session = CSession::attempt(backend);
@@ -269,7 +306,15 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backe
269306
}
270307

271308
Aquamarine::CDRMBackend::~CDRMBackend() {
272-
;
309+
for (auto conn : connectors) {
310+
conn->disconnect();
311+
conn.reset();
312+
}
313+
314+
rendererState.allocator->destroyBuffers();
315+
316+
rendererState.renderer.reset();
317+
rendererState.allocator.reset();
273318
}
274319

275320
void Aquamarine::CDRMBackend::log(eBackendLogLevel l, const std::string& s) {
@@ -663,8 +708,10 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
663708
}
664709
});
665710

666-
listeners.gpuRemove = gpu->events.remove.registerListener(
667-
[this](std::any d) { backend->log(AQ_LOG_ERROR, std::format("drm: !!!!FIXME: Got a remove event for {}, this is not handled properly!!!!!", gpuName)); });
711+
listeners.gpuRemove = gpu->events.remove.registerListener([this](std::any d) {
712+
std::erase_if(backend->implementations, [this](const auto& impl) { return impl->drmFD() == this->drmFD(); });
713+
backend->events.pollFDsChanged.emit();
714+
});
668715

669716
return true;
670717
}

src/backend/drm/Renderer.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,15 @@ bool CDRMRenderer::initDRMFormats() {
197197
return true;
198198
}
199199

200+
Aquamarine::CDRMRenderer::~CDRMRenderer() {
201+
eglMakeCurrent(egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
202+
eglDestroyContext(egl.display, egl.context);
203+
204+
eglTerminate(egl.display);
205+
206+
eglReleaseThread();
207+
}
208+
200209
SP<CDRMRenderer> CDRMRenderer::attempt(Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_, SP<CBackend> backend_) {
201210
SP<CDRMRenderer> renderer = SP<CDRMRenderer>(new CDRMRenderer());
202211
renderer->drmFD = allocator_->drmFD();

src/backend/drm/Renderer.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace Aquamarine {
4242

4343
class CDRMRenderer {
4444
public:
45+
~CDRMRenderer();
4546
static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_,
4647
Hyprutils::Memory::CSharedPointer<CBackend> backend_);
4748

0 commit comments

Comments
 (0)