mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 12:49:47 +01:00
drm: Implement hardware cursors
This commit is contained in:
parent
0027280d27
commit
41b1b28ce1
16 changed files with 236 additions and 77 deletions
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Aquamarine {
|
|||
class IBuffer {
|
||||
public:
|
||||
virtual ~IBuffer() {
|
||||
;
|
||||
attachments.clear();
|
||||
};
|
||||
|
||||
virtual eBufferCapability caps() = 0;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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_) {
|
||||
;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue