cam: drm: Support per-plane stride values

The stride is not always identical for all planes for multi-planar
formats. Semi-planar YUV formats without horizontal subsampling often
have a chroma stride equal to twice the luma stride, and tri-planar YUV
formats with a 1/2 horizontal subsampling often have a chroma stride
equal to half the luma stride. This isn't correctly taken into account
when creating a DRM frame buffer, as the same stride is set for all
planes.

libcamera doesn't report per-plane stride values yet, but uses chroma
strides that match the above description for all currently supported
platforms. Calculation the chrome strides appropriately in the KMSSink
class, and pass them to DRM::createFrameBuffer().

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2021-09-05 23:24:29 +03:00
parent f8f6bc657d
commit 843048499f
3 changed files with 34 additions and 6 deletions

View file

@ -595,12 +595,12 @@ const Object *Device::object(uint32_t id)
std::unique_ptr<FrameBuffer> Device::createFrameBuffer( std::unique_ptr<FrameBuffer> Device::createFrameBuffer(
const libcamera::FrameBuffer &buffer, const libcamera::FrameBuffer &buffer,
const libcamera::PixelFormat &format, const libcamera::PixelFormat &format,
const libcamera::Size &size, unsigned int stride) const libcamera::Size &size,
const std::array<uint32_t, 4> &strides)
{ {
std::unique_ptr<FrameBuffer> fb{ new FrameBuffer(this) }; std::unique_ptr<FrameBuffer> fb{ new FrameBuffer(this) };
uint32_t handles[4] = {}; uint32_t handles[4] = {};
uint32_t pitches[4] = {};
uint32_t offsets[4] = {}; uint32_t offsets[4] = {};
int ret; int ret;
@ -623,13 +623,12 @@ std::unique_ptr<FrameBuffer> Device::createFrameBuffer(
fb->planes_.push_back({ handle }); fb->planes_.push_back({ handle });
handles[i] = handle; handles[i] = handle;
pitches[i] = stride;
offsets[i] = 0; /* TODO */ offsets[i] = 0; /* TODO */
++i; ++i;
} }
ret = drmModeAddFB2(fd_, size.width, size.height, format.fourcc(), handles, ret = drmModeAddFB2(fd_, size.width, size.height, format.fourcc(), handles,
pitches, offsets, &fb->id_, 0); strides.data(), offsets, &fb->id_, 0);
if (ret < 0) { if (ret < 0) {
ret = -errno; ret = -errno;
std::cerr std::cerr

View file

@ -7,9 +7,11 @@
#ifndef __CAM_DRM_H__ #ifndef __CAM_DRM_H__
#define __CAM_DRM_H__ #define __CAM_DRM_H__
#include <array>
#include <list> #include <list>
#include <map> #include <map>
#include <memory> #include <memory>
#include <stdint.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -298,7 +300,8 @@ public:
std::unique_ptr<FrameBuffer> createFrameBuffer( std::unique_ptr<FrameBuffer> createFrameBuffer(
const libcamera::FrameBuffer &buffer, const libcamera::FrameBuffer &buffer,
const libcamera::PixelFormat &format, const libcamera::PixelFormat &format,
const libcamera::Size &size, unsigned int stride); const libcamera::Size &size,
const std::array<uint32_t, 4> &strides);
libcamera::Signal<AtomicRequest *> requestComplete; libcamera::Signal<AtomicRequest *> requestComplete;

View file

@ -7,10 +7,12 @@
#include "kms_sink.h" #include "kms_sink.h"
#include <array>
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <libcamera/camera.h> #include <libcamera/camera.h>
@ -65,8 +67,32 @@ KMSSink::KMSSink(const std::string &connectorName)
void KMSSink::mapBuffer(libcamera::FrameBuffer *buffer) void KMSSink::mapBuffer(libcamera::FrameBuffer *buffer)
{ {
std::array<uint32_t, 4> strides = {};
/* \todo Should libcamera report per-plane strides ? */
unsigned int uvStrideMultiplier;
switch (format_) {
case libcamera::formats::NV24:
case libcamera::formats::NV42:
uvStrideMultiplier = 4;
break;
case libcamera::formats::YUV420:
case libcamera::formats::YVU420:
case libcamera::formats::YUV422:
uvStrideMultiplier = 1;
break;
default:
uvStrideMultiplier = 2;
break;
}
strides[0] = stride_;
for (unsigned int i = 1; i < buffer->planes().size(); ++i)
strides[i] = stride_ * uvStrideMultiplier / 2;
std::unique_ptr<DRM::FrameBuffer> drmBuffer = std::unique_ptr<DRM::FrameBuffer> drmBuffer =
dev_.createFrameBuffer(*buffer, format_, size_, stride_); dev_.createFrameBuffer(*buffer, format_, size_, strides);
if (!drmBuffer) if (!drmBuffer)
return; return;