Patch Detail
Show a patch.
GET /api/patches/26944/?format=api
{ "id": 26944, "url": "https://patchwork.libcamera.org/api/patches/26944/?format=api", "web_url": "https://patchwork.libcamera.org/patch/26944/", "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": "<20260618122245.946138-12-bryan.odonoghue@linaro.org>", "date": "2026-06-18T12:22:24", "name": "[11/30] libcamera: software_isp: gpu_pipeline_shader_pass: Move common shader selection logic into base class in new method initShaders()", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "c8275afcd7c3116281ad6d51fbdbbf8557bb9115", "submitter": { "id": 175, "url": "https://patchwork.libcamera.org/api/people/175/?format=api", "name": "Bryan O'Donoghue", "email": "bryan.odonoghue@linaro.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/26944/mbox/", "series": [ { "id": 6005, "url": "https://patchwork.libcamera.org/api/series/6005/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6005", "date": "2026-06-18T12:22:13", "name": "RFC/RFT: gpuisp: Multipass with speed optimisations on top", "version": 1, "mbox": "https://patchwork.libcamera.org/series/6005/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/26944/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/26944/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 284FFC3307\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Jun 2026 12:23:22 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1CF1A656C5;\n\tThu, 18 Jun 2026 14:23:21 +0200 (CEST)", "from mail-wm1-x331.google.com (mail-wm1-x331.google.com\n\t[IPv6:2a00:1450:4864:20::331])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 25674629CE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Jun 2026 14:23:06 +0200 (CEST)", "by mail-wm1-x331.google.com with SMTP id\n\t5b1f17b1804b1-490a76757e5so5337745e9.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Jun 2026 05:23:06 -0700 (PDT)", "from inspiron14p-linux ([109.76.144.236])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-4922fa3a4easm275198015e9.3.2026.06.18.05.23.04\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 18 Jun 2026 05:23:05 -0700 (PDT)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=linaro.org header.i=@linaro.org\n\theader.b=\"ivn+yGV0\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=linaro.org; s=google; t=1781785386; x=1782390186;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=PNdjgk6oCBe7hqWUf41J1Jprz/dS4FsZEgZzAJ6B81A=;\n\tb=ivn+yGV0KSWZcRqF14yNXpc5vNc4KeIvDRosSvBn/xT+E1f9duzpLgOobgxBRzqdZE\n\tqIT5/ShDkAR877HcsiOZOEUBDHh4XmHAQFOhAENiEXGQo+3195rG5HfAxiMjHfRx2SEK\n\togkHqK0aKX1d2DWk+YaV0laXXvnKWuLysBJIxCG2cASCotpvkK4+7bK/GD+52ZPMg7kQ\n\tNuyETyZdcih0YwxSUxD16iJWsrVxoeC0auFsVCCnmqw2LodwLlny6oQtlKe6rcvZkn2i\n\tm+oHo4QbaKtEVEVyUak2xzraPgy3cpuIQHIKAIVQX+Ap6Xv2zh9Lh8MkkXWzYzik+Dle\n\tOEfA==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1781785386; x=1782390186;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n\t:to:cc:subject:date:message-id:reply-to;\n\tbh=PNdjgk6oCBe7hqWUf41J1Jprz/dS4FsZEgZzAJ6B81A=;\n\tb=DBevMqwBT7wZbySeRjIpkV18MMcZm12N/Zb2IVAkzcm2LrLoDr1IrrevuxyqhAx6pM\n\tuebNJaikUKGRfwXbKyr5AlpgdwaGchvMMKVwNzO9LW4EYfXygqegXb1gzfBwKaFf2lqR\n\tkZw9qMtEjuFZzMxgQcHljScxvi8aqA2R7QzUQ8jeUS7LpW767FtTFbIsTgFzumNJJf/Q\n\t+7EV6vtPqiQn9kIeKJDFVcAiFQfSOFm6Hjvwu0hNjsHNMFT1GZjNhR+vqA6RuoKNSA6o\n\tK+fRKSYQsOP2deN0mzBiu4G+4pEFGLS3Icj9IfPTAoxWCMq3/gjLjTgPbiCT/rXtt9gf\n\tp8dA==", "X-Gm-Message-State": "AOJu0YwDr/Q8i1cTkyf2wepx+GKAGdxz/G9cCVoqhjDFhSha/HPV9D1h\n\tCaDf9tFM5C5gAL9mpkmXPYNlXJZTkmgM9wkWOsiSDr4pygU/XVNc0bNO86C1vv+MsX0ZReV6ZDQ\n\tVPQJplsg=", "X-Gm-Gg": "AfdE7clrITOQ27CsZRffvI8bFF7VK6TJJ6sp6i1AZPs5oQalna5OcZeQoupSUzYA1mW\n\tednsSu6E+1JNoOPZALD29o+7DyhIYsWVrB2ysbPm7wyDBGr8aZn9xxqzb/l5yjNP1UZJCJnpB8r\n\twGBzGsntY21j8WUg5in7l01tchegLLUdAYraKL0hdtlsTPWNsd13COQB4BbbQHGUYT49WRsA46f\n\tpzx9tw0b9HK6/FyKPHJk4K8s6uk8Zayyw+VKP/icUlEW6A3jMgp2kcM+Lf1RgPqRwYIKFA3uyyn\n\tgl6xL3YUL3QJMVOXxe5t6vzA5LoZdsQO2mk7XjyVAmAq2tgkzXJUC8PUAOQTplmLQ7f8u6gzaIT\n\tv5em5tL+Oze4J/aoaJ3wBvJKUOU9ybZg8vJALBgpX9FOm44NwkvjKAarN2rb9uYy0/7ExfqeFQm\n\t+8sG3YrIlU1A7/biPmYOUku5aAv+PQBoAqgYXiqJc=", "X-Received": "by 2002:a05:600c:83cf:b0:492:2e1c:1d19 with SMTP id\n\t5b1f17b1804b1-49238225f8bmr54202185e9.31.1781785385527; \n\tThu, 18 Jun 2026 05:23:05 -0700 (PDT)", "From": "Bryan O'Donoghue <bryan.odonoghue@linaro.org>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "bryan.odonoghue@linaro.org,\n\tpavel@ucw.cz", "Subject": "[PATCH 11/30] libcamera: software_isp: gpu_pipeline_shader_pass:\n\tMove common shader selection logic into base class in new method\n\tinitShaders()", "Date": "Thu, 18 Jun 2026 13:22:24 +0100", "Message-ID": "<20260618122245.946138-12-bryan.odonoghue@linaro.org>", "X-Mailer": "git-send-email 2.54.0", "In-Reply-To": "<20260618122245.946138-1-bryan.odonoghue@linaro.org>", "References": "<20260618122245.946138-1-bryan.odonoghue@linaro.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Shader initialisation has some common and some pass-specific logic that\nneeds to happen.\n\n- Common: Environment setup such as defining top-level defines as flags to\n include features when compiling shaders. This will have to be consistent\n from one shader feeding the next.\n\n- Shader specific: Selecting which vertex, fragment and potentially compute\n shaders to run - populating the shader compile environment with any\n defines specific to that shader.\n\n- Common: Compiling and linking a shader program. Error checking and\n associating a compiled vertex/fragment or compute shader with a given\n programId_.\n\nMove the common code to the base class and have the base class call out to\na pure virtual funtion that the derived class must implement.\n\nIn this way GpuIspShaderPass::initShaders() calls the derived class\nGpuIspShaderPassDerivedClass::selectShader() while encapsulating that call\nin the afore mentioned common pieces of logic.\n\nSigned-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n---\n .../software_isp/gpu_pipeline_shader_pass.cpp | 118 ++++++++++++++-\n .../software_isp/gpu_pipeline_shader_pass.h | 11 +-\n .../gpu_pipeline_shader_pass_demosiac.cpp | 139 +++---------------\n .../gpu_pipeline_shader_pass_demosiac.h | 3 +-\n 4 files changed, 151 insertions(+), 120 deletions(-)", "diff": "diff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp b/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp\nindex 669a1c1b6..d0d13eef9 100644\n--- a/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp\n+++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp\n@@ -36,16 +36,29 @@ LOG_DEFINE_CATEGORY(GpuShaderPass)\n \n int GpuIspShaderPass::process(eGLImage &eglImageIn, eGLImage &eglImageOut, uint32_t width, uint32_t height, const DebayerParams ¶ms)\n {\n-\t/* Switch to the output framebuffer */\n+\tGLenum err;\n+\n \tegl_.useProgram(programId_);\n+\terr = glGetError();\n+\tif (err != GL_NO_ERROR)\n+\t\tLOG(GpuShaderPass, Error) << \"Switch program @ error \" << err;\n+\n+\t/* Switch to the output framebuffer */\n \tegl_.attachTextureToFBO(eglImageOut);\n+\terr = glGetError();\n+\tif (err != GL_NO_ERROR)\n+\t\tLOG(GpuShaderPass, Error) << \"attachTextureToFBO @ error \" << err;\n \n \tsetShaderVariableValues(params, eglImageIn);\n+\terr = glGetError();\n+\tif (err != GL_NO_ERROR)\n+\t\tLOG(GpuShaderPass, Error) << \"setShaderVariables @ error \" << err;\n+\n \tglViewport(0, 0, width, height);\n \tglClear(GL_COLOR_BUFFER_BIT);\n-\tglDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS);\n \n-\tGLenum err = glGetError();\n+\tglDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS);\n+\terr = glGetError();\n \tif (err != GL_NO_ERROR) {\n \t\tLOG(GpuShaderPass, Error) << \"Drawing scene fail \" << err;\n \t\treturn -ENODEV;\n@@ -71,4 +84,103 @@ void GpuIspShaderPass::configure(const struct PassConfig &passInputCfg, const st\n \tpassOutputCfg_ = passOutputCfg;\n }\n \n+int GpuIspShaderPass::initShaders(PixelFormat inputFormat, PixelFormat outputFormat)\n+{\n+\tstruct ShaderConfig shaderCfg;\n+\tGLenum err;\n+\tint ret;\n+\n+\t/* Target gles 100 glsl requires \"#version x\" as first directive in shader */\n+\tegl_.pushEnv(shaderCfg.shaderEnv, \"#version 100\");\n+\n+\t/* Specify GL_OES_EGL_image_external */\n+\tegl_.pushEnv(shaderCfg.shaderEnv, \"#extension GL_OES_EGL_image_external: enable\");\n+\n+\t/* The BLC and Demosiac shaders want to know this so do it in the base class */\n+\tswitch (inputFormat) {\n+\tcase libcamera::formats::SBGGR8:\n+\tcase libcamera::formats::SBGGR10_CSI2P:\n+\tcase libcamera::formats::SBGGR12_CSI2P:\n+\t\tfirstRed_x_ = 1.0;\n+\t\tfirstRed_y_ = 1.0;\n+\t\tbreak;\n+\tcase libcamera::formats::SGBRG8:\n+\tcase libcamera::formats::SGBRG10_CSI2P:\n+\tcase libcamera::formats::SGBRG12_CSI2P:\n+\t\tfirstRed_x_ = 0.0;\n+\t\tfirstRed_y_ = 1.0;\n+\t\tbreak;\n+\tcase libcamera::formats::SGRBG8:\n+\tcase libcamera::formats::SGRBG10_CSI2P:\n+\tcase libcamera::formats::SGRBG12_CSI2P:\n+\t\tfirstRed_x_ = 1.0;\n+\t\tfirstRed_y_ = 0.0;\n+\t\tbreak;\n+\tcase libcamera::formats::SRGGB8:\n+\tcase libcamera::formats::SRGGB10_CSI2P:\n+\tcase libcamera::formats::SRGGB12_CSI2P:\n+\t\tfirstRed_x_ = 0.0;\n+\t\tfirstRed_y_ = 0.0;\n+\t\tbreak;\n+\tdefault:\n+\t\tLOG(GpuShaderPass, Error) << \"Unsupported input format\";\n+\t\treturn -EINVAL;\n+\t};\n+\n+\t/*\n+\t * Tell shaders how to re-order output taking account of how the pixels\n+\t * are actually stored by EGL.\n+\t */\n+\tswitch (outputFormat) {\n+\tcase formats::ARGB8888:\n+\tcase formats::XRGB8888:\n+\t\tbreak;\n+\tcase formats::ABGR8888:\n+\tcase formats::XBGR8888:\n+\t\tegl_.pushEnv(shaderCfg.shaderEnv, \"#define SWAP_BLUE\");\n+\t\tbreak;\n+\tdefault:\n+\t\tLOG(GpuShaderPass, Error) << \"Unsupported output format\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = selectShaders(shaderCfg, inputFormat, outputFormat);\n+\tif (ret) {\n+\t\tLOG(GpuShaderPass, Error) << \"selectShaders fail\";\n+\t\treturn ret;\n+\t}\n+\n+\tLOG(GpuShaderPass, Info) << \"ShaderPass = \" << typeid(this).name();\n+\n+\tif (egl_.compileVertexShader(vertexShaderId_, shaderCfg.vertexShaderData, shaderCfg.vertexShaderDataLen, shaderCfg.shaderEnv)) {\n+\t\tLOG(GpuShaderPass, Error) << \"Compile vertex shader fail\";\n+\t\treturn -ENODEV;\n+\t}\n+\tutils::scope_exit vShaderGuard([&] { glDeleteShader(vertexShaderId_); });\n+\n+\tif (egl_.compileFragmentShader(fragmentShaderId_, shaderCfg.fragmentShaderData, shaderCfg.fragmentShaderDataLen, shaderCfg.shaderEnv)) {\n+\t\tLOG(GpuShaderPass, Error) << \"Compile fragment shader fail\";\n+\t\treturn -ENODEV;\n+\t}\n+\tutils::scope_exit fShaderGuard([&] { glDeleteShader(fragmentShaderId_); });\n+\n+\tif (egl_.linkProgram(programId_, vertexShaderId_, fragmentShaderId_)) {\n+\t\tLOG(GpuShaderPass, Error) << \"Linking program fail\";\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tegl_.dumpShaderSource(vertexShaderId_);\n+\tegl_.dumpShaderSource(fragmentShaderId_);\n+\n+\t/* Ensure we set the programId_ */\n+\tegl_.useProgram(programId_);\n+\terr = glGetError();\n+\tif (err != GL_NO_ERROR) {\n+\t\tLOG(GpuShaderPass, Error) << \"Use program error \" << err;\n+\t\treturn -ENODEV;\n+\t}\n+\n+\treturn getShaderVariableLocations();\n+}\n+\n }\ndiff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass.h b/src/libcamera/software_isp/gpu_pipeline_shader_pass.h\nindex d55b27a85..a329845ee 100644\n--- a/src/libcamera/software_isp/gpu_pipeline_shader_pass.h\n+++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass.h\n@@ -41,6 +41,14 @@ struct PassConfig {\n \tRectangle window;\n };\n \n+struct ShaderConfig {\n+\tstd::vector<std::string> shaderEnv;\n+\tconst unsigned char *vertexShaderData;\n+\tunsigned int vertexShaderDataLen;\n+\tconst unsigned char *fragmentShaderData;\n+\tunsigned int fragmentShaderDataLen;\n+};\n+\n class GpuIspShaderPass : public Object\n {\n public:\n@@ -51,7 +59,8 @@ public:\n \tvirtual int start();\n \tvirtual void stop();\n \tvirtual void configure(const struct PassConfig &passInputCfg, const struct PassConfig &passOutputCfg);\n-\tvirtual int initShaders(PixelFormat inputFormat, PixelFormat outputFormat) = 0;\n+\tvirtual int initShaders(PixelFormat inputFormat, PixelFormat outputFormat);\n+\tvirtual int selectShaders(struct ShaderConfig &shaderCfg, PixelFormat &inputFormat, PixelFormat &outputFormat) = 0;\n \tvirtual int getShaderVariableLocations(void) = 0;\n \tvirtual void setShaderVariableValues(const DebayerParams ¶ms, eGLImage &eglImageIn) = 0;\n \tvirtual const char *name() const { return \"GpuIspShaderPass\"; }\ndiff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.cpp b/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.cpp\nindex 02d9da2f0..b0c431c13 100644\n--- a/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.cpp\n+++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.cpp\n@@ -44,101 +44,41 @@ void GpuIspShaderPassDemosiac::stop()\n {\n }\n \n-int GpuIspShaderPassDemosiac::initShaders(PixelFormat inputFormat, PixelFormat outputFormat)\n+int GpuIspShaderPassDemosiac::selectShaders(struct ShaderConfig &shaderCfg, [[maybe_unused]]PixelFormat &inputFormat, [[maybe_unused]]PixelFormat &outputFormat)\n {\n-\tstd::vector<std::string> shaderEnv;\n-\tunsigned int fragmentShaderDataLen = 0;\n-\tconst unsigned char *fragmentShaderData = 0;\n-\tunsigned int vertexShaderDataLen = 0;\n-\tconst unsigned char *vertexShaderData = 0;\n-\tGLenum err;\n-\n-\t/* Target gles 100 glsl requires \"#version x\" as first directive in shader */\n-\tegl_.pushEnv(shaderEnv, \"#version 100\");\n-\n-\t/* Specify GL_OES_EGL_image_external */\n-\tegl_.pushEnv(shaderEnv, \"#extension GL_OES_EGL_image_external: enable\");\n-\n-\t/*\n-\t * Tell shaders how to re-order output taking account of how the pixels\n-\t * are actually stored by EGL.\n-\t */\n-\tswitch (outputFormat) {\n-\tcase formats::ARGB8888:\n-\tcase formats::XRGB8888:\n-\t\tbreak;\n-\tcase formats::ABGR8888:\n-\tcase formats::XBGR8888:\n-\t\tegl_.pushEnv(shaderEnv, \"#define SWAP_BLUE\");\n-\t\tbreak;\n-\tdefault:\n-\t\tLOG(GpuShaderDemosiac, Error) << \"Unsupported output format\";\n-\t\treturn -EINVAL;\n-\t}\n-\n \t/* Pixel location parameters */\n \tglFormat_ = GL_LUMINANCE;\n \tbytesPerPixel_ = 1;\n \tshaderStridePixels_ = passInputCfg_.stride;\n \n-\tswitch (inputFormat) {\n-\tcase libcamera::formats::SBGGR8:\n-\tcase libcamera::formats::SBGGR10_CSI2P:\n-\tcase libcamera::formats::SBGGR12_CSI2P:\n-\t\tfirstRed_x_ = 1.0;\n-\t\tfirstRed_y_ = 1.0;\n-\t\tbreak;\n-\tcase libcamera::formats::SGBRG8:\n-\tcase libcamera::formats::SGBRG10_CSI2P:\n-\tcase libcamera::formats::SGBRG12_CSI2P:\n-\t\tfirstRed_x_ = 0.0;\n-\t\tfirstRed_y_ = 1.0;\n-\t\tbreak;\n-\tcase libcamera::formats::SGRBG8:\n-\tcase libcamera::formats::SGRBG10_CSI2P:\n-\tcase libcamera::formats::SGRBG12_CSI2P:\n-\t\tfirstRed_x_ = 1.0;\n-\t\tfirstRed_y_ = 0.0;\n-\t\tbreak;\n-\tcase libcamera::formats::SRGGB8:\n-\tcase libcamera::formats::SRGGB10_CSI2P:\n-\tcase libcamera::formats::SRGGB12_CSI2P:\n-\t\tfirstRed_x_ = 0.0;\n-\t\tfirstRed_y_ = 0.0;\n-\t\tbreak;\n-\tdefault:\n-\t\tLOG(GpuShaderDemosiac, Error) << \"Unsupported input format\";\n-\t\treturn -EINVAL;\n-\t};\n-\n \t/* Shader selection */\n \tswitch (inputFormat) {\n \tcase libcamera::formats::SBGGR8:\n \tcase libcamera::formats::SGBRG8:\n \tcase libcamera::formats::SGRBG8:\n \tcase libcamera::formats::SRGGB8:\n-\t\tfragmentShaderData = bayer_unpacked_frag;\n-\t\tfragmentShaderDataLen = bayer_unpacked_frag_len;\n-\t\tvertexShaderData = bayer_unpacked_vert;\n-\t\tvertexShaderDataLen = bayer_unpacked_vert_len;\n+\t\tshaderCfg.fragmentShaderData = bayer_unpacked_frag;\n+\t\tshaderCfg.fragmentShaderDataLen = bayer_unpacked_frag_len;\n+\t\tshaderCfg.vertexShaderData = bayer_unpacked_vert;\n+\t\tshaderCfg.vertexShaderDataLen = bayer_unpacked_vert_len;\n \t\tbreak;\n \tcase libcamera::formats::SBGGR10_CSI2P:\n \tcase libcamera::formats::SGBRG10_CSI2P:\n \tcase libcamera::formats::SGRBG10_CSI2P:\n \tcase libcamera::formats::SRGGB10_CSI2P:\n-\t\tegl_.pushEnv(shaderEnv, \"#define RAW10P\");\n+\t\tegl_.pushEnv(shaderCfg.shaderEnv, \"#define RAW10P\");\n \t\tif (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) {\n-\t\t\tfragmentShaderData = bayer_unpacked_frag;\n-\t\t\tfragmentShaderDataLen = bayer_unpacked_frag_len;\n-\t\t\tvertexShaderData = bayer_unpacked_vert;\n-\t\t\tvertexShaderDataLen = bayer_unpacked_vert_len;\n+\t\t\tshaderCfg.fragmentShaderData = bayer_unpacked_frag;\n+\t\t\tshaderCfg.fragmentShaderDataLen = bayer_unpacked_frag_len;\n+\t\t\tshaderCfg.vertexShaderData = bayer_unpacked_vert;\n+\t\t\tshaderCfg.vertexShaderDataLen = bayer_unpacked_vert_len;\n \t\t\tglFormat_ = GL_RG;\n \t\t\tbytesPerPixel_ = 2;\n \t\t} else {\n-\t\t\tfragmentShaderData = bayer_1x_packed_frag;\n-\t\t\tfragmentShaderDataLen = bayer_1x_packed_frag_len;\n-\t\t\tvertexShaderData = identity_vert;\n-\t\t\tvertexShaderDataLen = identity_vert_len;\n+\t\t\tshaderCfg.fragmentShaderData = bayer_1x_packed_frag;\n+\t\t\tshaderCfg.fragmentShaderDataLen = bayer_1x_packed_frag_len;\n+\t\t\tshaderCfg.vertexShaderData = identity_vert;\n+\t\t\tshaderCfg.vertexShaderDataLen = identity_vert_len;\n \t\t\tshaderStridePixels_ = passInputCfg_.size.width;\n \t\t}\n \t\tbreak;\n@@ -146,56 +86,25 @@ int GpuIspShaderPassDemosiac::initShaders(PixelFormat inputFormat, PixelFormat o\n \tcase libcamera::formats::SGBRG12_CSI2P:\n \tcase libcamera::formats::SGRBG12_CSI2P:\n \tcase libcamera::formats::SRGGB12_CSI2P:\n-\t\tegl_.pushEnv(shaderEnv, \"#define RAW12P\");\n+\t\tegl_.pushEnv(shaderCfg.shaderEnv, \"#define RAW12P\");\n \t\tif (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) {\n-\t\t\tfragmentShaderData = bayer_unpacked_frag;\n-\t\t\tfragmentShaderDataLen = bayer_unpacked_frag_len;\n-\t\t\tvertexShaderData = bayer_unpacked_vert;\n-\t\t\tvertexShaderDataLen = bayer_unpacked_vert_len;\n+\t\t\tshaderCfg.fragmentShaderData = bayer_unpacked_frag;\n+\t\t\tshaderCfg.fragmentShaderDataLen = bayer_unpacked_frag_len;\n+\t\t\tshaderCfg.vertexShaderData = bayer_unpacked_vert;\n+\t\t\tshaderCfg.vertexShaderDataLen = bayer_unpacked_vert_len;\n \t\t\tglFormat_ = GL_RG;\n \t\t\tbytesPerPixel_ = 2;\n \t\t} else {\n-\t\t\tfragmentShaderData = bayer_1x_packed_frag;\n-\t\t\tfragmentShaderDataLen = bayer_1x_packed_frag_len;\n-\t\t\tvertexShaderData = identity_vert;\n-\t\t\tvertexShaderDataLen = identity_vert_len;\n+\t\t\tshaderCfg.fragmentShaderData = bayer_1x_packed_frag;\n+\t\t\tshaderCfg.fragmentShaderDataLen = bayer_1x_packed_frag_len;\n+\t\t\tshaderCfg.vertexShaderData = identity_vert;\n+\t\t\tshaderCfg.vertexShaderDataLen = identity_vert_len;\n \t\t\tshaderStridePixels_ = passInputCfg_.size.width;\n \t\t}\n \t\tbreak;\n \t};\n \n-\t/* TODO: move from here to the end of the method into a helper function in the base class\n-\t * this logic will be common to all pipeline instances\n-\t */\n-\tif (egl_.compileVertexShader(vertexShaderId_, vertexShaderData, vertexShaderDataLen, shaderEnv)) {\n-\t\tLOG(GpuShaderDemosiac, Error) << \"Compile vertex shader fail\";\n-\t\treturn -ENODEV;\n-\t}\n-\tutils::scope_exit vShaderGuard([&] { glDeleteShader(vertexShaderId_); });\n-\n-\tif (egl_.compileFragmentShader(fragmentShaderId_, fragmentShaderData, fragmentShaderDataLen, shaderEnv)) {\n-\t\tLOG(GpuShaderDemosiac, Error) << \"Compile fragment shader fail\";\n-\t\treturn -ENODEV;\n-\t}\n-\tutils::scope_exit fShaderGuard([&] { glDeleteShader(fragmentShaderId_); });\n-\n-\tif (egl_.linkProgram(programId_, vertexShaderId_, fragmentShaderId_)) {\n-\t\tLOG(GpuShaderDemosiac, Error) << \"Linking program fail\";\n-\t\treturn -ENODEV;\n-\t}\n-\n-\tegl_.dumpShaderSource(vertexShaderId_);\n-\tegl_.dumpShaderSource(fragmentShaderId_);\n-\n-\t/* Ensure we set the programId_ */\n-\tegl_.useProgram(programId_);\n-\terr = glGetError();\n-\tif (err != GL_NO_ERROR) {\n-\t\tLOG(GpuShaderDemosiac, Error) << \"Use program error \" << err;\n-\t\treturn -ENODEV;\n-\t}\n-\n-\treturn getShaderVariableLocations();\n+\treturn 0;\n }\n \n int GpuIspShaderPassDemosiac::getShaderVariableLocations(void)\ndiff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.h b/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.h\nindex 60f175ad3..c83024bc4 100644\n--- a/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.h\n+++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass_demosiac.h\n@@ -37,10 +37,11 @@ public:\n \tvoid stop();\n \n \t/* Things that every ISP pipeline pass will need to do */\n-\tint initShaders(PixelFormat inputFormat, PixelFormat outputFormat);\n \tint getShaderVariableLocations(void);\n \tvoid setShaderVariableValues(const DebayerParams ¶ms, eGLImage &eglImageIn);\n+\tint selectShaders(struct ShaderConfig &shaderCfg, PixelFormat &inputFormat, PixelFormat &outputFormat);\n \tconst char *name() const override { return \"GpuIspShaderPassDemosiac\"; }\n+\n private:\n \t/* Shader parameters */\n \tGLint textureUniformStep_;\n", "prefixes": [ "11/30" ] }