Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8026

Camera board • Re: Libcamera memcpy from mmap'd region very slow (CM4)

$
0
0
Hi Will,

I forgot to respond to this. If its still helpful, here is some pseudo code which works for me on Rpi4 with Bullseye.
Basically, you replace the DMA file descriptors libcamera allocates with one allocated manually from the CMA heap. The UniqueFd/SharedFD classes (part of libcamera) are memory managed wrappers of filedescriptors so setting new ones should in theory delete the previous ones automatically for you (when they go out scope - same as std::shared_ptr and std::unique_ptr)

After calling libcamera::FrameBufferAllocator::allocate(pStream) in your libcamera startup code, you'll want to find the DMA bufs for planes in the framebuffers, and replace them:

Code:

void ReplaceDMABufs(libcamera::FrameBuffer framebuffer){auto planes = framebuffer.planes();foreach(auto plane : planes){const auto& DMABufferName = std::string("dma") + std::to_string(BufferIndex++); // <-- Not really importantconst auto AlignedPlaneSize = J3Maths::RoundUp(Plane.length, 4096); // TODO: obtain alignment size programmaticallyauto DMAfd = libcamera::SharedFD(DMAHeap->Allocate(DMABufferName, AlignedPlaneSize));if (!DMAfd.isValid())error...Plane.fd = DMAfd;}}
Here is a class for allocating DMA bufs using the CMA heap:

Code:

class DMAHeap{public:DMAHeap(){static const std::vector<std::string> HeapNames = { "/dev/dma_heap/linux,cma", "/dev/dma_heap/reserved" };for (const auto& HeapName : HeapNames){auto Ret = ::open(HeapName.c_str(), O_RDWR, 0);if (Ret < 0) {Ret = errno;J3Log("Failed to open %s, error: %s", HeapName.c_str(), strerror(Ret));continue;}m_Handle = libcamera::UniqueFD(Ret);break;}if (!m_Handle.isValid())J3Log("Could not open any dmaHeap device");}~DMAHeap() = default;libcamera::UniqueFD Allocate(const std::string& Name, std::size_t Size){if (Name.empty())return {};struct dma_heap_allocation_data alloc = {};alloc.len = Size;alloc.fd_flags = O_CLOEXEC | O_RDWR;auto ret = ::ioctl(m_Handle.get(), DMA_HEAP_IOCTL_ALLOC, &alloc);if (ret < 0) {J3Log("dmaHeap allocation failure for %s", Name.c_str());return {};}libcamera::UniqueFD allocFd(alloc.fd);ret = ::ioctl(allocFd.get(), DMA_BUF_SET_NAME, Name.c_str());if (ret < 0) {J3Log("dmaHeap naming failure for %s", Name.c_str());return {};}return allocFd;}private:libcamera::UniqueFD m_Handle;};
And then make sure you wrap any memory mapped CPU access with DMA_BUF_IOCTL_SYNC something like this:

Code:

{...LockMappedBuffer(...);DoSomething(pMappedMemory);UnlockMappedBuffer(...);...}

Code:

static inline void LockMappedBuffer(const libcamera::FrameBuffer::Plane& BufferPlane, PC::IComputeBuffer::eMemoryHostAccess MemoryAccess = PC::IComputeBuffer::eMemoryHostAccess::READ_ONLY){dma_buf_sync syncStartFlags = { 0 };switch (MemoryAccess){case PC::IComputeBuffer::eMemoryHostAccess::READ_WRITE:syncStartFlags.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;break;case PC::IComputeBuffer::eMemoryHostAccess::READ_ONLY:syncStartFlags.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ;break;case PC::IComputeBuffer::eMemoryHostAccess::WRITE_ONLY:syncStartFlags.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE;break;default:J3AssertMsg(false, "Invalid memory access mode for Libcamera::LockMappedBuffer");break;}errno = 0;auto syncStartResult = ioctl(BufferPlane.fd.get(), DMA_BUF_IOCTL_SYNC, &syncStartFlags);while (syncStartResult != 0 && (errno == EINTR || errno == EAGAIN)) {errno = 0;syncStartResult = ioctl(BufferPlane.fd.get(), DMA_BUF_IOCTL_SYNC, &syncStartFlags);}J3Assert(syncStartResult == 0);}static inline void UnlockMappedBuffer(const libcamera::FrameBuffer::Plane& BufferPlane, PC::IComputeBuffer::eMemoryHostAccess MemoryAccess = PC::IComputeBuffer::eMemoryHostAccess::READ_ONLY){dma_buf_sync syncEndFlags = { 0 };switch (MemoryAccess){case PC::IComputeBuffer::eMemoryHostAccess::READ_WRITE:syncEndFlags.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;break;case PC::IComputeBuffer::eMemoryHostAccess::READ_ONLY:syncEndFlags.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;break;case PC::IComputeBuffer::eMemoryHostAccess::WRITE_ONLY:syncEndFlags.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE;break;default:J3AssertMsg(false, "Invalid memory access mode for Libcamera::UnlockMappedBuffer");break;}errno = 0;auto syncEndResult = ioctl(BufferPlane.fd.get(), DMA_BUF_IOCTL_SYNC, &syncEndFlags);while (syncEndResult != 0 && (errno == EINTR || errno == EAGAIN)) {errno = 0;syncEndResult = ioctl(BufferPlane.fd.get(), DMA_BUF_IOCTL_SYNC, &syncEndFlags);}J3Assert(syncEndResult == 0);}

Statistics: Posted by PeartreeStudios — Thu Jan 25, 2024 12:44 am



Viewing all articles
Browse latest Browse all 8026

Trending Articles