From patchwork Mon Aug 8 21:48:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17030 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 B6FB0C3272 for ; Mon, 8 Aug 2022 21:49:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0794363327; Mon, 8 Aug 2022 23:49:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1659995345; bh=O8NTOBXaio3ZAHaumbxSJA6EAfzLoU3YloAPeokh/XE=; 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=Ul/ybUDDQOCEOV43PMY2+MFTLfL1uBxHIOKGShCR3pAsWGti6IU0GYgmcCrhIdvup 80dxGP5pK/0D+D/Z3uggh4fYYhM1GtcPCtyWbQkUMF83eGMvBGVHWJLkO0vPj2ZmID s94tYHY5rsQ0x3ejGoa3rp9t5n/6bmN/fIJh5B3uXn1VU3tlx0mrcv47srDKENjLDm HpB0rILTEWVySD6UINwoXRvH7glOZ4g+Bopp3PFsTc8StMD3km1C7wEpVZOQcYET1r 7x/efFyhNriakraNR+m2LmJEsRsT0E+r5QyGQCyRmzt+miSyoZGRx2E96E0WjjEVu/ AvoKihOMuChVA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BC71463315 for ; Mon, 8 Aug 2022 23:49:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="GPcWFqAB"; 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 33735481; Mon, 8 Aug 2022 23:49:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1659995342; bh=O8NTOBXaio3ZAHaumbxSJA6EAfzLoU3YloAPeokh/XE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GPcWFqABUHojmR/71r41fA2PCf8BROEzK74tviJTL3O61Dkoio4YDJk6Pe9NQ5eUR Q4fR+UjUXrlWplpvnvWoPw5gQ1MJVGJDtb4vrZxmaJIUllHIeN1SC6T33jTZihokMs dz246eh4WOmNmz40PtVLCYxc64l2sdaaAOLYduyk= To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Aug 2022 00:48:51 +0300 Message-Id: <20220808214851.30804-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220807180100.396-4-laurent.pinchart@ideasonboard.com> References: <20220807180100.396-4-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1.1 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 fiyr 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 Reviewed-by: Kieran Bingham --- Changes since v1: - Maintain the aspect ratio if possible --- src/cam/kms_sink.cpp | 109 +++++++++++++++++++++++++++++++++++++++---- src/cam/kms_sink.h | 8 ++++ 2 files changed, 109 insertions(+), 8 deletions(-) diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp index 16435ede6b6a..17e2fa69bff7 100644 --- a/src/cam/kms_sink.cpp +++ b/src/cam/kms_sink.cpp @@ -284,6 +284,94 @@ 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, preserving aspect ratio. */ + libcamera::Rectangle src = framebuffer; + libcamera::Rectangle dst = display.size().boundedToAspectRatio(framebuffer.size()) + .centeredTo(display.center()); + + if (testModeSet(drmBuffer, src, dst)) { + std::cout << "KMS: full-screen scaled output, square pixels" + << std::endl; + src_ = src; + dst_ = dst; + return true; + } + + /* + * 2. Scale the frame buffer to full screen, without preserving aspect + * ratio. + */ + src = framebuffer; + dst = display; + + if (testModeSet(drmBuffer, src, dst)) { + std::cout << "KMS: full-screen scaled output, non-square pixels" + << std::endl; + src_ = src; + dst_ = dst; + return true; + } + + /* 3. 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; + } + + /* 4. 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 +395,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_;