Skip to content

Commit

Permalink
drm: properly blit multigpu surfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
vaxerski committed Jul 11, 2024
1 parent c3bfe3d commit c4a5faf
Show file tree
Hide file tree
Showing 10 changed files with 842 additions and 37 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(INCLUDE ${CMAKE_INSTALL_FULL_INCLUDEDIR})
set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR})

find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED COMPONENTS "GLES2")
find_package(hyprwayland-scanner 0.4.0 REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
libseat>=0.8.0 libinput>=1.26.0
Expand Down Expand Up @@ -51,7 +52,11 @@ set_target_properties(aquamarine PROPERTIES
VERSION ${AQUAMARINE_VERSION}
SOVERSION 0
)
target_link_libraries(aquamarine PkgConfig::deps)
target_link_libraries(aquamarine
OpenGL::EGL
OpenGL::GL
PkgConfig::deps
)

check_include_file("sys/timerfd.h" HAS_TIMERFD)
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
Expand Down
7 changes: 3 additions & 4 deletions include/aquamarine/backend/Backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,9 @@ namespace Aquamarine {
Hyprutils::Signal::CSignal newTabletPad;
} events;

Hyprutils::Memory::CSharedPointer<IAllocator> primaryAllocator;
std::vector<Hyprutils::Memory::CSharedPointer<IAllocator>> allocators;
bool ready = false;
Hyprutils::Memory::CSharedPointer<CSession> session;
Hyprutils::Memory::CSharedPointer<IAllocator> primaryAllocator;
bool ready = false;
Hyprutils::Memory::CSharedPointer<CSession> session;

private:
CBackend();
Expand Down
17 changes: 13 additions & 4 deletions include/aquamarine/backend/DRM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Aquamarine {
class CDRMFB;
class CDRMOutput;
struct SDRMConnector;
class CDRMRenderer;

typedef std::function<void(void)> FIdleCallback;

Expand Down Expand Up @@ -341,7 +342,6 @@ namespace Aquamarine {

std::vector<FIdleCallback> idleCallbacks;
std::string gpuName;
Hyprutils::Memory::CWeakPointer<IAllocator> allocator;

private:
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
Expand All @@ -350,15 +350,24 @@ namespace Aquamarine {
bool registerGPU(Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu_, Hyprutils::Memory::CSharedPointer<CDRMBackend> primary_ = {});
bool checkFeatures();
bool initResources();
bool initMgpu();
bool grabFormats();
bool shouldBlit();
void scanConnectors();
void scanLeases();
void restoreAfterVT();
void recheckCRTCs();

Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu;
Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl;
Hyprutils::Memory::CWeakPointer<CDRMBackend> primary;
Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu;
Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl;
Hyprutils::Memory::CWeakPointer<CDRMBackend> primary;

// multigpu state, only present if this backend is not primary, aka if this->primary != nullptr
struct {
Hyprutils::Memory::CSharedPointer<IAllocator> allocator;
Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain;
Hyprutils::Memory::CSharedPointer<CDRMRenderer> renderer;
} mgpu;

Hyprutils::Memory::CWeakPointer<CBackend> backend;

Expand Down
5 changes: 1 addition & 4 deletions include/aquamarine/output/Output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,7 @@ namespace Aquamarine {
std::vector<Hyprutils::Memory::CSharedPointer<SOutputMode>> modes;
Hyprutils::Memory::CSharedPointer<COutputState> state = Hyprutils::Memory::makeShared<COutputState>();

// please note that for multigpu setups, this swapchain resides on the target gpu,
// so it's recommended that if this swapchain's allocator FD doesn't match the primary
// drmFD used, you should render to a buffer on the main gpu and only perform the final copy to this swapchain.
Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain;
Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain;

//

Expand Down
7 changes: 3 additions & 4 deletions src/backend/Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,12 @@ bool Aquamarine::CBackend::start() {
// TODO: obviously change this when (if) we add different allocators.
for (auto& b : implementations) {
if (b->drmFD() >= 0) {
allocators.emplace_back(CGBMAllocator::create(b->drmFD(), self));
if (!primaryAllocator)
primaryAllocator = allocators.front();
primaryAllocator = CGBMAllocator::create(b->drmFD(), self);
break;
}
}

if (allocators.empty() || !primaryAllocator)
if (!primaryAllocator)
return false;

ready = true;
Expand Down
81 changes: 61 additions & 20 deletions src/backend/drm/DRM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <aquamarine/backend/DRM.hpp>
#include <aquamarine/backend/drm/Legacy.hpp>
#include <aquamarine/backend/drm/Atomic.hpp>
#include <aquamarine/allocator/GBM.hpp>
#include <hyprutils/string/VarList.hpp>
#include <chrono>
#include <thread>
Expand All @@ -24,6 +25,7 @@ extern "C" {
#include "FormatUtils.hpp"
#include "Shared.hpp"
#include "hwdata.hpp"
#include "Renderer.hpp"

using namespace Aquamarine;
using namespace Hyprutils::Memory;
Expand Down Expand Up @@ -465,6 +467,38 @@ bool Aquamarine::CDRMBackend::initResources() {
return true;
}

bool Aquamarine::CDRMBackend::shouldBlit() {
return primary;
}

bool Aquamarine::CDRMBackend::initMgpu() {
if (!primary)
return true;

mgpu.allocator = CGBMAllocator::create(gpu->fd, backend);

if (!mgpu.allocator) {
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no allocator");
return false;
}

mgpu.swapchain = CSwapchain::create(mgpu.allocator, self.lock());

if (!mgpu.swapchain) {
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no swapchain");
return false;
}

mgpu.renderer = CDRMRenderer::attempt(gpu->fd, backend.lock());

if (!mgpu.renderer) {
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no renderer");
return false;
}

return true;
}

void Aquamarine::CDRMBackend::recheckCRTCs() {
if (connectors.empty() || crtcs.empty())
return;
Expand Down Expand Up @@ -760,27 +794,18 @@ void Aquamarine::CDRMBackend::onReady() {

backend->log(AQ_LOG_DEBUG, std::format("drm: onReady: connector {} has output name {}", c->id, c->output->name));

// find our allocator, for multigpu setups there will be 2
for (auto& alloc : backend->allocators) {
if (alloc->drmFD() != gpu->fd)
continue;

allocator = alloc;
break;
}

if (!allocator) {
backend->log(AQ_LOG_ERROR, std::format("drm: backend for gpu {} doesn't have an allocator?!", gpu->path));
return;
}

// swapchain has to be created here because allocator is absent in connect if not ready
c->output->swapchain = CSwapchain::create(allocator.lock(), self.lock());
c->output->swapchain = CSwapchain::create(backend->primaryAllocator, self.lock());
c->output->swapchain->reconfigure(SSwapchainOptions{.length = 0, .scanout = true, .multigpu = !!primary}); // mark the swapchain for scanout
c->output->needsFrame = true;

backend->events.newOutput.emit(SP<IOutput>(c->output));
}

if (!initMgpu()) {
backend->log(AQ_LOG_ERROR, "drm: Failed initializing mgpu");
return;
}
}

std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() {
Expand Down Expand Up @@ -852,7 +877,7 @@ int Aquamarine::CDRMBackend::getNonMasterFD() {
}

SP<IAllocator> Aquamarine::CDRMBackend::preferredAllocator() {
return allocator.lock();
return backend->primaryAllocator;
}

bool Aquamarine::SDRMPlane::init(drmModePlane* plane) {
Expand Down Expand Up @@ -1172,7 +1197,7 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
if (!backend->backend->ready)
return;

output->swapchain = CSwapchain::create(backend->allocator.lock(), backend->self.lock());
output->swapchain = CSwapchain::create(backend->backend->primaryAllocator, backend->self.lock());
backend->backend->events.newOutput.emit(output);
output->scheduleFrame(IOutput::AQ_SCHEDULE_NEW_CONNECTOR);
}
Expand Down Expand Up @@ -1327,10 +1352,26 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: Committed a buffer, updating state"));

SP<CDRMFB> drmFB;
auto buf = STATE.buffer;
bool isNew = false;

drmFB = CDRMFB::create(buf, backend, &isNew); // will return attachment if present
if (backend->shouldBlit()) {
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: Backend requires blit, blitting"));

auto OPTIONS = swapchain->currentOptions();
OPTIONS.multigpu = false; // this is not a shared swapchain, and additionally, don't make it linear, nvidia would be mad
if (!backend->mgpu.swapchain->reconfigure(OPTIONS)) {
backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but the mgpu swapchain failed reconfiguring");
return false;
}

auto NEWAQBUF = backend->mgpu.swapchain->next(nullptr);
if (!backend->mgpu.renderer->blit(STATE.buffer, NEWAQBUF)) {
backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but blit failed");
return false;
}

drmFB = CDRMFB::create(NEWAQBUF, backend, nullptr); // will return attachment if present
} else
drmFB = CDRMFB::create(STATE.buffer, backend, nullptr); // will return attachment if present

if (!drmFB) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer failed to import to KMS");
Expand Down
Loading

0 comments on commit c4a5faf

Please sign in to comment.