From patchwork Thu Oct 8 21:11:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Mader X-Patchwork-Id: 28422 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 1F2D9C3305 for ; Thu, 8 Oct 2026 21:12:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6C72868E2B; Thu, 8 Oct 2026 23:12:17 +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="N9jMyC+k"; 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 F3B0C68A06 for ; Thu, 8 Oct 2026 23:12:12 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1791493929; cv=none; d=zohomail.com; s=zohoarc; b=L2/TVVQ/pjQQ2F2TXi6si6T45EuG7gUtg0eHocwjcbYmo4v/f1NC2kZ9QbpYNrdEPIb9u6uTGnQNmuluQf0nfx8QOPPyGT65LGXdcT7wSWfRDP4X/8aBg+ppM2RE2z3hKg9+cXbfmqJGb+zFR4PrFUGg2XP40BfAKEntc4k5cwQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1791493929; 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=PSx4y6rU1EVAHoxVbejfaVjLOgCmkloCi4cIdxvkrlo=; b=OLRb6Cz3fmFS483KkH0KOgltv4PgfJJxh7gT3CHFfFdn12nPymncODH0BmZuOwC/cjdIeiYXDAuCnHGnODzejqB61pPL1e/U2HDvcY3T9sw8Ghqv0Xu97TDprIMnUA/PdCY8Dv6RvF+0QZqZLMbAgu2Fhmi+lPVMuLfD8mJBuHw= 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=1791493929; 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=PSx4y6rU1EVAHoxVbejfaVjLOgCmkloCi4cIdxvkrlo=; b=N9jMyC+k/cWU2CL6/xYVfnxMbVObQojsOO+DIXPzGBx0sF4hcZ0MGdqKTHcoy+CP Lyu52lsNvQFdU9jc9UOiLXQJ0WJNeESXHDt5SkV9Qq3OZz74MGujUD0H0t/lk4mfFr7 f0XYjIDY4Yqu571vfXeQ+9QIHE1fYVanh5hxtvYg= Received: by smtp.zohomail.com with SMTPS id 1791493928248228.8795225111628; Thu, 8 Oct 2026 14:12:08 -0700 (PDT) From: Robert Mader To: libcamera-devel@lists.libcamera.org Cc: Robert Mader Subject: [PATCH 4/4] virtual: Align strides to 256 bytes Date: Thu, 8 Oct 2026 23:11:49 +0200 Message-ID: <20261008211149.51765-5-robert.mader@collabora.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261008211149.51765-1-robert.mader@collabora.com> References: <20261008211149.51765-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 70cd92907b63..31eea6392008 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 dcef90702e18..685c11a61029 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, @@ -159,9 +154,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: @@ -170,11 +167,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: @@ -184,7 +184,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 d8cdc1c91c24..1892854d63d3 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 349cb88a3f05..ac6c5ca67aa8 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -231,8 +231,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; @@ -342,7 +344,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); }