new file mode 100644
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Linaro Ltd
+ *
+ * Simple software ISP implementation
+ */
+
+#include <cmath>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/thread.h>
+#include <libcamera/base/utils.h>
+
+#include <libcamera/controls.h>
+#include <libcamera/formats.h>
+#include <libcamera/stream.h>
+
+#include "libcamera/internal/framebuffer.h"
+#include "libcamera/internal/ipa_manager.h"
+#include "libcamera/internal/software_isp/debayer_params.h"
+
+#include "gpu_pipeline_shader_pass.h"
+
+/**
+ * \file software_isp.cpp
+ * \brief Simple software ISP implementation
+ */
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(GpuShaderPass)
+
+int GpuIspShaderPass::process(eGLImage &eglImageIn, eGLImage &eglImageOut, uint32_t width, uint32_t height, const DebayerParams ¶ms)
+{
+ /* Switch to the output framebuffer */
+ egl_.useProgram(programId_);
+ egl_.attachTextureToFBO(eglImageOut);
+
+ setShaderVariableValues(params, eglImageIn);
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS);
+
+ GLenum err = glGetError();
+ if (err != GL_NO_ERROR) {
+ LOG(GpuShaderPass, Error) << "Drawing scene fail " << err;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int GpuIspShaderPass::start()
+{
+ return 0;
+}
+
+void GpuIspShaderPass::stop()
+{
+ if (programId_)
+ glDeleteProgram(programId_);
+}
+
+void GpuIspShaderPass::configure(const struct PassConfig &passInputCfg, const struct PassConfig &passOutputCfg)
+{
+ passInputCfg_ = passInputCfg;
+ passOutputCfg_ = passOutputCfg;
+}
+
+}
new file mode 100644
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Linaro Ltd
+ *
+ * Authors:
+ * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+ *
+ * GpuIspIspShaderPass base class
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/object.h>
+#include <libcamera/base/signal.h>
+
+#include <libcamera/geometry.h>
+#include <libcamera/stream.h>
+
+#include "libcamera/internal/egl.h"
+#include "libcamera/internal/software_isp/debayer_params.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl32.h>
+
+#include "../glsl_shaders.h"
+
+namespace libcamera {
+
+#define DEBAYER_OPENGL_COORDS 4
+
+class FrameBuffer;
+
+struct PassConfig {
+ Size size;
+ unsigned int stride;
+ PixelFormat format;
+ Rectangle window;
+};
+
+class GpuIspShaderPass : public Object
+{
+public:
+ GpuIspShaderPass(eGL& egl) : egl_(egl) {}
+ ~GpuIspShaderPass() {}
+
+ virtual int process(eGLImage &eglImageIn, eGLImage &eglImageOut, uint32_t width, uint32_t height, const DebayerParams ¶ms);
+ virtual int start();
+ virtual void stop();
+ virtual void configure(const struct PassConfig &passInputCfg, const struct PassConfig &passOutputCfg);
+ virtual int initShaders(PixelFormat inputFormat, PixelFormat outputFormat) = 0;
+ virtual int getShaderVariableLocations(void) = 0;
+ virtual void setShaderVariableValues(const DebayerParams ¶ms, eGLImage &eglImageIn) = 0;
+ virtual const char *name() const { return "GpuIspShaderPass"; }
+
+ unsigned int getBytesPerPixel() { return bytesPerPixel_; };
+
+ /* glFormat_ is a special case we are moving to one shader which will use GL_R
+ * so rather than do a hack make ShaderPasses do the Textrue allocation and thus have
+ * access to glFormat_. Make glFormat_ available to the upper level class.
+ * This variabile will be dropped at the end of the series anyway.
+ */
+ GLint glFormat_;
+
+protected:
+ eGL& egl_;
+
+ /* Shader calculates this getter provides ability to interrogate if needed */
+ unsigned int bytesPerPixel_;
+
+ /* Shader program identifiers */
+ GLuint vertexShaderId_ = 0;
+ GLuint fragmentShaderId_ = 0;
+ GLuint programId_ = 0;
+
+ struct PassConfig passInputCfg_;
+ struct PassConfig passOutputCfg_;
+};
+
+} /* namespace libcamera */
@@ -32,6 +32,7 @@ if mesa_works
libcamera_internal_sources += files([
'../egl.cpp',
'software_isp_pipeline_gpu.cpp',
+ 'gpu_pipeline_shader_pass.cpp',
])
libcamera_deps += [
libegl,
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> --- .../software_isp/gpu_pipeline_shader_pass.cpp | 74 +++++++++++++++++ .../software_isp/gpu_pipeline_shader_pass.h | 83 +++++++++++++++++++ src/libcamera/software_isp/meson.build | 1 + 3 files changed, 158 insertions(+) create mode 100644 src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp create mode 100644 src/libcamera/software_isp/gpu_pipeline_shader_pass.h