drm: reimport buffers when on a secondary gpu

This commit is contained in:
Vaxry 2024-06-28 20:14:56 +02:00
parent 8ecf8773db
commit 320a6d40a7
2 changed files with 46 additions and 13 deletions

View file

@ -45,11 +45,14 @@ namespace Aquamarine {
public:
~CDRMFB();
static Hyprutils::Memory::CSharedPointer<CDRMFB> create(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_);
static Hyprutils::Memory::CSharedPointer<CDRMFB> create(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, bool* isNew = nullptr);
void closeHandles();
// drops the buffer from KMS
void drop();
void drop();
// re-imports the buffer into KMS. Essentially drop and import.
void reimport();
uint32_t id = 0;
Hyprutils::Memory::CWeakPointer<IBuffer> buffer;
@ -59,6 +62,7 @@ namespace Aquamarine {
private:
CDRMFB(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_);
uint32_t submitBuffer();
void import();
bool dropped = false, handlesClosed = false;
};

View file

@ -192,15 +192,13 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backe
backend->log(AQ_LOG_DEBUG, std::format("drm: Found {} GPUs", gpus.size()));
std::vector<SP<CDRMBackend>> backends;
SP<CDRMBackend> primary;
SP<CDRMBackend> newPrimary;
for (auto& gpu : gpus) {
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
drmBackend->self = drmBackend;
if (primary)
drmBackend->primary = primary;
if (!drmBackend->registerGPU(gpu)) {
if (!drmBackend->registerGPU(gpu, newPrimary)) {
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to register gpu {}", gpu->path));
continue;
} else
@ -225,9 +223,9 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backe
drmBackend->scanConnectors();
if (!primary) {
if (!newPrimary) {
backend->log(AQ_LOG_DEBUG, std::format("drm: gpu {} becomes primary drm", gpu->path));
primary = drmBackend;
newPrimary = drmBackend;
}
backends.emplace_back(drmBackend);
@ -441,7 +439,9 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
gpuName = drmName;
backend->log(AQ_LOG_DEBUG, std::format("drm: Starting backend for {}, with driver {}", drmName ? drmName : "unknown", drmVer->name ? drmVer->name : "unknown"));
backend->log(AQ_LOG_DEBUG,
std::format("drm: Starting backend for {}, with driver {}{}", drmName ? drmName : "unknown", drmVer->name ? drmVer->name : "unknown",
(primary ? std::format(" with primary {}", primary->gpu->path) : "")));
drmFreeVersion(drmVer);
@ -1111,15 +1111,23 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
backend->backend->log(AQ_LOG_TRACE, "drm: Committed a buffer, updating state");
SP<CDRMFB> drmFB;
auto buf = STATE.buffer;
auto buf = STATE.buffer;
bool isNew = false;
drmFB = CDRMFB::create(buf, backend); // will return attachment if present
drmFB = CDRMFB::create(buf, backend, &isNew); // will return attachment if present
if (!drmFB) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer failed to import to KMS");
return false;
}
if (!isNew && backend->primary) {
// this is not a new buffer, and we are not on a primary GPU, which means
// this buffer lives on the primary. We need to re-import it to update
// the contents that have possibly (probably) changed
drmFB->reimport();
}
data.mainFB = drmFB;
}
@ -1197,18 +1205,24 @@ Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::
name = name_;
}
SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_) {
SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, bool* isNew) {
SP<CDRMFB> fb;
if (isNew)
*isNew = true;
if (buffer_->attachments.has(AQ_ATTACHMENT_DRM_BUFFER)) {
auto at = (CDRMBufferAttachment*)buffer_->attachments.get(AQ_ATTACHMENT_DRM_BUFFER).get();
fb = at->fb;
backend_->log(AQ_LOG_TRACE, std::format("drm: CDRMFB: buffer has drmfb attachment with fb {:x}", (uintptr_t)fb.get()));
}
if (fb)
if (fb) {
if (isNew)
*isNew = false;
return fb;
}
fb = SP<CDRMFB>(new CDRMFB(buffer_, backend_));
@ -1221,6 +1235,10 @@ SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CW
}
Aquamarine::CDRMFB::CDRMFB(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_) : buffer(buffer_), backend(backend_) {
import();
}
void Aquamarine::CDRMFB::import() {
auto attrs = buffer->dmabuf();
if (!attrs.success) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer submitted has no dmabuf");
@ -1259,6 +1277,15 @@ Aquamarine::CDRMFB::CDRMFB(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<
// closeHandles();
}
void Aquamarine::CDRMFB::reimport() {
drop();
dropped = false;
handlesClosed = false;
boHandles = {0, 0, 0, 0};
import();
}
Aquamarine::CDRMFB::~CDRMFB() {
drop();
}
@ -1299,6 +1326,8 @@ void Aquamarine::CDRMFB::drop() {
if (!id)
return;
closeHandles();
backend->backend->log(AQ_LOG_TRACE, std::format("drm: dropping buffer {}", id));
int ret = drmModeCloseFB(backend->gpu->fd, id);