From patchwork Mon Nov 9 21:34:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 10399 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 561B4BE082 for ; Mon, 9 Nov 2020 21:34:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 251AE63092; Mon, 9 Nov 2020 22:34:39 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="tJv5tCfh"; dkim-atps=neutral Received: from mail-lj1-x236.google.com (mail-lj1-x236.google.com [IPv6:2a00:1450:4864:20::236]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 41D896308E for ; Mon, 9 Nov 2020 22:34:37 +0100 (CET) Received: by mail-lj1-x236.google.com with SMTP id h23so7743556ljg.13 for ; Mon, 09 Nov 2020 13:34:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=waZ1r9rpLnabALA0VgcsP+5ckvQMLi/sijirHcmOdz4=; b=tJv5tCfhirJqXEIUudJfAPgHABr6JsjaZaCJAngjHP8f4c9iBu1LoK85b3MRTOwkNE DVP59F6uxzGT/OMd9kjg582caQ9G3AEqGKZIPhoJnK1ROVtaNHhIpwfsATRsqhKPQCCY L75a6ZCqkAekihoCngnHjHIhXRHqEHDskjx+RksQuud2vWH0Keyi1ET747hhWNlLn849 /pk7AJ7wycf+M6pUydLdyhWlZ9c4JK/9acGFJmgQpMhgPCGbPwJe4Ew9uADr35VHaQi+ CORgB9gzrdoBvzti8XNfZ7sXzGlOd17PqYImr/jYsYSNMr1IeYLV6BnxSCImo6F+SyP3 RELw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=waZ1r9rpLnabALA0VgcsP+5ckvQMLi/sijirHcmOdz4=; b=obTRazrJkvvB6pSW3WoyQyHq89McKdX0mYBpG19aEhojWL5p90nrZI6/7+Qa/c4++d HYXl3QRhyzNiP+tU4aJK/acKcxa6DTIxsRt9rQsbgXg4UxOPW9o2Jyel/1bCtKVYkMJI HrS3oQaGpXo0QXhR3g9IuaVlewxImtOApNSVW7DD4NLzQfsu0ujedBPcRol3EazRks6A GjGHy7VUNcdF1UmcuufQCdNjtsk9mWzL1mQxIrVJdWP1uFX7H5jClv8W8RXnIUgqCOUL Q1hTaw+jrFlLzEG+AfRxh8zMupvf/9/YUL7TMOEpqP0WJTjWtVQ0UyrkHakANoveNDpS SLqQ== X-Gm-Message-State: AOAM5310G5EHBVBtUZpDbIFB1jY/vXt43OOoRGW5eONpUCEltxMp2y77 NnsYO0VeeTsXC/Ttyaa6HlJ6FsH9nR9CNg== X-Google-Smtp-Source: ABdhPJy5xpkS5loF43aJuPnuo3XtBVG8fa2DA0tX91asK2J3YwV5DWcVQw5TaGmIlpVwelQseGakAQ== X-Received: by 2002:a2e:8216:: with SMTP id w22mr6503132ljg.358.1604957676046; Mon, 09 Nov 2020 13:34:36 -0800 (PST) Received: from localhost.localdomain ([85.249.41.73]) by smtp.googlemail.com with ESMTPSA id c1sm1375986lfj.222.2020.11.09.13.34.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Nov 2020 13:34:35 -0800 (PST) From: Andrey Konovalov To: libcamera-devel@lists.libcamera.org Date: Tue, 10 Nov 2020 00:34:11 +0300 Message-Id: <20201109213411.30987-3-andrey.konovalov@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201109213411.30987-1-andrey.konovalov@linaro.org> References: <20201109213411.30987-1-andrey.konovalov@linaro.org> Subject: [libcamera-devel] [PATCH][RFC 2/2] qcam: viewfinder_gl: Add shader to render packed RAW12 formats 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: , MIME-Version: 1.0 Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The shader supports all 4 packed RAW12 variants. Simple bi-linear filtering is implemented. The 4 LS bits of the 12-bit colour values are dropped as the RGBA format we convert into has only 8 bits per colour. Signed-off-by: Andrey Konovalov --- src/qcam/assets/shader/bayer.vert | 28 ++++++++ src/qcam/assets/shader/bayer_12_packed.frag | 68 +++++++++++++++++++ src/qcam/assets/shader/shaders.qrc | 2 + src/qcam/viewfinder_gl.cpp | 74 ++++++++++++++++++++- src/qcam/viewfinder_gl.h | 7 ++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/qcam/assets/shader/bayer.vert create mode 100644 src/qcam/assets/shader/bayer_12_packed.frag diff --git a/src/qcam/assets/shader/bayer.vert b/src/qcam/assets/shader/bayer.vert new file mode 100644 index 00000000..375e0b60 --- /dev/null +++ b/src/qcam/assets/shader/bayer.vert @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * bayer.vert - Vertex shader for raw Bayer to RGB conversion + */ + +attribute vec4 vertexIn; +attribute vec2 textureIn; + +uniform vec4 srcSize; +uniform vec2 firstRed; + +varying vec4 center; +varying vec2 xcoords; +varying vec2 ycoords; + +void main(void) +{ + center.xy = textureIn; + center.zw = textureIn * srcSize.xy + firstRed; + + vec2 invSize = srcSize.zw; + xcoords = center.x + vec2(-invSize.x, invSize.x); + ycoords = center.y + vec2(-invSize.y, invSize.y); + + gl_Position = vertexIn; +} diff --git a/src/qcam/assets/shader/bayer_12_packed.frag b/src/qcam/assets/shader/bayer_12_packed.frag new file mode 100644 index 00000000..eb822b85 --- /dev/null +++ b/src/qcam/assets/shader/bayer_12_packed.frag @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * bayer_12_packed.frag - Fragment shader code for raw Bayer 12-bit packed + * format + */ + +#ifdef GL_ES +precision mediump float; +#endif + +varying vec4 center; +varying vec2 xcoords; +varying vec2 ycoords; + +uniform sampler2D tex_raw; + +void main(void) +{ + vec3 rgb; + + vec2 alternate = mod(center.zw, 2.0); + + bool even_col = alternate.x < 1.0; + bool even_raw = alternate.y < 1.0; + + /* .xy = (0,-1).rg, zw = (0, 1).rg */ + vec4 vals_AD = vec4( + texture2D(tex_raw, vec2(center.x, ycoords[0])).rg, + texture2D(tex_raw, vec2(center.x, ycoords[1])).rg); + /* .xy = (0,0).rg, .z = (-1,0).g, .w = (1,0).r */ + vec4 vals_BCD = vec4( + texture2D(tex_raw, center.xy).rg, + texture2D(tex_raw, vec2(xcoords[0], center.y)).g, + texture2D(tex_raw, vec2(xcoords[1], center.y)).r); + /* .x = (-1,-1).g, .y = (-1,1).g, .z = (1,-1).r, .w = (1,1).r */ + vec4 vals_D = vec4( + texture2D(tex_raw, vec2(xcoords[0], ycoords[0])).g, + texture2D(tex_raw, vec2(xcoords[0], ycoords[1])).g, + texture2D(tex_raw, vec2(xcoords[1], ycoords[0])).r, + texture2D(tex_raw, vec2(xcoords[1], ycoords[1])).r); + + vec4 EFGH = vec4( + vals_AD.x + vals_AD.z, /* 2*E = (0,-1).r + (0, 1).r */ + vals_AD.y + vals_AD.w, /* 2*F = (0,-1).g + (0, 1).g */ + vals_BCD.y + vals_BCD.z, /* 2*G = (0,0).g + (-1,0).g */ + vals_BCD.x + vals_BCD.w /* 2*H = (0,0).r + (1,0).r */ + ) / 2.0; + vec2 JK = vec2( + vals_D.x + vals_D.y, /* 2*J = (-1,-1).g + (-1,1).g */ + vals_D.z + vals_D.w /* 2*K = (1,-1).r + (1,1).r */ + ) / 2.0; + + if (even_col) { + rgb = (even_raw) ? + vec3(vals_BCD.x, (EFGH.x + EFGH.z) / 2.0, + (EFGH.y + JK.x) / 2.0) : + vec3(EFGH.x, vals_BCD.x, EFGH.z); + } else { + rgb = (even_raw) ? + vec3(EFGH.w, vals_BCD.y, EFGH.y) : + vec3((EFGH.x + JK.y) / 2.0, + (EFGH.y + EFGH.w) / 2.0, + vals_BCD.y); + } + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/qcam/assets/shader/shaders.qrc b/src/qcam/assets/shader/shaders.qrc index 8a8f9de1..7bb18033 100644 --- a/src/qcam/assets/shader/shaders.qrc +++ b/src/qcam/assets/shader/shaders.qrc @@ -5,6 +5,8 @@ YUV_2_planes.frag YUV_3_planes.frag YUV_packed.frag + bayer_12_packed.frag + bayer.vert identity.vert diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp index c74ce77b..e504a6c2 100644 --- a/src/qcam/viewfinder_gl.cpp +++ b/src/qcam/viewfinder_gl.cpp @@ -36,6 +36,11 @@ static const QList supportedFormats{ libcamera::formats::RGBA8888, libcamera::formats::BGR888, libcamera::formats::RGB888, + /* Raw Bayer 12-bit packed */ + libcamera::formats::SBGGR12_CSI2P, + libcamera::formats::SGBRG12_CSI2P, + libcamera::formats::SGRBG12_CSI2P, + libcamera::formats::SRGGB12_CSI2P, }; ViewFinderGL::ViewFinderGL(QWidget *parent) @@ -115,6 +120,7 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format) bool ret = true; vertexShaderFile_ = ":identity.vert"; + textureMinMaxFilters_ = GL_LINEAR; fragmentShaderDefines_.clear(); @@ -205,6 +211,34 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format) fragmentShaderDefines_.append("#define RGB_PATTERN bgr"); fragmentShaderFile_ = ":RGB.frag"; break; + case libcamera::formats::SBGGR12_CSI2P: + firstRed_[0] = 1.0; + firstRed_[1] = 1.0; + fragmentShaderFile_ = ":bayer_12_packed.frag"; + vertexShaderFile_ = ":bayer.vert"; + textureMinMaxFilters_ = GL_NEAREST; + break; + case libcamera::formats::SGBRG12_CSI2P: + firstRed_[0] = 0.0; + firstRed_[1] = 1.0; + fragmentShaderFile_ = ":bayer_12_packed.frag"; + vertexShaderFile_ = ":bayer.vert"; + textureMinMaxFilters_ = GL_NEAREST; + break; + case libcamera::formats::SGRBG12_CSI2P: + firstRed_[0] = 1.0; + firstRed_[1] = 0.0; + fragmentShaderFile_ = ":bayer_12_packed.frag"; + vertexShaderFile_ = ":bayer.vert"; + textureMinMaxFilters_ = GL_NEAREST; + break; + case libcamera::formats::SRGGB12_CSI2P: + firstRed_[0] = 0.0; + firstRed_[1] = 0.0; + fragmentShaderFile_ = ":bayer_12_packed.frag"; + vertexShaderFile_ = ":bayer.vert"; + textureMinMaxFilters_ = GL_NEAREST; + break; default: ret = false; qWarning() << "[ViewFinderGL]:" @@ -292,6 +326,9 @@ bool ViewFinderGL::createFragmentShader() textureUniformU_ = shaderProgram_.uniformLocation("tex_u"); textureUniformV_ = shaderProgram_.uniformLocation("tex_v"); textureUniformStepX_ = shaderProgram_.uniformLocation("tex_stepx"); + textureUniformRaw_ = shaderProgram_.uniformLocation("tex_raw"); + textureUniformSrcSize_ = shaderProgram_.uniformLocation("srcSize"); + textureUniformFirstRed_ = shaderProgram_.uniformLocation("firstRed"); /* Create the textures. */ for (std::unique_ptr &texture : textures_) { @@ -308,8 +345,10 @@ bool ViewFinderGL::createFragmentShader() void ViewFinderGL::configureTexture(QOpenGLTexture &texture) { glBindTexture(GL_TEXTURE_2D, texture.textureId()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + textureMinMaxFilters_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + textureMinMaxFilters_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } @@ -548,6 +587,37 @@ void ViewFinderGL::doRender() shaderProgram_.setUniformValue(textureUniformY_, 0); break; + case libcamera::formats::SBGGR12_CSI2P: + case libcamera::formats::SGBRG12_CSI2P: + case libcamera::formats::SGRBG12_CSI2P: + case libcamera::formats::SRGGB12_CSI2P: + /* + * Packed raw Bayer 12-bit foramts are stored in RGB texture + * to match the OpenGL texel size with the 3 bytes repeating + * pattern in RAW12P. + * The texture width is thus half of the image with. + */ + glActiveTexture(GL_TEXTURE0); + configureTexture(*textures_[0]); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGB, + size_.width() / 2, + size_.height(), + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + data_); + shaderProgram_.setUniformValue(textureUniformRaw_, 0); + shaderProgram_.setUniformValue(textureUniformFirstRed_, + firstRed_[0], firstRed_[1]); + shaderProgram_.setUniformValue(textureUniformSrcSize_, + size_.width(), + size_.height(), + 1.0f / (size_.width() / 2 - 1), + 1.0f / (size_.height() - 1)); + break; + default: break; }; diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h index 6cf8f347..186492f3 100644 --- a/src/qcam/viewfinder_gl.h +++ b/src/qcam/viewfinder_gl.h @@ -82,6 +82,8 @@ private: /* Textures */ std::array, 3> textures_; + /* Common texture parameters */ + GLuint textureMinMaxFilters_; /* YUV texture parameters */ GLuint textureUniformU_; GLuint textureUniformV_; @@ -89,6 +91,11 @@ private: GLuint textureUniformStepX_; unsigned int horzSubSample_; unsigned int vertSubSample_; + /* Raw Bayer texture parameters */ + GLuint textureUniformRaw_; + GLuint textureUniformSrcSize_; + GLuint textureUniformFirstRed_; + GLfloat firstRed_[2]; QMutex mutex_; /* Prevent concurrent access to image_ */ };