{"id":12686,"url":"https://patchwork.libcamera.org/api/1.1/patches/12686/?format=json","web_url":"https://patchwork.libcamera.org/patch/12686/","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":"<20210622134652.1279260-3-andrey.konovalov@linaro.org>","date":"2021-06-22T13:46:45","name":"[libcamera-devel,v5,2/9] qcam: viewfinder_gl: Add shader to render packed RAW10 formats","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"538339ba9100c28f8e598d6e21c377794a0fc5c7","submitter":{"id":25,"url":"https://patchwork.libcamera.org/api/1.1/people/25/?format=json","name":"Andrey Konovalov","email":"andrey.konovalov@linaro.org"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/12686/mbox/","series":[{"id":2168,"url":"https://patchwork.libcamera.org/api/1.1/series/2168/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=2168","date":"2021-06-22T13:46:43","name":"qcam: viewfinder_gl: add RAW8, RAW10P and RAW12P formats","version":5,"mbox":"https://patchwork.libcamera.org/series/2168/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/12686/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/12686/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 F37ABC321B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 22 Jun 2021 13:47:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B20BF60294;\n\tTue, 22 Jun 2021 15:47:09 +0200 (CEST)","from mail-lj1-x22e.google.com (mail-lj1-x22e.google.com\n\t[IPv6:2a00:1450:4864:20::22e])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B32BF60292\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Jun 2021 15:47:08 +0200 (CEST)","by mail-lj1-x22e.google.com with SMTP id d13so30160639ljg.12\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Jun 2021 06:47:08 -0700 (PDT)","from localhost.localdomain ([85.249.44.185])\n\tby smtp.googlemail.com with ESMTPSA id\n\tb19sm163125ljo.37.2021.06.22.06.47.07\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 22 Jun 2021 06:47:07 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=linaro.org header.i=@linaro.org\n\theader.b=\"fZE+e+IJ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=2Dj5FDx+IVuIqaxo+q0MrvAfTbvMmkcbelmt5p+0kIs=;\n\tb=fZE+e+IJCBWaVMHVRqIDUYYTfHCog4SoH4GsKpVwNeUeEzekfD4yIoHV4c29l7BOmn\n\t8U6Xy+BC4nPV9BmjhHCE4CqDLJBA3mi5oK8Uw4hHrTM6pH+C71QXQV8Y/iPYrupQquJ6\n\t6twN4+9TbjJXGlc+/v1w/mT8AzVsm5ojToXJlDqk9U4KznKWkaAZ4fIoJxTU9rOHgibO\n\tbduOASUBsviCDWN7NkqWiXGZUBwj6lSDkfUUKgaW/kQ1bWrMyJb2hMtOH3SVvKmu0+HK\n\tFoec1QYOV4RftIxvO3vOFS04pNeToy0HZYJui7UePayyqrgiD8yuLxTDSuA9j6diSfVi\n\t3tNA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=2Dj5FDx+IVuIqaxo+q0MrvAfTbvMmkcbelmt5p+0kIs=;\n\tb=aBiD0SE+Z2iSNJcKIyvTWdK/s2Bs5OSsaR+73gVt2a2C6kcjvMN/pmQutuOV8TA2Yr\n\tC7b+mGAHhfhZYXkJa8Yrnm3Z0xruT9iZBqLerVQQ2wZQQl6RJqBaQ2Tt96yDKDNdcn/2\n\t6iqfY/Vr4GRl1vElA1RSnJ0ijPPdFmtTtKvhTcifL2nDrzFc/vdLng0fgi5C8nCYT6LC\n\ttAkDmJyU3cZ5XBlOyXYEbgtY+k4jb4PTNuBkHeb3LBQ0vHogQe1ESsO0huZ7GhhPaelL\n\tb0fqYbJc07zqj0FynU/eFq7PBWCu4y+gj0pWOJBvmaCzluZhLZxW8aEk5cfqFFpRk3GU\n\tqk5w==","X-Gm-Message-State":"AOAM531bi7+Ahmz0SJGzXzrvioOYWX5yKUQdT0wQR0MkIUlE3MOB7gGm\n\tWZFZoXMJcy8U+jBvtGxyyEXVLiM+QCpIVw==","X-Google-Smtp-Source":"ABdhPJyc39b6KWj7K2CILri5Cr+/nuSgkxVMd/YtL23NSXI7vU1z3aOjjTs2tIdGfERGPxq1NtowlA==","X-Received":"by 2002:a2e:a315:: with SMTP id\n\tl21mr3434735lje.158.1624369628054; \n\tTue, 22 Jun 2021 06:47:08 -0700 (PDT)","From":"Andrey Konovalov <andrey.konovalov@linaro.org>","To":"libcamera-devel@lists.libcamera.org,\n\tlaurent.pinchart@ideasonboard.com","Date":"Tue, 22 Jun 2021 16:46:45 +0300","Message-Id":"<20210622134652.1279260-3-andrey.konovalov@linaro.org>","X-Mailer":"git-send-email 2.25.1","In-Reply-To":"<20210622134652.1279260-1-andrey.konovalov@linaro.org>","References":"<20210622134652.1279260-1-andrey.konovalov@linaro.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v5 2/9] qcam: viewfinder_gl: Add shader to\n\trender packed RAW10 formats","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>","Cc":"morgan@casual-effects.com","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"The shader supports all 4 packed RAW10 variants.\nSimple bi-linear Bayer interpolation of nearest pixels is implemented.\nThe 2 LS bits of the 10-bit colour values are dropped as the RGBA\nformat we convert into has only 8 bits per colour.\n\nThe texture coordinates passed to the fragment shader are ajusted\nto point to the nearest pixel in the image. This prevents artifacts\nwhen the image is scaled from the frame resolution to the window size.\n\nSigned-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>\n---\n src/qcam/assets/shader/bayer_1x_packed.frag | 185 ++++++++++++++++++++\n src/qcam/assets/shader/shaders.qrc          |   1 +\n src/qcam/viewfinder_gl.cpp                  |  78 ++++++++-\n src/qcam/viewfinder_gl.h                    |   9 +\n 4 files changed, 271 insertions(+), 2 deletions(-)\n create mode 100644 src/qcam/assets/shader/bayer_1x_packed.frag","diff":"diff --git a/src/qcam/assets/shader/bayer_1x_packed.frag b/src/qcam/assets/shader/bayer_1x_packed.frag\nnew file mode 100644\nindex 00000000..fac8c3b8\n--- /dev/null\n+++ b/src/qcam/assets/shader/bayer_1x_packed.frag\n@@ -0,0 +1,185 @@\n+/* SPDX-License-Identifier: BSD-2-Clause */\n+/*\n+ * Based on the code from http://jgt.akpeters.com/papers/McGuire08/\n+ *\n+ * Efficient, High-Quality Bayer Demosaic Filtering on GPUs\n+ *\n+ * Morgan McGuire\n+ *\n+ * This paper appears in issue Volume 13, Number 4.\n+ * ---------------------------------------------------------\n+ * Copyright (c) 2008, Morgan McGuire. All rights reserved.\n+ *\n+ *\n+ * Modified by Linaro Ltd for 10/12-bit packed vs 8-bit raw Bayer format,\n+ * and for simpler demosaic algorithm.\n+ * Copyright (C) 2020, Linaro\n+ *\n+ * bayer_1x_packed.frag - Fragment shader code for raw Bayer 10-bit and 12-bit\n+ * packed formats\n+ */\n+\n+#ifdef GL_ES\n+precision mediump float;\n+#endif\n+\n+varying vec2 textureOut;\n+\n+/* the texture size in pixels */\n+uniform vec2 tex_size;\n+uniform vec2 tex_step;\n+uniform vec2 tex_bayer_first_red;\n+\n+uniform sampler2D tex_y;\n+\n+void main(void)\n+{\n+\tvec3 rgb;\n+\n+\t/*\n+\t * center_bytes holds the coordinates of the MS byte of the pixel\n+\t * being sampled on the [0, stride-1/height-1] range.\n+\t * center_pixel holds the coordinates of the pixel being sampled\n+\t * on the [0, width/height-1] range.\n+\t */\n+\tvec2 center_bytes;\n+\tvec2 center_pixel;\n+\n+\t/*\n+\t * x- and y-positions of the adjacent pixels on the [0, 1] range.\n+\t */\n+\tvec2 xcoords;\n+\tvec2 ycoords;\n+\n+\t/*\n+\t * The coordinates passed to the shader in textureOut may point\n+\t * to a place in between the pixels if the texture format doesn't\n+\t * match the image format. In particulr, MIPI packed raw Bayer\n+\t * formats don't have a matching texture format.\n+\t * In this case align the coordinates to the left nearest pixel\n+\t * by hand.\n+\t */\n+\tcenter_pixel = floor(textureOut * tex_size);\n+\tcenter_bytes.y = center_pixel.y;\n+\n+\t/*\n+\t * Add a small number (a few mantissa's LSBs) to avoid float\n+\t * representation issues. Maybe paranoic.\n+\t */\n+\tcenter_bytes.x = BPP_X * center_pixel.x + 0.02;\n+\n+\tconst float threshold_l = 0.127 /* fract(BPP_X) * 0.5 + 0.02 */;\n+\tconst float threshold_h = 0.625 /* 1.0 - fract(BPP_X) * 1.5 */;\n+\n+\tfloat fract_x = fract(center_bytes.x);\n+\n+\t/*\n+\t * The below floor() call ensures that center_bytes.x points\n+\t * at one of the bytes representing the 8 higher bits of\n+\t * the pixel value, not at the byte containing the LS bits\n+\t * of the group of the pixels.\n+\t */\n+\tcenter_bytes.x = floor(center_bytes.x);\n+\tcenter_bytes *= tex_step;\n+\n+\txcoords = center_bytes.x + vec2(-tex_step.x, tex_step.x);\n+\tycoords = center_bytes.y + vec2(-tex_step.y, tex_step.y);\n+\n+\t/*\n+\t * If xcoords[0] points at the byte containing the LS bits\n+\t * of the previous group of the pixels, move xcoords[0] one\n+\t * byte back.\n+\t */\n+\txcoords[0] += (fract_x < threshold_l) ? -tex_step.x : 0.0;\n+\n+\t/*\n+\t * If xcoords[1] points at the byte containing the LS bits\n+\t * of the current group of the pixels, move xcoords[1] one\n+\t * byte forward.\n+\t */\n+\txcoords[1] += (fract_x > threshold_h) ? tex_step.x : 0.0;\n+\n+\tvec2 alternate = mod(center_pixel.xy + tex_bayer_first_red, 2.0);\n+\tbool even_col = alternate.x < 1.0;\n+\tbool even_row = alternate.y < 1.0;\n+\n+\t/*\n+\t * We need to sample the central pixel and the ones with offset\n+\t * of -1 to +1 pixel in both X and Y directions. Let's name these\n+\t * pixels as below, where C is the central pixel:\n+\t *\n+\t *   +----+----+----+----+\n+\t *   | \\ x|    |    |    |\n+\t *   |y \\ | -1 |  0 | +1 | \n+\t *   +----+----+----+----+\n+\t *   | +1 | D2 | A1 | D3 |\n+\t *   +----+----+----+----+\n+\t *   |  0 | B0 |  C | B1 |\n+\t *   +----+----+----+----+\n+\t *   | -1 | D0 | A0 | D1 |\n+\t *   +----+----+----+----+\n+\t *\n+\t * In the below equations (0,-1).r means \"r component of the texel\n+\t * shifted by -tex_step.y from the center_bytes one\" etc.\n+\t *\n+\t * In the even row / even column (EE) case the colour values are:\n+\t *   R = C = (0,0).r,\n+\t *   G = (A0 + A1 + B0 + B1) / 4.0 =\n+\t *       ( (0,-1).r + (0,1).r + (-1,0).r + (1,0).r ) / 4.0,\n+\t *   B = (D0 + D1 + D2 + D3) / 4.0 =\n+\t *       ( (-1,-1).r + (1,-1).r + (-1,1).r + (1,1).r ) / 4.0\n+\t *\n+\t * For even row / odd column (EO):\n+\t *   R = (B0 + B1) / 2.0 = ( (-1,0).r + (1,0).r ) / 2.0,\n+\t *   G = C = (0,0).r,\n+\t *   B = (A0 + A1) / 2.0 = ( (0,-1).r + (0,1).r ) / 2.0\n+\t *\n+\t * For odd row / even column (OE):\n+\t *   R = (A0 + A1) / 2.0 = ( (0,-1).r + (0,1).r ) / 2.0,\n+\t *   G = C = (0,0).r,\n+\t *   B = (B0 + B1) / 2.0 = ( (-1,0).r + (1,0).r ) / 2.0\n+\t *\n+\t * For odd row / odd column (OO):\n+\t *   R = (D0 + D1 + D2 + D3) / 4.0 =\n+\t *       ( (-1,-1).r + (1,-1).r + (-1,1).r + (1,1).r ) / 4.0,\n+\t *   G = (A0 + A1 + B0 + B1) / 4.0 =\n+\t *       ( (0,-1).r + (0,1).r + (-1,0).r + (1,0).r ) / 4.0,\n+\t *   B = C = (0,0).r\n+\t */\n+\n+\t/*\n+\t * Fetch the values and precalculate the terms:\n+\t *   patterns.x = (A0 + A1) / 2.0\n+\t *   patterns.y = (B0 + B1) / 2.0\n+\t *   patterns.z = (A0 + A1 + B0 + B1) / 4.0\n+\t *   patterns.w = (D0 + D1 + D2 + D3) / 4.0\n+\t */\n+\t#define fetch(x, y) texture2D(tex_y, vec2(x, y)).r\n+\n+\tfloat C = texture2D(tex_y, center_bytes).r;\n+\tvec4 patterns = vec4(\n+\t\tfetch(center_bytes.x, ycoords[0]),\t/* A0: (0,-1) */\n+\t\tfetch(xcoords[0], center_bytes.y),\t/* B0: (-1,0) */\n+\t\tfetch(xcoords[0], ycoords[0]),\t/* D0: (-1,-1) */\n+\t\tfetch(xcoords[1], ycoords[0]));\t/* D1: (1,-1) */\n+\tvec4 temp = vec4(\n+\t\tfetch(center_bytes.x, ycoords[1]),\t/* A1: (0,1) */\n+\t\tfetch(xcoords[1], center_bytes.y),\t/* B1: (1,0) */\n+\t\tfetch(xcoords[1], ycoords[1]),\t/* D3: (1,1) */\n+\t\tfetch(xcoords[0], ycoords[1]));\t/* D2: (-1,1) */\n+\tpatterns = (patterns + temp) * 0.5;\n+\t\t/* .x = (A0 + A1) / 2.0, .y = (B0 + B1) / 2.0 */\n+\t\t/* .z = (D0 + D3) / 2.0, .w = (D1 + D2) / 2.0 */\n+\tpatterns.w = (patterns.z + patterns.w) * 0.5;\n+\tpatterns.z = (patterns.x + patterns.y) * 0.5;\n+\n+\trgb = even_col ?\n+\t\t(even_row ?\n+\t\t\tvec3(C, patterns.zw) :\n+\t\t\tvec3(patterns.x, C, patterns.y)) :\n+\t\t(even_row ?\n+\t\t\tvec3(patterns.y, C, patterns.x) :\n+\t\t\tvec3(patterns.wz, C));\n+\n+\tgl_FragColor = vec4(rgb, 1.0);\n+}\ndiff --git a/src/qcam/assets/shader/shaders.qrc b/src/qcam/assets/shader/shaders.qrc\nindex 8a8f9de1..d76d65c5 100644\n--- a/src/qcam/assets/shader/shaders.qrc\n+++ b/src/qcam/assets/shader/shaders.qrc\n@@ -5,6 +5,7 @@\n \t<file>YUV_2_planes.frag</file>\n \t<file>YUV_3_planes.frag</file>\n \t<file>YUV_packed.frag</file>\n+\t<file>bayer_1x_packed.frag</file>\n \t<file>identity.vert</file>\n </qresource>\n </RCC>\ndiff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp\nindex ff719418..ffbbc6c5 100644\n--- a/src/qcam/viewfinder_gl.cpp\n+++ b/src/qcam/viewfinder_gl.cpp\n@@ -36,6 +36,11 @@ static const QList<libcamera::PixelFormat> supportedFormats{\n \tlibcamera::formats::RGBA8888,\n \tlibcamera::formats::BGR888,\n \tlibcamera::formats::RGB888,\n+\t/* Raw Bayer 10-bit packed */\n+\tlibcamera::formats::SBGGR10_CSI2P,\n+\tlibcamera::formats::SGBRG10_CSI2P,\n+\tlibcamera::formats::SGRBG10_CSI2P,\n+\tlibcamera::formats::SRGGB10_CSI2P,\n };\n \n ViewFinderGL::ViewFinderGL(QWidget *parent)\n@@ -106,6 +111,10 @@ void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)\n \t\trenderComplete(buffer_);\n \n \tdata_ = static_cast<unsigned char *>(map->memory);\n+\t/*\n+\t * \\todo Get the stride from the buffer instead of computing it naively\n+\t */\n+\tstride_ = buffer->metadata().planes[0].bytesused / size_.height();\n \tupdate();\n \tbuffer_ = buffer;\n }\n@@ -114,6 +123,9 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format)\n {\n \tbool ret = true;\n \n+\t/* Set min/mag filters to GL_LINEAR by default. */\n+\ttextureMinMagFilters_ = GL_LINEAR;\n+\n \tfragmentShaderDefines_.clear();\n \n \tswitch (format) {\n@@ -203,6 +215,34 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format)\n \t\tfragmentShaderDefines_.append(\"#define RGB_PATTERN bgr\");\n \t\tfragmentShaderFile_ = \":RGB.frag\";\n \t\tbreak;\n+\tcase libcamera::formats::SBGGR10_CSI2P:\n+\t\tfirstRed_.setX(1.0);\n+\t\tfirstRed_.setY(1.0);\n+\t\tfragmentShaderDefines_.append(\"#define BPP_X 1.25\");\n+\t\tfragmentShaderFile_ = \":bayer_1x_packed.frag\";\n+\t\ttextureMinMagFilters_ = GL_NEAREST;\n+\t\tbreak;\n+\tcase libcamera::formats::SGBRG10_CSI2P:\n+\t\tfirstRed_.setX(0.0);\n+\t\tfirstRed_.setY(1.0);\n+\t\tfragmentShaderDefines_.append(\"#define BPP_X 1.25\");\n+\t\tfragmentShaderFile_ = \":bayer_1x_packed.frag\";\n+\t\ttextureMinMagFilters_ = GL_NEAREST;\n+\t\tbreak;\n+\tcase libcamera::formats::SGRBG10_CSI2P:\n+\t\tfirstRed_.setX(1.0);\n+\t\tfirstRed_.setY(0.0);\n+\t\tfragmentShaderDefines_.append(\"#define BPP_X 1.25\");\n+\t\tfragmentShaderFile_ = \":bayer_1x_packed.frag\";\n+\t\ttextureMinMagFilters_ = GL_NEAREST;\n+\t\tbreak;\n+\tcase libcamera::formats::SRGGB10_CSI2P:\n+\t\tfirstRed_.setX(0.0);\n+\t\tfirstRed_.setY(0.0);\n+\t\tfragmentShaderDefines_.append(\"#define BPP_X 1.25\");\n+\t\tfragmentShaderFile_ = \":bayer_1x_packed.frag\";\n+\t\ttextureMinMagFilters_ = GL_NEAREST;\n+\t\tbreak;\n \tdefault:\n \t\tret = false;\n \t\tqWarning() << \"[ViewFinderGL]:\"\n@@ -290,6 +330,8 @@ bool ViewFinderGL::createFragmentShader()\n \ttextureUniformU_ = shaderProgram_.uniformLocation(\"tex_u\");\n \ttextureUniformV_ = shaderProgram_.uniformLocation(\"tex_v\");\n \ttextureUniformStep_ = shaderProgram_.uniformLocation(\"tex_step\");\n+\ttextureUniformSize_ = shaderProgram_.uniformLocation(\"tex_size\");\n+\ttextureUniformBayerFirstRed_ = shaderProgram_.uniformLocation(\"tex_bayer_first_red\");\n \n \t/* Create the textures. */\n \tfor (std::unique_ptr<QOpenGLTexture> &texture : textures_) {\n@@ -306,8 +348,10 @@ bool ViewFinderGL::createFragmentShader()\n void ViewFinderGL::configureTexture(QOpenGLTexture &texture)\n {\n \tglBindTexture(GL_TEXTURE_2D, texture.textureId());\n-\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n-\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n+\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,\n+\t\t\ttextureMinMagFilters_);\n+\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,\n+\t\t\ttextureMinMagFilters_);\n \tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n \tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n }\n@@ -547,6 +591,36 @@ void ViewFinderGL::doRender()\n \t\tshaderProgram_.setUniformValue(textureUniformY_, 0);\n \t\tbreak;\n \n+\tcase libcamera::formats::SBGGR10_CSI2P:\n+\tcase libcamera::formats::SGBRG10_CSI2P:\n+\tcase libcamera::formats::SGRBG10_CSI2P:\n+\tcase libcamera::formats::SRGGB10_CSI2P:\n+\t\t/*\n+\t\t * Packed raw Bayer 10-bit formats are stored in GL_RED texture.\n+\t\t * The texture width is equal to the stride.\n+\t\t */\n+\t\tglActiveTexture(GL_TEXTURE0);\n+\t\tconfigureTexture(*textures_[0]);\n+\t\tglTexImage2D(GL_TEXTURE_2D,\n+\t\t\t     0,\n+\t\t\t     GL_RED,\n+\t\t\t     stride_,\n+\t\t\t     size_.height(),\n+\t\t\t     0,\n+\t\t\t     GL_RED,\n+\t\t\t     GL_UNSIGNED_BYTE,\n+\t\t\t     data_);\n+\t\tshaderProgram_.setUniformValue(textureUniformY_, 0);\n+\t\tshaderProgram_.setUniformValue(textureUniformBayerFirstRed_,\n+\t\t\t\t\t       firstRed_);\n+\t\tshaderProgram_.setUniformValue(textureUniformSize_,\n+\t\t\t\t\t       size_.width(), /* in pixels */\n+\t\t\t\t\t       size_.height());\n+\t\tshaderProgram_.setUniformValue(textureUniformStep_,\n+\t\t\t\t\t       1.0f / (stride_ - 1),\n+\t\t\t\t\t       1.0f / (size_.height() - 1));\n+\t\tbreak;\n+\n \tdefault:\n \t\tbreak;\n \t};\ndiff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h\nindex 1b1faa91..508155b1 100644\n--- a/src/qcam/viewfinder_gl.h\n+++ b/src/qcam/viewfinder_gl.h\n@@ -66,6 +66,7 @@ private:\n \tlibcamera::FrameBuffer *buffer_;\n \tlibcamera::PixelFormat format_;\n \tQSize size_;\n+\tunsigned int stride_;\n \tunsigned char *data_;\n \n \t/* Shaders */\n@@ -81,6 +82,9 @@ private:\n \t/* Textures */\n \tstd::array<std::unique_ptr<QOpenGLTexture>, 3> textures_;\n \n+\t/* Common texture parameters */\n+\tGLuint textureMinMagFilters_;\n+\n \t/* YUV texture parameters */\n \tGLuint textureUniformU_;\n \tGLuint textureUniformV_;\n@@ -89,6 +93,11 @@ private:\n \tunsigned int horzSubSample_;\n \tunsigned int vertSubSample_;\n \n+\t/* Raw Bayer texture parameters */\n+\tGLuint textureUniformSize_;\n+\tGLuint textureUniformBayerFirstRed_;\n+\tQPointF firstRed_;\n+\n \tQMutex mutex_; /* Prevent concurrent access to image_ */\n };\n \n","prefixes":["libcamera-devel","v5","2/9"]}