Patch Detail
Show a patch.
GET /api/patches/17119/?format=api
{ "id": 17119, "url": "https://patchwork.libcamera.org/api/patches/17119/?format=api", "web_url": "https://patchwork.libcamera.org/patch/17119/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/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": "<20220814160747.52093-4-kunalagarwal1072002@gmail.com>", "date": "2022-08-14T16:07:45", "name": "[libcamera-devel,v3,4/6] pipeline: simple: GL Converter implementation", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "6fd3a46535e6298b3bb883a0e5b61ddd89728a3c", "submitter": { "id": 116, "url": "https://patchwork.libcamera.org/api/people/116/?format=api", "name": "Kunal Agarwal", "email": "kunalagarwal1072002@gmail.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/17119/mbox/", "series": [ { "id": 3414, "url": "https://patchwork.libcamera.org/api/series/3414/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3414", "date": "2022-08-14T16:07:42", "name": "[libcamera-devel,v3,1/6] pipeline: simple: shader: Shaders for debayering", "version": 3, "mbox": "https://patchwork.libcamera.org/series/3414/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/17119/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/17119/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 8401FC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 14 Aug 2022 16:09:00 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2140661FC6;\n\tSun, 14 Aug 2022 18:09:00 +0200 (CEST)", "from mail-pf1-x430.google.com (mail-pf1-x430.google.com\n\t[IPv6:2607:f8b0:4864:20::430])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 064A661FBC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Aug 2022 18:08:59 +0200 (CEST)", "by mail-pf1-x430.google.com with SMTP id k14so4978993pfh.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Aug 2022 09:08:58 -0700 (PDT)", "from pop-os.localdomain ([115.96.217.20])\n\tby smtp.googlemail.com with ESMTPSA id\n\tj6-20020a170902da8600b001709aea1516sm5576653plx.276.2022.08.14.09.08.54\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tSun, 14 Aug 2022 09:08:56 -0700 (PDT)" ], "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1660493340;\n\tbh=xDQy7Yy0hcbmpWo62Aixp8tF1ZzVL9XntObilG+0xww=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=fSE1ybFlUWdVuqegh14DNjX6/tB7dFer3hKsomeNwYpoZJziLsee2FjZOzvlYOTB8\n\t0emJLoW3T2E/vmFgx2VYiYGTwEulbSFJeHpJ0zOr44cJffv27OtAVsvEDK65VRmIL0\n\tljkV9ZP86cOh+7lZ9m7IVyDeAR0jJOM16tuACHjaIOl1MfWwUPYxDRDgm6qPhVpbt+\n\trgpJdC4T5Tua5tugdzHZA4LUXsMC/XdNmVOGFLY55CyyEgk6T5K6wt8k6U1POg2Jag\n\t3X49EhEl8uLwZTEAgV5DAhpCs17Re0tpYnw0vK0tmVyNFAgV7iQGI34dTPzN6zUcmY\n\tiY+hKlmc+3hNQ==", "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc;\n\tbh=eQ+c35Jw1mdaAvRe1cjqx4UoVwJ02sxS2HxP9a+AEoo=;\n\tb=HKcLO1xdS+QANOigJsggytzfAnYBCDbIs2WLv2ygaDS1gJFguDolA1ybKri8VUOyFx\n\t/p2Z+1gRGj+TRaNO4YRXaxwBK4P7FflG4LUE2IgfTTKnk3e/2vv6+874lan5wCjRq2ON\n\tkNRjaBLtatB63QeEn9V5wUNBhE3Hm+hUJitT2qdVwDswBwAuf0NK+AUVRcV7ZZppUmq5\n\tqsHHQvOlb1nowtIxBMg7Lj8zx/Uc1pqPtcEQ4U3VkAUv/d6v8XqCsZHwOBKuhDn6Vk94\n\ttOI3o8yaGcUuw6J+SkpH5e80AzBCQU0gWkY3O+M/jkPMN8nJIikGYA7/MK46Bs02UnV1\n\t+TLw==" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"HKcLO1xd\"; dkim-atps=neutral", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc;\n\tbh=eQ+c35Jw1mdaAvRe1cjqx4UoVwJ02sxS2HxP9a+AEoo=;\n\tb=TrXCYtNYoo9LmJrrEtIxkHNbUy3dVQB6qgqScwYEUn3hMXXvfKhqyQcgMyg0fGRV+j\n\tRJx3TPvHGC0PFydXiegFFgJ5C6ihHNKeVu2cIWchCQCQHZ0iID4slvAxdKWafFa2B9Vx\n\tNTcte/2tZSXeEnXhIg+AL6oY+0ZeUq+G2x3VUsAymzXd5TKC/TH3EAtM9jI/h1IV6lys\n\t6oSFg5nfTIkGDZhfsq2TjiAROle8NBrzUOieUD41QAsmGM3rXwfFWk80gvODUh09ptnt\n\tVW+UWbaE9/j5QvrlZZo9qWyjh57pNYRv9tah9JsReBVn3S8Jr/vM+ifPOa1qMC796x29\n\tkweQ==", "X-Gm-Message-State": "ACgBeo2kz5C8sIhmEhNDwIQFW2tGnfkebUCoWmFhxCVmw1ZHFvCDiIyn\n\t1VZ6B6IPwCSqQoUFfHQFqqS+ajn5v8g=", "X-Google-Smtp-Source": "AA6agR5aIGL3dY+ggWYLc0g3w0bIYMt2P2gl4N3XSsWCC0vjO1V8U0O7xlG5qtz/k4i73XR/daEBEA==", "X-Received": "by 2002:aa7:9813:0:b0:52d:395d:c98d with SMTP id\n\te19-20020aa79813000000b0052d395dc98dmr12611450pfl.55.1660493336987; \n\tSun, 14 Aug 2022 09:08:56 -0700 (PDT)", "To": "libcamera-devel@lists.libcamera.org", "Date": "Sun, 14 Aug 2022 21:37:45 +0530", "Message-Id": "<20220814160747.52093-4-kunalagarwal1072002@gmail.com>", "X-Mailer": "git-send-email 2.25.1", "In-Reply-To": "<20220814160747.52093-1-kunalagarwal1072002@gmail.com>", "References": "<20220814160747.52093-1-kunalagarwal1072002@gmail.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v3 4/6] pipeline: simple: GL Converter\n\timplementation", "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>", "From": "Kunal Agarwal via libcamera-devel <libcamera-devel@lists.libcamera.org>", "Reply-To": "Kunal Agarwal <kunalagarwal1072002@gmail.com>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Drop-in replacement for already existing converter which performs\ndebayering on Raw input data and outputs data in RGB format\n\nThe GL converter uses GPU for debayering via OpenGL compute\nShaders\n\nSigned-off-by: Kunal Agarwal <kunalagarwal1072002@gmail.com>\n---\n .../pipeline/simple/converter_gl.cpp | 297 ++++++++++++++++++\n src/libcamera/pipeline/simple/converter_gl.h | 116 +++++++\n 2 files changed, 413 insertions(+)\n create mode 100644 src/libcamera/pipeline/simple/converter_gl.cpp\n create mode 100644 src/libcamera/pipeline/simple/converter_gl.h", "diff": "diff --git a/src/libcamera/pipeline/simple/converter_gl.cpp b/src/libcamera/pipeline/simple/converter_gl.cpp\nnew file mode 100644\nindex 00000000..2d123da7\n--- /dev/null\n+++ b/src/libcamera/pipeline/simple/converter_gl.cpp\n@@ -0,0 +1,297 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2022, Kunal Agarwal\n+ *\n+ * converter_gl.cpp - GL converter for debayering\n+ */\n+\n+#include \"converter_gl.h\"\n+\n+#include <gbm.h>\n+#include <limits.h>\n+\n+#include <libcamera/base/unique_fd.h>\n+\n+#include <libcamera/formats.h>\n+#include <libcamera/framebuffer.h>\n+\n+#include \"libcamera/internal/formats.h\"\n+\n+#include <GLES3/gl3.h>\n+#include <GLES3/gl3ext.h>\n+\n+#include \"texture.h\"\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(SimplePipeline)\n+\n+float rectangleVertices[] = {\n+\t/* Coords */ /* texCoords */\n+\t1.0f, -1.0f, 1.0f, 0.0f,\n+\t-1.0f, -1.0f, 0.0f, 0.0f,\n+\t-1.0f, 1.0f, 0.0f, 1.0f,\n+\n+\t1.0f, 1.0f, 1.0f, 1.0f,\n+\t1.0f, -1.0f, 1.0f, 0.0f,\n+\t-1.0f, 1.0f, 0.0f, 1.0f\n+};\n+\n+int SimpleConverter::configure(const StreamConfiguration &inputCfg,\n+\t\t\t const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs)\n+{\n+\tint ret = configureGL(inputCfg, outputCfgs.front());\n+\treturn ret;\n+}\n+\n+int SimpleConverter::configureGL(const StreamConfiguration &inputCfg,\n+\t\t\t\t const StreamConfiguration &outputCfg)\n+{\n+\tinformat_.size = inputCfg.size;\n+\tinformat_.planes[0].bpl_ = inputCfg.stride;\n+\toutformat_.size = outputCfg.size;\n+\toutformat_.planes[0].bpl_ = outputCfg.stride;\n+\treturn 0;\n+}\n+\n+std::vector<PixelFormat> SimpleConverter::formats([[maybe_unused]] PixelFormat input)\n+{\n+\treturn {\n+\t\tPixelFormat::fromString(\"RGB888\"),\n+\t\tPixelFormat::fromString(\"ARGB8888\"),\n+\t};\n+}\n+\n+SizeRange SimpleConverter::sizes(const Size &input)\n+{\n+\tSizeRange sizes({ 1, 1 }, input);\n+\treturn sizes;\n+}\n+\n+std::tuple<unsigned int, unsigned int>\n+SimpleConverter::strideAndFrameSize(const PixelFormat &pixelFormat, const Size &sz)\n+{\n+\tconst PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);\n+\treturn std::make_tuple(info.stride(sz.width, 0, 1), info.frameSize(sz, 1));\n+}\n+\n+int SimpleConverter::exportBuffers(unsigned int output, unsigned int count,\n+\t\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n+{\n+\tif (output != 0)\n+\t\treturn -EINVAL;\n+\n+\tif (outputBuffers.size() > 0)\n+\t\treturn -EINVAL;\n+\n+\tstd::vector<std::unique_ptr<FrameBuffer>> out;\n+\tfor (unsigned i = 0; i < count; ++i) {\n+\t\tauto tex = createBuffer();\n+\t\toutputBuffers.emplace_back(tex.second);\n+\t\tbuffers->push_back(std::move(tex.first));\n+\t}\n+\treturn count;\n+}\n+\n+std::pair<std::unique_ptr<FrameBuffer>, GlRenderTarget> SimpleConverter::createBuffer()\n+{\n+\tbo = gbm_bo_create(gbm, outformat_.size.width, outformat_.size.height,\n+\t\t\t GBM_BO_FORMAT_ARGB8888, GBM_BO_USE_RENDERING);\n+\tif (!bo)\n+\t\tLOG(SimplePipeline, Error) << \"GBM buffer not created \";\n+\n+\tunsigned int filedesc = gbm_bo_get_fd(bo);\n+\n+\tLOG(SimplePipeline, Debug) << \"File Descriptor value: \" << filedesc;\n+\n+\tDmabufImage dimg = importDmabuf(filedesc, outformat_.size, libcamera::formats::ARGB8888);\n+\n+\tstd::vector<FrameBuffer::Plane> planes;\n+\tUniqueFD fd(filedesc);\n+\tFrameBuffer::Plane plane;\n+\tplane.fd = SharedFD(std::move(fd));\n+\tplane.offset = gbm_bo_get_offset(bo, 0);\n+\tplane.length = gbm_bo_get_stride_for_plane(bo, 0) * outformat_.size.height;\n+\n+\tplanes.push_back(std::move(plane));\n+\n+\tauto fb = std::make_unique<FrameBuffer>(planes);\n+\treturn std::make_pair(std::move(fb), GlRenderTarget(fb.get(), dimg));\n+}\n+\n+SimpleConverter::DmabufImage SimpleConverter::importDmabuf(int fdesc, Size pixelSize, PixelFormat format)\n+{\n+\tint bytes_per_pixel = 4;\n+\tEGLint const attrs[] = {\n+\t\tEGL_WIDTH,\n+\t\t(int)pixelSize.width,\n+\t\tEGL_HEIGHT,\n+\t\t(int)pixelSize.height,\n+\t\tEGL_LINUX_DRM_FOURCC_EXT,\n+\t\t(int)format.fourcc(),\n+\t\tEGL_DMA_BUF_PLANE0_FD_EXT,\n+\t\tfdesc,\n+\t\tEGL_DMA_BUF_PLANE0_OFFSET_EXT,\n+\t\t0,\n+\t\tEGL_DMA_BUF_PLANE0_PITCH_EXT,\n+\t\t(int)pixelSize.width * bytes_per_pixel,\n+\t\tEGL_NONE,\n+\t};\n+\n+\tEGLImageKHR image = eglCreateImageKHR(\n+\t\tdisplay_,\n+\t\tEGL_NO_CONTEXT,\n+\t\tEGL_LINUX_DMA_BUF_EXT,\n+\t\tNULL,\n+\t\tattrs);\n+\n+\tint e = glGetError();\n+\n+\tif (e != GL_NO_ERROR)\n+\t\tLOG(SimplePipeline, Error) << \"GL_ERROR: \" << e;\n+\n+\tGLuint texture;\n+\tglGenTextures(1, &texture);\n+\tstruct DmabufImage img = {\n+\t\t.texture = texture,\n+\t\t.image = image,\n+\t};\n+\n+\tglBindTexture(GL_TEXTURE_2D, texture);\n+\tauto glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress(\"glEGLImageTargetTexture2DOES\");\n+\tglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);\n+\n+\treturn img;\n+}\n+\n+int SimpleConverter::start()\n+{\n+\teglBindAPI(EGL_OPENGL_API);\n+\tdevice_ = open(\"/dev/dri/card0\", O_RDWR);\n+\n+\tif (!device_)\n+\t\tLOG(SimplePipeline, Error) << \"GBM Device not opened \";\n+\n+\tgbm = gbm_create_device(device_);\n+\n+\tif (!gbm)\n+\t\tLOG(SimplePipeline, Error) << \" GBM Device not created \";\n+\n+\tauto eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress(\"eglGetPlatformDisplayEXT\");\n+\n+\t/* get an EGL display connection */\n+\tdisplay_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, gbm, NULL);\n+\n+\t/* initialize the EGL display connection */\n+\teglInitialize(display_, NULL, NULL);\n+\tEGLConfig config;\n+\tEGLint n_of_configs;\n+\n+\teglGetConfigs(display_, &config, 1, &n_of_configs);\n+\n+\tcontext_ = eglCreateContext(display_, config, EGL_NO_CONTEXT, NULL);\n+\n+\tif (context_ == EGL_NO_CONTEXT) {\n+\t\tEGLint err = eglGetError();\n+\t\tLOG(SimplePipeline, Error) << \" Context creation failed: \" << err;\n+\t\treturn -1;\n+\t}\n+\n+\t/* connect the context to the surface */\n+\teglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_);\n+\n+\tshaderProgram_.callShader(\"default.vert\", \"default.frag\");\n+\tframebufferProgram_.callShader(\"bayer_8.vert\", \"bayer_8.frag\");\n+\tframebufferProgram_.activate();\n+\tglBindAttribLocation(framebufferProgram_.id(), 0, \"vertexIn\");\n+\tglBindAttribLocation(framebufferProgram_.id(), 2, \"textureIn\");\n+\tglUniform1i(glGetUniformLocation(framebufferProgram_.id(), \"tex_y\"), 0);\n+\tglUniform2f(glGetUniformLocation(framebufferProgram_.id(), \"tex_step\"), 1.0f / (informat_.planes[0].bpl_ - 1),\n+\t\t 1.0f / (informat_.size.height - 1));\n+\tglUniform2i(glGetUniformLocation(framebufferProgram_.id(), \"tex_size\"), informat_.size.width,\n+\t\t informat_.size.height);\n+\tglUniform2f(glGetUniformLocation(framebufferProgram_.id(), \"tex_bayer_first_red\"), 0.0, 1.0);\n+\n+\t/* Prepare framebuffer rectangle VBO and VAO */\n+\n+\tglGenVertexArrays(1, &rectVAO);\n+\tglGenBuffers(1, &rectVBO);\n+\tglBindVertexArray(rectVAO);\n+\tglBindBuffer(GL_ARRAY_BUFFER, rectVBO);\n+\tglBufferData(GL_ARRAY_BUFFER, sizeof(rectangleVertices), &rectangleVertices, GL_STATIC_DRAW);\n+\tglEnableVertexAttribArray(0);\n+\tglVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);\n+\tglEnableVertexAttribArray(1);\n+\tglVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));\n+\n+\t/* create FrameBuffer object */\n+\n+\tglGenFramebuffers(1, &fbo_);\n+\tglBindFramebuffer(GL_FRAMEBUFFER, fbo_);\n+\n+\treturn 0;\n+}\n+\n+int SimpleConverter::queueBuffers(FrameBuffer *input,\n+\t\t\t\t const std::map<unsigned int, FrameBuffer *> &outputs)\n+{\n+\tint ret;\n+\tif (outputs.empty())\n+\t\treturn -EINVAL;\n+\n+\tfor (auto &ib : outputs) {\n+\t\tret = queueBufferGL(input, ib.second);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int SimpleConverter::queueBufferGL(FrameBuffer *input, FrameBuffer *output)\n+{\n+\tDmabufImage rend_tex = importDmabuf(output->planes()[0].fd.get(), outformat_.size, libcamera::formats::ARGB8888);\n+\n+\tTexture bayer(GL_TEXTURE_2D, rend_tex.texture);\n+\tbayer.initTexture(GL_TEXTURE0);\n+\tbayer.startTexture(mappedBuffers_[input].get(), GL_LUMINANCE, GL_UNSIGNED_BYTE, informat_.size);\n+\tbayer.unbind();\n+\n+\t/* Error checking framebuffer*/\n+\tGLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);\n+\n+\tif (fboStatus != GL_FRAMEBUFFER_COMPLETE)\n+\t\tLOG(SimplePipeline, Debug) << \"Framebuffer error: \" << fboStatus;\n+\n+\t/* Main */\n+\t/* Bind the custom framebuffer */\n+\tglBindFramebuffer(GL_FRAMEBUFFER, fbo_);\n+\t/* Specify the color of the background */\n+\tglClearColor(0.0f, 0.0f, 0.0f, 1.0f);\n+\t/* Clean the back buffer and assign the new color to it */\n+\tglClear(GL_COLOR_BUFFER_BIT);\n+\t/* Bind the default framebuffer */\n+\tglBindFramebuffer(GL_FRAMEBUFFER, 0);\n+\t/* Draw the framebuffer rectangle */\n+\tframebufferProgram_.activate();\n+\tglBindVertexArray(rectVAO);\n+\tbayer.bind();\n+\tglDrawArrays(GL_TRIANGLES, 0, 6);\n+\n+\treturn 0;\n+}\n+\n+void SimpleConverter::stop()\n+{\n+\t/* Delete all the objects we've created */\n+\tshaderProgram_.deleteProgram();\n+\tglDeleteFramebuffers(1, &fbo_);\n+\teglDestroyContext(display_, context_);\n+\teglTerminate(display_);\n+\n+\tgbm_bo_destroy(bo);\n+\tgbm_device_destroy(gbm);\n+\tclose(device_);\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/simple/converter_gl.h b/src/libcamera/pipeline/simple/converter_gl.h\nnew file mode 100644\nindex 00000000..a61cead0\n--- /dev/null\n+++ b/src/libcamera/pipeline/simple/converter_gl.h\n@@ -0,0 +1,116 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2022, Kunal Agarwal\n+ *\n+ * converter_gl.cpp - GL converter for debayering\n+ */\n+\n+#pragma once\n+\n+#include <assert.h>\n+#include <fcntl.h>\n+#include <gbm.h>\n+#include <map>\n+#include <math.h>\n+#include <stdlib.h>\n+#include <unistd.h>\n+\n+#include <libcamera/base/log.h>\n+#include <libcamera/base/signal.h>\n+\n+#include <libcamera/geometry.h>\n+#include <libcamera/stream.h>\n+\n+#include \"libcamera/internal/mapped_framebuffer.h\"\n+\n+#include <EGL/egl.h>\n+#include <EGL/eglext.h>\n+\n+#include \"shader.h\"\n+\n+namespace libcamera {\n+\n+class FrameBuffer;\n+class GlRenderTarget;\n+\n+class SimpleConverter\n+{\n+public:\n+\tint configure(const StreamConfiguration &inputCfg,\n+\t\t const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs);\n+\tstd::vector<PixelFormat> formats(PixelFormat input);\n+\tSizeRange sizes(const Size &input);\n+\n+\tstd::tuple<unsigned int, unsigned int>\n+\tstrideAndFrameSize(const PixelFormat &pixelFormat, const Size &size);\n+\n+\tint queueBuffers(FrameBuffer *input,\n+\t\t\t const std::map<unsigned int, FrameBuffer *> &outputs);\n+\n+\tint start();\n+\tvoid stop();\n+\n+\tint exportBuffers(unsigned int output, unsigned int count,\n+\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers);\n+\tstd::pair<std::unique_ptr<FrameBuffer>, GlRenderTarget> createBuffer();\n+\tbool isValid() const { return true; }\n+\n+\tSignal<FrameBuffer *> inputBufferReady;\n+\tSignal<FrameBuffer *> outputBufferReady;\n+\tstruct DmabufImage {\n+\t\tGLuint texture;\n+\t\tEGLImageKHR image;\n+\t};\n+\n+private:\n+\tint configureGL(const StreamConfiguration &inputCfg,\n+\t\t\tconst StreamConfiguration &outputCfg);\n+\tDmabufImage importDmabuf(int fdesc, Size pixelSize, PixelFormat format);\n+\tint queueBufferGL(FrameBuffer *input, FrameBuffer *output);\n+\n+\tstd::map<libcamera::FrameBuffer *, std::unique_ptr<MappedFrameBuffer>>\n+\t\tmappedBuffers_;\n+\n+\tstruct ConverterFormat {\n+\t\tstruct Plane {\n+\t\t\tuint32_t size_ = 0;\n+\t\t\tuint32_t bpl_ = 0;\n+\t\t};\n+\t\tPixelFormat fourcc;\n+\t\tSize size;\n+\t\tstd::array<Plane, 3> planes;\n+\t\tunsigned int planesCount = 0;\n+\t};\n+\n+\tint device_;\n+\tunsigned int rectVAO, rectVBO;\n+\tEGLDisplay display_;\n+\tEGLContext context_;\n+\n+\tstruct gbm_device *gbm;\n+\tstruct gbm_bo *bo;\n+\tunsigned int fbo_;\n+\n+\tConverterFormat informat_;\n+\tConverterFormat outformat_;\n+\tShaderProgram shaderProgram_;\n+\tShaderProgram framebufferProgram_;\n+\tstd::vector<GlRenderTarget> outputBuffers;\n+\tPFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress(\"eglCreateImageKHR\");\n+};\n+\n+class GlRenderTarget\n+{\n+public:\n+\tstruct SimpleConverter::DmabufImage texture_;\n+\n+\t/* This is never to be dereferenced. Only serves for comparison */\n+\tconst FrameBuffer *buffer_;\n+\n+\tGlRenderTarget(FrameBuffer *buffer, struct SimpleConverter::DmabufImage texture)\n+\t\t: texture_(texture), buffer_(buffer)\n+\t{\n+\t}\n+};\n+\n+} /* namespace libcamera */\n", "prefixes": [ "libcamera-devel", "v3", "4/6" ] }