DRM: Steady progress on getting a usable session

modesetting, rendering, etc. Hyprland now renders properly, although input devices are yet to be implemented.
This commit is contained in:
Vaxry 2024-06-24 23:22:02 +02:00
parent f888bfb6e4
commit 2e0052a21d
15 changed files with 769 additions and 30 deletions

View file

@ -16,7 +16,7 @@ set(INCLUDE ${CMAKE_INSTALL_FULL_INCLUDEDIR})
set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}) set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR})
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET libseat libinput wayland-client wayland-protocols hyprutils>=0.1.2 pixman-1 wayland-client libdrm gbm libudev) pkg_check_modules(deps REQUIRED IMPORTED_TARGET libseat libinput wayland-client wayland-protocols hyprutils>=0.1.2 pixman-1 wayland-client libdrm gbm libudev libdisplay-info)
configure_file(aquamarine.pc.in aquamarine.pc @ONLY) configure_file(aquamarine.pc.in aquamarine.pc @ONLY)

View file

@ -9,7 +9,8 @@ namespace Aquamarine {
struct SAllocatorBufferParams { struct SAllocatorBufferParams {
Hyprutils::Math::Vector2D size; Hyprutils::Math::Vector2D size;
uint32_t format = DRM_FORMAT_INVALID; uint32_t format = DRM_FORMAT_INVALID;
bool scanout = false;
}; };
class IAllocator { class IAllocator {

View file

@ -7,7 +7,8 @@ namespace Aquamarine {
struct SSwapchainOptions { struct SSwapchainOptions {
size_t length = 0; size_t length = 0;
Hyprutils::Math::Vector2D size; Hyprutils::Math::Vector2D size;
uint32_t format = DRM_FORMAT_INVALID; uint32_t format = DRM_FORMAT_INVALID;
bool scanout = false;
}; };
class CSwapchain { class CSwapchain {

View file

@ -100,6 +100,9 @@ namespace Aquamarine {
/* Get the primary DRM FD */ /* Get the primary DRM FD */
int drmFD(); int drmFD();
/* Get the render formats the primary backend supports */
std::vector<SDRMFormat> getPrimaryRenderFormats();
struct { struct {
Hyprutils::Signal::CSignal newOutput; Hyprutils::Signal::CSignal newOutput;
Hyprutils::Signal::CSignal newPointer; Hyprutils::Signal::CSignal newPointer;

View file

@ -10,16 +10,51 @@
namespace Aquamarine { namespace Aquamarine {
class CDRMBackend; class CDRMBackend;
class CDRMFB;
struct SDRMConnector; struct SDRMConnector;
struct SDRMFB { typedef std::function<void(void)> FIdleCallback;
class CDRMBufferUnimportable : public IAttachment {
public:
CDRMBufferUnimportable() {
;
}
virtual ~CDRMBufferUnimportable() {
;
}
virtual eAttachmentType type() {
return AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE;
}
};
class CDRMFB {
public:
~CDRMFB();
static Hyprutils::Memory::CSharedPointer<CDRMFB> create(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_);
void closeHandles();
// drops the buffer from KMS
void drop();
uint32_t id = 0; uint32_t id = 0;
Hyprutils::Memory::CSharedPointer<IBuffer> buffer; Hyprutils::Memory::CSharedPointer<IBuffer> buffer;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend; Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
private:
CDRMFB(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_);
uint32_t submitBuffer();
bool dropped = false, handlesClosed = false;
std::array<uint32_t, 4> boHandles = {0};
}; };
struct SDRMLayer { struct SDRMLayer {
Hyprutils::Memory::CSharedPointer<SDRMFB> current /* displayed */, queued /* submitted */, pending /* to be submitted */; // we expect the consumers to use double-buffering, so we keep the 2 last FBs around. If any of these goes out of
// scope, the DRM FB will be destroyed, but the IBuffer will stay, as long as it's ref'd somewhere.
Hyprutils::Memory::CSharedPointer<CDRMFB> front /* currently displaying */, back;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend; Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
}; };
@ -30,7 +65,7 @@ namespace Aquamarine {
uint32_t id = 0; uint32_t id = 0;
uint32_t initialID = 0; uint32_t initialID = 0;
Hyprutils::Memory::CSharedPointer<SDRMFB> current /* displayed */, queued /* submitted */; Hyprutils::Memory::CSharedPointer<CDRMFB> front /* currently displaying */, back /* submitted */;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend; Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
Hyprutils::Memory::CWeakPointer<SDRMPlane> self; Hyprutils::Memory::CWeakPointer<SDRMPlane> self;
std::vector<SDRMFormat> formats; std::vector<SDRMFormat> formats;
@ -108,12 +143,29 @@ namespace Aquamarine {
private: private:
CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_); CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_);
bool commitState(bool onlyTest = false);
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend; Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
Hyprutils::Memory::CSharedPointer<SDRMConnector> connector; Hyprutils::Memory::CSharedPointer<SDRMConnector> connector;
friend struct SDRMConnector; friend struct SDRMConnector;
}; };
struct SDRMPageFlip {
Hyprutils::Memory::CWeakPointer<SDRMConnector> connector;
};
struct SDRMConnectorCommitData {
Hyprutils::Memory::CSharedPointer<CDRMFB> mainFB, cursorFB;
bool modeset = false;
bool blocking = false;
uint32_t flags = 0;
bool test = false;
drmModeModeInfo modeInfo;
void calculateMode(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);
};
struct SDRMConnector { struct SDRMConnector {
~SDRMConnector(); ~SDRMConnector();
@ -123,6 +175,10 @@ namespace Aquamarine {
Hyprutils::Memory::CSharedPointer<SDRMCRTC> getCurrentCRTC(const drmModeConnector* connector); Hyprutils::Memory::CSharedPointer<SDRMCRTC> getCurrentCRTC(const drmModeConnector* connector);
drmModeModeInfo* getCurrentMode(); drmModeModeInfo* getCurrentMode();
void parseEDID(std::vector<uint8_t> data); void parseEDID(std::vector<uint8_t> data);
bool commitState(const SDRMConnectorCommitData& data);
void applyCommit(const SDRMConnectorCommitData& data);
void rollbackCommit(const SDRMConnectorCommitData& data);
void onPresent();
Hyprutils::Memory::CSharedPointer<CDRMOutput> output; Hyprutils::Memory::CSharedPointer<CDRMOutput> output;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend; Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
@ -135,10 +191,16 @@ namespace Aquamarine {
int32_t refresh = 0; int32_t refresh = 0;
uint32_t possibleCrtcs = 0; uint32_t possibleCrtcs = 0;
std::string make, serial, model; std::string make, serial, model;
bool canDoVrr = false;
bool cursorEnabled = false; bool cursorEnabled = false;
Hyprutils::Math::Vector2D cursorPos, cursorSize, cursorHotspot; Hyprutils::Math::Vector2D cursorPos, cursorSize, cursorHotspot;
Hyprutils::Memory::CSharedPointer<SDRMFB> pendingCursorFB; Hyprutils::Memory::CSharedPointer<CDRMFB> pendingCursorFB;
bool isPageFlipPending = false;
SDRMPageFlip pendingPageFlip;
drmModeModeInfo fallbackModeInfo;
union UDRMConnectorProps { union UDRMConnectorProps {
struct { struct {
@ -162,6 +224,11 @@ namespace Aquamarine {
UDRMConnectorProps props; UDRMConnectorProps props;
}; };
class IDRMImplementation {
public:
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data) = 0;
};
class CDRMBackend : public IBackendImplementation { class CDRMBackend : public IBackendImplementation {
public: public:
virtual ~CDRMBackend(); virtual ~CDRMBackend();
@ -178,6 +245,11 @@ namespace Aquamarine {
Hyprutils::Memory::CWeakPointer<CDRMBackend> self; Hyprutils::Memory::CWeakPointer<CDRMBackend> self;
void log(eBackendLogLevel, const std::string&);
bool sessionActive();
std::vector<FIdleCallback> idleCallbacks;
private: private:
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend); CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
@ -189,6 +261,7 @@ namespace Aquamarine {
void scanConnectors(); void scanConnectors();
Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu; Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu;
Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl;
Hyprutils::Memory::CWeakPointer<CDRMBackend> primary; Hyprutils::Memory::CWeakPointer<CDRMBackend> primary;
Hyprutils::Memory::CWeakPointer<CBackend> backend; Hyprutils::Memory::CWeakPointer<CBackend> backend;
@ -205,10 +278,13 @@ namespace Aquamarine {
} drmProps; } drmProps;
friend class CBackend; friend class CBackend;
friend struct SDRMFB; friend class CDRMFB;
friend class CDRMFBAttachment;
friend struct SDRMConnector; friend struct SDRMConnector;
friend struct SDRMCRTC; friend struct SDRMCRTC;
friend struct SDRMPlane; friend struct SDRMPlane;
friend struct CDRMOutput; friend class CDRMOutput;
friend struct SDRMPageFlip;
friend class CDRMLegacyImpl;
}; };
}; };

View file

@ -0,0 +1,18 @@
#pragma once
#include "../DRM.hpp"
namespace Aquamarine {
class CDRMLegacyImpl : public IDRMImplementation {
public:
CDRMLegacyImpl(Hyprutils::Memory::CSharedPointer<CDRMBackend> backend_);
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data);
private:
bool commitInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data);
bool testInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data);
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
};
};

View file

@ -4,6 +4,7 @@
#include <tuple> #include <tuple>
#include <hyprutils/signal/Signal.hpp> #include <hyprutils/signal/Signal.hpp>
#include <hyprutils/math/Region.hpp> #include <hyprutils/math/Region.hpp>
#include "../misc/Attachment.hpp"
namespace Aquamarine { namespace Aquamarine {
enum eBufferCapability { enum eBufferCapability {
@ -62,6 +63,8 @@ namespace Aquamarine {
Hyprutils::Math::Vector2D size; Hyprutils::Math::Vector2D size;
bool opaque = false; bool opaque = false;
CAttachmentManager attachments;
struct { struct {
Hyprutils::Signal::CSignal destroy; Hyprutils::Signal::CSignal destroy;
} events; } events;

View file

@ -0,0 +1,32 @@
#pragma once
#include <vector>
#include <hyprutils/memory/SharedPtr.hpp>
namespace Aquamarine {
enum eAttachmentType {
AQ_ATTACHMENT_DRM_BUFFER = 0,
AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE,
};
class IAttachment {
public:
virtual ~IAttachment() {
;
}
virtual eAttachmentType type() = 0;
};
class CAttachmentManager {
public:
bool has(eAttachmentType type);
Hyprutils::Memory::CSharedPointer<IAttachment> get(eAttachmentType type);
void add(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
void remove(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
void removeByType(eAttachmentType type);
private:
std::vector<Hyprutils::Memory::CSharedPointer<IAttachment>> attachments;
};
};

View file

@ -6,6 +6,7 @@
#include <hyprutils/memory/SharedPtr.hpp> #include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/math/Region.hpp> #include <hyprutils/math/Region.hpp>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <xf86drmMode.h>
#include "../allocator/Swapchain.hpp" #include "../allocator/Swapchain.hpp"
#include "../buffer/Buffer.hpp" #include "../buffer/Buffer.hpp"
@ -14,9 +15,10 @@ namespace Aquamarine {
class IBackendImplementation; class IBackendImplementation;
struct SOutputMode { struct SOutputMode {
Hyprutils::Math::Vector2D pixelSize; Hyprutils::Math::Vector2D pixelSize;
unsigned int refreshRate = 0 /* in mHz */; unsigned int refreshRate = 0 /* in mHz */;
bool preferred = false; bool preferred = false;
std::optional<drmModeModeInfo> modeInfo; // if this is a drm mode, this will be populated.
}; };
enum eOutputPresentationMode { enum eOutputPresentationMode {
@ -83,6 +85,7 @@ namespace Aquamarine {
friend class IOutput; friend class IOutput;
friend class CWaylandOutput; friend class CWaylandOutput;
friend class CDRMOutput;
}; };
class IOutput { class IOutput {
@ -106,6 +109,8 @@ namespace Aquamarine {
bool enabled = false; bool enabled = false;
bool nonDesktop = false; bool nonDesktop = false;
eSubpixelMode subpixel = AQ_SUBPIXEL_NONE; eSubpixelMode subpixel = AQ_SUBPIXEL_NONE;
bool vrrCapable = false;
bool needsFrame = false;
// //
std::vector<Hyprutils::Memory::CSharedPointer<SOutputMode>> modes; std::vector<Hyprutils::Memory::CSharedPointer<SOutputMode>> modes;
@ -113,10 +118,25 @@ namespace Aquamarine {
Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain; Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain;
// //
enum eOutputPresentFlags : uint32_t {
AQ_OUTPUT_PRESENT_VSYNC = (1 << 0),
AQ_OUTPUT_PRESENT_HW_CLOCK = (1 << 1),
AQ_OUTPUT_PRESENT_HW_COMPLETION = (1 << 2),
AQ_OUTPUT_PRESENT_ZEROCOPY = (1 << 3),
};
struct SStateEvent { struct SStateEvent {
Hyprutils::Math::Vector2D size; Hyprutils::Math::Vector2D size;
}; };
struct SPresentEvent {
bool presented = true;
timespec* when = nullptr;
unsigned int seq = 0;
int refresh = 0;
uint32_t flags = 0;
};
struct { struct {
Hyprutils::Signal::CSignal destroy; Hyprutils::Signal::CSignal destroy;
Hyprutils::Signal::CSignal frame; Hyprutils::Signal::CSignal frame;

View file

@ -15,10 +15,38 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
attrs.size = params.size; attrs.size = params.size;
attrs.format = params.format; attrs.format = params.format;
// FIXME: proper modifier support? This might implode on some GPUs on the Wayland backend const auto FORMATS = allocator->backend->getPrimaryRenderFormats();
// for sure.
bo = gbm_bo_create(allocator->gbmDevice, params.size.x, params.size.y, params.format, GBM_BO_USE_RENDERING); std::vector<uint64_t> explicitModifiers;
// check if we can use modifiers. If the requested support has any explicit modifier
// supported by the primary backend, we can.
allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Searching for modifiers. Format len: {}", FORMATS.size()));
for (auto& f : FORMATS) {
if (f.drmFormat != params.format)
continue;
allocator->backend->log(AQ_LOG_TRACE, "GBM: Format matched");
for (auto& m : f.modifiers) {
if (m == DRM_FORMAT_MOD_LINEAR || m == DRM_FORMAT_MOD_INVALID)
continue;
explicitModifiers.push_back(m);
allocator->backend->log(AQ_LOG_TRACE, "GBM: Modifier matched");
}
}
uint32_t flags = GBM_BO_USE_RENDERING;
if (params.scanout)
flags |= GBM_BO_USE_SCANOUT;
if (explicitModifiers.empty()) {
allocator->backend->log(AQ_LOG_WARNING, "GBM: Using modifier-less allocation");
bo = gbm_bo_create(allocator->gbmDevice, params.size.x, params.size.y, params.format, flags);
} else
bo = gbm_bo_create_with_modifiers2(allocator->gbmDevice, params.size.x, params.size.y, params.format, explicitModifiers.data(), explicitModifiers.size(), flags);
if (!bo) { if (!bo) {
allocator->backend->log(AQ_LOG_ERROR, "GBM: Failed to allocate a GBM buffer: bo null"); allocator->backend->log(AQ_LOG_ERROR, "GBM: Failed to allocate a GBM buffer: bo null");

View file

@ -4,6 +4,7 @@
using namespace Aquamarine; using namespace Aquamarine;
using namespace Hyprutils::Memory; using namespace Hyprutils::Memory;
using namespace Hyprutils::Math;
#define SP CSharedPointer #define SP CSharedPointer
Aquamarine::CSwapchain::CSwapchain(SP<IAllocator> allocator_) : allocator(allocator_) { Aquamarine::CSwapchain::CSwapchain(SP<IAllocator> allocator_) : allocator(allocator_) {
@ -15,6 +16,14 @@ bool Aquamarine::CSwapchain::reconfigure(const SSwapchainOptions& options_) {
if (!allocator) if (!allocator)
return false; return false;
if (options_.size == Vector2D{} || options_.length == 0) {
// clear the swapchain
allocator->getBackend()->log(AQ_LOG_DEBUG, "Swapchain: Clearing");
buffers.clear();
options = options_;
return true;
}
if (options_.format == options.format && options_.size == options.size && options_.length == options.length) if (options_.format == options.format && options_.size == options.size && options_.length == options.length)
return true; // no need to reconfigure return true; // no need to reconfigure

View file

@ -99,7 +99,12 @@ bool Aquamarine::CBackend::start() {
} }
// erase failed impls // erase failed impls
std::erase_if(implementations, [](const auto& i) { return i->pollFD() < 0; }); std::erase_if(implementations, [this](const auto& i) {
bool failed = i->pollFD() < 0;
if (failed)
log(AQ_LOG_ERROR, std::format("Implementation {} failed, erasing.", backendTypeToName(i->type())));
return failed;
});
// TODO: obviously change this when (if) we add different allocators. // TODO: obviously change this when (if) we add different allocators.
for (auto& b : implementations) { for (auto& b : implementations) {
@ -225,6 +230,20 @@ void Aquamarine::CBackend::dispatchEventsAsync() {
} }
bool Aquamarine::CBackend::hasSession() { bool Aquamarine::CBackend::hasSession() {
// TODO: return session;
return false; }
std::vector<SDRMFormat> Aquamarine::CBackend::getPrimaryRenderFormats() {
for (auto& b : implementations) {
if (b->type() != AQ_BACKEND_DRM && b->type() != AQ_BACKEND_WAYLAND)
continue;
return b->getRenderFormats();
}
for (auto& b : implementations) {
return b->getRenderFormats();
}
return {};
} }

View file

@ -1,17 +1,21 @@
#include <aquamarine/backend/DRM.hpp> #include <aquamarine/backend/DRM.hpp>
#include <aquamarine/backend/drm/Legacy.hpp>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <deque> #include <deque>
#include <cstring> #include <cstring>
#include <sys/mman.h>
extern "C" { extern "C" {
#include <libseat.h> #include <libseat.h>
#include <libudev.h> #include <libudev.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include <libdisplay-info/cvt.h>
} }
#include "Props.hpp" #include "Props.hpp"
#include "FormatUtils.hpp"
using namespace Aquamarine; using namespace Aquamarine;
using namespace Hyprutils::Memory; using namespace Hyprutils::Memory;
@ -194,6 +198,14 @@ Aquamarine::CDRMBackend::~CDRMBackend() {
; ;
} }
void Aquamarine::CDRMBackend::log(eBackendLogLevel l, const std::string& s) {
backend->log(l, s);
}
bool Aquamarine::CDRMBackend::sessionActive() {
return backend->session->active;
}
bool Aquamarine::CDRMBackend::checkFeatures() { bool Aquamarine::CDRMBackend::checkFeatures() {
uint64_t curW = 0, curH = 0; uint64_t curW = 0, curH = 0;
if (drmGetCap(gpu->fd, DRM_CAP_CURSOR_WIDTH, &curW)) if (drmGetCap(gpu->fd, DRM_CAP_CURSOR_WIDTH, &curW))
@ -227,6 +239,11 @@ bool Aquamarine::CDRMBackend::checkFeatures() {
drmProps.supportsAsyncCommit = drmGetCap(gpu->fd, DRM_CAP_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1; drmProps.supportsAsyncCommit = drmGetCap(gpu->fd, DRM_CAP_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
drmProps.supportsAddFb2Modifiers = drmGetCap(gpu->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap) == 0 && cap == 1; drmProps.supportsAddFb2Modifiers = drmGetCap(gpu->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap) == 0 && cap == 1;
backend->log(AQ_LOG_DEBUG, std::format("drm: drmProps.supportsAsyncCommit: {}", drmProps.supportsAsyncCommit));
backend->log(AQ_LOG_DEBUG, std::format("drm: drmProps.supportsAddFb2Modifiers: {}", drmProps.supportsAddFb2Modifiers));
impl = makeShared<CDRMLegacyImpl>(self.lock());
// TODO: allow no-modifiers? // TODO: allow no-modifiers?
return true; return true;
@ -303,11 +320,14 @@ bool Aquamarine::CDRMBackend::initResources() {
return false; return false;
} }
planes.emplace_back(aqPlane);
drmModeFreePlane(plane); drmModeFreePlane(plane);
} }
drmModeFreePlaneResources(planeResources); drmModeFreePlaneResources(planeResources);
drmModeFreeResources(resources); drmModeFreeResources(resources);
return true; return true;
} }
@ -372,7 +392,9 @@ void Aquamarine::CDRMBackend::scanConnectors() {
} else } else
conn = *it; conn = *it;
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connection state:", (int)drmConn->connection)); backend->log(AQ_LOG_DEBUG, std::format("drm: Connectors size {}", connectors.size()));
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connection state: {}", connectorID, (int)drmConn->connection));
if (conn->status == DRM_MODE_DISCONNECTED && drmConn->connection == DRM_MODE_CONNECTED) { if (conn->status == DRM_MODE_DISCONNECTED && drmConn->connection == DRM_MODE_CONNECTED) {
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connected", conn->szName)); backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connected", conn->szName));
@ -389,8 +411,6 @@ void Aquamarine::CDRMBackend::scanConnectors() {
} }
bool Aquamarine::CDRMBackend::start() { bool Aquamarine::CDRMBackend::start() {
scanConnectors();
return true; return true;
} }
@ -403,7 +423,38 @@ int Aquamarine::CDRMBackend::drmFD() {
} }
static void handlePF(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, unsigned crtc_id, void* data) { static void handlePF(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, unsigned crtc_id, void* data) {
// FIXME: auto pageFlip = (SDRMPageFlip*)data;
if (!pageFlip->connector)
return;
pageFlip->connector->isPageFlipPending = false;
const auto& BACKEND = pageFlip->connector->backend;
BACKEND->log(AQ_LOG_TRACE, std::format("drm: pf event seq {} sec {} usec {} crtc {}", seq, tv_sec, tv_usec, crtc_id));
if (pageFlip->connector->status != DRM_MODE_CONNECTED || !pageFlip->connector->crtc) {
BACKEND->log(AQ_LOG_DEBUG, "drm: Ignoring a pf event from a disabled crtc / connector");
return;
}
pageFlip->connector->onPresent();
uint32_t flags = IOutput::AQ_OUTPUT_PRESENT_VSYNC | IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK | IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION | IOutput::AQ_OUTPUT_PRESENT_ZEROCOPY;
timespec presented = {.tv_sec = tv_sec, .tv_nsec = tv_usec * 1000};
pageFlip->connector->output->events.present.emit(IOutput::SPresentEvent{
.presented = BACKEND->sessionActive(),
.when = &presented,
.seq = seq,
.refresh = (int)(pageFlip->connector->refresh ? (1000000000000LL / pageFlip->connector->refresh) : 0),
.flags = flags,
});
if (BACKEND->sessionActive())
pageFlip->connector->output->events.frame.emit();
} }
bool Aquamarine::CDRMBackend::dispatchEvents() { bool Aquamarine::CDRMBackend::dispatchEvents() {
@ -415,6 +466,13 @@ bool Aquamarine::CDRMBackend::dispatchEvents() {
if (drmHandleEvent(gpu->fd, &event) != 0) if (drmHandleEvent(gpu->fd, &event) != 0)
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to handle event on fd {}", gpu->fd)); backend->log(AQ_LOG_ERROR, std::format("drm: Failed to handle event on fd {}", gpu->fd));
if (!idleCallbacks.empty()) {
for (auto& c : idleCallbacks) {
c();
}
idleCallbacks.clear();
}
return true; return true;
} }
@ -427,7 +485,22 @@ bool Aquamarine::CDRMBackend::setCursor(SP<IBuffer> buffer, const Hyprutils::Mat
} }
void Aquamarine::CDRMBackend::onReady() { void Aquamarine::CDRMBackend::onReady() {
; backend->log(AQ_LOG_DEBUG, std::format("drm: Connectors size2 {}", connectors.size()));
for (auto& c : connectors) {
backend->log(AQ_LOG_DEBUG, std::format("drm: onReady: connector {}", c->id));
if (!c->output)
continue;
backend->log(AQ_LOG_DEBUG, std::format("drm: onReady: connector {} has output name {}", c->id, c->output->name));
// swapchain has to be created here because allocator is absent in connect if not ready
c->output->swapchain = makeShared<CSwapchain>(backend->allocator);
c->output->swapchain->reconfigure(SSwapchainOptions{.length = 0, .scanout = true}); // mark the swapchain for scanout
c->output->needsFrame = true;
backend->events.newOutput.emit(SP<IOutput>(c->output));
}
} }
std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() { std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() {
@ -463,26 +536,40 @@ bool Aquamarine::SDRMPlane::init(drmModePlane* plane) {
initialID = id; initialID = id;
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Plane {} has type {}", id, (int)type));
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Plane {} has {} formats", id, plane->count_formats));
for (size_t i = 0; i < plane->count_formats; ++i) { for (size_t i = 0; i < plane->count_formats; ++i) {
if (type != DRM_PLANE_TYPE_CURSOR) if (type != DRM_PLANE_TYPE_CURSOR)
formats.emplace_back(SDRMFormat{.drmFormat = plane->formats[i], .modifiers = {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}}); formats.emplace_back(SDRMFormat{.drmFormat = plane->formats[i], .modifiers = {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}});
else else
formats.emplace_back(SDRMFormat{.drmFormat = plane->formats[i], .modifiers = {DRM_FORMAT_MOD_LINEAR}}); formats.emplace_back(SDRMFormat{.drmFormat = plane->formats[i], .modifiers = {DRM_FORMAT_MOD_LINEAR}});
backend->backend->log(AQ_LOG_TRACE, std::format("drm: | Format {}", fourccToName(plane->formats[i])));
} }
if (props.in_formats && backend->drmProps.supportsAddFb2Modifiers) { if (props.in_formats && backend->drmProps.supportsAddFb2Modifiers) {
backend->backend->log(AQ_LOG_DEBUG, "drm: Plane: checking for modifiers");
uint64_t blobID = 0; uint64_t blobID = 0;
if (!getDRMProp(backend->gpu->fd, id, props.in_formats, &blobID)) if (!getDRMProp(backend->gpu->fd, id, props.in_formats, &blobID)) {
backend->backend->log(AQ_LOG_ERROR, "drm: Plane: No blob id");
return false; return false;
}
auto blob = drmModeGetPropertyBlob(backend->gpu->fd, blobID); auto blob = drmModeGetPropertyBlob(backend->gpu->fd, blobID);
if (!blob) if (!blob) {
backend->backend->log(AQ_LOG_ERROR, "drm: Plane: No property");
return false; return false;
}
drmModeFormatModifierIterator iter = {0}; drmModeFormatModifierIterator iter = {0};
while (drmModeFormatModifierBlobIterNext(blob, &iter)) { while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
auto it = std::find_if(formats.begin(), formats.end(), [iter](const auto& e) { return e.drmFormat == iter.fmt; }); auto it = std::find_if(formats.begin(), formats.end(), [iter](const auto& e) { return e.drmFormat == iter.fmt; });
backend->backend->log(AQ_LOG_TRACE, std::format("drm: | Modifier {} with format {}", iter.mod, fourccToName(iter.fmt)));
if (it == formats.end()) if (it == formats.end())
formats.emplace_back(SDRMFormat{.drmFormat = iter.fmt, .modifiers = {iter.mod}}); formats.emplace_back(SDRMFormat{.drmFormat = iter.fmt, .modifiers = {iter.mod}});
else else
@ -543,7 +630,8 @@ SP<SDRMCRTC> Aquamarine::SDRMConnector::getCurrentCRTC(const drmModeConnector* c
} }
bool Aquamarine::SDRMConnector::init(drmModeConnector* connector) { bool Aquamarine::SDRMConnector::init(drmModeConnector* connector) {
id = connector->connector_id; id = connector->connector_id;
pendingPageFlip.connector = self.lock();
if (!getDRMConnectorProps(backend->gpu->fd, id, &props)) if (!getDRMConnectorProps(backend->gpu->fd, id, &props))
return false; return false;
@ -640,10 +728,14 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
continue; continue;
} }
if (i == 1)
fallbackModeInfo = drmMode;
auto aqMode = makeShared<SOutputMode>(); auto aqMode = makeShared<SOutputMode>();
aqMode->pixelSize = {drmMode.hdisplay, drmMode.vdisplay}; aqMode->pixelSize = {drmMode.hdisplay, drmMode.vdisplay};
aqMode->refreshRate = calculateRefresh(drmMode); aqMode->refreshRate = calculateRefresh(drmMode);
aqMode->preferred = (drmMode.type & DRM_MODE_TYPE_PREFERRED); aqMode->preferred = (drmMode.type & DRM_MODE_TYPE_PREFERRED);
aqMode->modeInfo = drmMode;
output->modes.emplace_back(aqMode); output->modes.emplace_back(aqMode);
@ -682,6 +774,9 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
output->nonDesktop = prop; output->nonDesktop = prop;
} }
canDoVrr = props.vrr_capable && crtc->props.vrr_enabled && !getDRMProp(backend->gpu->fd, id, props.vrr_capable, &prop) && prop;
output->vrrCapable = canDoVrr;
maxBpcBounds.fill(0); maxBpcBounds.fill(0);
if (props.max_bpc && !introspectDRMPropRange(backend->gpu->fd, props.max_bpc, maxBpcBounds.data(), &maxBpcBounds[1])) if (props.max_bpc && !introspectDRMPropRange(backend->gpu->fd, props.max_bpc, maxBpcBounds.data(), &maxBpcBounds[1]))
@ -702,12 +797,18 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
output->model = model; output->model = model;
output->serial = serial; output->serial = serial;
output->description = std::format("{} {} {} ({})", make, model, serial, szName); output->description = std::format("{} {} {} ({})", make, model, serial, szName);
output->needsFrame = true;
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Description {}", output->description)); backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Description {}", output->description));
status = DRM_MODE_CONNECTED; status = DRM_MODE_CONNECTED;
if (!backend->backend->ready)
return;
output->swapchain = makeShared<CSwapchain>(backend->backend->allocator);
backend->backend->events.newOutput.emit(output); backend->backend->events.newOutput.emit(output);
output->scheduleFrame();
} }
void Aquamarine::SDRMConnector::disconnect() { void Aquamarine::SDRMConnector::disconnect() {
@ -722,16 +823,162 @@ void Aquamarine::SDRMConnector::disconnect() {
status = DRM_MODE_DISCONNECTED; status = DRM_MODE_DISCONNECTED;
} }
bool Aquamarine::SDRMConnector::commitState(const SDRMConnectorCommitData& data) {
const bool ok = backend->impl->commit(self.lock(), data);
if (ok && !data.test)
applyCommit(data);
else
rollbackCommit(data);
return ok;
}
void Aquamarine::SDRMConnector::applyCommit(const SDRMConnectorCommitData& data) {
crtc->primary->back = crtc->primary->front;
crtc->primary->front = data.mainFB;
if (crtc->cursor) {
crtc->cursor->back = crtc->cursor->front;
crtc->cursor->front = data.cursorFB;
}
pendingCursorFB.reset();
if (output->state->state().committed & COutputState::AQ_OUTPUT_STATE_MODE)
refresh = calculateRefresh(data.modeInfo);
}
void Aquamarine::SDRMConnector::rollbackCommit(const SDRMConnectorCommitData& data) {
;
}
void Aquamarine::SDRMConnector::onPresent() {
;
}
Aquamarine::CDRMOutput::~CDRMOutput() { Aquamarine::CDRMOutput::~CDRMOutput() {
; ;
} }
bool Aquamarine::CDRMOutput::commit() { bool Aquamarine::CDRMOutput::commit() {
return true; return commitState();
} }
bool Aquamarine::CDRMOutput::test() { bool Aquamarine::CDRMOutput::test() {
return true; return commitState(true);
}
bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
if (!backend->backend->session->active) {
backend->backend->log(AQ_LOG_ERROR, "drm: Session inactive");
return false;
}
if (!connector->crtc) {
backend->backend->log(AQ_LOG_ERROR, "drm: No CRTC attached to output");
return false;
}
const auto& STATE = state->state();
const uint32_t COMMITTED = STATE.committed;
if ((COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_ENABLED) && STATE.enabled) {
if (!STATE.mode && STATE.customMode) {
backend->backend->log(AQ_LOG_ERROR, "drm: No mode on enable commit");
return false;
}
}
if (STATE.adaptiveSync && !connector->canDoVrr) {
backend->backend->log(AQ_LOG_ERROR, "drm: No Adaptive sync support for output");
return false;
}
if (STATE.presentationMode == AQ_OUTPUT_PRESENTATION_IMMEDIATE && !backend->drmProps.supportsAsyncCommit) {
backend->backend->log(AQ_LOG_ERROR, "drm: No Immediate presentation support in the backend");
return false;
}
if (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_BUFFER && !STATE.buffer) {
backend->backend->log(AQ_LOG_ERROR, "drm: No buffer committed");
return false;
}
// If we are changing the rendering format, we may need to reconfigure the output (aka modeset)
// which may result in some glitches
const bool NEEDS_RECONFIG = COMMITTED &
(COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_ENABLED | COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_FORMAT |
COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_MODE);
const bool BLOCKING = NEEDS_RECONFIG || !(COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_BUFFER);
const auto MODE = STATE.mode ? STATE.mode : STATE.customMode;
uint32_t flags = 0;
if (!onlyTest) {
if (NEEDS_RECONFIG) {
if (STATE.enabled)
backend->backend->log(AQ_LOG_DEBUG,
std::format("drm: Modesetting {} with {}x{}@{:.2f}Hz", name, (int)MODE->pixelSize.x, (int)MODE->pixelSize.y, MODE->refreshRate / 1000.F));
else
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Disabling output {}", name));
}
if (!BLOCKING && connector->isPageFlipPending) {
backend->backend->log(AQ_LOG_ERROR, "drm: Cannot commit when a page-flip is awaiting");
return false;
}
if (STATE.enabled)
flags |= DRM_MODE_PAGE_FLIP_EVENT;
if (STATE.presentationMode == AQ_OUTPUT_PRESENTATION_IMMEDIATE)
flags |= DRM_MODE_PAGE_FLIP_ASYNC;
}
SDRMConnectorCommitData data;
if (STATE.buffer) {
backend->backend->log(AQ_LOG_TRACE, "drm: Committed a buffer, updating state");
SP<CDRMFB> drmFB;
auto buf = STATE.buffer;
// try to find the buffer in its layer
if (connector->crtc->primary->back && connector->crtc->primary->back->buffer == buf) {
backend->backend->log(AQ_LOG_TRACE, "drm: CRTC's back buffer matches committed :D");
drmFB = connector->crtc->primary->back;
} else if (connector->crtc->primary->front && connector->crtc->primary->front->buffer == buf) {
backend->backend->log(AQ_LOG_TRACE, "drm: CRTC's front buffer matches committed");
drmFB = connector->crtc->primary->front;
}
if (!drmFB)
drmFB = CDRMFB::create(buf, backend);
if (!drmFB) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer failed to import to KMS");
return false;
}
data.mainFB = drmFB;
}
data.blocking = BLOCKING;
data.modeset = NEEDS_RECONFIG;
data.flags = flags;
data.test = onlyTest;
if (MODE->modeInfo.has_value())
data.modeInfo = *MODE->modeInfo;
else
data.calculateMode(connector);
bool ok = connector->commitState(data);
events.commit.emit();
state->onCommit();
return ok;
} }
SP<IBackendImplementation> Aquamarine::CDRMOutput::getBackend() { SP<IBackendImplementation> Aquamarine::CDRMOutput::getBackend() {
@ -747,14 +994,175 @@ void Aquamarine::CDRMOutput::moveCursor(const Vector2D& coord) {
} }
void Aquamarine::CDRMOutput::scheduleFrame() { void Aquamarine::CDRMOutput::scheduleFrame() {
; if (connector->isPageFlipPending)
return;
backend->idleCallbacks.emplace_back([this]() { events.frame.emit(); });
} }
Vector2D Aquamarine::CDRMOutput::maxCursorSize() { Vector2D Aquamarine::CDRMOutput::maxCursorSize() {
return backend->drmProps.cursorSize; return backend->drmProps.cursorSize;
} }
Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_) : Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, SP<SDRMConnector> connector_) :
backend(backend_), connector(connector_) { backend(backend_), connector(connector_) {
name = name_; name = name_;
} }
SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_) {
auto fb = SP<CDRMFB>(new CDRMFB(buffer_, backend_));
if (!fb->id)
return nullptr;
return fb;
}
Aquamarine::CDRMFB::CDRMFB(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_) : buffer(buffer_), backend(backend_) {
auto attrs = buffer->dmabuf();
if (!attrs.success) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer submitted has no dmabuf");
return;
}
if (buffer->attachments.has(AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE)) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer submitted is unimportable");
return;
}
// TODO: check format
for (int i = 0; i < attrs.planes; ++i) {
int ret = drmPrimeFDToHandle(backend->gpu->fd, attrs.fds.at(i), &boHandles.at(i));
if (ret) {
backend->backend->log(AQ_LOG_ERROR, "drm: drmPrimeFDToHandle failed");
drop();
return;
}
backend->backend->log(AQ_LOG_TRACE, std::format("drm: CDRMFB: plane {} has fd {}, got handle {}", i, attrs.fds.at(i), boHandles.at(i)));
}
id = submitBuffer();
if (!id) {
backend->backend->log(AQ_LOG_ERROR, "drm: Failed to submit a buffer to KMS");
buffer->attachments.add(makeShared<CDRMBufferUnimportable>());
drop();
return;
}
backend->backend->log(AQ_LOG_TRACE, std::format("drm: new buffer {}", id));
// FIXME: wlroots does this, I am unsure why, but if I do, the gpu driver will kill us.
// closeHandles();
}
Aquamarine::CDRMFB::~CDRMFB() {
drop();
}
void Aquamarine::CDRMFB::closeHandles() {
if (handlesClosed)
return;
handlesClosed = true;
for (auto& h : boHandles) {
if (h == 0)
continue;
if (drmCloseBufferHandle(backend->gpu->fd, h))
backend->backend->log(AQ_LOG_ERROR, "drm: drmCloseBufferHandle failed");
h = 0;
}
}
void Aquamarine::CDRMFB::drop() {
if (dropped)
return;
dropped = true;
if (!id)
return;
backend->backend->log(AQ_LOG_TRACE, std::format("drm: dropping buffer {}", id));
int ret = drmModeCloseFB(backend->gpu->fd, id);
if (ret == -EINVAL)
ret = drmModeRmFB(backend->gpu->fd, id);
if (ret)
backend->backend->log(AQ_LOG_ERROR, std::format("drm: Failed to close a buffer: {}", strerror(-ret)));
}
uint32_t Aquamarine::CDRMFB::submitBuffer() {
auto attrs = buffer->dmabuf();
uint32_t newID = 0;
std::array<uint64_t, 4> mods = {0};
for (size_t i = 0; i < attrs.planes; ++i) {
mods.at(i) = attrs.modifier;
}
if (backend->drmProps.supportsAddFb2Modifiers && attrs.modifier != DRM_FORMAT_MOD_INVALID) {
backend->backend->log(AQ_LOG_TRACE,
std::format("drm: Using drmModeAddFB2WithModifiers to import buffer into KMS: Size {} with format {} and mod {}", attrs.size,
fourccToName(attrs.format), attrs.modifier));
if (drmModeAddFB2WithModifiers(backend->gpu->fd, attrs.size.x, attrs.size.y, attrs.format, boHandles.data(), attrs.strides.data(), attrs.offsets.data(), mods.data(),
&newID, DRM_MODE_FB_MODIFIERS)) {
backend->backend->log(AQ_LOG_ERROR, "drm: Failed to submit a buffer with AddFB2");
return 0;
}
} else {
if (attrs.modifier != DRM_FORMAT_MOD_INVALID && attrs.modifier != DRM_FORMAT_MOD_LINEAR) {
backend->backend->log(AQ_LOG_ERROR, "drm: drmModeAddFB2WithModifiers unsupported and buffer has explicit modifiers");
return 0;
}
backend->backend->log(
AQ_LOG_TRACE,
std::format("drm: Using drmModeAddFB2 to import buffer into KMS: Size {} with format {} and mod {}", attrs.size, fourccToName(attrs.format), attrs.modifier));
if (drmModeAddFB2(backend->gpu->fd, attrs.size.x, attrs.size.y, attrs.format, boHandles.data(), attrs.strides.data(), attrs.offsets.data(), &newID, 0)) {
backend->backend->log(AQ_LOG_ERROR, "drm: drmModeAddFB2 failed");
return 0;
}
}
return newID;
}
void Aquamarine::SDRMConnectorCommitData::calculateMode(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector) {
const auto& STATE = connector->output->state->state();
const auto MODE = STATE.mode ? STATE.mode : STATE.customMode;
di_cvt_options options = {
.red_blank_ver = DI_CVT_REDUCED_BLANKING_NONE,
.h_pixels = (int)MODE->pixelSize.x,
.v_lines = (int)MODE->pixelSize.y,
.ip_freq_rqd = MODE->refreshRate ? MODE->refreshRate / 1000.0 : 60.0,
};
di_cvt_timing timing;
di_cvt_compute(&timing, &options);
uint16_t hsync_start = (int)MODE->pixelSize.y + timing.h_front_porch;
uint16_t vsync_start = timing.v_lines_rnd + timing.v_front_porch;
uint16_t hsync_end = hsync_start + timing.h_sync;
uint16_t vsync_end = vsync_start + timing.v_sync;
modeInfo = (drmModeModeInfo){
.clock = (uint32_t)std::round(timing.act_pixel_freq * 1000),
.hdisplay = (uint16_t)MODE->pixelSize.y,
.hsync_start = hsync_start,
.hsync_end = hsync_end,
.htotal = (uint16_t)(hsync_end + timing.h_back_porch),
.vdisplay = (uint16_t)timing.v_lines_rnd,
.vsync_start = vsync_start,
.vsync_end = vsync_end,
.vtotal = (uint16_t)(vsync_end + timing.v_back_porch),
.vrefresh = (uint32_t)std::round(timing.act_frame_rate),
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
};
snprintf(modeInfo.name, sizeof(modeInfo.name), "%dx%d", (int)MODE->pixelSize.x, (int)MODE->pixelSize.y);
}

View file

@ -0,0 +1,88 @@
#include <aquamarine/backend/drm/Legacy.hpp>
#include <cstring>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <sys/mman.h>
using namespace Aquamarine;
using namespace Hyprutils::Memory;
using namespace Hyprutils::Math;
#define SP CSharedPointer
Aquamarine::CDRMLegacyImpl::CDRMLegacyImpl(Hyprutils::Memory::CSharedPointer<CDRMBackend> backend_) : backend(backend_) {
;
}
bool Aquamarine::CDRMLegacyImpl::commitInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data) {
const auto& STATE = connector->output->state->state();
SP<CDRMFB> mainFB;
bool enable = STATE.enabled;
if (enable) {
if (!data.mainFB)
connector->backend->backend->log(AQ_LOG_WARNING, "legacy drm: No buffer, will fall back to only modeset (if present)");
else
mainFB = data.mainFB;
}
if (data.modeset) {
connector->backend->backend->log(AQ_LOG_DEBUG, std::format("legacy drm: Modesetting CRTC {}", connector->crtc->id));
uint32_t dpms = enable ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF;
if (drmModeConnectorSetProperty(connector->backend->gpu->fd, connector->id, connector->props.dpms, dpms)) {
connector->backend->backend->log(AQ_LOG_ERROR, "legacy drm: Failed to set dpms");
return false;
}
std::vector<uint32_t> connectors;
drmModeModeInfo* mode = nullptr;
if (enable) {
connectors.push_back(connector->id);
mode = (drmModeModeInfo*)&data.modeInfo;
}
connector->backend->backend->log(AQ_LOG_DEBUG, std::format("legacy drm: Modesetting CRTC, connectors: {}", connectors.size()));
connector->backend->backend->log(
AQ_LOG_DEBUG,
std::format("legacy drm: Modesetting CRTC, mode: clock {} hdisplay {} vdisplay {} vrefresh {}", mode->clock, mode->hdisplay, mode->vdisplay, mode->vrefresh));
if (auto ret = drmModeSetCrtc(connector->backend->gpu->fd, connector->crtc->id, mainFB ? mainFB->id : -1, 0, 0, connectors.data(), connectors.size(), mode); ret) {
connector->backend->backend->log(AQ_LOG_ERROR, std::format("legacy drm: drmModeSetCrtc failed: {}", strerror(-ret)));
return false;
}
}
// TODO: gamma
// TODO: Adaptive sync
// TODO: cursor plane
if (drmModeSetCursor(connector->backend->gpu->fd, connector->crtc->id, 0, 0, 0))
connector->backend->backend->log(AQ_LOG_ERROR, "legacy drm: cursor null failed");
if (!enable)
return true;
if (!(data.flags & DRM_MODE_PAGE_FLIP_EVENT))
return true;
if (int ret = drmModePageFlip(connector->backend->gpu->fd, connector->crtc->id, mainFB ? mainFB->id : -1, data.flags, &connector->pendingPageFlip); ret) {
connector->backend->backend->log(AQ_LOG_ERROR, std::format("legacy drm: drmModePageFlip failed: {}", strerror(-ret)));
return false;
}
connector->isPageFlipPending = true;
return true;
}
bool Aquamarine::CDRMLegacyImpl::testInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data) {
return true; // TODO: lol
}
bool Aquamarine::CDRMLegacyImpl::commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data) {
if (!testInternal(connector, data))
return false;
return commitInternal(connector, data);
}

33
src/misc/Attachment.cpp Normal file
View file

@ -0,0 +1,33 @@
#include <aquamarine/misc/Attachment.hpp>
using namespace Aquamarine;
using namespace Hyprutils::Memory;
#define SP CSharedPointer
bool Aquamarine::CAttachmentManager::has(eAttachmentType type) {
for (auto& a : attachments) {
if (a->type() == type)
return true;
}
return false;
}
SP<IAttachment> Aquamarine::CAttachmentManager::get(eAttachmentType type) {
for (auto& a : attachments) {
if (a->type() == type)
return a;
}
return nullptr;
}
void Aquamarine::CAttachmentManager::add(SP<IAttachment> attachment) {
attachments.emplace_back(attachment);
}
void Aquamarine::CAttachmentManager::remove(SP<IAttachment> attachment) {
std::erase(attachments, attachment);
}
void Aquamarine::CAttachmentManager::removeByType(eAttachmentType type) {
std::erase_if(attachments, [type](const auto& e) { return e->type() == type; });
}