drm: very initial work on multigpu

This commit is contained in:
Vaxry 2024-06-28 17:13:03 +02:00
parent 944b0465fa
commit 40f6fa5173
4 changed files with 116 additions and 40 deletions

View file

@ -291,7 +291,7 @@ namespace Aquamarine {
private:
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
static Hyprutils::Memory::CSharedPointer<CDRMBackend> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend);
static std::vector<Hyprutils::Memory::CSharedPointer<CDRMBackend>> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend);
bool registerGPU(Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu_, Hyprutils::Memory::CSharedPointer<CDRMBackend> primary_ = {});
bool checkFeatures();
bool initResources();

View file

@ -52,12 +52,15 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const s
ref->self = ref;
} else if (b.backendType == AQ_BACKEND_DRM) {
auto ref = CDRMBackend::attempt(backend);
if (!ref) {
if (ref.empty()) {
backend->log(AQ_LOG_ERROR, "DRM Backend failed");
continue;
}
backend->implementations.emplace_back(ref);
ref->self = ref;
for (auto& r : ref) {
backend->implementations.emplace_back(r);
}
} else {
backend->log(AQ_LOG_ERROR, std::format("Unknown backend id: {}", (int)b.backendType));
continue;

View file

@ -1,6 +1,7 @@
#include <aquamarine/backend/DRM.hpp>
#include <aquamarine/backend/drm/Legacy.hpp>
#include <aquamarine/backend/drm/Atomic.hpp>
#include <hyprutils/string/VarList.hpp>
#include <chrono>
#include <thread>
#include <deque>
@ -50,8 +51,6 @@ static udev_enumerate* enumDRMCards(udev* udev) {
}
static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
// FIXME: This provides no explicit way to set a preferred gpu
auto enumerate = enumDRMCards(backend->session->udevHandle);
if (!enumerate) {
@ -123,20 +122,43 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
udev_enumerate_unref(enumerate);
std::vector<SP<CSessionDevice>> vecDevices;
for (auto& d : devices) {
vecDevices.push_back(d);
auto explicitGpus = getenv("AQ_DRM_DEVICES");
if (explicitGpus) {
backend->log(AQ_LOG_DEBUG, std::format("drm: Explicit device list {}", explicitGpus));
Hyprutils::String::CVarList explicitDevices(explicitGpus, ';', true);
for (auto& d : explicitDevices) {
bool found = false;
for (auto& vd : devices) {
if (vd->path == d) {
vecDevices.emplace_back(vd);
found = true;
break;
}
}
if (found)
backend->log(AQ_LOG_DEBUG, std::format("drm: Explicit device {} found", d));
else
backend->log(AQ_LOG_ERROR, std::format("drm: Explicit device {} not found", d));
}
} else {
for (auto& d : devices) {
vecDevices.push_back(d);
}
}
return vecDevices;
}
SP<CDRMBackend> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
if (!backend->session)
backend->session = CSession::attempt(backend);
if (!backend->session) {
backend->log(AQ_LOG_ERROR, "Failed to open a session");
return nullptr;
return {};
}
if (!backend->session->active) {
@ -156,7 +178,7 @@ SP<CDRMBackend> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
if (!backend->session->active) {
backend->log(AQ_LOG_DEBUG, "Session could not be activated in time");
return nullptr;
return {};
}
}
@ -164,41 +186,54 @@ SP<CDRMBackend> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
if (gpus.empty()) {
backend->log(AQ_LOG_ERROR, "drm: Found no gpus to use, cannot continue");
return nullptr;
return {};
}
backend->log(AQ_LOG_DEBUG, std::format("drm: Found {} GPUs", gpus.size()));
// FIXME: this will ignore multi-gpu setups and only create one backend
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
drmBackend->self = drmBackend;
std::vector<SP<CDRMBackend>> backends;
SP<CDRMBackend> primary;
if (!drmBackend->registerGPU(gpus.at(0))) {
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to register gpu at fd {}", gpus[0]->fd));
return nullptr;
} else
backend->log(AQ_LOG_DEBUG, std::format("drm: Registered gpu at fd {}", gpus[0]->fd));
for (auto& gpu : gpus) {
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
drmBackend->self = drmBackend;
if (primary)
drmBackend->primary = primary;
// TODO: consider listening for new devices
// But if you expect me to handle gpu hotswaps you are probably insane LOL
if (!drmBackend->registerGPU(gpus.at(0))) {
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to register gpu {}", gpu->path));
continue;
} 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;
// TODO: consider listening for new devices
// But if you expect me to handle gpu hotswaps you are probably insane LOL
if (!drmBackend->checkFeatures()) {
backend->log(AQ_LOG_ERROR, "drm: Failed checking features");
continue;
}
if (!drmBackend->initResources()) {
backend->log(AQ_LOG_ERROR, "drm: Failed initializing resources");
continue;
}
backend->log(AQ_LOG_DEBUG, std::format("drm: Basic init pass for gpu {}", gpu->path));
drmBackend->grabFormats();
drmBackend->scanConnectors();
if (!primary) {
backend->log(AQ_LOG_DEBUG, std::format("drm: gpu {} becomes primary drm", gpu->path));
primary = drmBackend;
}
backends.emplace_back(drmBackend);
}
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 {}", gpus[0]->path));
drmBackend->grabFormats();
drmBackend->scanConnectors();
return drmBackend;
return backends;
}
Aquamarine::CDRMBackend::~CDRMBackend() {
@ -587,6 +622,19 @@ std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() {
if (p->type != DRM_PLANE_TYPE_PRIMARY)
continue;
if (primary) {
backend->log(AQ_LOG_TRACE, std::format("drm: getRenderFormats on secondary {}", gpu->path));
// this is a secondary GPU renderer. In order to receive buffers,
// we'll force linear modifiers.
// TODO: don't. Find a common maybe?
auto fmts = p->formats;
for (auto& fmt : fmts) {
fmt.modifiers = {DRM_FORMAT_MOD_LINEAR};
}
return fmts;
}
return p->formats;
}
@ -598,6 +646,19 @@ std::vector<SDRMFormat> Aquamarine::CDRMBackend::getCursorFormats() {
if (p->type != DRM_PLANE_TYPE_CURSOR)
continue;
if (primary) {
backend->log(AQ_LOG_TRACE, std::format("drm: getCursorFormats on secondary {}", gpu->path));
// this is a secondary GPU renderer. In order to receive buffers,
// we'll force linear modifiers.
// TODO: don't. Find a common maybe?
auto fmts = p->formats;
for (auto& fmt : fmts) {
fmt.modifiers = {DRM_FORMAT_MOD_LINEAR};
}
return fmts;
}
return p->formats;
}

View file

@ -24,6 +24,8 @@ void Aquamarine::CDRMAtomicRequest::add(uint32_t id, uint32_t prop, uint64_t val
if (failed)
return;
backend->log(AQ_LOG_TRACE, std::format("atomic drm request: adding id {} prop {} with value {}", id, prop, val));
if (id == 0 || prop == 0) {
backend->log(AQ_LOG_ERROR, "atomic drm request: failed to add prop: id / prop == 0");
return;
@ -45,7 +47,9 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
// Disable the plane
backend->log(AQ_LOG_TRACE, std::format("atomic planeProps: disabling plane {}", plane->id));
add(plane->id, plane->props.fb_id, 0);
add(plane->id, plane->props.crtc_id, 0);
add(plane->id, plane->props.crtc_id, crtc);
add(plane->id, plane->props.crtc_x, (uint64_t)pos.x);
add(plane->id, plane->props.crtc_y, (uint64_t)pos.y);
return;
}
@ -69,7 +73,7 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
const auto& STATE = connector->output->state->state();
const bool enable = STATE.enabled && data.mainFB;
const bool enable = STATE.enabled;
backend->log(AQ_LOG_TRACE,
std::format("atomic addConnector blobs: mode_id {}, active {}, crtc_id {}, link_status {}, content_type {}", connector->crtc->props.mode_id,
@ -77,6 +81,11 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint
add(connector->id, connector->props.crtc_id, enable ? connector->crtc->id : 0);
if (data.modeset && enable) {
backend->log(AQ_LOG_TRACE, std::format("atomic: mode blob {}", data.atomic.modeBlob));
add(connector->crtc->id, connector->crtc->props.mode_id, data.atomic.modeBlob);
}
if (data.modeset && enable && connector->props.link_status)
add(connector->id, connector->props.link_status, DRM_MODE_LINK_STATUS_GOOD);
@ -87,7 +96,6 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint
if (data.modeset && enable && connector->props.max_bpc && connector->maxBpcBounds.at(1))
add(connector->id, connector->props.max_bpc, 8); // FIXME: this isnt always 8
// add(connector->crtc->id, connector->crtc->props.mode_id, data.atomic.modeBlob);
add(connector->crtc->id, connector->crtc->props.active, enable);
if (enable) {
@ -210,6 +218,10 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin
connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a modeset blob");
return false;
}
connector->backend->log(AQ_LOG_TRACE,
std::format("Connector blob id {}: clock {}, {}x{}, vrefresh {}, name: {}", data.atomic.modeBlob, data.modeInfo.clock, data.modeInfo.hdisplay,
data.modeInfo.vdisplay, data.modeInfo.vrefresh, data.modeInfo.name));
}
}