[libcamera-devel] [PATCH v5] cam: kms_sink: Remove limitation that camera and display must match

Laurent Pinchart laurent.pinchart at ideasonboard.com
Sun Jun 19 02:27:01 CEST 2022


From: Eric Curtin <ecurtin at redhat.com>

There is a limitation that requires input and output to be pixel
for pixel identical in terms of height and width. Remove this
limitation to enable more hardware that doesn't match. Just start
drawing from top left 0, 0 corner.

Signed-off-by: Eric Curtin <ecurtin at redhat.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
Hi Eric,

This is an extension of your patch that picks the mode closest to the
stream size if there is no exact match. It improves mode selection on my
board. Could you please test it ?
---
 src/cam/kms_sink.cpp | 45 +++++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp
index 7add81a64334..37a3bd50a2bf 100644
--- a/src/cam/kms_sink.cpp
+++ b/src/cam/kms_sink.cpp
@@ -11,6 +11,7 @@
 #include <algorithm>
 #include <assert.h>
 #include <iostream>
+#include <limits.h>
 #include <memory>
 #include <stdint.h>
 #include <string.h>
@@ -112,14 +113,32 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)
 
 	const libcamera::StreamConfiguration &cfg = config.at(0);
 
+	/* Find the best mode for the stream size. */
 	const std::vector<DRM::Mode> &modes = connector_->modes();
-	const auto iter = std::find_if(modes.begin(), modes.end(),
-				       [&](const DRM::Mode &mode) {
-					       return mode.hdisplay == cfg.size.width &&
-						      mode.vdisplay == cfg.size.height;
-				       });
-	if (iter == modes.end()) {
-		std::cerr << "No mode matching " << cfg.size << std::endl;
+
+	unsigned int cfgArea = cfg.size.width * cfg.size.height;
+	unsigned int bestDistance = UINT_MAX;
+
+	for (const DRM::Mode &mode : modes) {
+		unsigned int modeArea = mode.hdisplay * mode.vdisplay;
+		unsigned int distance = modeArea > cfgArea ? modeArea - cfgArea
+				      : cfgArea - modeArea;
+
+		if (distance < bestDistance) {
+			mode_ = &mode;
+			bestDistance = distance;
+
+			/*
+			 * If the sizes match exactly, there will be no better
+			 * match.
+			 */
+			if (distance == 0)
+				break;
+		}
+	}
+
+	if (!mode_) {
+		std::cerr << "No modes\n";
 		return -EINVAL;
 	}
 
@@ -127,7 +146,6 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)
 	if (ret < 0)
 		return ret;
 
-	mode_ = &*iter;
 	size_ = cfg.size;
 	stride_ = cfg.stride;
 
@@ -202,7 +220,8 @@ int KMSSink::configurePipeline(const libcamera::PixelFormat &format)
 	std::cout
 		<< "Using KMS plane " << plane_->id() << ", CRTC " << crtc_->id()
 		<< ", connector " << connector_->name()
-		<< " (" << connector_->id() << ")" << std::endl;
+		<< " (" << connector_->id() << "), mode " << mode_->hdisplay
+		<< "x" << mode_->vdisplay << "@" << mode_->vrefresh << std::endl;
 
 	return 0;
 }
@@ -295,12 +314,12 @@ bool KMSSink::processRequest(libcamera::Request *camRequest)
 		drmRequest->addProperty(plane_, "CRTC_ID", crtc_->id());
 		drmRequest->addProperty(plane_, "SRC_X", 0 << 16);
 		drmRequest->addProperty(plane_, "SRC_Y", 0 << 16);
-		drmRequest->addProperty(plane_, "SRC_W", mode_->hdisplay << 16);
-		drmRequest->addProperty(plane_, "SRC_H", mode_->vdisplay << 16);
+		drmRequest->addProperty(plane_, "SRC_W", size_.width << 16);
+		drmRequest->addProperty(plane_, "SRC_H", size_.height << 16);
 		drmRequest->addProperty(plane_, "CRTC_X", 0);
 		drmRequest->addProperty(plane_, "CRTC_Y", 0);
-		drmRequest->addProperty(plane_, "CRTC_W", mode_->hdisplay);
-		drmRequest->addProperty(plane_, "CRTC_H", mode_->vdisplay);
+		drmRequest->addProperty(plane_, "CRTC_W", size_.width);
+		drmRequest->addProperty(plane_, "CRTC_H", size_.height);
 
 		flags |= DRM::AtomicRequest::FlagAllowModeset;
 	}

-- 
Regards,

Laurent Pinchart



More information about the libcamera-devel mailing list