Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dumb allocator #31

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions include/aquamarine/allocator/Dumb.hpp
Original file line number Diff line number Diff line change
@@ -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;
};
};
1 change: 1 addition & 0 deletions include/aquamarine/allocator/Swapchain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ namespace Aquamarine {
int lastAcquired = 0;

friend class CGBMBuffer;
friend class CDumbBuffer;
};
};
6 changes: 5 additions & 1 deletion include/aquamarine/backend/Backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, no, no. The dumb allocator doesn't really hold any big allocs, so it should be per-drm-backend (can be always present, no big deal)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't really understand what needs to be done here. How HL should get access to dumb allocator?

Copy link
Member

@vaxerski vaxerski Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in CDRMBackend SP<CDumbAllocator>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then it can ->output->backend, cast that to drm and ->dumballocator

return nullptr;
};
virtual std::vector<SDRMFormat> getRenderableFormats(); // empty = use getRenderFormats
};

class CBackend {
Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions include/aquamarine/backend/DRM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/aquamarine/buffer/Buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace Aquamarine {
BUFFER_TYPE_DMABUF = 0,
BUFFER_TYPE_SHM,
BUFFER_TYPE_MISC,
BUFFER_TYPE_DUMB,
};

class CWLBufferResource;
Expand Down
190 changes: 190 additions & 0 deletions src/allocator/Dumb.cpp
Original file line number Diff line number Diff line change
@@ -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_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;
}
7 changes: 3 additions & 4 deletions src/allocator/GBM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,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;

Expand Down Expand Up @@ -199,7 +198,7 @@ Aquamarine::CGBMBuffer::~CGBMBuffer() {
}

eBufferCapability Aquamarine::CGBMBuffer::caps() {
return (Aquamarine::eBufferCapability)0;
return BUFFER_CAPABILITY_DATAPTR;
}

eBufferType Aquamarine::CGBMBuffer::type() {
Expand All @@ -215,7 +214,7 @@ bool Aquamarine::CGBMBuffer::isSynchronous() {
}

bool Aquamarine::CGBMBuffer::good() {
return true;
return attrs.success;
}

SDMABUFAttrs Aquamarine::CGBMBuffer::dmabuf() {
Expand Down
4 changes: 3 additions & 1 deletion src/backend/Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}
}
Expand Down
Loading
Loading