safesight/src/utils/dma_alloc.cpp

178 lines
4.3 KiB
C++

#include "utils/dma_alloc.h"
#include <cerrno>
#include <cstring>
#include <iostream>
#if defined(__linux__)
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
// dma_heap ioctl definitions (linux/dma-heap.h may not be available)
struct dma_heap_allocation_data {
uint64_t len;
uint32_t fd;
uint32_t fd_flags;
uint64_t heap_flags;
};
#define DMA_HEAP_IOC_MAGIC 'H'
#define DMA_HEAP_IOCTL_ALLOC _IOWR(DMA_HEAP_IOC_MAGIC, 0x0, struct dma_heap_allocation_data)
// DMA-BUF sync ioctl
struct dma_buf_sync {
uint64_t flags;
};
#define DMA_BUF_SYNC_READ (1 << 0)
#define DMA_BUF_SYNC_WRITE (2 << 0)
#define DMA_BUF_SYNC_START (0 << 2)
#define DMA_BUF_SYNC_END (1 << 2)
#define DMA_BUF_BASE 'b'
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
#endif
namespace rk3588 {
DmaBuffer::~DmaBuffer() {
#if defined(__linux__)
if (ptr && size > 0) {
munmap(ptr, size);
ptr = nullptr;
}
if (fd >= 0) {
close(fd);
fd = -1;
}
#endif
size = 0;
}
DmaBuffer::DmaBuffer(DmaBuffer&& other) noexcept
: fd(other.fd), ptr(other.ptr), size(other.size) {
other.fd = -1;
other.ptr = nullptr;
other.size = 0;
}
DmaBuffer& DmaBuffer::operator=(DmaBuffer&& other) noexcept {
if (this != &other) {
#if defined(__linux__)
if (ptr && size > 0) {
munmap(ptr, size);
}
if (fd >= 0) {
close(fd);
}
#endif
fd = other.fd;
ptr = other.ptr;
size = other.size;
other.fd = -1;
other.ptr = nullptr;
other.size = 0;
}
return *this;
}
DmaBufferPtr DmaAlloc(size_t alloc_size) {
#if defined(__linux__)
// Try different dma_heap devices - prefer CMA for RGA compatibility (<4GB)
const char* heap_paths[] = {
"/dev/dma_heap/cma",
"/dev/dma_heap/cma-uncached",
"/dev/dma_heap/linux,cma",
"/dev/dma_heap/reserved",
"/dev/dma_heap/system-uncached",
"/dev/dma_heap/system",
nullptr
};
int heap_fd = -1;
const char* used_heap = nullptr;
for (int i = 0; heap_paths[i] != nullptr; ++i) {
heap_fd = open(heap_paths[i], O_RDWR | O_CLOEXEC);
if (heap_fd >= 0) {
used_heap = heap_paths[i];
break;
}
}
if (heap_fd < 0) {
std::cerr << "[DmaAlloc] failed to open dma_heap device: " << strerror(errno) << "\n";
std::cerr << "[DmaAlloc] tried: ";
for (int i = 0; heap_paths[i] != nullptr; ++i) {
std::cerr << heap_paths[i] << " ";
}
std::cerr << "\n";
return nullptr;
}
static bool first_alloc = true;
if (first_alloc) {
std::cout << "[DmaAlloc] using heap: " << used_heap << "\n";
first_alloc = false;
}
dma_heap_allocation_data alloc_data{};
alloc_data.len = alloc_size;
alloc_data.fd_flags = O_RDWR | O_CLOEXEC;
alloc_data.heap_flags = 0;
if (ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data) < 0) {
std::cerr << "[DmaAlloc] DMA_HEAP_IOCTL_ALLOC failed: " << strerror(errno) << "\n";
close(heap_fd);
return nullptr;
}
close(heap_fd);
int dma_fd = static_cast<int>(alloc_data.fd);
void* ptr = mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED, dma_fd, 0);
if (ptr == MAP_FAILED) {
std::cerr << "[DmaAlloc] mmap failed: " << strerror(errno) << "\n";
close(dma_fd);
return nullptr;
}
auto buf = std::make_shared<DmaBuffer>();
buf->fd = dma_fd;
buf->ptr = ptr;
buf->size = alloc_size;
return buf;
#else
(void)alloc_size;
std::cerr << "[DmaAlloc] not supported on this platform\n";
return nullptr;
#endif
}
void DmaSyncStart(DmaBuffer* buf) {
#if defined(__linux__)
if (!buf || buf->fd < 0) return;
dma_buf_sync sync{};
sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE;
ioctl(buf->fd, DMA_BUF_IOCTL_SYNC, &sync);
#else
(void)buf;
#endif
}
void DmaSyncEnd(DmaBuffer* buf) {
#if defined(__linux__)
if (!buf || buf->fd < 0) return;
dma_buf_sync sync{};
sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE;
ioctl(buf->fd, DMA_BUF_IOCTL_SYNC, &sync);
#else
(void)buf;
#endif
}
} // namespace rk3588