diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
index 0ad2320b1..8d80d6fb5 100644
--- a/include/libcamera/internal/egl.h
+++ b/include/libcamera/internal/egl.h
@@ -57,8 +57,8 @@ public:
 	 * \param[in] texture_unit OpenGL texture unit
 	 * \param[in] texture_unit_uniform_id Shader uniform ID
 	 */
-	eGLImage(uint32_t width, uint32_t height, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)
-		: width_(width), height_(height), stride_(stride),
+	eGLImage(GLint format, uint32_t width, uint32_t height, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)
+		: format_(format), width_(width), height_(height), stride_(stride),
 		  framesize_(stride * height),
 		  texture_unit_uniform_id_(texture_unit_uniform_id),
 		  texture_unit_(texture_unit)
@@ -79,6 +79,7 @@ public:
 		glDeleteTextures(1, &texture_);
 	}
 
+	GLint format_;
 	uint32_t width_; /**< Image width in pixels */
 	uint32_t height_; /**< Image height in pixels */
 	uint32_t stride_; /**< Row stride in bytes */
@@ -103,7 +104,7 @@ public:
 
 	int createInputDMABufTexture2D(eGLImage &eglImage, int fd);
 	int createOutputDMABufTexture2D(eGLImage &eglImage, int fd);
-	void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data);
+	void createTexture2D(eGLImage &eglImage, void *data);
 
 	void pushEnv(std::vector<std::string> &shaderEnv, const char *str);
 	void makeCurrent();
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 357918711..b8f5d9b85 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -14,6 +14,8 @@
 #include <sys/mman.h>
 #include <unistd.h>
 
+#include <GLES3/gl32.h>
+
 #include <linux/dma-buf.h>
 #include <linux/dma-heap.h>
 #include <linux/drm_fourcc.h>
@@ -111,13 +113,31 @@ void eGL::syncOutput()
  */
 int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
 {
+	EGLint drm_format;
+
 	ASSERT(tid_ == Thread::currentId());
 
+	switch (eglImage.format_) {
+	case GL_RED:
+	case GL_LUMINANCE:
+		drm_format = DRM_FORMAT_R8;
+		break;
+	case GL_RG:
+		drm_format = DRM_FORMAT_RG88;
+		break;
+	case GL_RGBA:
+		drm_format = DRM_FORMAT_ARGB8888;
+		break;
+	default:
+		LOG(eGL, Error) << "unhandled GL format";
+		return -ENODEV;
+	}
+
 	// clang-format off
 	EGLint image_attrs[] = {
 		EGL_WIDTH, (EGLint)eglImage.width_,
 		EGL_HEIGHT, (EGLint)eglImage.height_,
-		EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
+		EGL_LINUX_DRM_FOURCC_EXT, drm_format,
 		EGL_DMA_BUF_PLANE0_FD_EXT, fd,
 		EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
 		EGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)eglImage.stride_,
@@ -207,9 +227,6 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
 /**
  * \brief Create a 2D texture from a memory buffer
  * \param[in,out] eglImage EGL image to associate with the texture
- * \param[in] format OpenGL internal format (e.g., GL_RGB, GL_RGBA)
- * \param[in] width Texture width in pixels
- * \param[in] height Texture height in pixels
  * \param[in] data Pointer to pixel data, or nullptr for uninitialised texture
  *
  * Creates a 2D texture from a CPU-accessible memory buffer. The texture
@@ -217,7 +234,7 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
  * is useful for uploading static data like lookup tables or uniform color
  * matrices to the GPU.
  */
-void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data)
+void eGL::createTexture2D(eGLImage &eglImage, void *data)
 {
 	ASSERT(tid_ == Thread::currentId());
 
@@ -225,7 +242,7 @@ void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint
 	glBindTexture(GL_TEXTURE_2D, eglImage.texture_);
 
 	// Generate texture, bind, associate image to texture, configure, unbind
-	glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
+	glTexImage2D(GL_TEXTURE_2D, 0, eglImage.format_, eglImage.width_, eglImage.height_, 0, eglImage.format_, GL_UNSIGNED_BYTE, data);
 
 	// Nearest filtering
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index eae4c57f4..a217e3798 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -506,7 +506,7 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam
 	egl_.makeCurrent();
 
 	/* Create a standard texture input */
-	egl_.createTexture2D(*eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data());
+	egl_.createTexture2D(*eglImageBayerIn_, in.planes()[0].data());
 
 	/* Generate the output render framebuffer as render to texture */
 	egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd);
@@ -582,14 +582,14 @@ int DebayerEGL::start()
 
 	LOG(Debayer, Debug) << "Available fragment shader texture units " << maxTextureImageUnits;
 
+	if (initBayerShaders(inputPixelFormat_, outputPixelFormat_))
+		return -EINVAL;
+
 	/* Raw bayer input as texture */
-	eglImageBayerIn_ = std::make_unique<eGLImage>(width_, height_, inputConfig_.stride, GL_TEXTURE0, 0);
+	eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, inputConfig_.stride / bytesPerPixel_, height_, inputConfig_.stride, GL_TEXTURE0, 0);
 
 	/* Texture we will render to */
-	eglImageBayerOut_ = std::make_unique<eGLImage>(outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1);
-
-	if (initBayerShaders(inputPixelFormat_, outputPixelFormat_))
-		return -EINVAL;
+	eglImageBayerOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1);
 
 	return 0;
 }
