From patchwork Fri Sep 4 08:43:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Show Liu X-Patchwork-Id: 9481 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 92944BE174 for ; Fri, 4 Sep 2020 08:43:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5E72662901; Fri, 4 Sep 2020 10:43:42 +0200 (CEST) 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="JfU1hyvc"; dkim-atps=neutral Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 896B160371 for ; Fri, 4 Sep 2020 10:43:40 +0200 (CEST) Received: by mail-pl1-x643.google.com with SMTP id h2so852196plr.0 for ; Fri, 04 Sep 2020 01:43:40 -0700 (PDT) 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 :mime-version:content-transfer-encoding; bh=c7W/TtOm2ltTdBzHZD8YHrJ6G0+toxHFvdCTp2LmP8M=; b=JfU1hyvc2nspDymilGrF4jAxQQnWkP0IbHnw3TdO7n7Ata+Cudy1/sRLtdUKgCIglr d7HvUOr9T9dqy/7X2V3iXUutKgD0LpHQac8E2HlSOB2/Qku1tuQBKdqmkJMgFwSXH+bJ xE4gQLEDKG2HjMYA1w559Di08DV+4L+ydroCfta/qLeFzA4MIG0lUOm+t2Qd4ypSLayI mHUgL0iEe7RnyCDIJmxjHlH6hmrdEYFWtNOiAtPsZqNMAm5186xmGmFrOS1O+Mys9GQP awsHQvpLyiP+CzFeHw2vYhZE+S4k7NRUNCr8LzVpOlv4XuwXtAD9FkdGFqf4z1J8Bbkh CP0A== 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:mime-version:content-transfer-encoding; bh=c7W/TtOm2ltTdBzHZD8YHrJ6G0+toxHFvdCTp2LmP8M=; b=AIJiXxKYxhjYdzs8+rIGXylyQ16dqmN2UO9xw08Fyk5Az28LQ85n+3RlB1kfj/i78W +N82Wgg+7gJxcPlJHRkKCSa+DU5a5GjByETQYm+xAzCaDXhFWKixTsjpg5/GicUYSw4S t2dxSNs891FZ/d1ViNSDBCYXrg3NWiSFHySHudHnc+A+0gY2Kkg4/rLq8IU7unCcrb0S paxR8bflKvkUOm27wtm6p0pHr+asAM807RGLybY8B1JF/PhP6Krhz7FfGwYSAQtrXZsS y7yWJJNx9s/s6XCz7T2i15HF6hacKZoolwimZifdDjGxWLXKL+1v/Q0kXkRALK/5JfeE 6+6g== X-Gm-Message-State: AOAM533thVj7E2ZNz7lTA+s2uMeEHZfSpF3aKKMU9H9ENbOBJ9tu5rgw ZM4pZ9nCaFLVs175KK9cUfcHRYEJhrRB8A== X-Google-Smtp-Source: ABdhPJxA0e7jFaBu59bATaPS0+ZPwoSQthP5VDkBR5jDqjIqFwbKLQeQkWxOA6rTpSiCJOAQ2lUSJg== X-Received: by 2002:a17:902:d68f:: with SMTP id v15mr7879682ply.251.1599209018478; Fri, 04 Sep 2020 01:43:38 -0700 (PDT) Received: from localhost.localdomain (211-20-20-223.HINET-IP.hinet.net. [211.20.20.223]) by smtp.gmail.com with ESMTPSA id a6sm5202148pgt.70.2020.09.04.01.43.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2020 01:43:38 -0700 (PDT) From: Show Liu To: libcamera-devel@lists.libcamera.org Date: Fri, 4 Sep 2020 16:43:12 +0800 Message-Id: <20200904084316.7319-2-show.liu@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200904084316.7319-1-show.liu@linaro.org> References: <20200904084316.7319-1-show.liu@linaro.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 1/4] qcam: add OpenGL shader code as Qt resource 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" qcam: add OpenGL shader code as Qt resource Signed-off-by: Show Liu Reviewed-by: Laurent Pinchart --- src/qcam/assets/shader/NV_2_planes_UV_f.glsl | 32 +++++++++++++++++++ src/qcam/assets/shader/NV_2_planes_VU_f.glsl | 32 +++++++++++++++++++ src/qcam/assets/shader/NV_3_planes_UV_f.glsl | 33 ++++++++++++++++++++ src/qcam/assets/shader/NV_3_planes_VU_f.glsl | 33 ++++++++++++++++++++ src/qcam/assets/shader/NV_vertex_shader.glsl | 16 ++++++++++ src/qcam/assets/shader/shaders.qrc | 10 ++++++ src/qcam/meson.build | 1 + 7 files changed, 157 insertions(+) create mode 100644 src/qcam/assets/shader/NV_2_planes_UV_f.glsl create mode 100644 src/qcam/assets/shader/NV_2_planes_VU_f.glsl create mode 100644 src/qcam/assets/shader/NV_3_planes_UV_f.glsl create mode 100644 src/qcam/assets/shader/NV_3_planes_VU_f.glsl create mode 100644 src/qcam/assets/shader/NV_vertex_shader.glsl create mode 100644 src/qcam/assets/shader/shaders.qrc diff --git a/src/qcam/assets/shader/NV_2_planes_UV_f.glsl b/src/qcam/assets/shader/NV_2_planes_UV_f.glsl new file mode 100644 index 0000000..54bb459 --- /dev/null +++ b/src/qcam/assets/shader/NV_2_planes_UV_f.glsl @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * NV_2_planes_UV_f.glsl - Fragment shader code for NV12, NV16 and NV24 formats + */ + +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 textureOut; +uniform sampler2D tex_y; +uniform sampler2D tex_u; + +void main(void) +{ + vec3 yuv; + vec3 rgb; + mat3 yuv2rgb_bt601_mat = mat3( + vec3(1.164, 1.164, 1.164), + vec3(0.000, -0.392, 2.017), + vec3(1.596, -0.813, 0.000) + ); + + yuv.x = texture2D(tex_y, textureOut).r - 0.063; + yuv.y = texture2D(tex_u, textureOut).r - 0.500; + yuv.z = texture2D(tex_u, textureOut).g - 0.500; + + rgb = yuv2rgb_bt601_mat * yuv; + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/qcam/assets/shader/NV_2_planes_VU_f.glsl b/src/qcam/assets/shader/NV_2_planes_VU_f.glsl new file mode 100644 index 0000000..6571ed6 --- /dev/null +++ b/src/qcam/assets/shader/NV_2_planes_VU_f.glsl @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * NV_2_planes_VU_f.glsl - Fragment shader code for NV21, NV61 and NV42 formats + */ + +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 textureOut; +uniform sampler2D tex_y; +uniform sampler2D tex_u; + +void main(void) +{ + vec3 yuv; + vec3 rgb; + mat3 yuv2rgb_bt601_mat = mat3( + vec3(1.164, 1.164, 1.164), + vec3(0.000, -0.392, 2.017), + vec3(1.596, -0.813, 0.000) + ); + + yuv.x = texture2D(tex_y, textureOut).r - 0.063; + yuv.y = texture2D(tex_u, textureOut).g - 0.500; + yuv.z = texture2D(tex_u, textureOut).r - 0.500; + + rgb = yuv2rgb_bt601_mat * yuv; + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/qcam/assets/shader/NV_3_planes_UV_f.glsl b/src/qcam/assets/shader/NV_3_planes_UV_f.glsl new file mode 100644 index 0000000..9d104fd --- /dev/null +++ b/src/qcam/assets/shader/NV_3_planes_UV_f.glsl @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * NV_3_planes_UV_f.glsl - Fragment shader code for YUV420 format + */ + +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 textureOut; +uniform sampler2D tex_y; +uniform sampler2D tex_u; +uniform sampler2D tex_v; + +void main(void) +{ + vec3 yuv; + vec3 rgb; + mat3 yuv2rgb_bt601_mat = mat3( + vec3(1.164, 1.164, 1.164), + vec3(0.000, -0.392, 2.017), + vec3(1.596, -0.813, 0.000) + ); + + yuv.x = texture2D(tex_y, textureOut).r - 0.063; + yuv.y = texture2D(tex_u, textureOut).r - 0.500; + yuv.z = texture2D(tex_v, textureOut).r - 0.500; + + rgb = yuv2rgb_bt601_mat * yuv; + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/qcam/assets/shader/NV_3_planes_VU_f.glsl b/src/qcam/assets/shader/NV_3_planes_VU_f.glsl new file mode 100644 index 0000000..245a619 --- /dev/null +++ b/src/qcam/assets/shader/NV_3_planes_VU_f.glsl @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * NV_3_planes_VU_f.glsl - Fragment shader code for YVU420 format + */ + +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 textureOut; +uniform sampler2D tex_y; +uniform sampler2D tex_u; +uniform sampler2D tex_v; + +void main(void) +{ + vec3 yuv; + vec3 rgb; + mat3 yuv2rgb_bt601_mat = mat3( + vec3(1.164, 1.164, 1.164), + vec3(0.000, -0.392, 2.017), + vec3(1.596, -0.813, 0.000) + ); + + yuv.x = texture2D(tex_y, textureOut).r - 0.063; + yuv.y = texture2D(tex_u, textureOut).r - 0.500; + yuv.z = texture2D(tex_v, textureOut).r - 0.500; + + rgb = yuv2rgb_bt601_mat * yuv; + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/qcam/assets/shader/NV_vertex_shader.glsl b/src/qcam/assets/shader/NV_vertex_shader.glsl new file mode 100644 index 0000000..403b791 --- /dev/null +++ b/src/qcam/assets/shader/NV_vertex_shader.glsl @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * NV_vertex_shader.glsl - Vertex shader code for NV family + */ + +attribute vec4 vertexIn; +attribute vec2 textureIn; +varying vec2 textureOut; + +void main(void) +{ + gl_Position = vertexIn; + textureOut = textureIn; +} diff --git a/src/qcam/assets/shader/shaders.qrc b/src/qcam/assets/shader/shaders.qrc new file mode 100644 index 0000000..6fe4c7f --- /dev/null +++ b/src/qcam/assets/shader/shaders.qrc @@ -0,0 +1,10 @@ + + + +./NV_vertex_shader.glsl +./NV_2_planes_UV_f.glsl +./NV_2_planes_VU_f.glsl +./NV_3_planes_UV_f.glsl +./NV_3_planes_VU_f.glsl + + diff --git a/src/qcam/meson.build b/src/qcam/meson.build index 6ea886a..e0c6f26 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -16,6 +16,7 @@ qcam_moc_headers = files([ qcam_resources = files([ 'assets/feathericons/feathericons.qrc', + 'assets/shader/shaders.qrc' ]) qt5 = import('qt5') From patchwork Fri Sep 4 08:43:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Show Liu X-Patchwork-Id: 9482 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 E08F3BE174 for ; Fri, 4 Sep 2020 08:43:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AE9ED62B2F; Fri, 4 Sep 2020 10:43:45 +0200 (CEST) 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="m3HVSCLl"; dkim-atps=neutral Received: from mail-pj1-x1036.google.com (mail-pj1-x1036.google.com [IPv6:2607:f8b0:4864:20::1036]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 75B0860371 for ; Fri, 4 Sep 2020 10:43:43 +0200 (CEST) Received: by mail-pj1-x1036.google.com with SMTP id b16so2879634pjp.0 for ; Fri, 04 Sep 2020 01:43:43 -0700 (PDT) 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 :mime-version:content-transfer-encoding; bh=pd0uFP/AovgRjHxc9WoEZwRE9JT0940ZP/Y05SE1T2o=; b=m3HVSCLl406iZbkT3bCITmzA79Of0mmz1Cyy7OaBfkvL++Emvm9/oa8sTRSgEaxKkv f/EDceN2/ftlNEaT9oTbEZS22c81dchaendld50/dyXiqICRNQp+BL+PkViQzCIyrLPH P2saqWsPQZMGfLu04bldgfTOnpYOIAANgBpCxCjYug2EpfCOzbE5oKlLHtHgiXW1Mm37 g+MAOUluKN12MeFCc4BgDRJ9TByrZTeyO/nXPzBOH0q+lhe/amml49aYR8dnpu9TIy+6 PB9EQ6qLd8liamiIPpYqBT68OOGYJOqwLUb+9OiHJEkDjI44OdFO/lywyBXyrwFjLNtV ZN4A== 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:mime-version:content-transfer-encoding; bh=pd0uFP/AovgRjHxc9WoEZwRE9JT0940ZP/Y05SE1T2o=; b=Vz1lgo3UVzv1e4BTTtDzZguMZr2xAs24eX7O/4Jcis+h4HB8oYfVuv2WP2rmGtPbXF 656CLT510zhUhKVe8LApatf/S0r1TFaz1arR2XGQu9MOOzpOzKJdLFtr9Ihq0uLoGmKz BVuQavFQ3vshwX+PjQLiwpX1volgDB4DUBQpgKjvVtOoLPeZ0KOYkF+2wnFska8tWkl2 BeTbVgamfWG5sSuFy9EPqVEyJWXAM7oS0p9edXFR0KmvFntIaUl5MnADQtfeX549f1Tk fYh6W28mvj3yprJ9H/CaCUq/m1t3DRAw66GIeUNu5OxuEv9u//M0sUnlqDXys7SvI87O xZjA== X-Gm-Message-State: AOAM5322n3xxOS5oabkczYiqMMdz4XjtsZtQM0N7paypa0ggkQhHe6JE h2JSHEWnU7fW6QQfqaxOT2E97HFhCuoM8w== X-Google-Smtp-Source: ABdhPJzT8jYBb05GgcpcswoMA+O64EYAoRvmba9R0UK7RxxyxypJ0D4bYXYBdFDNBHhY1g3oUmvSsQ== X-Received: by 2002:a17:90a:db49:: with SMTP id u9mr7090032pjx.90.1599209021500; Fri, 04 Sep 2020 01:43:41 -0700 (PDT) Received: from localhost.localdomain (211-20-20-223.HINET-IP.hinet.net. [211.20.20.223]) by smtp.gmail.com with ESMTPSA id a6sm5202148pgt.70.2020.09.04.01.43.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2020 01:43:41 -0700 (PDT) From: Show Liu To: libcamera-devel@lists.libcamera.org Date: Fri, 4 Sep 2020 16:43:13 +0800 Message-Id: <20200904084316.7319-3-show.liu@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200904084316.7319-1-show.liu@linaro.org> References: <20200904084316.7319-1-show.liu@linaro.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 2/3] qcam: add OpenGL renderer 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" qcam: add OpenGL renderer Signed-off-by: Show Liu --- src/qcam/meson.build | 2 + src/qcam/renderer.cpp | 346 ++++++++++++++++++++++++++++++++++++++++++ src/qcam/renderer.h | 81 ++++++++++ 3 files changed, 429 insertions(+) create mode 100644 src/qcam/renderer.cpp create mode 100644 src/qcam/renderer.h diff --git a/src/qcam/meson.build b/src/qcam/meson.build index e0c6f26..8c9032f 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -7,11 +7,13 @@ qcam_sources = files([ 'main.cpp', 'main_window.cpp', 'viewfinder.cpp', + 'renderer.cpp' ]) qcam_moc_headers = files([ 'main_window.h', 'viewfinder.h', + 'renderer.h' ]) qcam_resources = files([ diff --git a/src/qcam/renderer.cpp b/src/qcam/renderer.cpp new file mode 100644 index 0000000..23e8fa8 --- /dev/null +++ b/src/qcam/renderer.cpp @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * renderer.cpp - Render YUV format frame by OpenGL shader + */ + +#include "renderer.h" + +Renderer::Renderer() + : fbo_(nullptr), + vbo_(QOpenGLBuffer::VertexBuffer), + pFShader_(nullptr), + pVShader_(nullptr), + textureU_(QOpenGLTexture::Target2D), + textureV_(QOpenGLTexture::Target2D), + textureY_(QOpenGLTexture::Target2D) +{ + /* offscreen format setup */ + setFormat(requestedFormat()); + create(); + + /* create OpenGL context */ + if (ctx_.create()) { + ctx_.makeCurrent(this); + initializeOpenGLFunctions(); + } else { + qWarning() << "[Renderer]: " + << "OpenGL renderer is not available."; + } +} + +Renderer::~Renderer() +{ + if (vbo_.isCreated()) { + vbo_.release(); + vbo_.destroy(); + } + + if (fbo_) { + fbo_->release(); + delete fbo_; + } + + removeShader(); + + if (textureY_.isCreated()) + textureY_.destroy(); + + if (textureU_.isCreated()) + textureU_.destroy(); + + if (textureV_.isCreated()) + textureV_.destroy(); + + ctx_.doneCurrent(); +} + +void Renderer::initializeGL() +{ + glEnable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); + + static const GLfloat vertices[]{ + -1.0f, -1.0f, -1.0f, +1.0f, + +1.0f, +1.0f, +1.0f, -1.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 1.0f, 1.0f + }; + + vbo_.create(); + vbo_.bind(); + vbo_.allocate(vertices, sizeof(vertices)); + + glClearColor(1.0f, 1.0f, 1.0f, 0.0f); +} + +bool Renderer::selectShader(const libcamera::PixelFormat &format) +{ + bool ret = true; + switch (format) { + case libcamera::formats::NV12: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_UV_f.glsl"; + break; + case libcamera::formats::NV21: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_VU_f.glsl"; + break; + case libcamera::formats::NV16: + horzSubSample_ = 2; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_UV_f.glsl"; + break; + case libcamera::formats::NV61: + horzSubSample_ = 2; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_VU_f.glsl"; + break; + case libcamera::formats::NV24: + horzSubSample_ = 1; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_UV_f.glsl"; + break; + case libcamera::formats::NV42: + horzSubSample_ = 1; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_VU_f.glsl"; + break; + case libcamera::formats::YUV420: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_3_planes_UV_f.glsl"; + break; + default: + ret = false; + qWarning() << "[Renderer]: " + << "format not support yet."; + break; + }; + + return ret; +} + +void Renderer::removeShader() +{ + if (shaderProgram_.isLinked()) { + shaderProgram_.release(); + shaderProgram_.removeAllShaders(); + } + + if (pFShader_) + delete pFShader_; + + if (pVShader_) + delete pVShader_; +} + +bool Renderer::createShader() +{ + bool bCompile; + + /* Create Vertex Shader */ + pVShader_ = new QOpenGLShader(QOpenGLShader::Vertex, this); + + bCompile = pVShader_->compileSourceFile(vsrc_); + if (!bCompile) { + qWarning() << "[Renderer]: " << pVShader_->log(); + return bCompile; + } + + shaderProgram_.addShader(pVShader_); + + /* Create Fragment Shader */ + pFShader_ = new QOpenGLShader(QOpenGLShader::Fragment, this); + + bCompile = pFShader_->compileSourceFile(fsrc_); + if (!bCompile) { + qWarning() << "[Renderer]: " << pFShader_->log(); + return bCompile; + } + + shaderProgram_.addShader(pFShader_); + + // Link shader pipeline + if (!shaderProgram_.link()) { + qWarning() << "[Renderer]: " << shaderProgram_.log(); + return false; + } + + // Bind shader pipeline for use + if (!shaderProgram_.bind()) { + qWarning() << "[Renderer]: " << shaderProgram_.log(); + return false; + } + return true; +} + +bool Renderer::configure(const libcamera::PixelFormat &format, const QSize &size) +{ + bool ret = true; + + if (selectShader(format)) { + ret = createShader(); + if (!ret) + return ret; + + shaderProgram_.enableAttributeArray(ATTRIB_VERTEX); + shaderProgram_.enableAttributeArray(ATTRIB_TEXTURE); + + shaderProgram_.setAttributeBuffer(ATTRIB_VERTEX, + GL_FLOAT, + 0, + 2, + 2 * sizeof(GLfloat)); + shaderProgram_.setAttributeBuffer(ATTRIB_TEXTURE, + GL_FLOAT, + 8 * sizeof(GLfloat), + 2, + 2 * sizeof(GLfloat)); + + textureUniformY_ = shaderProgram_.uniformLocation("tex_y"); + textureUniformU_ = shaderProgram_.uniformLocation("tex_u"); + textureUniformV_ = shaderProgram_.uniformLocation("tex_v"); + + if (!textureY_.isCreated()) + textureY_.create(); + + if (!textureU_.isCreated()) + textureU_.create(); + + if (!textureV_.isCreated()) + textureV_.create(); + + id_y_ = textureY_.textureId(); + id_u_ = textureU_.textureId(); + id_v_ = textureV_.textureId(); + + fbo_ = new QOpenGLFramebufferObject(size.width(), + size.height(), + GL_TEXTURE_2D); + fbo_->bind(); + glViewport(0, 0, size.width(), size.height()); + + format_ = format; + size_ = size; + } else { + ret = false; + } + return ret; +} + +void Renderer::configureTexture(unsigned int id) +{ + glBindTexture(GL_TEXTURE_2D, id); + 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_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +void Renderer::render(unsigned char *buffer) +{ + QMutexLocker locker(&mutex_); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + switch (format_) { + case libcamera::formats::NV12: + case libcamera::formats::NV21: + case libcamera::formats::NV16: + case libcamera::formats::NV61: + case libcamera::formats::NV24: + case libcamera::formats::NV42: + /* activate texture 0 */ + glActiveTexture(GL_TEXTURE0); + configureTexture(id_y_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width(), + size_.height(), + 0, + GL_RED, + GL_UNSIGNED_BYTE, + buffer); + glUniform1i(textureUniformY_, 0); + + /* activate texture 1 */ + glActiveTexture(GL_TEXTURE1); + configureTexture(id_u_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RG, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RG, + GL_UNSIGNED_BYTE, + buffer + size_.width() * size_.height()); + glUniform1i(textureUniformU_, 1); + break; + case libcamera::formats::YUV420: + /* activate texture 0 */ + glActiveTexture(GL_TEXTURE0); + configureTexture(id_y_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width(), + size_.height(), + 0, + GL_RED, + GL_UNSIGNED_BYTE, + buffer); + glUniform1i(textureUniformY_, 0); + + /* activate texture 1 */ + glActiveTexture(GL_TEXTURE1); + configureTexture(id_u_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RG, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RG, + GL_UNSIGNED_BYTE, + buffer + size_.width() * size_.height()); + glUniform1i(textureUniformU_, 1); + + /* activate texture 2 */ + glActiveTexture(GL_TEXTURE2); + configureTexture(id_v_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RG, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, GL_RG, + GL_UNSIGNED_BYTE, + buffer + size_.width() * size_.height() * 5 / 4); + glUniform1i(textureUniformV_, 2); + break; + default: + break; + }; + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +QImage Renderer::toImage() +{ + QMutexLocker locker(&mutex_); + return (fbo_->toImage(true)); +} diff --git a/src/qcam/renderer.h b/src/qcam/renderer.h new file mode 100644 index 0000000..1ea0c48 --- /dev/null +++ b/src/qcam/renderer.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * renderer.h - Render YUV format frame by OpenGL shader + */ +#ifndef __QCAM_RENDERER_H__ +#define __QCAM_RENDERER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ATTRIB_VERTEX 0 +#define ATTRIB_TEXTURE 1 + +class Renderer : public QOffscreenSurface, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + Renderer(); + ~Renderer(); + + void initializeGL(); + bool configure(const libcamera::PixelFormat &format, const QSize &size); + void render(unsigned char *buffer); + QImage toImage(); + +private: + bool createShader(); + void configureTexture(unsigned int id); + void removeShader(); + bool selectShader(const libcamera::PixelFormat &format); + + /* OpenGL renderer components */ + QOpenGLContext ctx_; + QOpenGLFramebufferObject *fbo_; + QOpenGLBuffer vbo_; + QOpenGLShader *pFShader_; + QOpenGLShader *pVShader_; + QOpenGLShaderProgram shaderProgram_; + QSurfaceFormat surfaceFormat_; + + /* Fragment and Vertex shader file */ + QString fsrc_; + QString vsrc_; + + /* YUV frame size and format */ + libcamera::PixelFormat format_; + QSize size_; + + /* YUV texture planars and parameters*/ + GLuint id_u_; + GLuint id_v_; + GLuint id_y_; + GLuint textureUniformU_; + GLuint textureUniformV_; + GLuint textureUniformY_; + QOpenGLTexture textureU_; + QOpenGLTexture textureV_; + QOpenGLTexture textureY_; + unsigned int horzSubSample_; + unsigned int vertSubSample_; + + QImage image_; + QMutex mutex_; /* Prevent concurrent access to image_ */ +}; + +#endif /* __QCAM_RENDERER_H__ */ From patchwork Fri Sep 4 08:43:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Show Liu X-Patchwork-Id: 9484 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 DEDAFBE174 for ; Fri, 4 Sep 2020 08:43:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A9E3462B2F; Fri, 4 Sep 2020 10:43:49 +0200 (CEST) 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="HyKd0bAu"; dkim-atps=neutral Received: from mail-pl1-x62d.google.com (mail-pl1-x62d.google.com [IPv6:2607:f8b0:4864:20::62d]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E71E462B53 for ; Fri, 4 Sep 2020 10:43:47 +0200 (CEST) Received: by mail-pl1-x62d.google.com with SMTP id k13so816274plk.13 for ; Fri, 04 Sep 2020 01:43:47 -0700 (PDT) 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 :mime-version:content-transfer-encoding; bh=S1K5Qezo1F+B1oxZXo7RL/xyK70ykLOr3XuKqUwZJ7c=; b=HyKd0bAu8UM4gAdkTPdjoq9OJwDqYIstXh/Dyqmy9iCY+cFhK5Y7ZP8WV5O8uC4KvX jyFcdzL1Dlyq1kqLRiKfez4RuePVVkRMPAtcBLPbj99uRxsC+TLV7CEePefDmfjIpFyD CSTN1VCz1wa3mVZ+YZyFkSYp9XQn/oTphAZFeyD+670F29VX6y+4ePzoEeJIpd98Ftsd 6o9idLvSsIQTjpSg76YR2P7KQKPkMXnhriZWttecv48tkrglpDgZbxLq5I92uS0sY/E9 C6EISWVhhDBzk3FnJhaodizJ31PXBxI753UyPdj1+RJZ6FQ2UKqnRblG5NQO4oXiHnXC EWMQ== 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:mime-version:content-transfer-encoding; bh=S1K5Qezo1F+B1oxZXo7RL/xyK70ykLOr3XuKqUwZJ7c=; b=EDQHN11jAxPhKymnAsG6l9x29BZEkx/JGaXlPf12qIAqUV1bQ5/tQABHkeGYTceUIU rUk6cc2GBvJLd65ZIX306XSyhNBjaANGRZTGVaBNe3jBWxXdAlGpGwYDJy1P+uZzZzkI CiLtubBvcs6bwQelXH4kLMZsnF1iYHScRNsMgCMf5PHW+nTaMqIy/FfdxRw904jRgrGm ClS8y2mZ+PPFz4pN0Rl24KzbZlKgvaMDXX7qMj3Kjne3J9H+oXN918e1hPQ34I5Loxl0 fZonw74nkU538f2lLYRRsfU9rhVhpfcWuyhn+ihtmjRgL2BXAWRM6FWhhuiCW8y/5mFk MaLg== X-Gm-Message-State: AOAM533QqINEQ1M/V19fT5doH4i7+SU7J9eDjnK3hvPrqDEmKJ1vIJPX 6E7Gv9GRXMD1NH6HluOrrqPgIKWefEok1g== X-Google-Smtp-Source: ABdhPJwIF0Vjn4F35tPkLU2wHp5GbdC9220ttmosu4/axTkbrjsLhWNSbvlz+bXAw4CrfnjLmZcRCQ== X-Received: by 2002:a17:902:40a:: with SMTP id 10mr631937ple.25.1599209026120; Fri, 04 Sep 2020 01:43:46 -0700 (PDT) Received: from localhost.localdomain (211-20-20-223.HINET-IP.hinet.net. [211.20.20.223]) by smtp.gmail.com with ESMTPSA id a6sm5202148pgt.70.2020.09.04.01.43.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2020 01:43:45 -0700 (PDT) From: Show Liu To: libcamera-devel@lists.libcamera.org Date: Fri, 4 Sep 2020 16:43:15 +0800 Message-Id: <20200904084316.7319-5-show.liu@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200904084316.7319-1-show.liu@linaro.org> References: <20200904084316.7319-1-show.liu@linaro.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 3/4] qcam: add viewfinderGL class to accelerate the format convert 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" the viewfinderGL accelerates the format conversion by using OpenGL ES shader Signed-off-by: Show Liu --- src/qcam/meson.build | 2 + src/qcam/viewfinder_gl.cpp | 441 +++++++++++++++++++++++++++++++++++++ src/qcam/viewfinder_gl.h | 97 ++++++++ 3 files changed, 540 insertions(+) create mode 100644 src/qcam/viewfinder_gl.cpp create mode 100644 src/qcam/viewfinder_gl.h diff --git a/src/qcam/meson.build b/src/qcam/meson.build index a4bad0a..32c0fc3 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -7,11 +7,13 @@ qcam_sources = files([ 'main.cpp', 'main_window.cpp', 'viewfinder_qt.cpp', + 'viewfinder_gl.cpp', ]) qcam_moc_headers = files([ 'main_window.h', 'viewfinder_qt.h', + 'viewfinder_gl.h', ]) qcam_resources = files([ diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp new file mode 100644 index 0000000..5591916 --- /dev/null +++ b/src/qcam/viewfinder_gl.cpp @@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * viewfinderGL.cpp - Render YUV format frame by OpenGL shader + */ + +#include "viewfinder_gl.h" + +#include + +#include + +#define ATTRIB_VERTEX 0 +#define ATTRIB_TEXTURE 1 + +static const QList supportFormats{ + libcamera::formats::NV12, + libcamera::formats::NV21, + libcamera::formats::NV16, + libcamera::formats::NV61, + libcamera::formats::NV24, + libcamera::formats::NV42, + libcamera::formats::YUV420, + libcamera::formats::YVU420 +}; + +ViewFinderGL::ViewFinderGL(QWidget *parent) + : QOpenGLWidget(parent), + buffer_(nullptr), + pFShader_(nullptr), + pVShader_(nullptr), + vbuf_(QOpenGLBuffer::VertexBuffer), + yuvDataPtr_(nullptr), + textureU_(QOpenGLTexture::Target2D), + textureV_(QOpenGLTexture::Target2D), + textureY_(QOpenGLTexture::Target2D) +{ +} + +ViewFinderGL::~ViewFinderGL() +{ + removeShader(); + + if (textureY_.isCreated()) + textureY_.destroy(); + + if (textureU_.isCreated()) + textureU_.destroy(); + + if (textureV_.isCreated()) + textureV_.destroy(); + + vbuf_.destroy(); +} + +const QList &ViewFinderGL::nativeFormats() const +{ + return (::supportFormats); +} + +int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, + const QSize &size) +{ + int ret = 0; + + if (isFormatSupport(format)) { + format_ = format; + size_ = size; + } else { + ret = -1; + } + updateGeometry(); + return ret; +} + +void ViewFinderGL::stop() +{ + if (buffer_) { + renderComplete(buffer_); + buffer_ = nullptr; + } +} + +QImage ViewFinderGL::getCurrentImage() +{ + QMutexLocker locker(&mutex_); + + return (grabFramebuffer()); +} + +void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) +{ + if (buffer->planes().size() != 1) { + qWarning() << "Multi-planar buffers are not supported"; + return; + } + + if (buffer_) + renderComplete(buffer_); + + unsigned char *memory = static_cast(map->memory); + if (memory) { + yuvDataPtr_ = memory; + update(); + buffer_ = buffer; + } +} + +bool ViewFinderGL::isFormatSupport(const libcamera::PixelFormat &format) +{ + bool ret = true; + switch (format) { + case libcamera::formats::NV12: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_UV_f.glsl"; + break; + case libcamera::formats::NV21: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_VU_f.glsl"; + break; + case libcamera::formats::NV16: + horzSubSample_ = 2; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_UV_f.glsl"; + break; + case libcamera::formats::NV61: + horzSubSample_ = 2; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_VU_f.glsl"; + break; + case libcamera::formats::NV24: + horzSubSample_ = 1; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_UV_f.glsl"; + break; + case libcamera::formats::NV42: + horzSubSample_ = 1; + vertSubSample_ = 1; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_2_planes_VU_f.glsl"; + break; + case libcamera::formats::YUV420: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_3_planes_UV_f.glsl"; + break; + case libcamera::formats::YVU420: + horzSubSample_ = 2; + vertSubSample_ = 2; + vsrc_ = ":NV_vertex_shader.glsl"; + fsrc_ = ":NV_3_planes_VU_f.glsl"; + break; + default: + ret = false; + qWarning() << "[ViewFinderGL]:" + << "format not support yet."; + break; + }; + + return ret; +} + +void ViewFinderGL::createVertexShader() +{ + bool bCompile; + /* Create Vertex Shader */ + pVShader_ = new QOpenGLShader(QOpenGLShader::Vertex, this); + + bCompile = pVShader_->compileSourceFile(vsrc_); + if (!bCompile) { + qWarning() << "[ViewFinderGL]:" << pVShader_->log(); + } + + shaderProgram_.addShader(pVShader_); +} + +bool ViewFinderGL::createFragmentShader() +{ + bool bCompile; + + /* Create Fragment Shader */ + pFShader_ = new QOpenGLShader(QOpenGLShader::Fragment, this); + + bCompile = pFShader_->compileSourceFile(fsrc_); + if (!bCompile) { + qWarning() << "[ViewFinderGL]:" << pFShader_->log(); + return bCompile; + } + + shaderProgram_.addShader(pFShader_); + + /* Link shader pipeline */ + if (!shaderProgram_.link()) { + qWarning() << "[ViewFinderGL]:" << shaderProgram_.log(); + close(); + } + + /* Bind shader pipeline for use */ + if (!shaderProgram_.bind()) { + qWarning() << "[ViewFinderGL]:" << shaderProgram_.log(); + close(); + } + + shaderProgram_.enableAttributeArray(ATTRIB_VERTEX); + shaderProgram_.enableAttributeArray(ATTRIB_TEXTURE); + + shaderProgram_.setAttributeBuffer(ATTRIB_VERTEX, + GL_FLOAT, + 0, + 2, + 2 * sizeof(GLfloat)); + shaderProgram_.setAttributeBuffer(ATTRIB_TEXTURE, + GL_FLOAT, + 8 * sizeof(GLfloat), + 2, + 2 * sizeof(GLfloat)); + + textureUniformY_ = shaderProgram_.uniformLocation("tex_y"); + textureUniformU_ = shaderProgram_.uniformLocation("tex_u"); + textureUniformV_ = shaderProgram_.uniformLocation("tex_v"); + + if (!textureY_.isCreated()) + textureY_.create(); + + if (!textureU_.isCreated()) + textureU_.create(); + + if (!textureV_.isCreated()) + textureV_.create(); + + id_y_ = textureY_.textureId(); + id_u_ = textureU_.textureId(); + id_v_ = textureV_.textureId(); + return true; +} + +void ViewFinderGL::configureTexture(unsigned int id) +{ + glBindTexture(GL_TEXTURE_2D, id); + 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_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +void ViewFinderGL::removeShader() +{ + if (shaderProgram_.isLinked()) { + shaderProgram_.release(); + shaderProgram_.removeAllShaders(); + } + + if (pFShader_) + delete pFShader_; + + if (pVShader_) + delete pVShader_; +} + +void ViewFinderGL::initializeGL() +{ + initializeOpenGLFunctions(); + glEnable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); + + static const GLfloat vertices[]{ + -1.0f, -1.0f, -1.0f, +1.0f, + +1.0f, +1.0f, +1.0f, -1.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 1.0f, 1.0f + }; + + vbuf_.create(); + vbuf_.bind(); + vbuf_.allocate(vertices, sizeof(vertices)); + + /* Create Vertex Shader */ + createVertexShader(); + + glClearColor(1.0f, 1.0f, 1.0f, 0.0f); +} + +void ViewFinderGL::doRender() +{ + switch (format_) { + case libcamera::formats::NV12: + case libcamera::formats::NV21: + case libcamera::formats::NV16: + case libcamera::formats::NV61: + case libcamera::formats::NV24: + case libcamera::formats::NV42: + /* activate texture 0 */ + glActiveTexture(GL_TEXTURE0); + configureTexture(id_y_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width(), + size_.height(), + 0, + GL_RED, + GL_UNSIGNED_BYTE, + yuvDataPtr_); + glUniform1i(textureUniformY_, 0); + + /* activate texture 1 */ + glActiveTexture(GL_TEXTURE1); + configureTexture(id_u_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RG, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RG, + GL_UNSIGNED_BYTE, + (char *)yuvDataPtr_ + size_.width() * size_.height()); + glUniform1i(textureUniformU_, 1); + break; + case libcamera::formats::YUV420: + /* activate texture 0 */ + glActiveTexture(GL_TEXTURE0); + configureTexture(id_y_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width(), + size_.height(), + 0, + GL_RED, + GL_UNSIGNED_BYTE, + yuvDataPtr_); + glUniform1i(textureUniformY_, 0); + + /* activate texture 1 */ + glActiveTexture(GL_TEXTURE1); + configureTexture(id_u_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + (char *)yuvDataPtr_ + size_.width() * size_.height()); + glUniform1i(textureUniformU_, 1); + + /* activate texture 2 */ + glActiveTexture(GL_TEXTURE2); + configureTexture(id_v_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + (char *)yuvDataPtr_ + size_.width() * size_.height() * 5 / 4); + glUniform1i(textureUniformV_, 2); + break; + case libcamera::formats::YVU420: + /* activate texture 0 */ + glActiveTexture(GL_TEXTURE0); + configureTexture(id_y_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width(), + size_.height(), + 0, + GL_RED, + GL_UNSIGNED_BYTE, + yuvDataPtr_); + glUniform1i(textureUniformY_, 0); + + /* activate texture 1 */ + glActiveTexture(GL_TEXTURE2); + configureTexture(id_v_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + (char *)yuvDataPtr_ + size_.width() * size_.height()); + glUniform1i(textureUniformV_, 1); + + /* activate texture 2 */ + glActiveTexture(GL_TEXTURE1); + configureTexture(id_u_); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RED, + size_.width() / horzSubSample_, + size_.height() / vertSubSample_, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + (char *)yuvDataPtr_ + size_.width() * size_.height() * 5 / 4); + glUniform1i(textureUniformU_, 2); + default: + break; + }; +} + +void ViewFinderGL::paintGL() +{ + if (pFShader_ == nullptr) + createFragmentShader(); + + if (yuvDataPtr_) { + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + doRender(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } +} + +void ViewFinderGL::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); +} + +QSize ViewFinderGL::sizeHint() const +{ + return size_.isValid() ? size_ : QSize(640, 480); +} diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h new file mode 100644 index 0000000..e708c32 --- /dev/null +++ b/src/qcam/viewfinder_gl.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Linaro + * + * viewfinder_GL.h - OpenGL Viewfinder for rendering by OpenGL shader + * + */ +#ifndef __VIEWFINDER_GL_H__ +#define __VIEWFINDER_GL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "viewfinder.h" + +class ViewFinderGL : public QOpenGLWidget, + public ViewFinder, + protected QOpenGLFunctions +{ + Q_OBJECT + +public: + ViewFinderGL(QWidget *parent = 0); + ~ViewFinderGL(); + + const QList &nativeFormats() const override; + + int setFormat(const libcamera::PixelFormat &format, const QSize &size) override; + void render(libcamera::FrameBuffer *buffer, MappedBuffer *map) override; + void stop() override; + + QImage getCurrentImage() override; + +Q_SIGNALS: + void renderComplete(libcamera::FrameBuffer *buffer); + +protected: + void initializeGL() override; + void paintGL() override; + void resizeGL(int w, int h) override; + QSize sizeHint() const override; + +private: + bool isFormatSupport(const libcamera::PixelFormat &format); + + void configureTexture(unsigned int id); + bool createFragmentShader(); + void createVertexShader(); + void removeShader(); + void doRender(); + + /* Captured image size, format and buffer */ + libcamera::FrameBuffer *buffer_; + libcamera::PixelFormat format_; + QSize size_; + + /* OpenGL components for render */ + QOpenGLShader *pFShader_; + QOpenGLShader *pVShader_; + QOpenGLShaderProgram shaderProgram_; + + /* Vertex buffer */ + QOpenGLBuffer vbuf_; + + /* Fragment and Vertex shader file name */ + QString fsrc_; + QString vsrc_; + + unsigned char *yuvDataPtr_; + + /* YUV texture planars and parameters */ + GLuint id_u_; + GLuint id_v_; + GLuint id_y_; + GLuint textureUniformU_; + GLuint textureUniformV_; + GLuint textureUniformY_; + QOpenGLTexture textureU_; + QOpenGLTexture textureV_; + QOpenGLTexture textureY_; + unsigned int horzSubSample_; + unsigned int vertSubSample_; + + QImage image_; + QMutex mutex_; /* Prevent concurrent access to image_ */ +}; +#endif /* __VIEWFINDER_GL_H__ */ From patchwork Fri Sep 4 08:43:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Show Liu X-Patchwork-Id: 9485 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 49588BE174 for ; Fri, 4 Sep 2020 08:43:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 12E9E62B5E; Fri, 4 Sep 2020 10:43:52 +0200 (CEST) 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="JabvbRHE"; dkim-atps=neutral Received: from mail-pg1-x52f.google.com (mail-pg1-x52f.google.com [IPv6:2607:f8b0:4864:20::52f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9C5AA62B29 for ; Fri, 4 Sep 2020 10:43:50 +0200 (CEST) Received: by mail-pg1-x52f.google.com with SMTP id 67so3964126pgd.12 for ; Fri, 04 Sep 2020 01:43:50 -0700 (PDT) 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 :mime-version:content-transfer-encoding; bh=gn2JH7tF1O7M0KrQ6KFsWgs+zDBHROUzYsKfAYJPK6Y=; b=JabvbRHEOcBM2+jzz/4sbu6nPlczB1VWPQ3mJfoAyKdPcMWf7GNT2j5onThx1Ryd+M k+xE908vL5GS6BLyqFs04197oqBk4RlZc1U35Bxe7IZS4pSwwR7KPTb5bXqD7JId1TJ1 8reYn+2ZVRzTsRmdQnZ/G3SOY7/oWdPhe0UpE10IITHxYZhKO2GBSTU2M98vBICQChey jOMCI5rvZ+btZIkj70ACiyaX7UFxoCn8wjuUh9AMnP45z0EscbUv/bRYGPz0NoUmD5f/ tntp0lCsdGGZe4RasoZ6BnGqj2UT+m4s62JyLVe92UetxoFBJv7HJyd1bFgGDgqqwlNh pMKA== 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:mime-version:content-transfer-encoding; bh=gn2JH7tF1O7M0KrQ6KFsWgs+zDBHROUzYsKfAYJPK6Y=; b=OlEsYuUpJ0Q/AFoRUkeSVpZPEaI0hDeiPcFifidtwSwMNx+FrIPGAVKCAu9PBx4pie I4vSDXKX4PlPUnr9wZEu5UWwlQ6VqCa/oJNIWAIIZ8EoHKnGoQr3dXpFrxe5KZlB0mcy NBwCNABXbE+LyJuC0s2EU8hG/XM8drFCdRnNCbTbcqFZdAXOPHWFt5rl5f/l4sEnHiaU jMaNwWI55cTXYonDzSJ1+XElU8Efhlzk2TxHtSBhDwkXGNlTWDLzDmM8RhYXvrnHmBxC KTk5sFbjhvqLe8D/m8G1A4Dn6x30sGiALPB0t4NNGzML0/vf30H2tA7OE1+NJbyiw1Zk XtiA== X-Gm-Message-State: AOAM53166+w5El60hJQJxkrbvdr2oyWJ5D6XuDc4v0bCqqo41zM0wLxc W5BQ/tE9Jo1Gesq537s9q7feKfApqEnw/Q== X-Google-Smtp-Source: ABdhPJw/oXxecjyH1fXNVR9uOE7TaAPHBKzLqBSEretmTyQkGWJhXHJuI/c8c5znb1KgwqBKd/ysiQ== X-Received: by 2002:a63:26c6:: with SMTP id m189mr6393156pgm.68.1599209029032; Fri, 04 Sep 2020 01:43:49 -0700 (PDT) Received: from localhost.localdomain (211-20-20-223.HINET-IP.hinet.net. [211.20.20.223]) by smtp.gmail.com with ESMTPSA id a6sm5202148pgt.70.2020.09.04.01.43.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2020 01:43:48 -0700 (PDT) From: Show Liu To: libcamera-devel@lists.libcamera.org Date: Fri, 4 Sep 2020 16:43:16 +0800 Message-Id: <20200904084316.7319-6-show.liu@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200904084316.7319-1-show.liu@linaro.org> References: <20200904084316.7319-1-show.liu@linaro.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 4/4] qcam: add additional command line option to select the render type 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add new option "--render=qt|gles" to select the render type, "--render=gles" to accelerate format conversion and rendering "--render=qt" is the original Qt rendering Signed-off-by: Show Liu Reviewed-by: Laurent Pinchart --- src/qcam/main.cpp | 3 +++ src/qcam/main_window.cpp | 29 ++++++++++++++++++++++++----- src/qcam/main_window.h | 6 ++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/qcam/main.cpp b/src/qcam/main.cpp index bae358d..19d0559 100644 --- a/src/qcam/main.cpp +++ b/src/qcam/main.cpp @@ -35,6 +35,9 @@ OptionsParser::Options parseOptions(int argc, char *argv[]) "help"); parser.addOption(OptStream, &streamKeyValue, "Set configuration of a camera stream", "stream", true); + parser.addOption(OptRender, OptionString, + "Choose the render type use qt|gles", "render", + ArgumentRequired, "render"); OptionsParser::Options options = parser.parse(argc, argv); if (options.isSet(OptHelp)) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 612d978..467cc74 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -91,7 +91,7 @@ private: MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) : saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr), - isCapturing_(false), captureRaw_(false) + isCapturing_(false), captureRaw_(false), renderType_("qt") { int ret; @@ -105,10 +105,29 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) setWindowTitle(title_); connect(&titleTimer_, SIGNAL(timeout()), this, SLOT(updateTitle())); - viewfinder_ = new ViewFinder(this); - connect(viewfinder_, &ViewFinder::renderComplete, - this, &MainWindow::queueRequest); - setCentralWidget(viewfinder_); + if (options_.isSet(OptRender)) + renderType_ = options_[OptRender].toString().c_str(); + + if (renderType_ == "qt") { + viewfinder_ = new ViewFinderQt(this); + ViewFinderQt *vf = dynamic_cast(viewfinder_); + connect(vf, &ViewFinderQt::renderComplete, + this, &MainWindow::queueRequest); + setCentralWidget(vf); + } else if (renderType_ == "gles") { + viewfinder_ = new ViewFinderGL(this); + ViewFinderGL *vf = dynamic_cast(viewfinder_); + connect(vf, &ViewFinderGL::renderComplete, + this, &MainWindow::queueRequest); + setCentralWidget(vf); + } else { + qWarning() << "Render Type:" + << QString::fromStdString(renderType_) + << " is not support."; + quit(); + return; + } + adjustSize(); /* Hotplug/unplug support */ diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 3d21779..a69b399 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -26,6 +26,8 @@ #include "../cam/stream_options.h" #include "viewfinder.h" +#include "viewfinder_gl.h" +#include "viewfinder_qt.h" using namespace libcamera; @@ -38,6 +40,7 @@ enum { OptCamera = 'c', OptHelp = 'h', OptStream = 's', + OptRender = 'r', }; class CaptureRequest @@ -134,6 +137,9 @@ private: QElapsedTimer frameRateInterval_; uint32_t previousFrames_; uint32_t framesCaptured_; + + /* Render Type Qt or GLES */ + std::string renderType_; }; #endif /* __QCAM_MAIN_WINDOW__ */