Patch Detail
Show a patch.
GET /api/1.1/patches/9482/?format=api
{ "id": 9482, "url": "https://patchwork.libcamera.org/api/1.1/patches/9482/?format=api", "web_url": "https://patchwork.libcamera.org/patch/9482/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20200904084316.7319-3-show.liu@linaro.org>", "date": "2020-09-04T08:43:13", "name": "[libcamera-devel,v4,2/3] qcam: add OpenGL renderer", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "ed6fe20eb0655bc0c8433bef6a8a70cb59b6a312", "submitter": { "id": 24, "url": "https://patchwork.libcamera.org/api/1.1/people/24/?format=api", "name": "Show Liu", "email": "show.liu@linaro.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/9482/mbox/", "series": [ { "id": 1262, "url": "https://patchwork.libcamera.org/api/1.1/series/1262/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1262", "date": "2020-09-04T08:43:11", "name": "qcam: accelerate format conversion by OpenGL shader", "version": 5, "mbox": "https://patchwork.libcamera.org/series/1262/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/9482/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/9482/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E08F3BE174\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 4 Sep 2020 08:43:45 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AE9ED62B2F;\n\tFri, 4 Sep 2020 10:43:45 +0200 (CEST)", "from mail-pj1-x1036.google.com (mail-pj1-x1036.google.com\n\t[IPv6:2607:f8b0:4864:20::1036])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 75B0860371\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 4 Sep 2020 10:43:43 +0200 (CEST)", "by mail-pj1-x1036.google.com with SMTP id b16so2879634pjp.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 04 Sep 2020 01:43:43 -0700 (PDT)", "from localhost.localdomain (211-20-20-223.HINET-IP.hinet.net.\n\t[211.20.20.223]) by smtp.gmail.com with ESMTPSA id\n\ta6sm5202148pgt.70.2020.09.04.01.43.40\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tFri, 04 Sep 2020 01:43:41 -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=\"m3HVSCLl\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=pd0uFP/AovgRjHxc9WoEZwRE9JT0940ZP/Y05SE1T2o=;\n\tb=m3HVSCLl406iZbkT3bCITmzA79Of0mmz1Cyy7OaBfkvL++Emvm9/oa8sTRSgEaxKkv\n\tf/EDceN2/ftlNEaT9oTbEZS22c81dchaendld50/dyXiqICRNQp+BL+PkViQzCIyrLPH\n\tP2saqWsPQZMGfLu04bldgfTOnpYOIAANgBpCxCjYug2EpfCOzbE5oKlLHtHgiXW1Mm37\n\tg+MAOUluKN12MeFCc4BgDRJ9TByrZTeyO/nXPzBOH0q+lhe/amml49aYR8dnpu9TIy+6\n\tPB9EQ6qLd8liamiIPpYqBT68OOGYJOqwLUb+9OiHJEkDjI44OdFO/lywyBXyrwFjLNtV\n\tZN4A==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=pd0uFP/AovgRjHxc9WoEZwRE9JT0940ZP/Y05SE1T2o=;\n\tb=Vz1lgo3UVzv1e4BTTtDzZguMZr2xAs24eX7O/4Jcis+h4HB8oYfVuv2WP2rmGtPbXF\n\t656CLT510zhUhKVe8LApatf/S0r1TFaz1arR2XGQu9MOOzpOzKJdLFtr9Ihq0uLoGmKz\n\tBVuQavFQ3vshwX+PjQLiwpX1volgDB4DUBQpgKjvVtOoLPeZ0KOYkF+2wnFska8tWkl2\n\tBeTbVgamfWG5sSuFy9EPqVEyJWXAM7oS0p9edXFR0KmvFntIaUl5MnADQtfeX549f1Tk\n\tfYh6W28mvj3yprJ9H/CaCUq/m1t3DRAw66GIeUNu5OxuEv9u//M0sUnlqDXys7SvI87O\n\txZjA==", "X-Gm-Message-State": "AOAM5322n3xxOS5oabkczYiqMMdz4XjtsZtQM0N7paypa0ggkQhHe6JE\n\th2JSHEWnU7fW6QQfqaxOT2E97HFhCuoM8w==", "X-Google-Smtp-Source": "ABdhPJzT8jYBb05GgcpcswoMA+O64EYAoRvmba9R0UK7RxxyxypJ0D4bYXYBdFDNBHhY1g3oUmvSsQ==", "X-Received": "by 2002:a17:90a:db49:: with SMTP id\n\tu9mr7090032pjx.90.1599209021500; \n\tFri, 04 Sep 2020 01:43:41 -0700 (PDT)", "From": "Show Liu <show.liu@linaro.org>", "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": "<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>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "qcam: add OpenGL renderer\n\nSigned-off-by: Show Liu <show.liu@linaro.org>\n---\n src/qcam/meson.build | 2 +\n src/qcam/renderer.cpp | 346 ++++++++++++++++++++++++++++++++++++++++++\n src/qcam/renderer.h | 81 ++++++++++\n 3 files changed, 429 insertions(+)\n create mode 100644 src/qcam/renderer.cpp\n create mode 100644 src/qcam/renderer.h", "diff": "diff --git a/src/qcam/meson.build b/src/qcam/meson.build\nindex e0c6f26..8c9032f 100644\n--- a/src/qcam/meson.build\n+++ b/src/qcam/meson.build\n@@ -7,11 +7,13 @@ qcam_sources = files([\n 'main.cpp',\n 'main_window.cpp',\n 'viewfinder.cpp',\n+ 'renderer.cpp'\n ])\n \n qcam_moc_headers = files([\n 'main_window.h',\n 'viewfinder.h',\n+ 'renderer.h'\n ])\n \n qcam_resources = files([\ndiff --git a/src/qcam/renderer.cpp b/src/qcam/renderer.cpp\nnew file mode 100644\nindex 0000000..23e8fa8\n--- /dev/null\n+++ b/src/qcam/renderer.cpp\n@@ -0,0 +1,346 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (C) 2020, Linaro\n+ *\n+ * renderer.cpp - Render YUV format frame by OpenGL shader\n+ */\n+\n+#include \"renderer.h\"\n+\n+Renderer::Renderer()\n+\t: fbo_(nullptr),\n+\t vbo_(QOpenGLBuffer::VertexBuffer),\n+\t pFShader_(nullptr),\n+\t pVShader_(nullptr),\n+\t textureU_(QOpenGLTexture::Target2D),\n+\t textureV_(QOpenGLTexture::Target2D),\n+\t textureY_(QOpenGLTexture::Target2D)\n+{\n+\t/* offscreen format setup */\n+\tsetFormat(requestedFormat());\n+\tcreate();\n+\n+\t/* create OpenGL context */\n+\tif (ctx_.create()) {\n+\t\tctx_.makeCurrent(this);\n+\t\tinitializeOpenGLFunctions();\n+\t} else {\n+\t\tqWarning() << \"[Renderer]: \"\n+\t\t\t << \"OpenGL renderer is not available.\";\n+\t}\n+}\n+\n+Renderer::~Renderer()\n+{\n+\tif (vbo_.isCreated()) {\n+\t\tvbo_.release();\n+\t\tvbo_.destroy();\n+\t}\n+\n+\tif (fbo_) {\n+\t\tfbo_->release();\n+\t\tdelete fbo_;\n+\t}\n+\n+\tremoveShader();\n+\n+\tif (textureY_.isCreated())\n+\t\ttextureY_.destroy();\n+\n+\tif (textureU_.isCreated())\n+\t\ttextureU_.destroy();\n+\n+\tif (textureV_.isCreated())\n+\t\ttextureV_.destroy();\n+\n+\tctx_.doneCurrent();\n+}\n+\n+void Renderer::initializeGL()\n+{\n+\tglEnable(GL_TEXTURE_2D);\n+\tglDisable(GL_DEPTH_TEST);\n+\n+\tstatic const GLfloat vertices[]{\n+\t\t-1.0f, -1.0f, -1.0f, +1.0f,\n+\t\t+1.0f, +1.0f, +1.0f, -1.0f,\n+\t\t0.0f, 1.0f, 0.0f, 0.0f,\n+\t\t1.0f, 0.0f, 1.0f, 1.0f\n+\t};\n+\n+\tvbo_.create();\n+\tvbo_.bind();\n+\tvbo_.allocate(vertices, sizeof(vertices));\n+\n+\tglClearColor(1.0f, 1.0f, 1.0f, 0.0f);\n+}\n+\n+bool Renderer::selectShader(const libcamera::PixelFormat &format)\n+{\n+\tbool ret = true;\n+\tswitch (format) {\n+\tcase libcamera::formats::NV12:\n+\t\thorzSubSample_ = 2;\n+\t\tvertSubSample_ = 2;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_2_planes_UV_f.glsl\";\n+\t\tbreak;\n+\tcase libcamera::formats::NV21:\n+\t\thorzSubSample_ = 2;\n+\t\tvertSubSample_ = 2;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_2_planes_VU_f.glsl\";\n+\t\tbreak;\n+\tcase libcamera::formats::NV16:\n+\t\thorzSubSample_ = 2;\n+\t\tvertSubSample_ = 1;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_2_planes_UV_f.glsl\";\n+\t\tbreak;\n+\tcase libcamera::formats::NV61:\n+\t\thorzSubSample_ = 2;\n+\t\tvertSubSample_ = 1;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_2_planes_VU_f.glsl\";\n+\t\tbreak;\n+\tcase libcamera::formats::NV24:\n+\t\thorzSubSample_ = 1;\n+\t\tvertSubSample_ = 1;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_2_planes_UV_f.glsl\";\n+\t\tbreak;\n+\tcase libcamera::formats::NV42:\n+\t\thorzSubSample_ = 1;\n+\t\tvertSubSample_ = 1;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_2_planes_VU_f.glsl\";\n+\t\tbreak;\n+\tcase libcamera::formats::YUV420:\n+\t\thorzSubSample_ = 2;\n+\t\tvertSubSample_ = 2;\n+\t\tvsrc_ = \":NV_vertex_shader.glsl\";\n+\t\tfsrc_ = \":NV_3_planes_UV_f.glsl\";\n+\t\tbreak;\n+\tdefault:\n+\t\tret = false;\n+\t\tqWarning() << \"[Renderer]: \"\n+\t\t\t << \"format not support yet.\";\n+\t\tbreak;\n+\t};\n+\n+\treturn ret;\n+}\n+\n+void Renderer::removeShader()\n+{\n+\tif (shaderProgram_.isLinked()) {\n+\t\tshaderProgram_.release();\n+\t\tshaderProgram_.removeAllShaders();\n+\t}\n+\n+\tif (pFShader_)\n+\t\tdelete pFShader_;\n+\n+\tif (pVShader_)\n+\t\tdelete pVShader_;\n+}\n+\n+bool Renderer::createShader()\n+{\n+\tbool bCompile;\n+\n+\t/* Create Vertex Shader */\n+\tpVShader_ = new QOpenGLShader(QOpenGLShader::Vertex, this);\n+\n+\tbCompile = pVShader_->compileSourceFile(vsrc_);\n+\tif (!bCompile) {\n+\t\tqWarning() << \"[Renderer]: \" << pVShader_->log();\n+\t\treturn bCompile;\n+\t}\n+\n+\tshaderProgram_.addShader(pVShader_);\n+\n+\t/* Create Fragment Shader */\n+\tpFShader_ = new QOpenGLShader(QOpenGLShader::Fragment, this);\n+\n+\tbCompile = pFShader_->compileSourceFile(fsrc_);\n+\tif (!bCompile) {\n+\t\tqWarning() << \"[Renderer]: \" << pFShader_->log();\n+\t\treturn bCompile;\n+\t}\n+\n+\tshaderProgram_.addShader(pFShader_);\n+\n+\t// Link shader pipeline\n+\tif (!shaderProgram_.link()) {\n+\t\tqWarning() << \"[Renderer]: \" << shaderProgram_.log();\n+\t\treturn false;\n+\t}\n+\n+\t// Bind shader pipeline for use\n+\tif (!shaderProgram_.bind()) {\n+\t\tqWarning() << \"[Renderer]: \" << shaderProgram_.log();\n+\t\treturn false;\n+\t}\n+\treturn true;\n+}\n+\n+bool Renderer::configure(const libcamera::PixelFormat &format, const QSize &size)\n+{\n+\tbool ret = true;\n+\n+\tif (selectShader(format)) {\n+\t\tret = createShader();\n+\t\tif (!ret)\n+\t\t\treturn ret;\n+\n+\t\tshaderProgram_.enableAttributeArray(ATTRIB_VERTEX);\n+\t\tshaderProgram_.enableAttributeArray(ATTRIB_TEXTURE);\n+\n+\t\tshaderProgram_.setAttributeBuffer(ATTRIB_VERTEX,\n+\t\t\t\t\t\t GL_FLOAT,\n+\t\t\t\t\t\t 0,\n+\t\t\t\t\t\t 2,\n+\t\t\t\t\t\t 2 * sizeof(GLfloat));\n+\t\tshaderProgram_.setAttributeBuffer(ATTRIB_TEXTURE,\n+\t\t\t\t\t\t GL_FLOAT,\n+\t\t\t\t\t\t 8 * sizeof(GLfloat),\n+\t\t\t\t\t\t 2,\n+\t\t\t\t\t\t 2 * sizeof(GLfloat));\n+\n+\t\ttextureUniformY_ = shaderProgram_.uniformLocation(\"tex_y\");\n+\t\ttextureUniformU_ = shaderProgram_.uniformLocation(\"tex_u\");\n+\t\ttextureUniformV_ = shaderProgram_.uniformLocation(\"tex_v\");\n+\n+\t\tif (!textureY_.isCreated())\n+\t\t\ttextureY_.create();\n+\n+\t\tif (!textureU_.isCreated())\n+\t\t\ttextureU_.create();\n+\n+\t\tif (!textureV_.isCreated())\n+\t\t\ttextureV_.create();\n+\n+\t\tid_y_ = textureY_.textureId();\n+\t\tid_u_ = textureU_.textureId();\n+\t\tid_v_ = textureV_.textureId();\n+\n+\t\tfbo_ = new QOpenGLFramebufferObject(size.width(),\n+\t\t\t\t\t\t size.height(),\n+\t\t\t\t\t\t GL_TEXTURE_2D);\n+\t\tfbo_->bind();\n+\t\tglViewport(0, 0, size.width(), size.height());\n+\n+\t\tformat_ = format;\n+\t\tsize_ = size;\n+\t} else {\n+\t\tret = false;\n+\t}\n+\treturn ret;\n+}\n+\n+void Renderer::configureTexture(unsigned int id)\n+{\n+\tglBindTexture(GL_TEXTURE_2D, id);\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_WRAP_S, GL_CLAMP_TO_EDGE);\n+\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n+}\n+\n+void Renderer::render(unsigned char *buffer)\n+{\n+\tQMutexLocker locker(&mutex_);\n+\n+\tglClearColor(0.0, 0.0, 0.0, 1.0);\n+\tglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n+\n+\tswitch (format_) {\n+\tcase libcamera::formats::NV12:\n+\tcase libcamera::formats::NV21:\n+\tcase libcamera::formats::NV16:\n+\tcase libcamera::formats::NV61:\n+\tcase libcamera::formats::NV24:\n+\tcase libcamera::formats::NV42:\n+\t\t/* activate texture 0 */\n+\t\tglActiveTexture(GL_TEXTURE0);\n+\t\tconfigureTexture(id_y_);\n+\t\tglTexImage2D(GL_TEXTURE_2D,\n+\t\t\t 0,\n+\t\t\t GL_RED,\n+\t\t\t size_.width(),\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 buffer);\n+\t\tglUniform1i(textureUniformY_, 0);\n+\n+\t\t/* activate texture 1 */\n+\t\tglActiveTexture(GL_TEXTURE1);\n+\t\tconfigureTexture(id_u_);\n+\t\tglTexImage2D(GL_TEXTURE_2D,\n+\t\t\t 0,\n+\t\t\t GL_RG,\n+\t\t\t size_.width() / horzSubSample_,\n+\t\t\t size_.height() / vertSubSample_,\n+\t\t\t 0,\n+\t\t\t GL_RG,\n+\t\t\t GL_UNSIGNED_BYTE,\n+\t\t\t buffer + size_.width() * size_.height());\n+\t\tglUniform1i(textureUniformU_, 1);\n+\t\tbreak;\n+\tcase libcamera::formats::YUV420:\n+\t\t/* activate texture 0 */\n+\t\tglActiveTexture(GL_TEXTURE0);\n+\t\tconfigureTexture(id_y_);\n+\t\tglTexImage2D(GL_TEXTURE_2D,\n+\t\t\t 0,\n+\t\t\t GL_RED,\n+\t\t\t size_.width(),\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 buffer);\n+\t\tglUniform1i(textureUniformY_, 0);\n+\n+\t\t/* activate texture 1 */\n+\t\tglActiveTexture(GL_TEXTURE1);\n+\t\tconfigureTexture(id_u_);\n+\t\tglTexImage2D(GL_TEXTURE_2D,\n+\t\t\t 0,\n+\t\t\t GL_RG,\n+\t\t\t size_.width() / horzSubSample_,\n+\t\t\t size_.height() / vertSubSample_,\n+\t\t\t 0,\n+\t\t\t GL_RG,\n+\t\t\t GL_UNSIGNED_BYTE,\n+\t\t\t buffer + size_.width() * size_.height());\n+\t\tglUniform1i(textureUniformU_, 1);\n+\n+\t\t/* activate texture 2 */\n+\t\tglActiveTexture(GL_TEXTURE2);\n+\t\tconfigureTexture(id_v_);\n+\t\tglTexImage2D(GL_TEXTURE_2D,\n+\t\t\t 0,\n+\t\t\t GL_RG,\n+\t\t\t size_.width() / horzSubSample_,\n+\t\t\t size_.height() / vertSubSample_,\n+\t\t\t 0, GL_RG,\n+\t\t\t GL_UNSIGNED_BYTE,\n+\t\t\t buffer + size_.width() * size_.height() * 5 / 4);\n+\t\tglUniform1i(textureUniformV_, 2);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t};\n+\n+\tglDrawArrays(GL_TRIANGLE_FAN, 0, 4);\n+}\n+\n+QImage Renderer::toImage()\n+{\n+\tQMutexLocker locker(&mutex_);\n+\treturn (fbo_->toImage(true));\n+}\ndiff --git a/src/qcam/renderer.h b/src/qcam/renderer.h\nnew file mode 100644\nindex 0000000..1ea0c48\n--- /dev/null\n+++ b/src/qcam/renderer.h\n@@ -0,0 +1,81 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (C) 2020, Linaro\n+ *\n+ * renderer.h - Render YUV format frame by OpenGL shader\n+ */\n+#ifndef __QCAM_RENDERER_H__\n+#define __QCAM_RENDERER_H__\n+\n+#include <QImage>\n+#include <QMutex>\n+#include <QOffscreenSurface>\n+#include <QOpenGLBuffer>\n+#include <QOpenGLContext>\n+#include <QOpenGLFramebufferObject>\n+#include <QOpenGLFunctions>\n+#include <QOpenGLShader>\n+#include <QOpenGLShaderProgram>\n+#include <QOpenGLTexture>\n+#include <QSize>\n+#include <QSurfaceFormat>\n+\n+#include <libcamera/formats.h>\n+\n+#define ATTRIB_VERTEX 0\n+#define ATTRIB_TEXTURE 1\n+\n+class Renderer : public QOffscreenSurface, protected QOpenGLFunctions\n+{\n+\tQ_OBJECT\n+\n+public:\n+\tRenderer();\n+\t~Renderer();\n+\n+\tvoid initializeGL();\n+\tbool configure(const libcamera::PixelFormat &format, const QSize &size);\n+\tvoid render(unsigned char *buffer);\n+\tQImage toImage();\n+\n+private:\n+\tbool createShader();\n+\tvoid configureTexture(unsigned int id);\n+\tvoid removeShader();\n+\tbool selectShader(const libcamera::PixelFormat &format);\n+\n+\t/* OpenGL renderer components */\n+\tQOpenGLContext ctx_;\n+\tQOpenGLFramebufferObject *fbo_;\n+\tQOpenGLBuffer vbo_;\n+\tQOpenGLShader *pFShader_;\n+\tQOpenGLShader *pVShader_;\n+\tQOpenGLShaderProgram shaderProgram_;\n+\tQSurfaceFormat surfaceFormat_;\n+\n+\t/* Fragment and Vertex shader file */\n+\tQString fsrc_;\n+\tQString vsrc_;\n+\n+\t/* YUV frame size and format */\n+\tlibcamera::PixelFormat format_;\n+\tQSize size_;\n+\n+\t/* YUV texture planars and parameters*/\n+\tGLuint id_u_;\n+\tGLuint id_v_;\n+\tGLuint id_y_;\n+\tGLuint textureUniformU_;\n+\tGLuint textureUniformV_;\n+\tGLuint textureUniformY_;\n+\tQOpenGLTexture textureU_;\n+\tQOpenGLTexture textureV_;\n+\tQOpenGLTexture textureY_;\n+\tunsigned int horzSubSample_;\n+\tunsigned int vertSubSample_;\n+\n+\tQImage image_;\n+\tQMutex mutex_; /* Prevent concurrent access to image_ */\n+};\n+\n+#endif /* __QCAM_RENDERER_H__ */\n", "prefixes": [ "libcamera-devel", "v4", "2/3" ] }