From patchwork Fri Oct 9 19:40:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Mader X-Patchwork-Id: 28433 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 822ACC3305 for ; Fri, 9 Oct 2026 19:40:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7A1B868A36; Fri, 9 Oct 2026 21:40:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=collabora.com header.i=robert.mader@collabora.com header.b="WNpTXbXy"; dkim-atps=neutral Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3853468A2B for ; Fri, 9 Oct 2026 21:40:39 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1791574836; cv=none; d=zohomail.com; s=zohoarc; b=ETpS4wxCugm3Rl6pMZ54rNKp8is30svkz3AQdHA3ItfNuOOTJ8QLQFt7ber56tmnrM01zolGXH1Qirc1Biii7ypItdJIrpLFaol6fQ+CbAKAsK33YDDm8YFtN+7mA9kOMHzI2YSXxFzC8kn97U0hL0hRskbdg0SS99VQ5ImBnDI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1791574836; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=mUgINCyECrWqZtk3yx6T4m8p+rnHi01f5hgL1xkhNAk=; b=TvrNQux28rCH8PHnP8mNlmHirnXb0xB5WO290yYw9SemnCfjRFB+L/bvtMwhw6P7id+FJAJx4xC+961eKRS/awbXu9ko13N4E2LsvFRcd/VM95pbc8HPKGwD08xC0woFLpqJSbH1ztiZVag8uQLWtO0mBzpzPpH7Bxz+I8woOjU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=robert.mader@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1791574836; s=zohomail; d=collabora.com; i=robert.mader@collabora.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:In-Reply-To:MIME-Version:Content-Transfer-Encoding:Message-Id:Reply-To; bh=mUgINCyECrWqZtk3yx6T4m8p+rnHi01f5hgL1xkhNAk=; b=WNpTXbXyvv3VSQl5rv1NfF9dC4TtAk+rXDN6HbcCWwwvlRfsYPPn1apJCqFIuX1Q 7TIx/BBlLcOpzWEhKszrSp8LiRrTFPMNUVG1VhpluGlkjAKz3SosIbyH5Ejofn5Osdv LgSGF+NTgVGA3RhTeU5d7QIFscpyEAp0NOSMY7pI= Received: by smtp.zohomail.com with SMTPS id 1791574835930936.4345989161416; Fri, 9 Oct 2026 12:40:35 -0700 (PDT) From: Robert Mader To: libcamera-devel@lists.libcamera.org Cc: Robert Mader Subject: [PATCH v2 4/4] virtual: Align strides to 256 bytes Date: Fri, 9 Oct 2026 21:40:07 +0200 Message-ID: <20261009194007.23175-5-robert.mader@collabora.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261009194007.23175-1-robert.mader@collabora.com> References: <20261009194007.23175-1-robert.mader@collabora.com> MIME-Version: 1.0 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" This patch was originally developed to help debugging and testing https://webrtc-review.googlesource.com/c/src/+/491680, however I see some benefits in always doing it: 1. It is common for hardware ISPs to have some stride alignment - even though usually somewhat lower. Using the given alignment should thus help ensure that clients implement stride handling correctly, preventing cases like the one linked above where a major implemention went without that - unnocited - for quite a long time. 2. It makes it more likely that output buffers can be imported by GPUs and display engines. 2. It paves the way for GPU-accelerated frame generators (similar to DebayerEGL), which may become desirable going forward in order to provide high resolution / high framerate / high bit-depth / HDR content. Signed-off-by: Robert Mader --- .../pipeline/virtual/frame_generator.h | 1 + .../virtual/image_frame_generator.cpp | 23 ++++++++++--------- .../virtual/test_pattern_generator.cpp | 18 ++++++++++----- src/libcamera/pipeline/virtual/virtual.cpp | 9 +++++--- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/libcamera/pipeline/virtual/frame_generator.h b/src/libcamera/pipeline/virtual/frame_generator.h index fd34a91a5e50..d575c28a3ce0 100644 --- a/src/libcamera/pipeline/virtual/frame_generator.h +++ b/src/libcamera/pipeline/virtual/frame_generator.h @@ -23,6 +23,7 @@ public: virtual int generateFrame(const StreamConfiguration &cfg, const FrameBuffer *buffer) = 0; + static constexpr unsigned int kStrideAlignment = 256; protected: FrameGenerator() {} }; diff --git a/src/libcamera/pipeline/virtual/image_frame_generator.cpp b/src/libcamera/pipeline/virtual/image_frame_generator.cpp index 5c56db96d8e2..be5633050a11 100644 --- a/src/libcamera/pipeline/virtual/image_frame_generator.cpp +++ b/src/libcamera/pipeline/virtual/image_frame_generator.cpp @@ -110,11 +110,6 @@ void ImageFrameGenerator::configure(const Size &size) std::make_unique(halfSizeWidth * halfSizeHeight * 2); auto &src = imageFrameDatas_[i]; - /* - * \todo Some platforms might enforce stride due to GPU. - * The width needs to be a multiple of the stride to work - * properly for now. - */ libyuv::NV12Scale(src.Y.get(), src.size.width, src.UV.get(), src.size.width, src.size.width, src.size.height, @@ -158,9 +153,11 @@ int ImageFrameGenerator::generateFrame(const StreamConfiguration &cfg, const Fra scaledFrameDatas_[frameIndex_].UV.get(), size.width, planes[0].data(), - info.stride(size.width, 0), + info.stride(size.width, 0, + kStrideAlignment), planes[1].data(), - info.stride(size.width, 1), + info.stride(size.width, 1, + kStrideAlignment), size.width, size.height); break; case formats::YUV420: @@ -169,11 +166,14 @@ int ImageFrameGenerator::generateFrame(const StreamConfiguration &cfg, const Fra scaledFrameDatas_[frameIndex_].UV.get(), size.width, planes[0].data(), - info.stride(size.width, 0), + info.stride(size.width, 0, + kStrideAlignment), planes[1].data(), - info.stride(size.width, 1), + info.stride(size.width, 1, + kStrideAlignment), planes[2].data(), - info.stride(size.width, 2), + info.stride(size.width, 2, + kStrideAlignment), size.width, size.height); break; case formats::ABGR8888: @@ -183,7 +183,8 @@ int ImageFrameGenerator::generateFrame(const StreamConfiguration &cfg, const Fra scaledFrameDatas_[frameIndex_].UV.get(), size.width, planes[0].data(), - info.stride(size.width, 0), + info.stride(size.width, 0, + kStrideAlignment), size.width, size.height); break; default: diff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp index 4cde32176661..9ed5f6e74f84 100644 --- a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp +++ b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp @@ -72,20 +72,25 @@ int TestPatternGenerator::generateFrame(const StreamConfiguration &cfg, ret = libyuv::ARGBToNV12(template_.get(), size.width * kARGBSize, planes[0].data(), - info.stride(size.width, 0), + info.stride(size.width, 0, + kStrideAlignment), planes[1].data(), - info.stride(size.width, 1), + info.stride(size.width, 1, + kStrideAlignment), size.width, size.height); break; case formats::YUV420: ret = libyuv::ARGBToI420(template_.get(), size.width * kARGBSize, planes[0].data(), - info.stride(size.width, 0), + info.stride(size.width, 0, + kStrideAlignment), planes[1].data(), - info.stride(size.width, 1), + info.stride(size.width, 1, + kStrideAlignment), planes[2].data(), - info.stride(size.width, 2), + info.stride(size.width, 2, + kStrideAlignment), size.width, size.height); break; case formats::ABGR8888: @@ -93,7 +98,8 @@ int TestPatternGenerator::generateFrame(const StreamConfiguration &cfg, ret = libyuv::ARGBCopy(template_.get(), size.width * kARGBSize, planes[0].data(), - info.stride(size.width, 0), + info.stride(size.width, 0, + kStrideAlignment), size.width, size.height); break; default: diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index 6e97981b0f40..a9c1a5a85fc1 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -240,8 +240,10 @@ CameraConfiguration::Status VirtualCameraConfiguration::validate() adjusted = true; } - auto stride = info.stride(cfg.size.width, 0); - auto frameSize = info.frameSize(cfg.size); + auto stride = info.stride(cfg.size.width, 0, + FrameGenerator::kStrideAlignment); + auto frameSize = info.frameSize(cfg.size, + FrameGenerator::kStrideAlignment); if ((cfg.stride && cfg.stride != stride) || (cfg.frameSize && cfg.frameSize != frameSize)) { status = Adjusted; @@ -346,7 +348,8 @@ int PipelineHandlerVirtual::exportFrameBuffers([[maybe_unused]] Camera *camera, std::vector planeSizes; for (size_t i = 0; i < info.numPlanes(); ++i) - planeSizes.push_back(info.planeSize(config.size, i)); + planeSizes.push_back(info.planeSize(config.size, i, + FrameGenerator::kStrideAlignment)); return dmaBufAllocator_.exportBuffers(config.bufferCount, planeSizes, buffers); }