[{"id":17538,"web_url":"https://patchwork.libcamera.org/comment/17538/","msgid":"<YMf4VyAUKagHzQGR@pendragon.ideasonboard.com>","date":"2021-06-15T00:46:15","subject":"Re: [libcamera-devel] [PATCH v3 2/4] qcam: viewfinder_gl: Add\n\tshader to render packed RAW10 formats","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Andrey,\n\nThank you for the patch.\n\nIt looks like most of the comments on v2 have been ignored, was that on\npurpose ?\n\nOn Fri, Jun 11, 2021 at 07:27:24PM +0300, Andrey Konovalov wrote:\n> The shader supports all 4 packed RAW10 variants.\n> Simple bi-linear filtering is implemented.\n> The 2 LS bits of the 10-bit colour values are dropped as the RGBA\n> format we convert into has only 8 bits per colour.\n> \n> The texture coordinates passed to the fragment shader are ajusted\n> to point to the nearest pixel in the image. This prevents artifacts\n> when the image is scaled from the frame resolution to the window size.\n> \n> Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>\n> ---\n>  src/qcam/assets/shader/bayer_1x_packed.frag | 174 ++++++++++++++++++++\n>  src/qcam/assets/shader/shaders.qrc          |   1 +\n>  src/qcam/viewfinder_gl.cpp                  |  80 ++++++++-\n>  src/qcam/viewfinder_gl.h                    |   7 +\n>  4 files changed, 260 insertions(+), 2 deletions(-)\n>  create mode 100644 src/qcam/assets/shader/bayer_1x_packed.frag\n> \n> diff --git a/src/qcam/assets/shader/bayer_1x_packed.frag b/src/qcam/assets/shader/bayer_1x_packed.frag\n> new file mode 100644\n> index 00000000..0a87c6db\n> --- /dev/null\n> +++ b/src/qcam/assets/shader/bayer_1x_packed.frag\n> @@ -0,0 +1,174 @@\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: tex_size.xy is in bytes, tex_size.zw is in pixels */\n> +uniform vec4 tex_size;\n> +uniform vec2 tex_step;\n> +uniform vec2 tex_bayer_first_red;\n> +\n> +uniform sampler2D tex_raw;\n> +\n> +void main(void)\n> +{\n> +\tvec3 rgb;\n> +\n> +\t/*\n> +\t * center.xy holds the coordinates of the pixel being sampled\n> +\t * on the [0, 1] range.\n> +\t * center.zw holds the coordinates of the pixel being sampled\n> +\t * on the [0, width/height-1] range.\n> +\t */\n> +\tvec4 center;\n> +\t/*\n> +\t * x-positions of the adjacent pixels on the [0, 1] range.\n> +\t */\n> +\tvec2 xcoords;\n> +\t/*\n> +\t * y-positions of the adjacent pixels on the [0, 1] range.\n> +\t */\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 viewfinder window is scaled\n> +\t * from the original captured frame size. Align them to the nearest\n> +\t * pixel.\n> +\t */\n> +\tcenter.zw = floor(textureOut * tex_size.zw);\n> +\tcenter.y = center.w;\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.x = BPP_X * center.z + 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.x);\n> +\t/*\n> +\t * The below floor() call ensures that center.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.x = floor(center.x);\n> +\tcenter.xy *= tex_step;\n> +\n> +\txcoords = center.x + vec2(-tex_step.x, tex_step.x);\n> +\tycoords = center.y + vec2(-tex_step.y, tex_step.y);\n> +\t/*\n> +\t * If xcoords[0] points at the byte containing the LS bits\n> +         * 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> +\t/*\n> +\t * If xcoords[1] points at the byte containing the LS bits\n> +         * 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.zw + tex_bayer_first_red, 2.0);\n> +\tbool even_col = alternate.x < 1.0;\n> +\tbool even_raw = 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 *   | \\ 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 * In the below equations (0,-1).r means \"r component of the texel\n> +\t * shifted by -tex_step.y from the center.xy one\" etc.\n> +\t * In the even raw / 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 * For even raw / 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 * For odd raw / 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 * For odd raw / 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_raw, vec2(x, y)).r\n> +\n> +\tfloat C = texture2D(tex_raw, center.xy).r;\n> +\tvec4 patterns = vec4(\n> +\t\tfetch(center.x, ycoords[0]),\t/* A0: (0,-1) */\n> +\t\tfetch(xcoords[0], center.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.x, ycoords[1]),\t/* A1: (0,1) */\n> +\t\tfetch(xcoords[1], center.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_raw) ?\n> +\t\t\tvec3(C, patterns.zw) :\n> +\t\t\tvec3(patterns.x, C, patterns.y)) :\n> +\t\t((even_raw) ?\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> +}\n> diff --git a/src/qcam/assets/shader/shaders.qrc b/src/qcam/assets/shader/shaders.qrc\n> index 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>\n> diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp\n> index ff719418..44e410c9 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,38 @@ 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       stride_, /* width in bytes */\n> +\t\t\t\t\t       size_.height(),\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};\n> diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h\n> index 1b1faa91..0171885a 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,13 +82,19 @@ private:\n>  \t/* Textures */\n>  \tstd::array<std::unique_ptr<QOpenGLTexture>, 3> textures_;\n>  \n> +\t/* Common texture parameters */\n> +\tGLuint textureMinMagFilters_;\n>  \t/* YUV texture parameters */\n>  \tGLuint textureUniformU_;\n>  \tGLuint textureUniformV_;\n>  \tGLuint textureUniformY_;\n> +\tGLuint textureUniformSize_;\n>  \tGLuint textureUniformStep_;\n>  \tunsigned int horzSubSample_;\n>  \tunsigned int vertSubSample_;\n> +\t/* Raw Bayer texture parameters */\n> +\tGLuint textureUniformBayerFirstRed_;\n> +\tQPointF firstRed_;\n>  \n>  \tQMutex mutex_; /* Prevent concurrent access to image_ */\n>  };","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 A46CBBD78E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 15 Jun 2021 00:46:37 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 212FA68932;\n\tTue, 15 Jun 2021 02:46:37 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 51ACF68925\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Jun 2021 02:46:36 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C70174A3;\n\tTue, 15 Jun 2021 02:46:35 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"lmRzv7kV\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1623717996;\n\tbh=TMbf4A+6kNh0EvJipP5FTylTfWRYCJEhaFFi2CKtpjg=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=lmRzv7kVsNDF5tWqr9BbVA4YsYXj73wua0tqQUFYwYnbEwR2MN3UdprHkb/Z38A1l\n\tgRF23bCmzJUjuyjYvSaIczcdHDQt5cv8MYxHS1LpfvFj6PGJvFeiahnNbzXl3sn/tU\n\tim60Ash68KUERKknY/WaqlIoGr68sEM+CXEZXd6U=","Date":"Tue, 15 Jun 2021 03:46:15 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Andrey Konovalov <andrey.konovalov@linaro.org>","Message-ID":"<YMf4VyAUKagHzQGR@pendragon.ideasonboard.com>","References":"<20210611162726.824789-1-andrey.konovalov@linaro.org>\n\t<20210611162726.824789-3-andrey.konovalov@linaro.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20210611162726.824789-3-andrey.konovalov@linaro.org>","Subject":"Re: [libcamera-devel] [PATCH v3 2/4] qcam: viewfinder_gl: Add\n\tshader to render 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, libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17553,"web_url":"https://patchwork.libcamera.org/comment/17553/","msgid":"<c77a104c-80aa-c087-43ca-4d1467e93899@linaro.org>","date":"2021-06-15T07:09:30","subject":"Re: [libcamera-devel] [PATCH v3 2/4] qcam: viewfinder_gl: Add\n\tshader to render packed RAW10 formats","submitter":{"id":25,"url":"https://patchwork.libcamera.org/api/people/25/","name":"Andrey Konovalov","email":"andrey.konovalov@linaro.org"},"content":"Hi Laurent,\n\nOn 15.06.2021 03:46, Laurent Pinchart wrote:\n> Hi Andrey,\n> \n> Thank you for the patch.\n> \n> It looks like most of the comments on v2 have been ignored, was that on\n> purpose ?\n\nHmm.. No, not on purpose. I've managed to miss part of your review emails somehow..\nSorry for that.\nI'll go through all of them and get back with v4.\n\nSorry,\nAndrey\n\n> On Fri, Jun 11, 2021 at 07:27:24PM +0300, Andrey Konovalov wrote:\n>> The shader supports all 4 packed RAW10 variants.\n>> Simple bi-linear filtering is implemented.\n>> The 2 LS bits of the 10-bit colour values are dropped as the RGBA\n>> format we convert into has only 8 bits per colour.\n>>\n>> The texture coordinates passed to the fragment shader are ajusted\n>> to point to the nearest pixel in the image. This prevents artifacts\n>> when the image is scaled from the frame resolution to the window size.\n>>\n>> Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>\n>> ---\n>>   src/qcam/assets/shader/bayer_1x_packed.frag | 174 ++++++++++++++++++++\n>>   src/qcam/assets/shader/shaders.qrc          |   1 +\n>>   src/qcam/viewfinder_gl.cpp                  |  80 ++++++++-\n>>   src/qcam/viewfinder_gl.h                    |   7 +\n>>   4 files changed, 260 insertions(+), 2 deletions(-)\n>>   create mode 100644 src/qcam/assets/shader/bayer_1x_packed.frag\n>>\n>> diff --git a/src/qcam/assets/shader/bayer_1x_packed.frag b/src/qcam/assets/shader/bayer_1x_packed.frag\n>> new file mode 100644\n>> index 00000000..0a87c6db\n>> --- /dev/null\n>> +++ b/src/qcam/assets/shader/bayer_1x_packed.frag\n>> @@ -0,0 +1,174 @@\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: tex_size.xy is in bytes, tex_size.zw is in pixels */\n>> +uniform vec4 tex_size;\n>> +uniform vec2 tex_step;\n>> +uniform vec2 tex_bayer_first_red;\n>> +\n>> +uniform sampler2D tex_raw;\n>> +\n>> +void main(void)\n>> +{\n>> +\tvec3 rgb;\n>> +\n>> +\t/*\n>> +\t * center.xy holds the coordinates of the pixel being sampled\n>> +\t * on the [0, 1] range.\n>> +\t * center.zw holds the coordinates of the pixel being sampled\n>> +\t * on the [0, width/height-1] range.\n>> +\t */\n>> +\tvec4 center;\n>> +\t/*\n>> +\t * x-positions of the adjacent pixels on the [0, 1] range.\n>> +\t */\n>> +\tvec2 xcoords;\n>> +\t/*\n>> +\t * y-positions of the adjacent pixels on the [0, 1] range.\n>> +\t */\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 viewfinder window is scaled\n>> +\t * from the original captured frame size. Align them to the nearest\n>> +\t * pixel.\n>> +\t */\n>> +\tcenter.zw = floor(textureOut * tex_size.zw);\n>> +\tcenter.y = center.w;\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.x = BPP_X * center.z + 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.x);\n>> +\t/*\n>> +\t * The below floor() call ensures that center.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.x = floor(center.x);\n>> +\tcenter.xy *= tex_step;\n>> +\n>> +\txcoords = center.x + vec2(-tex_step.x, tex_step.x);\n>> +\tycoords = center.y + vec2(-tex_step.y, tex_step.y);\n>> +\t/*\n>> +\t * If xcoords[0] points at the byte containing the LS bits\n>> +         * 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>> +\t/*\n>> +\t * If xcoords[1] points at the byte containing the LS bits\n>> +         * 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.zw + tex_bayer_first_red, 2.0);\n>> +\tbool even_col = alternate.x < 1.0;\n>> +\tbool even_raw = 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 *   | \\ 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 * In the below equations (0,-1).r means \"r component of the texel\n>> +\t * shifted by -tex_step.y from the center.xy one\" etc.\n>> +\t * In the even raw / 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 * For even raw / 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 * For odd raw / 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 * For odd raw / 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_raw, vec2(x, y)).r\n>> +\n>> +\tfloat C = texture2D(tex_raw, center.xy).r;\n>> +\tvec4 patterns = vec4(\n>> +\t\tfetch(center.x, ycoords[0]),\t/* A0: (0,-1) */\n>> +\t\tfetch(xcoords[0], center.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.x, ycoords[1]),\t/* A1: (0,1) */\n>> +\t\tfetch(xcoords[1], center.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_raw) ?\n>> +\t\t\tvec3(C, patterns.zw) :\n>> +\t\t\tvec3(patterns.x, C, patterns.y)) :\n>> +\t\t((even_raw) ?\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>> +}\n>> diff --git a/src/qcam/assets/shader/shaders.qrc b/src/qcam/assets/shader/shaders.qrc\n>> index 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>\n>> diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp\n>> index ff719418..44e410c9 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,38 @@ 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       stride_, /* width in bytes */\n>> +\t\t\t\t\t       size_.height(),\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};\n>> diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h\n>> index 1b1faa91..0171885a 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,13 +82,19 @@ private:\n>>   \t/* Textures */\n>>   \tstd::array<std::unique_ptr<QOpenGLTexture>, 3> textures_;\n>>   \n>> +\t/* Common texture parameters */\n>> +\tGLuint textureMinMagFilters_;\n>>   \t/* YUV texture parameters */\n>>   \tGLuint textureUniformU_;\n>>   \tGLuint textureUniformV_;\n>>   \tGLuint textureUniformY_;\n>> +\tGLuint textureUniformSize_;\n>>   \tGLuint textureUniformStep_;\n>>   \tunsigned int horzSubSample_;\n>>   \tunsigned int vertSubSample_;\n>> +\t/* Raw Bayer texture parameters */\n>> +\tGLuint textureUniformBayerFirstRed_;\n>> +\tQPointF firstRed_;\n>>   \n>>   \tQMutex mutex_; /* Prevent concurrent access to image_ */\n>>   };\n>","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 81306BD78E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 15 Jun 2021 07:09:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4202B68943;\n\tTue, 15 Jun 2021 09:09:34 +0200 (CEST)","from mail-lj1-x22b.google.com (mail-lj1-x22b.google.com\n\t[IPv6:2a00:1450:4864:20::22b])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1D0C660299\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Jun 2021 09:09:33 +0200 (CEST)","by mail-lj1-x22b.google.com with SMTP id e25so2414853ljj.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Jun 2021 00:09:33 -0700 (PDT)","from [192.168.88.254] ([85.249.44.185])\n\tby smtp.gmail.com with ESMTPSA id\n\tc15sm1714676lfh.32.2021.06.15.00.09.31\n\t(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n\tTue, 15 Jun 2021 00:09:31 -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=\"YWV2zIK2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google;\n\th=subject:to:cc:references:from:message-id:date:user-agent\n\t:mime-version:in-reply-to:content-language:content-transfer-encoding; \n\tbh=Td62O3xi5MKcM2Lj56IPQFskhHgxmLh/JqNT2jqw240=;\n\tb=YWV2zIK2h2ENszmnM/b51kuC8loDe3ruy2IbvGZbeiEW7dG8yBVYoAug5RxnqAO17F\n\tSQD6bpeCc74+uegSlUysrpXqX9uMYiqZY+woX18Huf5Lhk8N+HKxY8CTlHmbUg7fn0XO\n\t7zaqlaQu0I/qyLav7y/nAOpm7sTulJByPIKTLCFFb/ybbcTvHZUQricDtvy3eN36Mh0v\n\tn7GvEmOLHgrqa8QYfBdJimqS2FbQA12y+sfzGMbHEXNrhlPXKy/1vpJS9u/+jKLQvaGV\n\tZVBGWZZTCa1cqolRMuvI2aLN4NnmFbEFR7e+e36wTVKObLhz86I+VSoFAaUWWpSROXPI\n\tgSTQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:subject:to:cc:references:from:message-id:date\n\t:user-agent:mime-version:in-reply-to:content-language\n\t:content-transfer-encoding;\n\tbh=Td62O3xi5MKcM2Lj56IPQFskhHgxmLh/JqNT2jqw240=;\n\tb=CZVk+/n1vzlmvzJ/VpXYIpogAWf0c0+LXJdYZhAIOmyFB50430oSBd0e3qVEDlXEIm\n\tIBibA0obgAZX3I7KgaoUZrpHK6Oq+cNBggQNWjxCYGzEiZ1EkwUT33aI853rm55kQ5Qn\n\tkm3H1eVTH9LGX9DPvEKwGc5g/U5Mzjy3SynJdBG/RtaLLyjdgmX8VGp48CP4RG+8xGkt\n\tW9nFnV8zu10t+rbPQCmPLiaC39Q9vntiLSvrN1a4fo0YTs8V/S43NIGPAVZr4GqW81J3\n\to0PwFKiFxAZU0aSfrURSBZo+pNEVjox3Im/8gEktFa749rC9A3MnDgnr4UrMjdaCfO+v\n\t3rsQ==","X-Gm-Message-State":"AOAM530KIrSfWrZjTu2WVrWipneMYU6oheFi/PQeTOXH0nNtAHoGwjy4\n\tx+T2sfEj2qRgBKW5WZIi8oUG6A==","X-Google-Smtp-Source":"ABdhPJx07fj7zLsDpCd8tCKUI82mUTQ7TBArc3rzFPfJmIAkzD84Wi59lnXPWio4a5ru4qaDOk7eSg==","X-Received":"by 2002:a2e:a263:: with SMTP id k3mr16664536ljm.41.1623740972224;\n\tTue, 15 Jun 2021 00:09:32 -0700 (PDT)","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","References":"<20210611162726.824789-1-andrey.konovalov@linaro.org>\n\t<20210611162726.824789-3-andrey.konovalov@linaro.org>\n\t<YMf4VyAUKagHzQGR@pendragon.ideasonboard.com>","From":"Andrey Konovalov <andrey.konovalov@linaro.org>","Message-ID":"<c77a104c-80aa-c087-43ca-4d1467e93899@linaro.org>","Date":"Tue, 15 Jun 2021 10:09:30 +0300","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101\n\tThunderbird/78.8.1","MIME-Version":"1.0","In-Reply-To":"<YMf4VyAUKagHzQGR@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=utf-8; format=flowed","Content-Language":"en-US","Content-Transfer-Encoding":"7bit","Subject":"Re: [libcamera-devel] [PATCH v3 2/4] qcam: viewfinder_gl: Add\n\tshader to render 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, libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]