backend: add a null backend

Adds a null backend. A null backend doesn't do anything, but allows us to use e.g. the GBM allocator and swapchains by manually passing a drm fd
This commit is contained in:
Vaxry 2025-09-19 18:15:53 +01:00
parent 81584dae2d
commit 83bd1e12a7
Signed by: vaxry
GPG key ID: 665806380871D640
5 changed files with 142 additions and 3 deletions

View file

@ -25,6 +25,7 @@ namespace Aquamarine {
AQ_BACKEND_WAYLAND = 0,
AQ_BACKEND_DRM,
AQ_BACKEND_HEADLESS,
AQ_BACKEND_NULL,
};
enum eBackendRequestMode : uint32_t {

View file

@ -0,0 +1,45 @@
#pragma once
#include "./Backend.hpp"
#include "../allocator/Swapchain.hpp"
#include "../output/Output.hpp"
#include <hyprutils/memory/WeakPtr.hpp>
namespace Aquamarine {
class CBackend;
class IAllocator;
class CNullBackend : public IBackendImplementation {
public:
virtual ~CNullBackend();
virtual eBackendType type();
virtual bool start();
virtual std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
virtual int drmFD();
virtual bool dispatchEvents();
virtual uint32_t capabilities();
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void onReady();
virtual std::vector<SDRMFormat> getRenderFormats();
virtual std::vector<SDRMFormat> getCursorFormats();
virtual bool createOutput(const std::string& name = "");
virtual Hyprutils::Memory::CSharedPointer<IAllocator> preferredAllocator();
virtual std::vector<Hyprutils::Memory::CSharedPointer<IAllocator>> getAllocators();
virtual Hyprutils::Memory::CWeakPointer<IBackendImplementation> getPrimary();
Hyprutils::Memory::CWeakPointer<CNullBackend> self;
virtual int drmRenderNodeFD();
void setFormats(const std::vector<SDRMFormat>& fmts);
private:
CNullBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend_);
Hyprutils::Memory::CWeakPointer<CBackend> backend;
std::vector<SDRMFormat> m_formats;
friend class CBackend;
friend class CHeadlessOutput;
};
};

View file

@ -2,6 +2,7 @@
#include <aquamarine/backend/Wayland.hpp>
#include <aquamarine/backend/Headless.hpp>
#include <aquamarine/backend/DRM.hpp>
#include <aquamarine/backend/Null.hpp>
#include <aquamarine/allocator/GBM.hpp>
#include <ranges>
#include <sys/timerfd.h>
@ -83,6 +84,10 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const s
auto ref = SP<CHeadlessBackend>(new CHeadlessBackend(backend));
backend->implementations.emplace_back(ref);
ref->self = ref;
} else if (b.backendType == AQ_BACKEND_NULL) {
auto ref = SP<CNullBackend>(new CNullBackend(backend));
backend->implementations.emplace_back(ref);
ref->self = ref;
} else {
backend->log(AQ_LOG_ERROR, std::format("Unknown backend id: {}", (int)b.backendType));
continue;
@ -133,7 +138,7 @@ bool Aquamarine::CBackend::start() {
// erase failed impls
std::erase_if(implementations, [this](const auto& i) {
bool failed = i->pollFDs().empty();
bool failed = i->pollFDs().empty() && i->type() != AQ_BACKEND_NULL;
if (failed)
log(AQ_LOG_ERROR, std::format("Implementation {} failed, erasing.", backendTypeToName(i->type())));
return failed;
@ -153,7 +158,7 @@ bool Aquamarine::CBackend::start() {
}
}
if (!primaryAllocator) {
if (!primaryAllocator && (implementations.empty() || implementations.at(0)->type() != AQ_BACKEND_NULL)) {
log(AQ_LOG_CRITICAL, "Cannot open backend: no allocator available");
return false;
}

89
src/backend/Null.cpp Normal file
View file

@ -0,0 +1,89 @@
#include <aquamarine/backend/Null.hpp>
#include <fcntl.h>
#include <ctime>
#include <sys/timerfd.h>
#include <cstring>
#include "Shared.hpp"
using namespace Aquamarine;
using namespace Hyprutils::Memory;
using namespace Hyprutils::Math;
#define SP CSharedPointer
Aquamarine::CNullBackend::~CNullBackend() {
;
}
Aquamarine::CNullBackend::CNullBackend(SP<CBackend> backend_) : backend(backend_) {
;
}
eBackendType Aquamarine::CNullBackend::type() {
return eBackendType::AQ_BACKEND_NULL;
}
bool Aquamarine::CNullBackend::start() {
return true;
}
std::vector<SP<SPollFD>> Aquamarine::CNullBackend::pollFDs() {
return {};
}
int Aquamarine::CNullBackend::drmFD() {
return -1;
}
int Aquamarine::CNullBackend::drmRenderNodeFD() {
return -1;
}
bool Aquamarine::CNullBackend::dispatchEvents() {
return true;
}
uint32_t Aquamarine::CNullBackend::capabilities() {
return 0;
}
bool Aquamarine::CNullBackend::setCursor(SP<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot) {
return false;
}
void Aquamarine::CNullBackend::onReady() {
;
}
std::vector<SDRMFormat> Aquamarine::CNullBackend::getRenderFormats() {
for (const auto& impl : backend->getImplementations()) {
if (impl->type() != AQ_BACKEND_DRM || impl->getRenderableFormats().empty())
continue;
return impl->getRenderableFormats();
}
return m_formats;
}
void Aquamarine::CNullBackend::setFormats(const std::vector<SDRMFormat>& fmts) {
m_formats = fmts;
}
std::vector<SDRMFormat> Aquamarine::CNullBackend::getCursorFormats() {
return {}; // No cursor support
}
bool Aquamarine::CNullBackend::createOutput(const std::string& name) {
return false;
}
SP<IAllocator> Aquamarine::CNullBackend::preferredAllocator() {
return backend->primaryAllocator;
}
std::vector<SP<IAllocator>> Aquamarine::CNullBackend::getAllocators() {
return {backend->primaryAllocator};
}
Hyprutils::Memory::CWeakPointer<IBackendImplementation> Aquamarine::CNullBackend::getPrimary() {
return {};
}

View file

@ -196,7 +196,6 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint
}
}
void Aquamarine::CDRMAtomicRequest::addConnectorModeset(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
if (!data.modeset)
return;