From patchwork Sun Aug 7 18:00:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17015 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id DF2ABC3272 for ; Sun, 7 Aug 2022 18:01:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8FD2B63312; Sun, 7 Aug 2022 20:01:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1659895273; bh=I+jNgFIS+tYoVjGigewxj3/nQWAU2L2qv8r2TpTkgg4=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=ajIRlJEPPGJpCXUyxaGfENXIVG2dxFUq1GZLgEtdqQyLzILuQCkcwyXZscD042iJF jDmwUQ6M7cR0gc0PwMVL4Cbx9skWOUSGgI963fucV/IXNQnHt86+276vj73S7bz+DQ 89lsoK1u9TIrMqOr6wgkQdwywwNcQJFFFC4imjY8pQ9k0sqpFrlJRJEqSmShSKG1Cj MSi8YQIrvAq8rd4Rm5HcNZXwBKSV8/Xfz/FGCjozxTISGEN6T82xpakUK4MTH7t4UM DV1WHiWut49IDKBlqUvNWTnXDu60AinF1o0Kp4rP9I2xABaOFGzcSuvJbqN+vFjdNh n9Z0sIco4HnCA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A57163312 for ; Sun, 7 Aug 2022 20:01:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IryRgv02"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3311787F; Sun, 7 Aug 2022 20:01:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1659895271; bh=I+jNgFIS+tYoVjGigewxj3/nQWAU2L2qv8r2TpTkgg4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IryRgv02XuczyERoS40jFL8lLT6qC2CwdcaC3ght3rb7fDBvjjGHFP4sSsJCj/izv LPC9ue9XOi6D20SzXqEijBwfKvMBTWx1TKMHzVFdfiCMOcz1ZSbuhqqloz0Q827aNF o7H0B6lypDAuIA+XMkuC31SZGaz39ByU91BlR+aE= To: libcamera-devel@lists.libcamera.org Date: Sun, 7 Aug 2022 21:00:58 +0300 Message-Id: <20220807180100.396-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220807180100.396-1-laurent.pinchart@ideasonboard.com> References: <20220807180100.396-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/3] cam: drm: Add support for test-only commits X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Test-only commits are used to test a commit without applying any modification to the device. This will be used by the KMS sink to test feature support. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Eric Curtin --- src/cam/drm.cpp | 2 ++ src/cam/drm.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp index fbfc0a595d36..b0602c942853 100644 --- a/src/cam/drm.cpp +++ b/src/cam/drm.cpp @@ -377,6 +377,8 @@ int AtomicRequest::commit(unsigned int flags) drmFlags |= DRM_MODE_ATOMIC_ALLOW_MODESET; if (flags & FlagAsync) drmFlags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK; + if (flags & FlagTestOnly) + drmFlags |= DRM_MODE_ATOMIC_TEST_ONLY; return drmModeAtomicCommit(dev_->fd(), request_, drmFlags, this); } diff --git a/src/cam/drm.h b/src/cam/drm.h index 655a7509c001..ebaea04d3974 100644 --- a/src/cam/drm.h +++ b/src/cam/drm.h @@ -251,6 +251,7 @@ public: enum Flags { FlagAllowModeset = (1 << 0), FlagAsync = (1 << 1), + FlagTestOnly = (1 << 2), }; AtomicRequest(Device *dev); From patchwork Sun Aug 7 18:00:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17016 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BF2D4C3272 for ; Sun, 7 Aug 2022 18:01:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 17F7D63332; Sun, 7 Aug 2022 20:01:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1659895275; bh=wYfz9+aPgxCtDCWKhZd5OrCfMyu7hutN/qxqf3+DEpU=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=VRjVUOlcIjhi4k5rM4HcSlp/uKuHVMpUzYrPrzAwjPSglhKsGSFL46OrTZ4ZAhFah O79wytaCbWSG1I3xCKeTBj59GeeHm/n6DrV0oa1FKo2VXq0CX1CAtCkuetpNK3Rp09 ddwC5siT5J+3l+WAolCstO11zh8c9enlVgrVq2y3TZwWBWM8k4Q1TcoYJVVXSLkGRA sQ1wApLE5sl+WgYpAEkTtyUD6fXfuuximGDvCultqWyuHdebzT8eeF+/pH6HG/b1E8 Bir7OrE5RslbCnIZyeCOxzZVGzAJ4eGFbhOLwoonD26EP7fosAAmARxmPY1p4ma8xX /Zlrb2PqZsEEA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2CFC16332E for ; Sun, 7 Aug 2022 20:01:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="eVY9UIaR"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A01C69DA; Sun, 7 Aug 2022 20:01:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1659895272; bh=wYfz9+aPgxCtDCWKhZd5OrCfMyu7hutN/qxqf3+DEpU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eVY9UIaRCeDRCabs6v5/kwwtGFVygPHDVjzEWAfP9EYzdUhd/8Ju7U/nI8C39Xntz JSjP95721ly7A0xmv2Jxs4piEfys+pNcKaMHTqL1SZBzNbF4E7CRff+hGV0jBLexm4 oD3CTGtW1QlfCcGYnKGohVenV6eqkS1LPlk13uEE= To: libcamera-devel@lists.libcamera.org Date: Sun, 7 Aug 2022 21:00:59 +0300 Message-Id: <20220807180100.396-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220807180100.396-1-laurent.pinchart@ideasonboard.com> References: <20220807180100.396-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/3] cam: kms_sink: Make lifetime management of DRM request safer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The drmRequest is KMSSink::processRequest() is created as a naked pointer, passed to the constructor of the KMSSink::Request object that stores it in a std::unique_ptr<>, and used later in the function. The current implementation is safe, but could be prone to both memory leaks and use-after-free bugs if modified. Improve it by replacing the naked pointer with a std::unique_ptr<>. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Eric Curtin --- src/cam/kms_sink.cpp | 7 ++++--- src/cam/kms_sink.h | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp index 37a3bd50a2bf..16435ede6b6a 100644 --- a/src/cam/kms_sink.cpp +++ b/src/cam/kms_sink.cpp @@ -301,7 +301,8 @@ bool KMSSink::processRequest(libcamera::Request *camRequest) DRM::FrameBuffer *drmBuffer = iter->second.get(); unsigned int flags = DRM::AtomicRequest::FlagAsync; - DRM::AtomicRequest *drmRequest = new DRM::AtomicRequest(&dev_); + std::unique_ptr drmRequest = + std::make_unique(&dev_); drmRequest->addProperty(plane_, "FB_ID", drmBuffer->id()); if (!active_ && !queued_) { @@ -324,12 +325,12 @@ bool KMSSink::processRequest(libcamera::Request *camRequest) flags |= DRM::AtomicRequest::FlagAllowModeset; } - pending_ = std::make_unique(drmRequest, camRequest); + pending_ = std::make_unique(std::move(drmRequest), camRequest); std::lock_guard lock(lock_); if (!queued_) { - int ret = drmRequest->commit(flags); + int ret = pending_->drmRequest_->commit(flags); if (ret < 0) { std::cerr << "Failed to commit atomic request: " diff --git a/src/cam/kms_sink.h b/src/cam/kms_sink.h index 4a0a872cb653..8f5f08667cea 100644 --- a/src/cam/kms_sink.h +++ b/src/cam/kms_sink.h @@ -38,8 +38,9 @@ private: class Request { public: - Request(DRM::AtomicRequest *drmRequest, libcamera::Request *camRequest) - : drmRequest_(drmRequest), camRequest_(camRequest) + Request(std::unique_ptr drmRequest, + libcamera::Request *camRequest) + : drmRequest_(std::move(drmRequest)), camRequest_(camRequest) { } From patchwork Sun Aug 7 18:01:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17017 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id B6F50C3272 for ; Sun, 7 Aug 2022 18:01:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 793CF6332C; Sun, 7 Aug 2022 20:01:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1659895277; bh=Dm1ig5xeC1QUDBLV1JhWKZs9FDz9jlFFiDVsAReKptI=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=KvgwVWjqZI3+yAHgNmf7n4LWPN8RmRhaMVpdmjsLDsPOn1vG2LPO4OePMiPqOYJa4 Sxrfc+nkVIBMJgcKG0BbVhQIuvc1ElHsAH1AI3SwgCf0rAGqkTnnjRYSo/VUvI+2P/ thbYdPj6FGLF4xPOct7SWvCQDSZf9DjsxNwpgIxzPnzb4F12cXsxmkrsNEdu+iwCXT +J6SjaYhuc/qtrQMZFK8/9fvTeLLeOpBC+e+HIcPXEcjrt+W8I2UaIMhfS7AqyWAVF R64fEaAS8Ajh0lWw7gM8QOd9Jbpq6bwNUea4Mdae7fyLD/QuFrNjbVWJMLMHd4icwi Xh1E9wv4aZt4A== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 496ED6332B for ; Sun, 7 Aug 2022 20:01:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="TvqwyJRg"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DA63F749; Sun, 7 Aug 2022 20:01:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1659895274; bh=Dm1ig5xeC1QUDBLV1JhWKZs9FDz9jlFFiDVsAReKptI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TvqwyJRgj+WpNTcDJCXMTAYikXzysfmT7hAU5mGWAwqxaJ6jLXNm+fQLsP9IkdIDw tVPhr9LLcyp8sNQTj1FOSaomqVmpEWXw+yqePpFepiOodz45vIhNEJ05iyf03vNTZo hhracaDpH9DIQu8/mIMfYDTNlxJq+NsJdNyDGgIA= To: libcamera-devel@lists.libcamera.org Date: Sun, 7 Aug 2022 21:01:00 +0300 Message-Id: <20220807180100.396-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220807180100.396-1-laurent.pinchart@ideasonboard.com> References: <20220807180100.396-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/3] cam: kms_sink: Scale the frame buffer to full screen if supported X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The KMS sink currently displays the frame buffer on the top-left corner of the screen, resulting in either a black area on the bottom and right sides (if the frame buffer is smaller than the display resolution) of in a restricted field of view (if the frame buffer is larger than the display resolution). Improve this by scaling the frame buffer to full screen if supported, and aligning the crop rectangle to the frame buffer center if the field of view needs to be restricted. The implementation test three possible composition options, from best to worst. The tests are performed when the camera is started, as testing atomic commits requires access to frame buffer objects, which are not available at configure time. Changing this would require either a large refactoring of the cam application to provide frame buffers earlier, or extending the KMS API to support testing commits with dummy buffer objects. Both are candidates for later development. Signed-off-by: Laurent Pinchart Reviewed-by: Eric Curtin --- src/cam/kms_sink.cpp | 92 ++++++++++++++++++++++++++++++++++++++++---- src/cam/kms_sink.h | 8 ++++ 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp index 16435ede6b6a..2f306955cf51 100644 --- a/src/cam/kms_sink.cpp +++ b/src/cam/kms_sink.cpp @@ -284,6 +284,77 @@ int KMSSink::stop() return FrameSink::stop(); } +bool KMSSink::testModeSet(DRM::FrameBuffer *drmBuffer, + const libcamera::Rectangle &src, + const libcamera::Rectangle &dst) +{ + DRM::AtomicRequest drmRequest{ &dev_ }; + + drmRequest.addProperty(connector_, "CRTC_ID", crtc_->id()); + + drmRequest.addProperty(crtc_, "ACTIVE", 1); + drmRequest.addProperty(crtc_, "MODE_ID", mode_->toBlob(&dev_)); + + drmRequest.addProperty(plane_, "CRTC_ID", crtc_->id()); + drmRequest.addProperty(plane_, "FB_ID", drmBuffer->id()); + drmRequest.addProperty(plane_, "SRC_X", src.x << 16); + drmRequest.addProperty(plane_, "SRC_Y", src.y << 16); + drmRequest.addProperty(plane_, "SRC_W", src.width << 16); + drmRequest.addProperty(plane_, "SRC_H", src.height << 16); + drmRequest.addProperty(plane_, "CRTC_X", dst.x); + drmRequest.addProperty(plane_, "CRTC_Y", dst.y); + drmRequest.addProperty(plane_, "CRTC_W", dst.width); + drmRequest.addProperty(plane_, "CRTC_H", dst.height); + + return !drmRequest.commit(DRM::AtomicRequest::FlagAllowModeset | + DRM::AtomicRequest::FlagTestOnly); +} + +bool KMSSink::setupComposition(DRM::FrameBuffer *drmBuffer) +{ + /* + * Test composition options, from most to least desirable, to select the + * best one. + */ + const libcamera::Rectangle framebuffer{ size_ }; + const libcamera::Rectangle display{ 0, 0, mode_->hdisplay, mode_->vdisplay }; + + /* 1. Scale the frame buffer to full screen. */ + libcamera::Rectangle src = libcamera::Rectangle{ size_ }; + libcamera::Rectangle dst = display; + + if (testModeSet(drmBuffer, src, dst)) { + std::cout << "KMS: full-screen scaled output" << std::endl; + src_ = src; + dst_ = dst; + return true; + } + + /* 2. Center the frame buffer on the display. */ + src = display.size().centeredTo(framebuffer.center()).boundedTo(framebuffer); + dst = framebuffer.size().centeredTo(display.center()).boundedTo(display); + + if (testModeSet(drmBuffer, src, dst)) { + std::cout << "KMS: centered output" << std::endl; + src_ = src; + dst_ = dst; + return true; + } + + /* 3. Align the frame buffer on the top-left of the display. */ + src = framebuffer.boundedTo(display); + dst = display.boundedTo(framebuffer); + + if (testModeSet(drmBuffer, src, dst)) { + std::cout << "KMS: top-left aligned output" << std::endl; + src_ = src; + dst_ = dst; + return true; + } + + return false; +} + bool KMSSink::processRequest(libcamera::Request *camRequest) { /* @@ -307,20 +378,25 @@ bool KMSSink::processRequest(libcamera::Request *camRequest) if (!active_ && !queued_) { /* Enable the display pipeline on the first frame. */ + if (!setupComposition(drmBuffer)) { + std::cerr << "Failed to setup composition" << std::endl; + return true; + } + drmRequest->addProperty(connector_, "CRTC_ID", crtc_->id()); drmRequest->addProperty(crtc_, "ACTIVE", 1); drmRequest->addProperty(crtc_, "MODE_ID", mode_->toBlob(&dev_)); 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", 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", size_.width); - drmRequest->addProperty(plane_, "CRTC_H", size_.height); + drmRequest->addProperty(plane_, "SRC_X", src_.x << 16); + drmRequest->addProperty(plane_, "SRC_Y", src_.y << 16); + drmRequest->addProperty(plane_, "SRC_W", src_.width << 16); + drmRequest->addProperty(plane_, "SRC_H", src_.height << 16); + drmRequest->addProperty(plane_, "CRTC_X", dst_.x); + drmRequest->addProperty(plane_, "CRTC_Y", dst_.y); + drmRequest->addProperty(plane_, "CRTC_W", dst_.width); + drmRequest->addProperty(plane_, "CRTC_H", dst_.height); flags |= DRM::AtomicRequest::FlagAllowModeset; } diff --git a/src/cam/kms_sink.h b/src/cam/kms_sink.h index 8f5f08667cea..76c4e611bf85 100644 --- a/src/cam/kms_sink.h +++ b/src/cam/kms_sink.h @@ -50,6 +50,11 @@ private: int selectPipeline(const libcamera::PixelFormat &format); int configurePipeline(const libcamera::PixelFormat &format); + bool testModeSet(DRM::FrameBuffer *drmBuffer, + const libcamera::Rectangle &src, + const libcamera::Rectangle &dst); + bool setupComposition(DRM::FrameBuffer *drmBuffer); + void requestComplete(DRM::AtomicRequest *request); DRM::Device dev_; @@ -63,6 +68,9 @@ private: libcamera::Size size_; unsigned int stride_; + libcamera::Rectangle src_; + libcamera::Rectangle dst_; + std::map> buffers_; std::mutex lock_;