{"id":22386,"url":"https://patchwork.libcamera.org/api/patches/22386/?format=json","web_url":"https://patchwork.libcamera.org/patch/22386/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20241217174707.174777-3-pobrn@protonmail.com>","date":"2024-12-17T17:47:19","name":"[v2,3/3] libcamera: virtual: Speed up test pattern animation","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"4543c46d62cb298135fa365763d268c0cbb5c579","submitter":{"id":133,"url":"https://patchwork.libcamera.org/api/people/133/?format=json","name":"Pőcze Barnabás","email":"pobrn@protonmail.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/22386/mbox/","series":[{"id":4907,"url":"https://patchwork.libcamera.org/api/series/4907/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4907","date":"2024-12-17T17:47:09","name":"[v2,1/3] libcamera: virtual: Avoid some copies","version":2,"mbox":"https://patchwork.libcamera.org/series/4907/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/22386/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/22386/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D7CE4C32F6\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 17 Dec 2024 17:47:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8FF1367FFB;\n\tTue, 17 Dec 2024 18:47:28 +0100 (CET)","from mail-10629.protonmail.ch (mail-10629.protonmail.ch\n\t[79.135.106.29])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 567F267FFD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 17 Dec 2024 18:47:27 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=protonmail.com header.i=@protonmail.com\n\theader.b=\"Imr4INO/\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;\n\ts=protonmail3; t=1734457645; x=1734716845;\n\tbh=/yXHIzUTjdZA7BKaCtbtyOVj/RvpoPMikN5ULfPmu5Y=;\n\th=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post;\n\tb=Imr4INO/GjwBIXsT5q1VDQdue+C/UnC43qawv3W7pqoYIWQXmQFNv8ixJey2nF/PS\n\tTuIRRGjlYLIX1ocxRgxP1ksgRi+DBFFC5p5l3hqwwyvyu3yjg/sLQ7QVfB261SKMrw\n\tpVeiVP+TDssdNKQw2hrWuycHF45M8TEGzDpBlE5NBvi6GO4pDq6NMx2smjcGcpX1v8\n\tMwW9FTC5ZZF0SQyPztfd2jMhu1UeYMJYeMyynJgiYQFErgJX/sUL0Z5H4ar7R3PoSo\n\tDZa8I40k4pnDHkSiDYp5kr+BZyBccSFSX8vaiu6CsksXw4FmHRSKmwiYsFCkrH73r/\n\tw4HlvaD2XSETQ==","Date":"Tue, 17 Dec 2024 17:47:19 +0000","To":"libcamera-devel@lists.libcamera.org","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <pobrn@protonmail.com>","Cc":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"[PATCH v2 3/3] libcamera: virtual: Speed up test pattern animation","Message-ID":"<20241217174707.174777-3-pobrn@protonmail.com>","In-Reply-To":"<20241217174707.174777-1-pobrn@protonmail.com>","References":"<20241217174707.174777-1-pobrn@protonmail.com>","Feedback-ID":"20568564:user:proton","X-Pm-Message-ID":"980984d988e6f882dc862c4c94e6884d40e8fafe","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"After the initial generation, when a frame is requested,\nthe test pattern generator rotates the image left by 1 column.\n\nThe current approach has two shortcomings:\n  (1) it allocates a temporary buffer to hold one column;\n  (2) it swaps two columns at a time.\n\nThe test patterns are simple ARGB images, in row-major order,\nso doing (2) works against memory prefetching. This can be\naddressed by doing the rotation one row at a time as that way\nthe image is addressed in a purely linear fashion. Doing so also\neliminates the need for a dynamically allocated temporary buffer,\nas the required buffer now only needs to hold one sample,\nwhich is 4 bytes in this case.\n\nIn an optimized build, this results in about a 2x increase in the\nnumber of frames per second as reported by `cam`. In an unoptimized,\nASAN and UBSAN intrumented build, the difference is even bigger,\nwhich is useful for running lc-compliance in CI in a reasonable time.\n\nSigned-off-by: Barnabás Pőcze <pobrn@protonmail.com>\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\nTested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n .../virtual/test_pattern_generator.cpp        | 57 ++++++++-----------\n .../pipeline/virtual/test_pattern_generator.h |  4 --\n 2 files changed, 23 insertions(+), 38 deletions(-)","diff":"diff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\nindex 47d341919..afb98f5e5 100644\n--- a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n+++ b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n@@ -5,6 +5,8 @@\n  * Derived class of FrameGenerator for generating test patterns\n  */\n \n+#include <string.h>\n+\n #include \"test_pattern_generator.h\"\n \n #include <libcamera/base/log.h>\n@@ -13,6 +15,26 @@\n \n #include <libyuv/convert_from_argb.h>\n \n+namespace {\n+\n+template<size_t SampleSize>\n+void rotateLeft1Column(const libcamera::Size &size, uint8_t *image)\n+{\n+\tif (size.width < 2)\n+\t\treturn;\n+\n+\tconst size_t stride = size.width * SampleSize;\n+\tuint8_t first[SampleSize];\n+\n+\tfor (size_t i = 0; i < size.height; i++, image += stride) {\n+\t\tmemcpy(first, &image[0], SampleSize);\n+\t\tmemmove(&image[0], &image[SampleSize], stride - SampleSize);\n+\t\tmemcpy(&image[stride - SampleSize], first, SampleSize);\n+\t}\n+}\n+\n+}\n+\n namespace libcamera {\n \n LOG_DECLARE_CATEGORY(Virtual)\n@@ -27,7 +49,7 @@ int TestPatternGenerator::generateFrame(const Size &size,\n \n \tconst auto &planes = mappedFrameBuffer.planes();\n \n-\tshiftLeft(size);\n+\trotateLeft1Column<kARGBSize>(size, template_.get());\n \n \t/* Convert the template_ to the frame buffer */\n \tint ret = libyuv::ARGBToNV12(template_.get(), size.width * kARGBSize,\n@@ -40,39 +62,6 @@ int TestPatternGenerator::generateFrame(const Size &size,\n \treturn ret;\n }\n \n-void TestPatternGenerator::shiftLeft(const Size &size)\n-{\n-\t/* Store the first column temporarily */\n-\tauto firstColumn = std::make_unique<uint8_t[]>(size.height * kARGBSize);\n-\tfor (size_t h = 0; h < size.height; h++) {\n-\t\tunsigned int index = h * size.width * kARGBSize;\n-\t\tunsigned int index1 = h * kARGBSize;\n-\t\tfirstColumn[index1] = template_[index];\n-\t\tfirstColumn[index1 + 1] = template_[index + 1];\n-\t\tfirstColumn[index1 + 2] = template_[index + 2];\n-\t\tfirstColumn[index1 + 3] = 0x00;\n-\t}\n-\n-\t/* Overwrite template_ */\n-\tuint8_t *buf = template_.get();\n-\tfor (size_t h = 0; h < size.height; h++) {\n-\t\tfor (size_t w = 0; w < size.width - 1; w++) {\n-\t\t\t/* Overwrite with the pixel on the right */\n-\t\t\tunsigned int index = (h * size.width + w + 1) * kARGBSize;\n-\t\t\t*buf++ = template_[index]; /* B */\n-\t\t\t*buf++ = template_[index + 1]; /* G */\n-\t\t\t*buf++ = template_[index + 2]; /* R */\n-\t\t\t*buf++ = 0x00; /* A */\n-\t\t}\n-\t\t/* Overwrite the new last column with the original first column */\n-\t\tunsigned int index1 = h * kARGBSize;\n-\t\t*buf++ = firstColumn[index1]; /* B */\n-\t\t*buf++ = firstColumn[index1 + 1]; /* G */\n-\t\t*buf++ = firstColumn[index1 + 2]; /* R */\n-\t\t*buf++ = 0x00; /* A */\n-\t}\n-}\n-\n void ColorBarsGenerator::configure(const Size &size)\n {\n \tconstexpr uint8_t kColorBar[8][3] = {\ndiff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.h b/src/libcamera/pipeline/virtual/test_pattern_generator.h\nindex 05f4ab7a7..2a51bd31a 100644\n--- a/src/libcamera/pipeline/virtual/test_pattern_generator.h\n+++ b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n@@ -29,10 +29,6 @@ public:\n protected:\n \t/* Buffer of test pattern template */\n \tstd::unique_ptr<uint8_t[]> template_;\n-\n-private:\n-\t/* Shift the buffer by 1 pixel left each frame */\n-\tvoid shiftLeft(const Size &size);\n };\n \n class ColorBarsGenerator : public TestPatternGenerator\n","prefixes":["v2","3/3"]}