[libcamera-devel] [PATCH][RFC 2/2] qcam: viewfinder_gl: Add shader to render packed RAW12 formats

Andrey Konovalov andrey.konovalov at linaro.org
Mon Nov 9 22:34:11 CET 2020


The shader supports all 4 packed RAW12 variants.
Simple bi-linear filtering is implemented.
The 4 LS bits of the 12-bit colour values are dropped as the RGBA
format we convert into has only 8 bits per colour.

Signed-off-by: Andrey Konovalov <andrey.konovalov at linaro.org>
---
 src/qcam/assets/shader/bayer.vert           | 28 ++++++++
 src/qcam/assets/shader/bayer_12_packed.frag | 68 +++++++++++++++++++
 src/qcam/assets/shader/shaders.qrc          |  2 +
 src/qcam/viewfinder_gl.cpp                  | 74 ++++++++++++++++++++-
 src/qcam/viewfinder_gl.h                    |  7 ++
 5 files changed, 177 insertions(+), 2 deletions(-)
 create mode 100644 src/qcam/assets/shader/bayer.vert
 create mode 100644 src/qcam/assets/shader/bayer_12_packed.frag

diff --git a/src/qcam/assets/shader/bayer.vert b/src/qcam/assets/shader/bayer.vert
new file mode 100644
index 00000000..375e0b60
--- /dev/null
+++ b/src/qcam/assets/shader/bayer.vert
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * bayer.vert - Vertex shader for raw Bayer to RGB conversion
+ */
+
+attribute vec4 vertexIn;
+attribute vec2 textureIn;
+
+uniform vec4 srcSize;
+uniform vec2 firstRed;
+
+varying vec4 center;
+varying vec2 xcoords;
+varying vec2 ycoords;
+
+void main(void)
+{
+	center.xy = textureIn;
+	center.zw = textureIn * srcSize.xy + firstRed;
+
+	vec2 invSize = srcSize.zw;
+	xcoords = center.x + vec2(-invSize.x, invSize.x);
+	ycoords = center.y + vec2(-invSize.y, invSize.y);
+
+	gl_Position = vertexIn;
+}
diff --git a/src/qcam/assets/shader/bayer_12_packed.frag b/src/qcam/assets/shader/bayer_12_packed.frag
new file mode 100644
index 00000000..eb822b85
--- /dev/null
+++ b/src/qcam/assets/shader/bayer_12_packed.frag
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * bayer_12_packed.frag - Fragment shader code for raw Bayer 12-bit packed
+ * format
+ */
+
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+varying vec4 center;
+varying vec2 xcoords;
+varying vec2 ycoords;
+
+uniform sampler2D tex_raw;
+
+void main(void)
+{
+	vec3 rgb;
+
+	vec2 alternate = mod(center.zw, 2.0);
+
+	bool even_col = alternate.x < 1.0;
+	bool even_raw = alternate.y < 1.0;
+
+	/* .xy = (0,-1).rg, zw = (0, 1).rg */
+	vec4 vals_AD = vec4(
+		texture2D(tex_raw, vec2(center.x, ycoords[0])).rg,
+		texture2D(tex_raw, vec2(center.x, ycoords[1])).rg);
+	/* .xy = (0,0).rg, .z = (-1,0).g, .w = (1,0).r */
+	vec4 vals_BCD = vec4(
+		texture2D(tex_raw, center.xy).rg,
+		texture2D(tex_raw, vec2(xcoords[0], center.y)).g,
+		texture2D(tex_raw, vec2(xcoords[1], center.y)).r);
+	/* .x = (-1,-1).g, .y = (-1,1).g, .z = (1,-1).r, .w = (1,1).r */
+	vec4 vals_D = vec4(
+		texture2D(tex_raw, vec2(xcoords[0], ycoords[0])).g,
+		texture2D(tex_raw, vec2(xcoords[0], ycoords[1])).g,
+		texture2D(tex_raw, vec2(xcoords[1], ycoords[0])).r,
+		texture2D(tex_raw, vec2(xcoords[1], ycoords[1])).r);
+
+	vec4 EFGH = vec4(
+		vals_AD.x + vals_AD.z,		/* 2*E = (0,-1).r + (0, 1).r */
+		vals_AD.y + vals_AD.w, 		/* 2*F = (0,-1).g + (0, 1).g */
+		vals_BCD.y + vals_BCD.z,	/* 2*G = (0,0).g + (-1,0).g */
+		vals_BCD.x + vals_BCD.w		/* 2*H = (0,0).r + (1,0).r */
+		) / 2.0;
+	vec2 JK = vec2(
+		vals_D.x + vals_D.y,		/* 2*J = (-1,-1).g + (-1,1).g */
+		vals_D.z + vals_D.w		/* 2*K = (1,-1).r + (1,1).r */
+		) / 2.0;
+
+	if (even_col) {
+		rgb = (even_raw) ?
+			vec3(vals_BCD.x, (EFGH.x + EFGH.z) / 2.0,
+			     (EFGH.y + JK.x) / 2.0) :
+			vec3(EFGH.x, vals_BCD.x, EFGH.z);
+	} else {
+		rgb = (even_raw) ?
+			vec3(EFGH.w, vals_BCD.y, EFGH.y) :
+			vec3((EFGH.x + JK.y) / 2.0,
+			     (EFGH.y + EFGH.w) / 2.0,
+			     vals_BCD.y);
+	}
+	gl_FragColor = vec4(rgb, 1.0);
+}
diff --git a/src/qcam/assets/shader/shaders.qrc b/src/qcam/assets/shader/shaders.qrc
index 8a8f9de1..7bb18033 100644
--- a/src/qcam/assets/shader/shaders.qrc
+++ b/src/qcam/assets/shader/shaders.qrc
@@ -5,6 +5,8 @@
 	<file>YUV_2_planes.frag</file>
 	<file>YUV_3_planes.frag</file>
 	<file>YUV_packed.frag</file>
+	<file>bayer_12_packed.frag</file>
+	<file>bayer.vert</file>
 	<file>identity.vert</file>
 </qresource>
 </RCC>
diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp
index c74ce77b..e504a6c2 100644
--- a/src/qcam/viewfinder_gl.cpp
+++ b/src/qcam/viewfinder_gl.cpp
@@ -36,6 +36,11 @@ static const QList<libcamera::PixelFormat> supportedFormats{
 	libcamera::formats::RGBA8888,
 	libcamera::formats::BGR888,
 	libcamera::formats::RGB888,
+	/* Raw Bayer 12-bit packed */
+	libcamera::formats::SBGGR12_CSI2P,
+	libcamera::formats::SGBRG12_CSI2P,
+	libcamera::formats::SGRBG12_CSI2P,
+	libcamera::formats::SRGGB12_CSI2P,
 };
 
 ViewFinderGL::ViewFinderGL(QWidget *parent)
@@ -115,6 +120,7 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format)
 	bool ret = true;
 
 	vertexShaderFile_ = ":identity.vert";
+	textureMinMaxFilters_ = GL_LINEAR;
 
 	fragmentShaderDefines_.clear();
 
@@ -205,6 +211,34 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format)
 		fragmentShaderDefines_.append("#define RGB_PATTERN bgr");
 		fragmentShaderFile_ = ":RGB.frag";
 		break;
+	case libcamera::formats::SBGGR12_CSI2P:
+		firstRed_[0] = 1.0;
+		firstRed_[1] = 1.0;
+		fragmentShaderFile_ = ":bayer_12_packed.frag";
+		vertexShaderFile_ = ":bayer.vert";
+		textureMinMaxFilters_ = GL_NEAREST;
+		break;
+	case libcamera::formats::SGBRG12_CSI2P:
+		firstRed_[0] = 0.0;
+		firstRed_[1] = 1.0;
+		fragmentShaderFile_ = ":bayer_12_packed.frag";
+		vertexShaderFile_ = ":bayer.vert";
+		textureMinMaxFilters_ = GL_NEAREST;
+		break;
+	case libcamera::formats::SGRBG12_CSI2P:
+		firstRed_[0] = 1.0;
+		firstRed_[1] = 0.0;
+		fragmentShaderFile_ = ":bayer_12_packed.frag";
+		vertexShaderFile_ = ":bayer.vert";
+		textureMinMaxFilters_ = GL_NEAREST;
+		break;
+	case libcamera::formats::SRGGB12_CSI2P:
+		firstRed_[0] = 0.0;
+		firstRed_[1] = 0.0;
+		fragmentShaderFile_ = ":bayer_12_packed.frag";
+		vertexShaderFile_ = ":bayer.vert";
+		textureMinMaxFilters_ = GL_NEAREST;
+		break;
 	default:
 		ret = false;
 		qWarning() << "[ViewFinderGL]:"
@@ -292,6 +326,9 @@ bool ViewFinderGL::createFragmentShader()
 	textureUniformU_ = shaderProgram_.uniformLocation("tex_u");
 	textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
 	textureUniformStepX_ = shaderProgram_.uniformLocation("tex_stepx");
+	textureUniformRaw_ = shaderProgram_.uniformLocation("tex_raw");
+	textureUniformSrcSize_ = shaderProgram_.uniformLocation("srcSize");
+	textureUniformFirstRed_ = shaderProgram_.uniformLocation("firstRed");
 
 	/* Create the textures. */
 	for (std::unique_ptr<QOpenGLTexture> &texture : textures_) {
@@ -308,8 +345,10 @@ bool ViewFinderGL::createFragmentShader()
 void ViewFinderGL::configureTexture(QOpenGLTexture &texture)
 {
 	glBindTexture(GL_TEXTURE_2D, texture.textureId());
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+			textureMinMaxFilters_);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+			textureMinMaxFilters_);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 }
@@ -548,6 +587,37 @@ void ViewFinderGL::doRender()
 		shaderProgram_.setUniformValue(textureUniformY_, 0);
 		break;
 
+	case libcamera::formats::SBGGR12_CSI2P:
+	case libcamera::formats::SGBRG12_CSI2P:
+	case libcamera::formats::SGRBG12_CSI2P:
+	case libcamera::formats::SRGGB12_CSI2P:
+		/*
+		 * Packed raw Bayer 12-bit foramts are stored in RGB texture
+		 * to match the OpenGL texel size with the 3 bytes repeating
+		 * pattern in RAW12P.
+		 * The texture width is thus half of the image with.
+		 */
+		glActiveTexture(GL_TEXTURE0);
+		configureTexture(*textures_[0]);
+		glTexImage2D(GL_TEXTURE_2D,
+			     0,
+			     GL_RGB,
+			     size_.width() / 2,
+			     size_.height(),
+			     0,
+			     GL_RGB,
+			     GL_UNSIGNED_BYTE,
+			     data_);
+		shaderProgram_.setUniformValue(textureUniformRaw_, 0);
+		shaderProgram_.setUniformValue(textureUniformFirstRed_,
+					       firstRed_[0], firstRed_[1]);
+		shaderProgram_.setUniformValue(textureUniformSrcSize_,
+					       size_.width(),
+					       size_.height(),
+					       1.0f / (size_.width() / 2 - 1),
+					       1.0f / (size_.height() - 1));
+		break;
+
 	default:
 		break;
 	};
diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h
index 6cf8f347..186492f3 100644
--- a/src/qcam/viewfinder_gl.h
+++ b/src/qcam/viewfinder_gl.h
@@ -82,6 +82,8 @@ private:
 	/* Textures */
 	std::array<std::unique_ptr<QOpenGLTexture>, 3> textures_;
 
+	/* Common texture parameters */
+	GLuint textureMinMaxFilters_;
 	/* YUV texture parameters */
 	GLuint textureUniformU_;
 	GLuint textureUniformV_;
@@ -89,6 +91,11 @@ private:
 	GLuint textureUniformStepX_;
 	unsigned int horzSubSample_;
 	unsigned int vertSubSample_;
+	/* Raw Bayer texture parameters */
+	GLuint textureUniformRaw_;
+	GLuint textureUniformSrcSize_;
+	GLuint textureUniformFirstRed_;
+	GLfloat firstRed_[2];
 
 	QMutex mutex_; /* Prevent concurrent access to image_ */
 };
-- 
2.17.1



More information about the libcamera-devel mailing list