dumb allocator

This commit is contained in:
UjinT34 2024-07-26 12:41:42 +03:00
parent 493f2c8cd4
commit 95d6c8ac0e
9 changed files with 283 additions and 164 deletions

View File

@ -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<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
private:
CDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CDumbAllocator> allocator_, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain);
Hyprutils::Memory::CWeakPointer<CDumbAllocator> 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<CDumbAllocator> create(int drmfd_, Hyprutils::Memory::CWeakPointer<CBackend> backend_);
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain_);
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
virtual int drmFD();
//
Hyprutils::Memory::CWeakPointer<CDumbAllocator> self;
private:
CDumbAllocator(int fd_, Hyprutils::Memory::CWeakPointer<CBackend> backend_);
// a vector purely for tracking (debugging) the buffers and nothing more
std::vector<Hyprutils::Memory::CWeakPointer<CDumbBuffer>> buffers;
int fd = -1;
Hyprutils::Memory::CWeakPointer<CBackend> backend;
// gbm stuff
gbm_device* gbmDevice = nullptr;
std::string gbmDeviceBackendName = "";
std::string drmName = "";
friend class CDumbBuffer;
friend class CDRMRenderer;
};
};

View File

@ -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<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
private:
CGBMDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator_, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain);
Hyprutils::Memory::CWeakPointer<CGBMAllocator> 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<CBackend> backend_);
// a vector purely for tracking (debugging) the buffers and nothing more
std::vector<Hyprutils::Memory::CWeakPointer<IBuffer>> buffers;
std::vector<Hyprutils::Memory::CWeakPointer<CGBMBuffer>> buffers;
int fd = -1;
Hyprutils::Memory::CWeakPointer<CBackend> backend;
int fd = -1;
Hyprutils::Memory::CWeakPointer<CBackend> 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;
};
};

View File

@ -45,6 +45,6 @@ namespace Aquamarine {
int lastAcquired = 0;
friend class CGBMBuffer;
friend class CGBMDumbBuffer;
friend class CDumbBuffer;
};
};

View File

@ -77,7 +77,10 @@ namespace Aquamarine {
virtual std::vector<SDRMFormat> getCursorFormats() = 0;
virtual bool createOutput(const std::string& name = "") = 0; // "" means auto
virtual Hyprutils::Memory::CSharedPointer<IAllocator> preferredAllocator() = 0;
virtual std::vector<SDRMFormat> getRenderableFormats(); // empty = use getRenderFormats
virtual Hyprutils::Memory::CSharedPointer<IAllocator> fallbackAllocator() {
return nullptr;
};
virtual std::vector<SDRMFormat> getRenderableFormats(); // empty = use getRenderFormats
};
class CBackend {
@ -128,6 +131,7 @@ namespace Aquamarine {
} events;
Hyprutils::Memory::CSharedPointer<IAllocator> primaryAllocator;
Hyprutils::Memory::CSharedPointer<IAllocator> fallbackAllocator;
bool ready = false;
Hyprutils::Memory::CSharedPointer<CSession> session;

View File

@ -342,6 +342,7 @@ namespace Aquamarine {
virtual std::vector<SDRMFormat> getCursorFormats();
virtual bool createOutput(const std::string& name = "");
virtual Hyprutils::Memory::CSharedPointer<IAllocator> preferredAllocator();
virtual Hyprutils::Memory::CSharedPointer<IAllocator> fallbackAllocator();
virtual std::vector<SDRMFormat> getRenderableFormats();
Hyprutils::Memory::CWeakPointer<CDRMBackend> self;

190
src/allocator/Dumb.cpp Normal file
View File

@ -0,0 +1,190 @@
#include <aquamarine/allocator/Dumb.hpp>
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/allocator/Swapchain.hpp>
#include "FormatUtils.hpp"
#include "Shared.hpp"
#include "aquamarine/buffer/Buffer.hpp"
#include <cstring>
#include <fcntl.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <gbm.h>
#include <unistd.h>
using namespace Aquamarine;
using namespace Hyprutils::Memory;
#define SP CSharedPointer
Aquamarine::CDumbBuffer::CDumbBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CDumbAllocator> allocator_,
Hyprutils::Memory::CSharedPointer<CSwapchain> 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<uint8_t*, uint32_t, size_t> 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<CDumbAllocator> Aquamarine::CDumbAllocator::create(int drmfd_, Hyprutils::Memory::CWeakPointer<CBackend> 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<CDumbAllocator>(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<CBackend> 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<IBuffer> Aquamarine::CDumbAllocator::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 dumb buffer with invalid size {}", params.size));
return nullptr;
}
auto newBuffer = SP<CDumbBuffer>(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<CBackend> Aquamarine::CDumbAllocator::getBackend() {
return backend.lock();
}
int Aquamarine::CDumbAllocator::drmFD() {
return fd;
}

View File

@ -3,9 +3,6 @@
#include <aquamarine/allocator/Swapchain.hpp>
#include "FormatUtils.hpp"
#include "Shared.hpp"
#include <cstring>
#include <fcntl.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <gbm.h>
#include <unistd.h>
@ -56,8 +53,7 @@ static SDRMFormat guessFormatFrom(std::vector<SDRMFormat> formats, bool cursor)
}
Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hyprutils::Memory::CWeakPointer<CGBMAllocator> allocator_,
Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain) :
allocator(allocator_) {
Hyprutils::Memory::CSharedPointer<CSwapchain> 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<CGBMAllocator> allocator_,
Hyprutils::Memory::CSharedPointer<CSwapchain> 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<uint8_t*, uint32_t, size_t> 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<IBuffer> Aquamarine::CGBMAllocator::acquire(const SAllocatorBufferParams& par
return nullptr;
}
SP<IBuffer> newBuffer = SP<CGBMBuffer>(new CGBMBuffer(params, self, swapchain_));
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)));
newBuffer = SP<CGBMDumbBuffer>(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);

View File

@ -3,6 +3,7 @@
#include <aquamarine/backend/Headless.hpp>
#include <aquamarine/backend/DRM.hpp>
#include <aquamarine/allocator/GBM.hpp>
#include <aquamarine/allocator/Dumb.hpp>
#include <sys/poll.h>
#include <thread>
#include <chrono>
@ -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;
}
}

View File

@ -932,6 +932,10 @@ SP<IAllocator> Aquamarine::CDRMBackend::preferredAllocator() {
return backend->primaryAllocator;
}
SP<IAllocator> Aquamarine::CDRMBackend::fallbackAllocator() {
return backend->fallbackAllocator;
}
bool Aquamarine::SDRMPlane::init(drmModePlane* plane) {
id = plane->plane_id;