From 493f2c8cd4f5476c30443260c91b9886d88d23d9 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 25 Jul 2024 21:32:39 +0300 Subject: [PATCH 1/4] allocate dumb buffer if gbm fails --- include/aquamarine/allocator/GBM.hpp | 36 +++++- include/aquamarine/allocator/Swapchain.hpp | 1 + include/aquamarine/buffer/Buffer.hpp | 1 + src/allocator/GBM.cpp | 135 +++++++++++++++++++-- 4 files changed, 163 insertions(+), 10 deletions(-) diff --git a/include/aquamarine/allocator/GBM.hpp b/include/aquamarine/allocator/GBM.hpp index 3f1af0b..baa70b6 100644 --- a/include/aquamarine/allocator/GBM.hpp +++ b/include/aquamarine/allocator/GBM.hpp @@ -37,6 +37,35 @@ namespace Aquamarine { friend class CGBMAllocator; }; + class CGBMDumbBuffer : public IBuffer { + public: + virtual ~CGBMDumbBuffer(); + + virtual eBufferCapability caps(); + virtual eBufferType type(); + virtual void update(const Hyprutils::Math::CRegion& damage); + virtual bool isSynchronous(); + virtual bool good(); + virtual SDMABUFAttrs dmabuf(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + + private: + CGBMDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, Hyprutils::Memory::CSharedPointer swapchain); + + Hyprutils::Memory::CWeakPointer allocator; + + // dumb stuff + int m_drmFd; + uint32_t m_handle; + void* m_data = nullptr; + size_t m_size = 0; + + SDMABUFAttrs attrs{.success = false}; + + friend class CGBMAllocator; + }; + class CGBMAllocator : public IAllocator { public: ~CGBMAllocator(); @@ -53,10 +82,10 @@ namespace Aquamarine { CGBMAllocator(int fd_, Hyprutils::Memory::CWeakPointer backend_); // a vector purely for tracking (debugging) the buffers and nothing more - std::vector> buffers; + std::vector> buffers; - int fd = -1; - Hyprutils::Memory::CWeakPointer backend; + int fd = -1; + Hyprutils::Memory::CWeakPointer backend; // gbm stuff gbm_device* gbmDevice = nullptr; @@ -64,6 +93,7 @@ namespace Aquamarine { std::string drmName = ""; friend class CGBMBuffer; + friend class CGBMDumbBuffer; friend class CDRMRenderer; }; }; diff --git a/include/aquamarine/allocator/Swapchain.hpp b/include/aquamarine/allocator/Swapchain.hpp index 0e49025..2ee27eb 100644 --- a/include/aquamarine/allocator/Swapchain.hpp +++ b/include/aquamarine/allocator/Swapchain.hpp @@ -45,5 +45,6 @@ namespace Aquamarine { int lastAcquired = 0; friend class CGBMBuffer; + friend class CGBMDumbBuffer; }; }; diff --git a/include/aquamarine/buffer/Buffer.hpp b/include/aquamarine/buffer/Buffer.hpp index 99c21bf..94b1d7e 100644 --- a/include/aquamarine/buffer/Buffer.hpp +++ b/include/aquamarine/buffer/Buffer.hpp @@ -16,6 +16,7 @@ namespace Aquamarine { BUFFER_TYPE_DMABUF = 0, BUFFER_TYPE_SHM, BUFFER_TYPE_MISC, + BUFFER_TYPE_DMABUF_DUMB, }; class CWLBufferResource; diff --git a/src/allocator/GBM.cpp b/src/allocator/GBM.cpp index 42666a6..9b504ca 100644 --- a/src/allocator/GBM.cpp +++ b/src/allocator/GBM.cpp @@ -3,6 +3,9 @@ #include #include "FormatUtils.hpp" #include "Shared.hpp" +#include +#include +#include #include #include #include @@ -142,9 +145,9 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti bo = gbm_bo_create_with_modifiers2(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size(), flags); if (!bo && CURSOR) { - // allow non-renderable cursor buffer for nvidia - allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers and flags failed, falling back to modifiers without flags"); - bo = gbm_bo_create_with_modifiers(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size()); + // use dumb buffers for cursors + allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers and flags failed for cursor plane, falling back to dumb"); + return; } if (!bo) { @@ -199,7 +202,7 @@ Aquamarine::CGBMBuffer::~CGBMBuffer() { } eBufferCapability Aquamarine::CGBMBuffer::caps() { - return (Aquamarine::eBufferCapability)0; + return BUFFER_CAPABILITY_DATAPTR; } eBufferType Aquamarine::CGBMBuffer::type() { @@ -215,7 +218,7 @@ bool Aquamarine::CGBMBuffer::isSynchronous() { } bool Aquamarine::CGBMBuffer::good() { - return true; + return attrs.success; } SDMABUFAttrs Aquamarine::CGBMBuffer::dmabuf() { @@ -240,6 +243,118 @@ void Aquamarine::CGBMBuffer::endDataPtr() { } } +Aquamarine::CGBMDumbBuffer::CGBMDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, + Hyprutils::Memory::CSharedPointer swapchain) : + allocator(allocator_) { + if (!allocator) + return; + + drm_mode_create_dumb createArgs{ + .height = uint32_t(params.size.x), + .width = uint32_t(params.size.y), + .bpp = 32, + }; + + TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Allocating a dumb buffer: size {}, format {}", params.size, fourccToName(params.format)))); + if (drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { + allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: DRM_IOCTL_MODE_CREATE_DUMB failed {}", strerror(errno))); + return; + } + + int primeFd; + if (drmPrimeHandleToFD(gbm_device_get_fd(allocator->gbmDevice), createArgs.handle, DRM_CLOEXEC, &primeFd) != 0) { + allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: drmPrimeHandleToFD() failed {}", strerror(errno))); + drm_mode_destroy_dumb destroyArgs{ + .handle = createArgs.handle, + }; + drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); + return; + } + + m_drmFd = gbm_device_get_fd(allocator->gbmDevice); + m_handle = createArgs.handle; + m_size = createArgs.pitch * params.size.y; + + attrs.planes = 1; + attrs.size = params.size; + attrs.format = DRM_FORMAT_ARGB8888; + attrs.modifier = DRM_FORMAT_MOD_LINEAR; + attrs.offsets = {0, 0, 0, 0}; + attrs.fds = {primeFd, 0, 0, 0}; + attrs.strides = {createArgs.pitch, 0, 0, 0}; + + attrs.success = true; + + allocator->backend->log(AQ_LOG_DEBUG, std::format("GBM: Allocated a new dumb buffer with size {} and format {}", attrs.size, fourccToName(attrs.format))); +} + +Aquamarine::CGBMDumbBuffer::~CGBMDumbBuffer() { + events.destroy.emit(); + + endDataPtr(); + + if (m_handle) { + drm_mode_destroy_dumb destroyArgs{ + .handle = m_handle, + }; + drmIoctl(m_drmFd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); + } +} + +eBufferCapability Aquamarine::CGBMDumbBuffer::caps() { + return BUFFER_CAPABILITY_DATAPTR; +} + +eBufferType Aquamarine::CGBMDumbBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF_DUMB; +} + +void Aquamarine::CGBMDumbBuffer::update(const Hyprutils::Math::CRegion& damage) { + ; +} + +bool Aquamarine::CGBMDumbBuffer::isSynchronous() { + return false; // FIXME is it correct? +} + +bool Aquamarine::CGBMDumbBuffer::good() { + return true; +} + +SDMABUFAttrs Aquamarine::CGBMDumbBuffer::dmabuf() { + return attrs; +} + +std::tuple Aquamarine::CGBMDumbBuffer::beginDataPtr(uint32_t flags) { + if (!m_data) { + drm_mode_map_dumb mapArgs{ + .handle = m_handle, + }; + if (drmIoctl(m_drmFd, DRM_IOCTL_MODE_MAP_DUMB, &mapArgs) != 0) { + allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: DRM_IOCTL_MODE_MAP_DUMB failed {}", strerror(errno))); + return {}; + } + + void* address = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_drmFd, mapArgs.offset); + if (address == MAP_FAILED) { + allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: mmap failed {}", strerror(errno))); + return {}; + } + + m_data = address; + } + + // FIXME: assumes a 32-bit pixel format + return {(uint8_t*)m_data, attrs.format, attrs.strides[0]}; +} + +void Aquamarine::CGBMDumbBuffer::endDataPtr() { + if (m_data) { + munmap(m_data, m_size); + m_data = nullptr; + } +} + CGBMAllocator::~CGBMAllocator() { if (gbmDevice) gbm_device_destroy(gbmDevice); @@ -285,11 +400,17 @@ SP Aquamarine::CGBMAllocator::acquire(const SAllocatorBufferParams& par return nullptr; } - auto newBuffer = SP(new CGBMBuffer(params, self, swapchain_)); + SP newBuffer = SP(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))); - return nullptr; + + newBuffer = SP(new CGBMDumbBuffer(params, self, swapchain_)); + + if (!newBuffer->good()) { + backend->log(AQ_LOG_ERROR, std::format("Couldn't allocate a dumb gbm buffer with size {} and format {}", params.size, fourccToName(params.format))); + return nullptr; + } } buffers.emplace_back(newBuffer); From 95d6c8ac0efbe23fb2dedbe0afec5215e4072fca Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 26 Jul 2024 12:41:42 +0300 Subject: [PATCH 2/4] dumb allocator --- include/aquamarine/allocator/Dumb.hpp | 70 ++++++++ include/aquamarine/allocator/GBM.hpp | 36 +--- include/aquamarine/allocator/Swapchain.hpp | 2 +- include/aquamarine/backend/Backend.hpp | 6 +- include/aquamarine/backend/DRM.hpp | 1 + src/allocator/Dumb.cpp | 190 +++++++++++++++++++++ src/allocator/GBM.cpp | 134 +-------------- src/backend/Backend.cpp | 4 +- src/backend/drm/DRM.cpp | 4 + 9 files changed, 283 insertions(+), 164 deletions(-) create mode 100644 include/aquamarine/allocator/Dumb.hpp create mode 100644 src/allocator/Dumb.cpp diff --git a/include/aquamarine/allocator/Dumb.hpp b/include/aquamarine/allocator/Dumb.hpp new file mode 100644 index 0000000..bdea040 --- /dev/null +++ b/include/aquamarine/allocator/Dumb.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include "Allocator.hpp" + +struct gbm_device; + +namespace Aquamarine { + class CDumbAllocator; + class CBackend; + class CSwapchain; + + class CDumbBuffer : public IBuffer { + public: + virtual ~CDumbBuffer(); + + virtual eBufferCapability caps(); + virtual eBufferType type(); + virtual void update(const Hyprutils::Math::CRegion& damage); + virtual bool isSynchronous(); + virtual bool good(); + virtual SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + + private: + CDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, Hyprutils::Memory::CSharedPointer swapchain); + + Hyprutils::Memory::CWeakPointer allocator; + + // dumb stuff + int drmFd; + uint32_t handle; + void* data = nullptr; + size_t length = 0; + + SSHMAttrs attrs{.success = false}; + + friend class CDumbAllocator; + }; + + class CDumbAllocator : public IAllocator { + public: + ~CDumbAllocator(); + static Hyprutils::Memory::CSharedPointer create(int drmfd_, Hyprutils::Memory::CWeakPointer backend_); + + virtual Hyprutils::Memory::CSharedPointer acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer swapchain_); + virtual Hyprutils::Memory::CSharedPointer getBackend(); + virtual int drmFD(); + + // + Hyprutils::Memory::CWeakPointer self; + + private: + CDumbAllocator(int fd_, Hyprutils::Memory::CWeakPointer backend_); + + // a vector purely for tracking (debugging) the buffers and nothing more + std::vector> buffers; + + int fd = -1; + Hyprutils::Memory::CWeakPointer backend; + + // gbm stuff + gbm_device* gbmDevice = nullptr; + std::string gbmDeviceBackendName = ""; + std::string drmName = ""; + + friend class CDumbBuffer; + friend class CDRMRenderer; + }; +}; diff --git a/include/aquamarine/allocator/GBM.hpp b/include/aquamarine/allocator/GBM.hpp index baa70b6..3f1af0b 100644 --- a/include/aquamarine/allocator/GBM.hpp +++ b/include/aquamarine/allocator/GBM.hpp @@ -37,35 +37,6 @@ namespace Aquamarine { friend class CGBMAllocator; }; - class CGBMDumbBuffer : public IBuffer { - public: - virtual ~CGBMDumbBuffer(); - - virtual eBufferCapability caps(); - virtual eBufferType type(); - virtual void update(const Hyprutils::Math::CRegion& damage); - virtual bool isSynchronous(); - virtual bool good(); - virtual SDMABUFAttrs dmabuf(); - virtual std::tuple beginDataPtr(uint32_t flags); - virtual void endDataPtr(); - - private: - CGBMDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, Hyprutils::Memory::CSharedPointer swapchain); - - Hyprutils::Memory::CWeakPointer allocator; - - // dumb stuff - int m_drmFd; - uint32_t m_handle; - void* m_data = nullptr; - size_t m_size = 0; - - SDMABUFAttrs attrs{.success = false}; - - friend class CGBMAllocator; - }; - class CGBMAllocator : public IAllocator { public: ~CGBMAllocator(); @@ -82,10 +53,10 @@ namespace Aquamarine { CGBMAllocator(int fd_, Hyprutils::Memory::CWeakPointer backend_); // a vector purely for tracking (debugging) the buffers and nothing more - std::vector> buffers; + std::vector> buffers; - int fd = -1; - Hyprutils::Memory::CWeakPointer backend; + int fd = -1; + Hyprutils::Memory::CWeakPointer backend; // gbm stuff gbm_device* gbmDevice = nullptr; @@ -93,7 +64,6 @@ namespace Aquamarine { std::string drmName = ""; friend class CGBMBuffer; - friend class CGBMDumbBuffer; friend class CDRMRenderer; }; }; diff --git a/include/aquamarine/allocator/Swapchain.hpp b/include/aquamarine/allocator/Swapchain.hpp index 2ee27eb..9bcc59b 100644 --- a/include/aquamarine/allocator/Swapchain.hpp +++ b/include/aquamarine/allocator/Swapchain.hpp @@ -45,6 +45,6 @@ namespace Aquamarine { int lastAcquired = 0; friend class CGBMBuffer; - friend class CGBMDumbBuffer; + friend class CDumbBuffer; }; }; diff --git a/include/aquamarine/backend/Backend.hpp b/include/aquamarine/backend/Backend.hpp index 6e40d62..f496c9f 100644 --- a/include/aquamarine/backend/Backend.hpp +++ b/include/aquamarine/backend/Backend.hpp @@ -77,7 +77,10 @@ namespace Aquamarine { virtual std::vector getCursorFormats() = 0; virtual bool createOutput(const std::string& name = "") = 0; // "" means auto virtual Hyprutils::Memory::CSharedPointer preferredAllocator() = 0; - virtual std::vector getRenderableFormats(); // empty = use getRenderFormats + virtual Hyprutils::Memory::CSharedPointer fallbackAllocator() { + return nullptr; + }; + virtual std::vector getRenderableFormats(); // empty = use getRenderFormats }; class CBackend { @@ -128,6 +131,7 @@ namespace Aquamarine { } events; Hyprutils::Memory::CSharedPointer primaryAllocator; + Hyprutils::Memory::CSharedPointer fallbackAllocator; bool ready = false; Hyprutils::Memory::CSharedPointer session; diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index 7bb441d..1dfe440 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -342,6 +342,7 @@ namespace Aquamarine { virtual std::vector getCursorFormats(); virtual bool createOutput(const std::string& name = ""); virtual Hyprutils::Memory::CSharedPointer preferredAllocator(); + virtual Hyprutils::Memory::CSharedPointer fallbackAllocator(); virtual std::vector getRenderableFormats(); Hyprutils::Memory::CWeakPointer self; diff --git a/src/allocator/Dumb.cpp b/src/allocator/Dumb.cpp new file mode 100644 index 0000000..403af02 --- /dev/null +++ b/src/allocator/Dumb.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +#include "FormatUtils.hpp" +#include "Shared.hpp" +#include "aquamarine/buffer/Buffer.hpp" +#include +#include +#include +#include +#include +#include + +using namespace Aquamarine; +using namespace Hyprutils::Memory; +#define SP CSharedPointer + +Aquamarine::CDumbBuffer::CDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, + Hyprutils::Memory::CSharedPointer swapchain) : allocator(allocator_) { + if (!allocator) + return; + + drm_mode_create_dumb createArgs{ + .height = uint32_t(params.size.x), + .width = uint32_t(params.size.y), + .bpp = 32, + }; + + TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("DUMB: Allocating a dumb buffer: size {}, format {}", params.size, fourccToName(params.format)))); + if (drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { + allocator->backend->log(AQ_LOG_ERROR, std::format("DUMB: DRM_IOCTL_MODE_CREATE_DUMB failed {}", strerror(errno))); + return; + } + + int primeFd; + if (drmPrimeHandleToFD(gbm_device_get_fd(allocator->gbmDevice), createArgs.handle, DRM_CLOEXEC, &primeFd) != 0) { + allocator->backend->log(AQ_LOG_ERROR, std::format("DUMB: drmPrimeHandleToFD() failed {}", strerror(errno))); + drm_mode_destroy_dumb destroyArgs{ + .handle = createArgs.handle, + }; + drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); + return; + } + + drmFd = gbm_device_get_fd(allocator->gbmDevice); + handle = createArgs.handle; + length = createArgs.pitch * params.size.y; + + attrs.size = params.size; + attrs.format = DRM_FORMAT_ARGB8888; + attrs.offset = 0; + attrs.fd = primeFd; + attrs.stride = createArgs.pitch; + + attrs.success = true; + + allocator->backend->log(AQ_LOG_DEBUG, std::format("DUMB: Allocated a new dumb buffer with size {} and format {}", attrs.size, fourccToName(attrs.format))); +} + +Aquamarine::CDumbBuffer::~CDumbBuffer() { + events.destroy.emit(); + + endDataPtr(); + + if (handle) { + drm_mode_destroy_dumb destroyArgs{ + .handle = handle, + }; + drmIoctl(drmFd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); + } +} + +eBufferCapability Aquamarine::CDumbBuffer::caps() { + return BUFFER_CAPABILITY_DATAPTR; +} + +eBufferType Aquamarine::CDumbBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF_DUMB; +} + +void Aquamarine::CDumbBuffer::update(const Hyprutils::Math::CRegion& damage) { + ; +} + +bool Aquamarine::CDumbBuffer::isSynchronous() { + return false; // FIXME is it correct? +} + +bool Aquamarine::CDumbBuffer::good() { + return true; +} + +SSHMAttrs Aquamarine::CDumbBuffer::shm() { + return attrs; +} + +std::tuple Aquamarine::CDumbBuffer::beginDataPtr(uint32_t flags) { + if (!data) { + drm_mode_map_dumb mapArgs{ + .handle = handle, + }; + if (drmIoctl(drmFd, DRM_IOCTL_MODE_MAP_DUMB, &mapArgs) != 0) { + allocator->backend->log(AQ_LOG_ERROR, std::format("DUMB: DRM_IOCTL_MODE_MAP_DUMB failed {}", strerror(errno))); + return {}; + } + + void* address = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, drmFd, mapArgs.offset); + if (address == MAP_FAILED) { + allocator->backend->log(AQ_LOG_ERROR, std::format("DUMB: mmap failed {}", strerror(errno))); + return {}; + } + + data = address; + } + + // FIXME: assumes a 32-bit pixel format + return {(uint8_t*)data, attrs.format, attrs.stride}; +} + +void Aquamarine::CDumbBuffer::endDataPtr() { + if (data) { + munmap(data, length); + data = nullptr; + } +} + +CDumbAllocator::~CDumbAllocator() { + if (gbmDevice) + gbm_device_destroy(gbmDevice); +} + +SP Aquamarine::CDumbAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer backend_) { + uint64_t capabilities = 0; + if (drmGetCap(drmfd_, DRM_CAP_PRIME, &capabilities) || !(capabilities & DRM_PRIME_CAP_EXPORT)) { + backend_->log(AQ_LOG_ERROR, "Cannot create a Dumb Allocator: PRIME export is not supported by the gpu."); + return nullptr; + } + + auto allocator = SP(new CDumbAllocator(drmfd_, backend_)); + + if (!allocator->gbmDevice) { + backend_->log(AQ_LOG_ERROR, "Cannot create a Dumb Allocator: gbm failed to create a device."); + return nullptr; + } + + backend_->log(AQ_LOG_DEBUG, std::format("Created a Dumb Allocator with drm fd {}", drmfd_)); + + allocator->self = allocator; + + return allocator; +} + +Aquamarine::CDumbAllocator::CDumbAllocator(int fd_, Hyprutils::Memory::CWeakPointer backend_) : fd(fd_), backend(backend_) { + gbmDevice = gbm_create_device(fd_); + if (!gbmDevice) { + backend->log(AQ_LOG_ERROR, std::format("Couldn't open a GBM device at fd {}", fd_)); + return; + } + + gbmDeviceBackendName = gbm_device_get_backend_name(gbmDevice); + auto drmName_ = drmGetDeviceNameFromFd2(fd_); + drmName = drmName_; + free(drmName_); +} + +SP Aquamarine::CDumbAllocator::acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer swapchain_) { + if (params.size.x < 1 || params.size.y < 1) { + backend->log(AQ_LOG_ERROR, std::format("Couldn't allocate a dumb buffer with invalid size {}", params.size)); + return nullptr; + } + + auto newBuffer = SP(new CDumbBuffer(params, self, swapchain_)); + + if (!newBuffer->good()) { + backend->log(AQ_LOG_ERROR, std::format("Couldn't allocate a dumb buffer with size {} and format {}", params.size, fourccToName(params.format))); + return nullptr; + } + + buffers.emplace_back(newBuffer); + std::erase_if(buffers, [](const auto& b) { return b.expired(); }); + return newBuffer; +} + +Hyprutils::Memory::CSharedPointer Aquamarine::CDumbAllocator::getBackend() { + return backend.lock(); +} + +int Aquamarine::CDumbAllocator::drmFD() { + return fd; +} diff --git a/src/allocator/GBM.cpp b/src/allocator/GBM.cpp index 9b504ca..cde9153 100644 --- a/src/allocator/GBM.cpp +++ b/src/allocator/GBM.cpp @@ -3,9 +3,6 @@ #include #include "FormatUtils.hpp" #include "Shared.hpp" -#include -#include -#include #include #include #include @@ -56,8 +53,7 @@ static SDRMFormat guessFormatFrom(std::vector formats, bool cursor) } Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, - Hyprutils::Memory::CSharedPointer swapchain) : - allocator(allocator_) { + Hyprutils::Memory::CSharedPointer swapchain) : allocator(allocator_) { if (!allocator) return; @@ -145,9 +141,9 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti bo = gbm_bo_create_with_modifiers2(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size(), flags); if (!bo && CURSOR) { - // use dumb buffers for cursors - allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers and flags failed for cursor plane, falling back to dumb"); - return; + // allow non-renderable cursor buffer for nvidia + allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers and flags failed, falling back to modifiers without flags"); + bo = gbm_bo_create_with_modifiers(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size()); } if (!bo) { @@ -243,118 +239,6 @@ void Aquamarine::CGBMBuffer::endDataPtr() { } } -Aquamarine::CGBMDumbBuffer::CGBMDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer allocator_, - Hyprutils::Memory::CSharedPointer swapchain) : - allocator(allocator_) { - if (!allocator) - return; - - drm_mode_create_dumb createArgs{ - .height = uint32_t(params.size.x), - .width = uint32_t(params.size.y), - .bpp = 32, - }; - - TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Allocating a dumb buffer: size {}, format {}", params.size, fourccToName(params.format)))); - if (drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { - allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: DRM_IOCTL_MODE_CREATE_DUMB failed {}", strerror(errno))); - return; - } - - int primeFd; - if (drmPrimeHandleToFD(gbm_device_get_fd(allocator->gbmDevice), createArgs.handle, DRM_CLOEXEC, &primeFd) != 0) { - allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: drmPrimeHandleToFD() failed {}", strerror(errno))); - drm_mode_destroy_dumb destroyArgs{ - .handle = createArgs.handle, - }; - drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); - return; - } - - m_drmFd = gbm_device_get_fd(allocator->gbmDevice); - m_handle = createArgs.handle; - m_size = createArgs.pitch * params.size.y; - - attrs.planes = 1; - attrs.size = params.size; - attrs.format = DRM_FORMAT_ARGB8888; - attrs.modifier = DRM_FORMAT_MOD_LINEAR; - attrs.offsets = {0, 0, 0, 0}; - attrs.fds = {primeFd, 0, 0, 0}; - attrs.strides = {createArgs.pitch, 0, 0, 0}; - - attrs.success = true; - - allocator->backend->log(AQ_LOG_DEBUG, std::format("GBM: Allocated a new dumb buffer with size {} and format {}", attrs.size, fourccToName(attrs.format))); -} - -Aquamarine::CGBMDumbBuffer::~CGBMDumbBuffer() { - events.destroy.emit(); - - endDataPtr(); - - if (m_handle) { - drm_mode_destroy_dumb destroyArgs{ - .handle = m_handle, - }; - drmIoctl(m_drmFd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); - } -} - -eBufferCapability Aquamarine::CGBMDumbBuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; -} - -eBufferType Aquamarine::CGBMDumbBuffer::type() { - return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF_DUMB; -} - -void Aquamarine::CGBMDumbBuffer::update(const Hyprutils::Math::CRegion& damage) { - ; -} - -bool Aquamarine::CGBMDumbBuffer::isSynchronous() { - return false; // FIXME is it correct? -} - -bool Aquamarine::CGBMDumbBuffer::good() { - return true; -} - -SDMABUFAttrs Aquamarine::CGBMDumbBuffer::dmabuf() { - return attrs; -} - -std::tuple Aquamarine::CGBMDumbBuffer::beginDataPtr(uint32_t flags) { - if (!m_data) { - drm_mode_map_dumb mapArgs{ - .handle = m_handle, - }; - if (drmIoctl(m_drmFd, DRM_IOCTL_MODE_MAP_DUMB, &mapArgs) != 0) { - allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: DRM_IOCTL_MODE_MAP_DUMB failed {}", strerror(errno))); - return {}; - } - - void* address = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_drmFd, mapArgs.offset); - if (address == MAP_FAILED) { - allocator->backend->log(AQ_LOG_ERROR, std::format("GBM: mmap failed {}", strerror(errno))); - return {}; - } - - m_data = address; - } - - // FIXME: assumes a 32-bit pixel format - return {(uint8_t*)m_data, attrs.format, attrs.strides[0]}; -} - -void Aquamarine::CGBMDumbBuffer::endDataPtr() { - if (m_data) { - munmap(m_data, m_size); - m_data = nullptr; - } -} - CGBMAllocator::~CGBMAllocator() { if (gbmDevice) gbm_device_destroy(gbmDevice); @@ -400,17 +284,11 @@ SP Aquamarine::CGBMAllocator::acquire(const SAllocatorBufferParams& par return nullptr; } - SP newBuffer = SP(new CGBMBuffer(params, self, swapchain_)); + auto newBuffer = SP(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))); - - newBuffer = SP(new CGBMDumbBuffer(params, self, swapchain_)); - - if (!newBuffer->good()) { - backend->log(AQ_LOG_ERROR, std::format("Couldn't allocate a dumb gbm buffer with size {} and format {}", params.size, fourccToName(params.format))); - return nullptr; - } + return nullptr; } buffers.emplace_back(newBuffer); diff --git a/src/backend/Backend.cpp b/src/backend/Backend.cpp index a6db06a..65c3721 100644 --- a/src/backend/Backend.cpp +++ b/src/backend/Backend.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,8 @@ bool Aquamarine::CBackend::start() { log(AQ_LOG_CRITICAL, "Failed to create an allocator (reopenDRMNode failed)"); return false; } - primaryAllocator = CGBMAllocator::create(fd, self); + primaryAllocator = CGBMAllocator::create(fd, self); + fallbackAllocator = CDumbAllocator::create(fd, self); break; } } diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 93ba80c..957cec4 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -932,6 +932,10 @@ SP Aquamarine::CDRMBackend::preferredAllocator() { return backend->primaryAllocator; } +SP Aquamarine::CDRMBackend::fallbackAllocator() { + return backend->fallbackAllocator; +} + bool Aquamarine::SDRMPlane::init(drmModePlane* plane) { id = plane->plane_id; From 36e4934c136f8e5ff03da16c1185387f56ecf16b Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 26 Jul 2024 14:58:01 +0300 Subject: [PATCH 3/4] accept dumb buffers --- include/aquamarine/buffer/Buffer.hpp | 2 +- src/allocator/Dumb.cpp | 2 +- src/backend/drm/DRM.cpp | 26 +++++++++++++++++--------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/include/aquamarine/buffer/Buffer.hpp b/include/aquamarine/buffer/Buffer.hpp index 94b1d7e..644650f 100644 --- a/include/aquamarine/buffer/Buffer.hpp +++ b/include/aquamarine/buffer/Buffer.hpp @@ -16,7 +16,7 @@ namespace Aquamarine { BUFFER_TYPE_DMABUF = 0, BUFFER_TYPE_SHM, BUFFER_TYPE_MISC, - BUFFER_TYPE_DMABUF_DUMB, + BUFFER_TYPE_DUMB, }; class CWLBufferResource; diff --git a/src/allocator/Dumb.cpp b/src/allocator/Dumb.cpp index 403af02..f78f9e0 100644 --- a/src/allocator/Dumb.cpp +++ b/src/allocator/Dumb.cpp @@ -75,7 +75,7 @@ eBufferCapability Aquamarine::CDumbBuffer::caps() { } eBufferType Aquamarine::CDumbBuffer::type() { - return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF_DUMB; + return Aquamarine::eBufferType::BUFFER_TYPE_DUMB; } void Aquamarine::CDumbBuffer::update(const Hyprutils::Math::CRegion& damage) { diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 957cec4..943bfa4 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1550,14 +1550,14 @@ SP Aquamarine::CDRMOutput::getBackend() { } bool Aquamarine::CDRMOutput::setCursor(SP buffer, const Vector2D& hotspot) { - if (buffer && !buffer->dmabuf().success) { - backend->backend->log(AQ_LOG_ERROR, "drm: Cursor buffer has to be a dmabuf"); - return false; - } - if (!buffer) setCursorVisible(false); else { + auto isDumb = buffer->type() == BUFFER_TYPE_DUMB; + if (!(buffer->dmabuf().success || (isDumb && buffer->shm().success))) { + backend->backend->log(AQ_LOG_ERROR, "drm: Cursor buffer has to be a dmabuf or dumb"); + return false; + } SP fb; if (backend->primary) { @@ -1572,8 +1572,8 @@ bool Aquamarine::CDRMOutput::setCursor(SP buffer, const Vector2D& hotsp OPTIONS.multigpu = false; OPTIONS.scanout = true; OPTIONS.cursor = true; - OPTIONS.format = buffer->dmabuf().format; - OPTIONS.size = buffer->dmabuf().size; + OPTIONS.format = isDumb ? buffer->shm().format : buffer->dmabuf().format; + OPTIONS.size = isDumb ? buffer->shm().size : buffer->dmabuf().size; OPTIONS.length = 2; if (!mgpu.cursorSwapchain->reconfigure(OPTIONS)) { @@ -1702,7 +1702,11 @@ Aquamarine::CDRMFB::CDRMFB(SP buffer_, Hyprutils::Memory::CWeakPointer< } void Aquamarine::CDRMFB::import() { - auto attrs = buffer->dmabuf(); + // FIXME easier to pretend that we are a dmabuf then to change everything. shm and dmabuf should have the same offset and stride types? + auto attrs = buffer->type() == BUFFER_TYPE_DUMB ? + SDMABUFAttrs{buffer->shm().success, buffer->shm().size, buffer->shm().format, 0, 1, {(uint32_t)buffer->shm().offset}, {(uint32_t)buffer->shm().stride}, + {buffer->shm().fd, -1, -1, -1}} : + buffer->dmabuf(); if (!attrs.success) { backend->backend->log(AQ_LOG_ERROR, "drm: Buffer submitted has no dmabuf"); return; @@ -1811,7 +1815,11 @@ void Aquamarine::CDRMFB::drop() { } uint32_t Aquamarine::CDRMFB::submitBuffer() { - auto attrs = buffer->dmabuf(); + // FIXME easier to pretend that we are a dmabuf then to change everything. shm and dmabuf should have the same offset and stride types? + auto attrs = buffer->type() == BUFFER_TYPE_DUMB ? + SDMABUFAttrs{buffer->shm().success, buffer->shm().size, buffer->shm().format, 0, 1, {(uint32_t)buffer->shm().offset}, {(uint32_t)buffer->shm().stride}, + {buffer->shm().fd, -1, -1, -1}} : + buffer->dmabuf(); uint32_t newID = 0; std::array mods = {0, 0, 0, 0}; for (size_t i = 0; i < attrs.planes; ++i) { From 584fd4e99a36f02efa1f06199060954e53e46e0b Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 26 Jul 2024 20:59:52 +0300 Subject: [PATCH 4/4] clean unneeded stuff --- include/aquamarine/allocator/Dumb.hpp | 13 ++------- src/allocator/Dumb.cpp | 41 +++++++-------------------- 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/include/aquamarine/allocator/Dumb.hpp b/include/aquamarine/allocator/Dumb.hpp index bdea040..40c8aea 100644 --- a/include/aquamarine/allocator/Dumb.hpp +++ b/include/aquamarine/allocator/Dumb.hpp @@ -2,8 +2,6 @@ #include "Allocator.hpp" -struct gbm_device; - namespace Aquamarine { class CDumbAllocator; class CBackend; @@ -28,8 +26,8 @@ namespace Aquamarine { Hyprutils::Memory::CWeakPointer allocator; // dumb stuff - int drmFd; - uint32_t handle; + int drmFd = -1; + uint32_t handle = 0; void* data = nullptr; size_t length = 0; @@ -51,7 +49,7 @@ namespace Aquamarine { Hyprutils::Memory::CWeakPointer self; private: - CDumbAllocator(int fd_, Hyprutils::Memory::CWeakPointer backend_); + CDumbAllocator(int drmfd_, Hyprutils::Memory::CWeakPointer backend_); // a vector purely for tracking (debugging) the buffers and nothing more std::vector> buffers; @@ -59,11 +57,6 @@ namespace Aquamarine { int fd = -1; Hyprutils::Memory::CWeakPointer backend; - // gbm stuff - gbm_device* gbmDevice = nullptr; - std::string gbmDeviceBackendName = ""; - std::string drmName = ""; - friend class CDumbBuffer; friend class CDRMRenderer; }; diff --git a/src/allocator/Dumb.cpp b/src/allocator/Dumb.cpp index f78f9e0..2154199 100644 --- a/src/allocator/Dumb.cpp +++ b/src/allocator/Dumb.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include using namespace Aquamarine; @@ -27,22 +26,22 @@ Aquamarine::CDumbBuffer::CDumbBuffer(const SAllocatorBufferParams& params, Hypru }; TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("DUMB: Allocating a dumb buffer: size {}, format {}", params.size, fourccToName(params.format)))); - if (drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { + if (drmIoctl(allocator->drmFD(), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { allocator->backend->log(AQ_LOG_ERROR, std::format("DUMB: DRM_IOCTL_MODE_CREATE_DUMB failed {}", strerror(errno))); return; } int primeFd; - if (drmPrimeHandleToFD(gbm_device_get_fd(allocator->gbmDevice), createArgs.handle, DRM_CLOEXEC, &primeFd) != 0) { + if (drmPrimeHandleToFD(allocator->drmFD(), createArgs.handle, DRM_CLOEXEC, &primeFd) != 0) { allocator->backend->log(AQ_LOG_ERROR, std::format("DUMB: drmPrimeHandleToFD() failed {}", strerror(errno))); drm_mode_destroy_dumb destroyArgs{ .handle = createArgs.handle, }; - drmIoctl(gbm_device_get_fd(allocator->gbmDevice), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); + drmIoctl(allocator->drmFD(), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); return; } - drmFd = gbm_device_get_fd(allocator->gbmDevice); + drmFd = allocator->drmFD(); handle = createArgs.handle; length = createArgs.pitch * params.size.y; @@ -83,7 +82,7 @@ void Aquamarine::CDumbBuffer::update(const Hyprutils::Math::CRegion& damage) { } bool Aquamarine::CDumbBuffer::isSynchronous() { - return false; // FIXME is it correct? + return true; } bool Aquamarine::CDumbBuffer::good() { @@ -124,44 +123,24 @@ void Aquamarine::CDumbBuffer::endDataPtr() { } } -CDumbAllocator::~CDumbAllocator() { - if (gbmDevice) - gbm_device_destroy(gbmDevice); -} +CDumbAllocator::~CDumbAllocator() {} SP Aquamarine::CDumbAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer backend_) { - uint64_t capabilities = 0; - if (drmGetCap(drmfd_, DRM_CAP_PRIME, &capabilities) || !(capabilities & DRM_PRIME_CAP_EXPORT)) { - backend_->log(AQ_LOG_ERROR, "Cannot create a Dumb Allocator: PRIME export is not supported by the gpu."); - return nullptr; - } - auto allocator = SP(new CDumbAllocator(drmfd_, backend_)); - if (!allocator->gbmDevice) { - backend_->log(AQ_LOG_ERROR, "Cannot create a Dumb Allocator: gbm failed to create a device."); + if (allocator->drmFD() < 0) { + backend_->log(AQ_LOG_ERROR, "Cannot create a Dumb Allocator: drm fd is required."); return nullptr; } - backend_->log(AQ_LOG_DEBUG, std::format("Created a Dumb Allocator with drm fd {}", drmfd_)); + backend_->log(AQ_LOG_DEBUG, std::format("Created a Dumb Allocator")); allocator->self = allocator; return allocator; } -Aquamarine::CDumbAllocator::CDumbAllocator(int fd_, Hyprutils::Memory::CWeakPointer backend_) : fd(fd_), backend(backend_) { - gbmDevice = gbm_create_device(fd_); - if (!gbmDevice) { - backend->log(AQ_LOG_ERROR, std::format("Couldn't open a GBM device at fd {}", fd_)); - return; - } - - gbmDeviceBackendName = gbm_device_get_backend_name(gbmDevice); - auto drmName_ = drmGetDeviceNameFromFd2(fd_); - drmName = drmName_; - free(drmName_); -} +Aquamarine::CDumbAllocator::CDumbAllocator(int drmfd_, Hyprutils::Memory::CWeakPointer backend_) : fd(drmfd_), backend(backend_) {} SP Aquamarine::CDumbAllocator::acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer swapchain_) { if (params.size.x < 1 || params.size.y < 1) {