drm: Implement hardware cursors

This commit is contained in:
Vaxry 2024-06-26 19:26:38 +02:00
parent 0027280d27
commit 41b1b28ce1
16 changed files with 236 additions and 77 deletions

View file

@ -6,16 +6,17 @@
namespace Aquamarine {
class CBackend;
class CSwapchain;
struct SAllocatorBufferParams {
Hyprutils::Math::Vector2D size;
uint32_t format = DRM_FORMAT_INVALID;
bool scanout = false;
bool scanout = false, cursor = false;
};
class IAllocator {
public:
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params) = 0;
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain) = 0;
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
};
};

View file

@ -8,6 +8,7 @@ struct gbm_bo;
namespace Aquamarine {
class CGBMAllocator;
class CBackend;
class CSwapchain;
class CGBMBuffer : public IBuffer {
public:
@ -21,7 +22,7 @@ namespace Aquamarine {
virtual SDMABUFAttrs dmabuf();
private:
CGBMBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator_);
CGBMBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator_, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain);
Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator;
@ -36,8 +37,8 @@ namespace Aquamarine {
public:
static Hyprutils::Memory::CSharedPointer<CGBMAllocator> create(int drmfd_, Hyprutils::Memory::CWeakPointer<CBackend> backend_);
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params);
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain_);
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
//
Hyprutils::Memory::CWeakPointer<CGBMAllocator> self;

View file

@ -4,31 +4,40 @@
namespace Aquamarine {
class IBackendImplementation;
struct SSwapchainOptions {
size_t length = 0;
Hyprutils::Math::Vector2D size;
uint32_t format = DRM_FORMAT_INVALID;
bool scanout = false;
bool scanout = false, cursor = false /* requires scanout = true */;
};
class CSwapchain {
public:
CSwapchain(Hyprutils::Memory::CSharedPointer<IAllocator> allocator_);
static Hyprutils::Memory::CSharedPointer<CSwapchain> create(Hyprutils::Memory::CSharedPointer<IAllocator> allocator_,
Hyprutils::Memory::CSharedPointer<IBackendImplementation> backendImpl_);
bool reconfigure(const SSwapchainOptions& options_);
bool reconfigure(const SSwapchainOptions& options_);
bool contains(Hyprutils::Memory::CSharedPointer<IBuffer> buffer);
Hyprutils::Memory::CSharedPointer<IBuffer> next(int* age);
const SSwapchainOptions& currentOptions();
bool contains(Hyprutils::Memory::CSharedPointer<IBuffer> buffer);
Hyprutils::Memory::CSharedPointer<IBuffer> next(int* age);
const SSwapchainOptions& currentOptions();
private:
CSwapchain(Hyprutils::Memory::CSharedPointer<IAllocator> allocator_, Hyprutils::Memory::CSharedPointer<IBackendImplementation> backendImpl_);
bool fullReconfigure(const SSwapchainOptions& options_);
bool resize(size_t newSize);
//
Hyprutils::Memory::CWeakPointer<CSwapchain> self;
SSwapchainOptions options;
Hyprutils::Memory::CSharedPointer<IAllocator> allocator;
Hyprutils::Memory::CWeakPointer<IBackendImplementation> backendImpl;
std::vector<Hyprutils::Memory::CSharedPointer<IBuffer>> buffers;
int lastAcquired = 0;
friend class CGBMBuffer;
};
};

View file

@ -15,6 +15,19 @@ namespace Aquamarine {
typedef std::function<void(void)> FIdleCallback;
class CDRMBufferAttachment : public IAttachment {
public:
CDRMBufferAttachment(Hyprutils::Memory::CSharedPointer<CDRMFB> fb_);
virtual ~CDRMBufferAttachment() {
;
}
virtual eAttachmentType type() {
return AQ_ATTACHMENT_DRM_BUFFER;
}
Hyprutils::Memory::CSharedPointer<CDRMFB> fb;
};
class CDRMBufferUnimportable : public IAttachment {
public:
CDRMBufferUnimportable() {
@ -39,16 +52,15 @@ namespace Aquamarine {
void drop();
uint32_t id = 0;
Hyprutils::Memory::CSharedPointer<IBuffer> buffer;
Hyprutils::Memory::CWeakPointer<IBuffer> buffer;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
std::array<uint32_t, 4> boHandles = {0, 0, 0, 0};
private:
CDRMFB(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_);
uint32_t submitBuffer();
uint32_t submitBuffer();
bool dropped = false, handlesClosed = false;
std::array<uint32_t, 4> boHandles = {0};
bool dropped = false, handlesClosed = false;
};
struct SDRMLayer {
@ -109,6 +121,7 @@ namespace Aquamarine {
Hyprutils::Memory::CSharedPointer<SDRMPlane> primary;
Hyprutils::Memory::CSharedPointer<SDRMPlane> cursor;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
Hyprutils::Memory::CSharedPointer<CDRMFB> pendingCursor;
union UDRMCRTCProps {
struct {
@ -136,9 +149,13 @@ namespace Aquamarine {
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord);
virtual void scheduleFrame();
virtual Hyprutils::Math::Vector2D maxCursorSize();
virtual void setCursorVisible(bool visible);
virtual Hyprutils::Math::Vector2D cursorPlaneSize();
Hyprutils::Memory::CWeakPointer<CDRMOutput> self;
bool cursorVisible = true;
Hyprutils::Math::Vector2D cursorPos; // without hotspot
Hyprutils::Math::Vector2D cursorHotspot;
private:
CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_);
@ -228,6 +245,9 @@ namespace Aquamarine {
public:
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data) = 0;
virtual bool reset(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector) = 0;
// moving a cursor IIRC is almost instant on most hardware so we don't have to wait for a commit.
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector) = 0;
};
class CDRMBackend : public IBackendImplementation {

View file

@ -47,7 +47,7 @@ namespace Aquamarine {
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord);
virtual void scheduleFrame();
virtual Hyprutils::Math::Vector2D maxCursorSize();
virtual Hyprutils::Math::Vector2D cursorPlaneSize();
Hyprutils::Memory::CWeakPointer<CWaylandOutput> self;

View file

@ -8,6 +8,7 @@ namespace Aquamarine {
CDRMLegacyImpl(Hyprutils::Memory::CSharedPointer<CDRMBackend> backend_);
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data);
virtual bool reset(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);
private:

View file

@ -43,7 +43,7 @@ namespace Aquamarine {
class IBuffer {
public:
virtual ~IBuffer() {
;
attachments.clear();
};
virtual eBufferCapability caps() = 0;

View file

@ -25,6 +25,7 @@ namespace Aquamarine {
void add(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
void remove(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
void removeByType(eAttachmentType type);
void clear();
private:
std::vector<Hyprutils::Memory::CSharedPointer<IAttachment>> attachments;

View file

@ -100,7 +100,8 @@ namespace Aquamarine {
virtual Hyprutils::Memory::CSharedPointer<SOutputMode> preferredMode();
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord); // includes the hotspot
virtual Hyprutils::Math::Vector2D maxCursorSize(); // -1, -1 means no limit, 0, 0 means error
virtual void setCursorVisible(bool visible); // moving the cursor will make it visible again without this util
virtual Hyprutils::Math::Vector2D cursorPlaneSize(); // -1, -1 means no set size, 0, 0 means error
virtual void scheduleFrame();
virtual size_t getGammaSize();

View file

@ -1,5 +1,6 @@
#include <aquamarine/allocator/GBM.hpp>
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/allocator/Swapchain.hpp>
#include "FormatUtils.hpp"
#include <xf86drm.h>
#include <gbm.h>
@ -8,36 +9,45 @@ using namespace Aquamarine;
using namespace Hyprutils::Memory;
#define SP CSharedPointer
Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator_) : allocator(allocator_) {
Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator_,
Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain) :
allocator(allocator_) {
if (!allocator)
return;
attrs.size = params.size;
attrs.format = params.format;
size = attrs.size;
const auto FORMATS = allocator->backend->getPrimaryRenderFormats();
const bool CURSOR = params.cursor && params.scanout;
if (CURSOR)
allocator->backend->log(AQ_LOG_WARNING, "GBM: Allocating a cursor buffer");
const auto FORMATS = CURSOR ? swapchain->backendImpl->getCursorFormats() : swapchain->backendImpl->getRenderFormats();
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");
}
}
if (explicitModifiers.empty()) {
// fall back to using a linear buffer.
// FIXME: Nvidia cannot render to linear buffers.
explicitModifiers.push_back(DRM_FORMAT_MOD_LINEAR);
}
uint32_t flags = GBM_BO_USE_RENDERING;
if (params.scanout)
flags |= GBM_BO_USE_SCANOUT;
@ -46,7 +56,7 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
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);
bo = gbm_bo_create_with_modifiers(allocator->gbmDevice, params.size.x, params.size.y, params.format, explicitModifiers.data(), explicitModifiers.size());
if (!bo) {
allocator->backend->log(AQ_LOG_ERROR, "GBM: Failed to allocate a GBM buffer: bo null");
@ -147,7 +157,7 @@ Aquamarine::CGBMAllocator::CGBMAllocator(int fd_, Hyprutils::Memory::CWeakPointe
free(drmName_);
}
SP<IBuffer> Aquamarine::CGBMAllocator::acquire(const SAllocatorBufferParams& params) {
SP<IBuffer> Aquamarine::CGBMAllocator::acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain_) {
if (params.size.x < 1 || params.size.y < 1) {
backend->log(AQ_LOG_ERROR, std::format("Couldn't allocate a gbm buffer with invalid size {}", params.size));
return nullptr;
@ -158,7 +168,7 @@ SP<IBuffer> Aquamarine::CGBMAllocator::acquire(const SAllocatorBufferParams& par
return nullptr;
}
auto newBuffer = SP<CGBMBuffer>(new CGBMBuffer(params, self));
auto newBuffer = SP<CGBMBuffer>(new CGBMBuffer(params, self, swapchain_));
if (!newBuffer->good()) {
backend->log(AQ_LOG_ERROR, std::format("Couldn't allocate a gbm buffer with size {} and format {}", params.size, fourccToName(params.format)));

View file

@ -7,8 +7,14 @@ using namespace Hyprutils::Memory;
using namespace Hyprutils::Math;
#define SP CSharedPointer
Aquamarine::CSwapchain::CSwapchain(SP<IAllocator> allocator_) : allocator(allocator_) {
if (!allocator)
SP<CSwapchain> Aquamarine::CSwapchain::create(SP<IAllocator> allocator_, SP<IBackendImplementation> backendImpl_) {
auto p = SP<CSwapchain>(new CSwapchain(allocator_, backendImpl_));
p->self = p;
return p;
}
Aquamarine::CSwapchain::CSwapchain(SP<IAllocator> allocator_, SP<IBackendImplementation> backendImpl_) : allocator(allocator_), backendImpl(backendImpl_) {
if (!allocator || !backendImpl)
return;
}
@ -64,7 +70,8 @@ SP<IBuffer> Aquamarine::CSwapchain::next(int* age) {
bool Aquamarine::CSwapchain::fullReconfigure(const SSwapchainOptions& options_) {
buffers.clear();
for (size_t i = 0; i < options_.length; ++i) {
auto buf = allocator->acquire(SAllocatorBufferParams{.size = options_.size, .format = options_.format});
auto buf =
allocator->acquire(SAllocatorBufferParams{.size = options_.size, .format = options_.format, .scanout = options_.scanout, .cursor = options_.cursor}, self.lock());
if (!buf) {
allocator->getBackend()->log(AQ_LOG_ERROR, "Swapchain: Failed acquiring a buffer");
return false;
@ -85,7 +92,8 @@ bool Aquamarine::CSwapchain::resize(size_t newSize) {
}
} else {
while (buffers.size() < newSize) {
auto buf = allocator->acquire(SAllocatorBufferParams{.size = options.size, .format = options.format});
auto buf =
allocator->acquire(SAllocatorBufferParams{.size = options.size, .format = options.format, .scanout = options.scanout, .cursor = options.cursor}, self.lock());
if (!buf) {
allocator->getBackend()->log(AQ_LOG_ERROR, "Swapchain: Failed acquiring a buffer");
return false;

View file

@ -184,7 +184,7 @@ bool Aquamarine::CWaylandBackend::setCursor(Hyprutils::Memory::CSharedPointer<IB
void Aquamarine::CWaylandBackend::onReady() {
for (auto& o : outputs) {
o->swapchain = makeShared<CSwapchain>(backend->allocator);
o->swapchain = CSwapchain::create(backend->allocator, self.lock());
if (!o->swapchain) {
backend->log(AQ_LOG_ERROR, std::format("Output {} failed: swapchain creation failed", o->name));
continue;
@ -703,7 +703,7 @@ void Aquamarine::CWaylandOutput::onEnter(SP<CCWlPointer> pointer, uint32_t seria
pointer->sendSetCursor(serial, cursorState.cursorSurface.get(), cursorState.hotspot.x, cursorState.hotspot.y);
}
Hyprutils::Math::Vector2D Aquamarine::CWaylandOutput::maxCursorSize() {
Hyprutils::Math::Vector2D Aquamarine::CWaylandOutput::cursorPlaneSize() {
return {-1, -1}; // no limit
}

View file

@ -525,12 +525,16 @@ bool Aquamarine::CDRMBackend::dispatchEvents() {
.page_flip_handler2 = ::handlePF,
};
// we will call this asynchronously and not only when drm fd polls, so we
// ignore the errors (from e.g. a partial read)
// TODO: is this ok?
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();
if (c)
c();
}
idleCallbacks.clear();
}
@ -557,7 +561,7 @@ void Aquamarine::CDRMBackend::onReady() {
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 = CSwapchain::create(backend->allocator, self.lock());
c->output->swapchain->reconfigure(SSwapchainOptions{.length = 0, .scanout = true}); // mark the swapchain for scanout
c->output->needsFrame = true;
@ -868,7 +872,7 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
if (!backend->backend->ready)
return;
output->swapchain = makeShared<CSwapchain>(backend->backend->allocator);
output->swapchain = CSwapchain::create(backend->backend->allocator, backend->self.lock());
backend->backend->events.newOutput.emit(output);
output->scheduleFrame();
}
@ -898,7 +902,7 @@ bool Aquamarine::SDRMConnector::commitState(const SDRMConnectorCommitData& data)
void Aquamarine::SDRMConnector::applyCommit(const SDRMConnectorCommitData& data) {
crtc->primary->back = data.mainFB;
if (crtc->cursor)
if (crtc->cursor && data.cursorFB)
crtc->cursor->back = data.cursorFB;
pendingCursorFB.reset();
@ -908,13 +912,17 @@ void Aquamarine::SDRMConnector::applyCommit(const SDRMConnectorCommitData& data)
}
void Aquamarine::SDRMConnector::rollbackCommit(const SDRMConnectorCommitData& data) {
;
// cursors are applied regardless.
if (crtc->cursor && data.cursorFB)
crtc->cursor->back = data.cursorFB;
crtc->pendingCursor.reset();
}
void Aquamarine::SDRMConnector::onPresent() {
crtc->primary->last = crtc->primary->front;
crtc->primary->front = crtc->primary->back;
if (crtc->cursor) {
if (crtc->cursor && crtc->cursor->back /* Don't shift if it hasn't updated */) {
crtc->cursor->last = crtc->cursor->front;
crtc->cursor->front = crtc->cursor->back;
}
@ -932,6 +940,12 @@ bool Aquamarine::CDRMOutput::test() {
return commitState(true);
}
void Aquamarine::CDRMOutput::setCursorVisible(bool visible) {
cursorVisible = visible;
needsFrame = true;
scheduleFrame();
}
bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
if (!backend->backend->session->active) {
backend->backend->log(AQ_LOG_ERROR, "drm: Session inactive");
@ -994,9 +1008,9 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
return false;
}
if (STATE.enabled)
if (STATE.enabled && (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_BUFFER))
flags |= DRM_MODE_PAGE_FLIP_EVENT;
if (STATE.presentationMode == AQ_OUTPUT_PRESENTATION_IMMEDIATE)
if (STATE.presentationMode == AQ_OUTPUT_PRESENTATION_IMMEDIATE && (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_BUFFER))
flags |= DRM_MODE_PAGE_FLIP_ASYNC;
}
@ -1007,20 +1021,8 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
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");
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;
} else if (connector->crtc->primary->last && connector->crtc->primary->last->buffer == buf) {
backend->backend->log(AQ_LOG_TRACE, "drm: CRTC's last buffer matches committed :D"); // best case scenario and what is expected
drmFB = connector->crtc->primary->last;
}
if (!drmFB)
drmFB = CDRMFB::create(buf, backend);
drmFB = CDRMFB::create(buf, backend); // will return attachment if present
if (!drmFB) {
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer failed to import to KMS");
@ -1030,6 +1032,9 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
data.mainFB = drmFB;
}
if (connector->crtc->pendingCursor)
data.cursorFB = connector->crtc->pendingCursor;
data.blocking = BLOCKING;
data.modeset = NEEDS_RECONFIG;
data.flags = flags;
@ -1053,11 +1058,29 @@ SP<IBackendImplementation> Aquamarine::CDRMOutput::getBackend() {
}
bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotspot) {
return false; // FIXME:
if (!buffer)
setCursorVisible(false);
else {
cursorHotspot = hotspot;
auto fb = CDRMFB::create(buffer, backend);
if (!fb) {
backend->backend->log(AQ_LOG_ERROR, "drm: Cursor buffer failed to import to KMS");
return false;
}
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Cursor buffer imported into KMS with id {}", fb->id));
connector->crtc->pendingCursor = fb;
}
needsFrame = true;
scheduleFrame();
return true;
}
void Aquamarine::CDRMOutput::moveCursor(const Vector2D& coord) {
; // FIXME:
cursorPos = coord;
backend->impl->moveCursor(connector);
}
void Aquamarine::CDRMOutput::scheduleFrame() {
@ -1067,7 +1090,7 @@ void Aquamarine::CDRMOutput::scheduleFrame() {
backend->idleCallbacks.emplace_back([this]() { events.frame.emit(); });
}
Vector2D Aquamarine::CDRMOutput::maxCursorSize() {
Vector2D Aquamarine::CDRMOutput::cursorPlaneSize() {
return backend->drmProps.cursorSize;
}
@ -1077,11 +1100,25 @@ Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::
}
SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_) {
auto fb = SP<CDRMFB>(new CDRMFB(buffer_, backend_));
SP<CDRMFB> fb;
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)
return fb;
fb = SP<CDRMFB>(new CDRMFB(buffer_, backend_));
if (!fb->id)
return nullptr;
buffer_->attachments.add(makeShared<CDRMBufferAttachment>(fb));
return fb;
}
@ -1100,7 +1137,7 @@ Aquamarine::CDRMFB::CDRMFB(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<
// TODO: check format
for (int i = 0; i < attrs.planes; ++i) {
int ret = drmPrimeFDToHandle(backend->gpu->fd, attrs.fds.at(i), &boHandles.at(i));
int ret = drmPrimeFDToHandle(backend->gpu->fd, attrs.fds.at(i), &boHandles[i]);
if (ret) {
backend->backend->log(AQ_LOG_ERROR, "drm: drmPrimeFDToHandle failed");
drop();
@ -1120,7 +1157,7 @@ Aquamarine::CDRMFB::CDRMFB(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<
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.
// FIXME: why does this implode when it doesnt on wlroots or kwin?
// closeHandles();
}
@ -1134,13 +1171,24 @@ void Aquamarine::CDRMFB::closeHandles() {
handlesClosed = true;
for (auto& h : boHandles) {
if (h == 0)
std::vector<uint32_t> closed;
for (size_t i = 0; i < 4; ++i) {
if (boHandles.at(i) == 0)
continue;
if (drmCloseBufferHandle(backend->gpu->fd, h))
bool exists = false;
for (size_t j = 0; j < i; ++j) {
if (boHandles.at(i) == boHandles.at(j)) {
exists = true;
break;
}
}
if (exists)
continue;
if (drmCloseBufferHandle(backend->gpu->fd, boHandles.at(i)))
backend->backend->log(AQ_LOG_ERROR, "drm: drmCloseBufferHandle failed");
h = 0;
}
}
@ -1166,9 +1214,9 @@ void Aquamarine::CDRMFB::drop() {
uint32_t Aquamarine::CDRMFB::submitBuffer() {
auto attrs = buffer->dmabuf();
uint32_t newID = 0;
std::array<uint64_t, 4> mods = {0};
std::array<uint64_t, 4> mods = {0, 0, 0, 0};
for (size_t i = 0; i < attrs.planes; ++i) {
mods.at(i) = attrs.modifier;
mods[i] = attrs.modifier;
}
if (backend->drmProps.supportsAddFb2Modifiers && attrs.modifier != DRM_FORMAT_MOD_INVALID) {
@ -1177,7 +1225,7 @@ uint32_t Aquamarine::CDRMFB::submitBuffer() {
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");
backend->backend->log(AQ_LOG_ERROR, "drm: Failed to submit a buffer with drmModeAddFB2WithModifiers");
return 0;
}
} else {
@ -1191,7 +1239,7 @@ uint32_t Aquamarine::CDRMFB::submitBuffer() {
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");
backend->backend->log(AQ_LOG_ERROR, "drm: Failed to submit a buffer with drmModeAddFB2");
return 0;
}
}
@ -1233,3 +1281,7 @@ void Aquamarine::SDRMConnectorCommitData::calculateMode(Hyprutils::Memory::CShar
};
snprintf(modeInfo.name, sizeof(modeInfo.name), "%dx%d", (int)MODE->pixelSize.x, (int)MODE->pixelSize.y);
}
Aquamarine::CDRMBufferAttachment::CDRMBufferAttachment(SP<CDRMFB> fb_) : fb(fb_) {
;
}

View file

@ -13,6 +13,18 @@ Aquamarine::CDRMLegacyImpl::CDRMLegacyImpl(Hyprutils::Memory::CSharedPointer<CDR
;
}
bool Aquamarine::CDRMLegacyImpl::moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector) {
Vector2D cursorPos = connector->output->cursorPos;
if (int ret2 = drmModeMoveCursor(connector->backend->gpu->fd, connector->crtc->id, cursorPos.x, cursorPos.y)) {
connector->backend->backend->log(AQ_LOG_ERROR, std::format("legacy drm: drmModeMoveCursor failed: {}", strerror(-ret2)));
return false;
}
connector->backend->backend->log(AQ_LOG_DEBUG, "legacy drm: cursor move");
return true;
}
bool Aquamarine::CDRMLegacyImpl::commitInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, const SDRMConnectorCommitData& data) {
const auto& STATE = connector->output->state->state();
SP<CDRMFB> mainFB;
@ -69,13 +81,48 @@ bool Aquamarine::CDRMLegacyImpl::commitInternal(Hyprutils::Memory::CSharedPointe
}
connector->output->vrrActive = STATE.adaptiveSync;
connector->backend->backend->log(AQ_LOG_ERROR, std::format("legacy drm: connector {} vrr -> {}", connector->id, STATE.adaptiveSync));
connector->backend->backend->log(AQ_LOG_DEBUG, std::format("legacy drm: connector {} vrr -> {}", connector->id, STATE.adaptiveSync));
}
// TODO: gamma
// TODO: cursor plane
if (drmModeSetCursor(connector->backend->gpu->fd, connector->crtc->id, 0, 0, 0))
if (data.cursorFB && connector->crtc->cursor && connector->output->cursorVisible && enable) {
uint32_t boHandle = 0;
auto attrs = data.cursorFB->buffer->dmabuf();
if (int ret = drmPrimeFDToHandle(connector->backend->gpu->fd, attrs.fds.at(0), &boHandle); ret) {
connector->backend->backend->log(AQ_LOG_ERROR, std::format("legacy drm: drmPrimeFDToHandle failed: {}", strerror(-ret)));
return false;
}
connector->backend->backend->log(AQ_LOG_DEBUG,
std::format("legacy drm: cursor fb: {} with bo handle {} from fd {}, size {}", connector->backend->gpu->fd, boHandle,
data.cursorFB->buffer->dmabuf().fds.at(0), data.cursorFB->buffer->size));
Vector2D cursorPos = connector->output->cursorPos;
struct drm_mode_cursor2 request = {
.flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE,
.crtc_id = connector->crtc->id,
.x = (int32_t)cursorPos.x,
.y = (int32_t)cursorPos.y,
.width = (uint32_t)data.cursorFB->buffer->size.x,
.height = (uint32_t)data.cursorFB->buffer->size.y,
.handle = boHandle,
.hot_x = (int32_t)connector->output->cursorHotspot.x,
.hot_y = (int32_t)connector->output->cursorHotspot.y,
};
int ret = drmIoctl(connector->backend->gpu->fd, DRM_IOCTL_MODE_CURSOR2, &request);
if (boHandle && drmCloseBufferHandle(connector->backend->gpu->fd, boHandle))
connector->backend->backend->log(AQ_LOG_ERROR, "legacy drm: drmCloseBufferHandle in cursor failed");
if (ret) {
connector->backend->backend->log(AQ_LOG_ERROR, std::format("legacy drm: cursor drmIoctl failed: {}", strerror(errno)));
return false;
}
} else 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)

View file

@ -31,3 +31,7 @@ void Aquamarine::CAttachmentManager::remove(SP<IAttachment> attachment) {
void Aquamarine::CAttachmentManager::removeByType(eAttachmentType type) {
std::erase_if(attachments, [type](const auto& e) { return e->type() == type; });
}
void Aquamarine::CAttachmentManager::clear() {
attachments.clear();
}

View file

@ -19,11 +19,15 @@ bool Aquamarine::IOutput::setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> b
return false;
}
void Aquamarine::IOutput::setCursorVisible(bool visible) {
;
}
void Aquamarine::IOutput::scheduleFrame() {
;
}
Hyprutils::Math::Vector2D Aquamarine::IOutput::maxCursorSize() {
Hyprutils::Math::Vector2D Aquamarine::IOutput::cursorPlaneSize() {
return {}; // error
}