{"id":22290,"url":"https://patchwork.libcamera.org/api/1.1/patches/22290/?format=json","web_url":"https://patchwork.libcamera.org/patch/22290/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/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":"<20241211152542.1095857-3-pobrn@protonmail.com>","date":"2024-12-11T15:25:56","name":"[v1,3/3] libcamera: virtual: Speed up test pattern animation","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"09836df5b14ce989e910e18b20171b53b81cdfff","submitter":{"id":133,"url":"https://patchwork.libcamera.org/api/1.1/people/133/?format=json","name":"Pőcze Barnabás","email":"pobrn@protonmail.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/22290/mbox/","series":[{"id":4874,"url":"https://patchwork.libcamera.org/api/1.1/series/4874/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4874","date":"2024-12-11T15:25:45","name":"[v1,1/3] libcamera: virtual: Avoid some copies","version":1,"mbox":"https://patchwork.libcamera.org/series/4874/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/22290/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/22290/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 11232BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 11 Dec 2024 15:26:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BAA5E67EBA;\n\tWed, 11 Dec 2024 16:26:05 +0100 (CET)","from mail-40133.protonmail.ch (mail-40133.protonmail.ch\n\t[185.70.40.133])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C0E9B67EB1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 11 Dec 2024 16:26:03 +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=\"WgfVUf/j\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;\n\ts=protonmail3; t=1733930763; x=1734189963;\n\tbh=uLrSfwP4FXc2HR+sNpRAijAkImv9mgf1ETXXrtpNPdk=;\n\th=Date:To:From: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=WgfVUf/jqoqOfowK9oVJ/jd9m7uJ3LJUaXxfsJ02a7ASdPFpNz/lYzG2sI9x3VJdb\n\tQbQWzgf/kQ+uYUwoe4YVo+Zs9QlCnqaLZGDBu5eiAbXQttnRtfG2kSAxuT2TE3UEm+\n\thYhZAdV9JcN5hVf5QZU1BvjVckcMPvsh28lJYIsBh2rfi0tVKtXE3N1c0ghoEmenXL\n\ttX4es1F7CaS/VIBk6j/0fuO25d6/wnpJ2FIi7CJNgdfjdLvTBxH/pepgntz/OdtEHP\n\tOgfyoj9Wk/xHh0mmbL6OC4LsJVa4DNNIMy4KMXWXIAJHcDDJ1wk6n+j1x+3PCvuXB4\n\tC4segC6kk/38A==","Date":"Wed, 11 Dec 2024 15:25:56 +0000","To":"libcamera-devel@lists.libcamera.org","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <pobrn@protonmail.com>","Subject":"[PATCH v1 3/3] libcamera: virtual: Speed up test pattern animation","Message-ID":"<20241211152542.1095857-3-pobrn@protonmail.com>","In-Reply-To":"<20241211152542.1095857-1-pobrn@protonmail.com>","References":"<20241211152542.1095857-1-pobrn@protonmail.com>","Feedback-ID":"20568564:user:proton","X-Pm-Message-ID":"869d255ffcfb0670811601ba1af026beb2cf5323","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>\n---\n .../virtual/test_pattern_generator.cpp        | 68 +++++++++----------\n .../pipeline/virtual/test_pattern_generator.h |  4 --\n 2 files changed, 34 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..eeadc1646 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,37 @@\n \n #include <libyuv/convert_from_argb.h>\n \n+namespace {\n+\n+template<size_t SampleSize>\n+void rotateLeft1Sample(uint8_t *samples, size_t width)\n+{\n+\tif (width <= 0)\n+\t\treturn;\n+\n+\tconst size_t stride = width * SampleSize;\n+\tuint8_t first[SampleSize];\n+\n+\tmemcpy(first, &samples[0], SampleSize);\n+\tfor (size_t i = 0; i < stride - SampleSize; i += SampleSize)\n+\t\tmemcpy(&samples[i], &samples[i + SampleSize], SampleSize);\n+\tmemcpy(&samples[stride - SampleSize], first, SampleSize);\n+}\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+\n+\tfor (size_t i = 0; i < size.height; i++, image += stride)\n+\t\trotateLeft1Sample<SampleSize>(image, size.width);\n+}\n+\n+}\n+\n namespace libcamera {\n \n LOG_DECLARE_CATEGORY(Virtual)\n@@ -27,7 +60,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 +73,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":["v1","3/3"]}