From 40f6fa51738280f8f7087f4b8cbfb2ecebc8472b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 28 Jun 2024 17:13:03 +0200 Subject: [PATCH] drm: very initial work on multigpu --- include/aquamarine/backend/DRM.hpp | 2 +- src/backend/Backend.cpp | 9 +- src/backend/drm/DRM.cpp | 127 +++++++++++++++++++++-------- src/backend/drm/impl/Atomic.cpp | 18 +++- 4 files changed, 116 insertions(+), 40 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index 92f20c7..0b0925a 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -291,7 +291,7 @@ namespace Aquamarine { private: CDRMBackend(Hyprutils::Memory::CSharedPointer backend); - static Hyprutils::Memory::CSharedPointer attempt(Hyprutils::Memory::CSharedPointer backend); + static std::vector> attempt(Hyprutils::Memory::CSharedPointer backend); bool registerGPU(Hyprutils::Memory::CSharedPointer gpu_, Hyprutils::Memory::CSharedPointer primary_ = {}); bool checkFeatures(); bool initResources(); diff --git a/src/backend/Backend.cpp b/src/backend/Backend.cpp index fd33564..90ffae9 100644 --- a/src/backend/Backend.cpp +++ b/src/backend/Backend.cpp @@ -52,12 +52,15 @@ Hyprutils::Memory::CSharedPointer 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; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 53ef5bf..c28c70d 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -50,8 +51,6 @@ static udev_enumerate* enumDRMCards(udev* udev) { } static std::vector> scanGPUs(SP 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> scanGPUs(SP backend) { udev_enumerate_unref(enumerate); std::vector> 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 Aquamarine::CDRMBackend::attempt(SP backend) { +std::vector> Aquamarine::CDRMBackend::attempt(SP 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 Aquamarine::CDRMBackend::attempt(SP 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 Aquamarine::CDRMBackend::attempt(SP 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(new CDRMBackend(backend)); - drmBackend->self = drmBackend; + std::vector> backends; + SP 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(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 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 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; } diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index 47a8217..01d52db 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -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 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)); } }