mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 16:09:47 +01:00
drm: very initial work on multigpu
This commit is contained in:
parent
944b0465fa
commit
40f6fa5173
4 changed files with 116 additions and 40 deletions
|
@ -291,7 +291,7 @@ namespace Aquamarine {
|
||||||
private:
|
private:
|
||||||
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
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 registerGPU(Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu_, Hyprutils::Memory::CSharedPointer<CDRMBackend> primary_ = {});
|
||||||
bool checkFeatures();
|
bool checkFeatures();
|
||||||
bool initResources();
|
bool initResources();
|
||||||
|
|
|
@ -52,12 +52,15 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const s
|
||||||
ref->self = ref;
|
ref->self = ref;
|
||||||
} else if (b.backendType == AQ_BACKEND_DRM) {
|
} else if (b.backendType == AQ_BACKEND_DRM) {
|
||||||
auto ref = CDRMBackend::attempt(backend);
|
auto ref = CDRMBackend::attempt(backend);
|
||||||
if (!ref) {
|
if (ref.empty()) {
|
||||||
backend->log(AQ_LOG_ERROR, "DRM Backend failed");
|
backend->log(AQ_LOG_ERROR, "DRM Backend failed");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
backend->implementations.emplace_back(ref);
|
|
||||||
ref->self = ref;
|
for (auto& r : ref) {
|
||||||
|
backend->implementations.emplace_back(r);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
backend->log(AQ_LOG_ERROR, std::format("Unknown backend id: {}", (int)b.backendType));
|
backend->log(AQ_LOG_ERROR, std::format("Unknown backend id: {}", (int)b.backendType));
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <aquamarine/backend/DRM.hpp>
|
#include <aquamarine/backend/DRM.hpp>
|
||||||
#include <aquamarine/backend/drm/Legacy.hpp>
|
#include <aquamarine/backend/drm/Legacy.hpp>
|
||||||
#include <aquamarine/backend/drm/Atomic.hpp>
|
#include <aquamarine/backend/drm/Atomic.hpp>
|
||||||
|
#include <hyprutils/string/VarList.hpp>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
@ -50,8 +51,6 @@ static udev_enumerate* enumDRMCards(udev* udev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
|
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);
|
auto enumerate = enumDRMCards(backend->session->udevHandle);
|
||||||
|
|
||||||
if (!enumerate) {
|
if (!enumerate) {
|
||||||
|
@ -123,20 +122,43 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
|
||||||
udev_enumerate_unref(enumerate);
|
udev_enumerate_unref(enumerate);
|
||||||
|
|
||||||
std::vector<SP<CSessionDevice>> vecDevices;
|
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;
|
return vecDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CDRMBackend> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
|
std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
|
||||||
if (!backend->session)
|
if (!backend->session)
|
||||||
backend->session = CSession::attempt(backend);
|
backend->session = CSession::attempt(backend);
|
||||||
|
|
||||||
if (!backend->session) {
|
if (!backend->session) {
|
||||||
backend->log(AQ_LOG_ERROR, "Failed to open a session");
|
backend->log(AQ_LOG_ERROR, "Failed to open a session");
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backend->session->active) {
|
if (!backend->session->active) {
|
||||||
|
@ -156,7 +178,7 @@ SP<CDRMBackend> Aquamarine::CDRMBackend::attempt(SP<CBackend> backend) {
|
||||||
|
|
||||||
if (!backend->session->active) {
|
if (!backend->session->active) {
|
||||||
backend->log(AQ_LOG_DEBUG, "Session could not be activated in time");
|
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()) {
|
if (gpus.empty()) {
|
||||||
backend->log(AQ_LOG_ERROR, "drm: Found no gpus to use, cannot continue");
|
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()));
|
backend->log(AQ_LOG_DEBUG, std::format("drm: Found {} GPUs", gpus.size()));
|
||||||
|
|
||||||
// FIXME: this will ignore multi-gpu setups and only create one backend
|
std::vector<SP<CDRMBackend>> backends;
|
||||||
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
|
SP<CDRMBackend> primary;
|
||||||
drmBackend->self = drmBackend;
|
|
||||||
|
|
||||||
if (!drmBackend->registerGPU(gpus.at(0))) {
|
for (auto& gpu : gpus) {
|
||||||
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to register gpu at fd {}", gpus[0]->fd));
|
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
|
||||||
return nullptr;
|
drmBackend->self = drmBackend;
|
||||||
} else
|
if (primary)
|
||||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Registered gpu at fd {}", gpus[0]->fd));
|
drmBackend->primary = primary;
|
||||||
|
|
||||||
// TODO: consider listening for new devices
|
if (!drmBackend->registerGPU(gpus.at(0))) {
|
||||||
// But if you expect me to handle gpu hotswaps you are probably insane LOL
|
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()) {
|
// TODO: consider listening for new devices
|
||||||
backend->log(AQ_LOG_ERROR, "drm: Failed checking features");
|
// But if you expect me to handle gpu hotswaps you are probably insane LOL
|
||||||
return nullptr;
|
|
||||||
|
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()) {
|
return backends;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Aquamarine::CDRMBackend::~CDRMBackend() {
|
Aquamarine::CDRMBackend::~CDRMBackend() {
|
||||||
|
@ -587,6 +622,19 @@ std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() {
|
||||||
if (p->type != DRM_PLANE_TYPE_PRIMARY)
|
if (p->type != DRM_PLANE_TYPE_PRIMARY)
|
||||||
continue;
|
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;
|
return p->formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,6 +646,19 @@ std::vector<SDRMFormat> Aquamarine::CDRMBackend::getCursorFormats() {
|
||||||
if (p->type != DRM_PLANE_TYPE_CURSOR)
|
if (p->type != DRM_PLANE_TYPE_CURSOR)
|
||||||
continue;
|
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;
|
return p->formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ void Aquamarine::CDRMAtomicRequest::add(uint32_t id, uint32_t prop, uint64_t val
|
||||||
if (failed)
|
if (failed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
backend->log(AQ_LOG_TRACE, std::format("atomic drm request: adding id {} prop {} with value {}", id, prop, val));
|
||||||
|
|
||||||
if (id == 0 || prop == 0) {
|
if (id == 0 || prop == 0) {
|
||||||
backend->log(AQ_LOG_ERROR, "atomic drm request: failed to add prop: id / prop == 0");
|
backend->log(AQ_LOG_ERROR, "atomic drm request: failed to add prop: id / prop == 0");
|
||||||
return;
|
return;
|
||||||
|
@ -45,7 +47,9 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
|
||||||
// Disable the plane
|
// Disable the plane
|
||||||
backend->log(AQ_LOG_TRACE, std::format("atomic planeProps: disabling plane {}", plane->id));
|
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.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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +73,7 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
|
||||||
|
|
||||||
void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
|
void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
|
||||||
const auto& STATE = connector->output->state->state();
|
const auto& STATE = connector->output->state->state();
|
||||||
const bool enable = STATE.enabled && data.mainFB;
|
const bool enable = STATE.enabled;
|
||||||
|
|
||||||
backend->log(AQ_LOG_TRACE,
|
backend->log(AQ_LOG_TRACE,
|
||||||
std::format("atomic addConnector blobs: mode_id {}, active {}, crtc_id {}, link_status {}, content_type {}", connector->crtc->props.mode_id,
|
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);
|
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)
|
if (data.modeset && enable && connector->props.link_status)
|
||||||
add(connector->id, connector->props.link_status, DRM_MODE_LINK_STATUS_GOOD);
|
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))
|
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->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);
|
add(connector->crtc->id, connector->crtc->props.active, enable);
|
||||||
|
|
||||||
if (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");
|
connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a modeset blob");
|
||||||
return false;
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue