[3/3] qcam: viewfinder_gl: Render image centered in letterbox
diff mbox series

Message ID 20240910234649.28591-4-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • qcam: Fix GL renderer on Qt 6
Related show

Commit Message

Laurent Pinchart Sept. 10, 2024, 11:46 p.m. UTC
Mimic the letterbox behaviour of the Qt viewfinder by rendering the
image centered. This is done by adding a projection matrix to the vertex
shader to scale the rendered rectangle.

Another option would have been to keep using glViewport() (which would
have needed to be moved to paintGL(), as Qt resets the viewport to span
the full widget before calling). Hidpi displays would then need special
handling of the device pixel ratio, which is done automatically by Qt
when it sets the default viewport. Using a projection matrix avoids this
complication.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/apps/qcam/assets/shader/bayer_8.vert  |  4 ++-
 src/apps/qcam/assets/shader/identity.vert |  3 ++-
 src/apps/qcam/viewfinder_gl.cpp           | 31 +++++++++++++++--------
 src/apps/qcam/viewfinder_gl.h             |  2 +-
 4 files changed, 26 insertions(+), 14 deletions(-)

Patch
diff mbox series

diff --git a/src/apps/qcam/assets/shader/bayer_8.vert b/src/apps/qcam/assets/shader/bayer_8.vert
index 3695a5e910c9..fb5109eee3f5 100644
--- a/src/apps/qcam/assets/shader/bayer_8.vert
+++ b/src/apps/qcam/assets/shader/bayer_8.vert
@@ -19,6 +19,8 @@  Copyright (C) 2021, Linaro
 attribute vec4 vertexIn;
 attribute vec2 textureIn;
 
+uniform mat4 proj_matrix;
+
 uniform vec2 tex_size;	/* The texture size in pixels */
 uniform vec2 tex_step;
 
@@ -47,5 +49,5 @@  void main(void) {
     yCoord = center.y + vec4(-2.0 * tex_step.y,
                               -tex_step.y, tex_step.y, 2.0 * tex_step.y);
 
-    gl_Position = vertexIn;
+    gl_Position = proj_matrix * vertexIn;
 }
diff --git a/src/apps/qcam/assets/shader/identity.vert b/src/apps/qcam/assets/shader/identity.vert
index 12c41377cfe7..907e8741fae7 100644
--- a/src/apps/qcam/assets/shader/identity.vert
+++ b/src/apps/qcam/assets/shader/identity.vert
@@ -9,10 +9,11 @@  attribute vec4 vertexIn;
 attribute vec2 textureIn;
 varying vec2 textureOut;
 
+uniform mat4 proj_matrix;
 uniform float stride_factor;
 
 void main(void)
 {
-	gl_Position = vertexIn;
+	gl_Position = proj_matrix * vertexIn;
 	textureOut = vec2(textureIn.x * stride_factor, textureIn.y);
 }
diff --git a/src/apps/qcam/viewfinder_gl.cpp b/src/apps/qcam/viewfinder_gl.cpp
index b2096faf859f..f31956ff0504 100644
--- a/src/apps/qcam/viewfinder_gl.cpp
+++ b/src/apps/qcam/viewfinder_gl.cpp
@@ -12,6 +12,7 @@ 
 #include <QByteArray>
 #include <QFile>
 #include <QImage>
+#include <QMatrix4x4>
 #include <QStringList>
 
 #include <libcamera/formats.h>
@@ -464,6 +465,7 @@  bool ViewFinderGL::createFragmentShader()
 
 	vertexBuffer_.release();
 
+	projMatrixUniform_ = shaderProgram_.uniformLocation("proj_matrix");
 	textureUniformY_ = shaderProgram_.uniformLocation("tex_y");
 	textureUniformU_ = shaderProgram_.uniformLocation("tex_u");
 	textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
@@ -509,7 +511,7 @@  void ViewFinderGL::initializeGL()
 	glEnable(GL_TEXTURE_2D);
 	glDisable(GL_DEPTH_TEST);
 
-	static const GLfloat coordinates[2][4][2]{
+	const GLfloat coordinates[2][4][2]{
 		{
 			/* Vertex coordinates */
 			{ -1.0f, -1.0f },
@@ -801,6 +803,17 @@  void ViewFinderGL::doRender()
 	shaderProgram_.setUniformValue(textureUniformStrideFactor_,
 				       static_cast<float>(size_.width() - 1) /
 				       (stridePixels - 1));
+
+	/*
+	 * Place the viewfinder in the centre of the widget, preserving the
+	 * aspect ratio of the image.
+	 */
+	QMatrix4x4 projMatrix;
+	QSizeF scaledSize = size_.scaled(size(), Qt::KeepAspectRatio);
+	projMatrix.scale(scaledSize.width() / size().width(),
+			 scaledSize.height() / size().height());
+
+	shaderProgram_.setUniformValue(projMatrixUniform_, projMatrix);
 }
 
 void ViewFinderGL::paintGL()
@@ -818,18 +831,14 @@  void ViewFinderGL::paintGL()
 		close();
 	}
 
-	if (image_) {
-		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	if (!image_)
+		return;
 
-		doRender();
-		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-	}
-}
+	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-void ViewFinderGL::resizeGL(int w, int h)
-{
-	glViewport(0, 0, w, h);
+	doRender();
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
 
 QSize ViewFinderGL::sizeHint() const
diff --git a/src/apps/qcam/viewfinder_gl.h b/src/apps/qcam/viewfinder_gl.h
index 23744b411c86..23c657bcfae2 100644
--- a/src/apps/qcam/viewfinder_gl.h
+++ b/src/apps/qcam/viewfinder_gl.h
@@ -51,7 +51,6 @@  Q_SIGNALS:
 protected:
 	void initializeGL() override;
 	void paintGL() override;
-	void resizeGL(int w, int h) override;
 	QSize sizeHint() const override;
 
 private:
@@ -88,6 +87,7 @@  private:
 
 	/* Common texture parameters */
 	GLuint textureMinMagFilters_;
+	GLuint projMatrixUniform_;
 
 	/* YUV texture parameters */
 	GLuint textureUniformU_;