[05/30] libcamera: software_isp: gpu_pipeline_shader_pass: Add base class GpuPipelineShaderPass
diff mbox series

Message ID 20260618122245.946138-6-bryan.odonoghue@linaro.org
State RFC
Headers show
Series
  • RFC/RFT: gpuisp: Multipass with speed optimisations on top
Related show

Commit Message

Bryan O'Donoghue June 18, 2026, 12:22 p.m. UTC
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

Comments

Milan Zamazal June 22, 2026, 7:43 p.m. UTC | #1
Bryan O'Donoghue <bryan.odonoghue@linaro.org> writes:

> 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
>
> diff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp b/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp
> new file mode 100644
> index 000000000..669a1c1b6
> --- /dev/null
> +++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp
> @@ -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 &params)
> +{
> +	/* 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;

I wonder in some places what device is missing...

> +	}
> +
> +	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;
> +}
> +
> +}
> diff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass.h b/src/libcamera/software_isp/gpu_pipeline_shader_pass.h
> new file mode 100644
> index 000000000..d4d4cf34d
> --- /dev/null
> +++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass.h
> @@ -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 &params);
> +	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;

s/void//

> +	virtual void setShaderVariableValues(const DebayerParams &params, 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

s/Textrue/texture/

> +	 * 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 */

I can't parse this sentence.

> +	unsigned int bytesPerPixel_;
> +
> +	/* Shader program identifiers */
> +	GLuint vertexShaderId_ = 0;
> +	GLuint fragmentShaderId_ = 0;
> +	GLuint programId_ = 0;
> +
> +	struct PassConfig passInputCfg_;
> +	struct PassConfig passOutputCfg_;
> +};

Looks reasonable at the first glance, let's see how it evolves in the
followup patches.

> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build
> index 51cc6ac3e..f8bce5203 100644
> --- a/src/libcamera/software_isp/meson.build
> +++ b/src/libcamera/software_isp/meson.build
> @@ -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,

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp b/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp
new file mode 100644
index 000000000..669a1c1b6
--- /dev/null
+++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass.cpp
@@ -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 &params)
+{
+	/* 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;
+}
+
+}
diff --git a/src/libcamera/software_isp/gpu_pipeline_shader_pass.h b/src/libcamera/software_isp/gpu_pipeline_shader_pass.h
new file mode 100644
index 000000000..d4d4cf34d
--- /dev/null
+++ b/src/libcamera/software_isp/gpu_pipeline_shader_pass.h
@@ -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 &params);
+	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 &params, 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 */
diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build
index 51cc6ac3e..f8bce5203 100644
--- a/src/libcamera/software_isp/meson.build
+++ b/src/libcamera/software_isp/meson.build
@@ -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,