[libcamera-devel,v2,5/5] qcam: viewfinder_gl: Support configurable stride in shaders
diff mbox series

Message ID 20210907002044.7319-6-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • qcam: Fix stride handling
Related show

Commit Message

Laurent Pinchart Sept. 7, 2021, 12:20 a.m. UTC
The RGB and YUV conversion doesn't take the stride into account, neither
when creating the textures, nor when sampling them. Fix it by using the
stride as the texture width, and multiplying the x coordinate in the
vertex shaders by a factor to only sample the active portion of the
image.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/qcam/assets/shader/identity.vert |  4 ++-
 src/qcam/viewfinder_gl.cpp           | 54 ++++++++++++++++++++++------
 src/qcam/viewfinder_gl.h             |  1 +
 3 files changed, 47 insertions(+), 12 deletions(-)

Comments

Kieran Bingham Sept. 21, 2021, 3:38 p.m. UTC | #1
On 07/09/2021 01:20, Laurent Pinchart wrote:
> The RGB and YUV conversion doesn't take the stride into account, neither
> when creating the textures, nor when sampling them. Fix it by using the
> stride as the texture width, and multiplying the x coordinate in the
> vertex shaders by a factor to only sample the active portion of the
> image.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

A somewhat not-particularly-confident, but no disagreement:

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> ---
>  src/qcam/assets/shader/identity.vert |  4 ++-
>  src/qcam/viewfinder_gl.cpp           | 54 ++++++++++++++++++++++------
>  src/qcam/viewfinder_gl.h             |  1 +
>  3 files changed, 47 insertions(+), 12 deletions(-)
> 
> diff --git a/src/qcam/assets/shader/identity.vert b/src/qcam/assets/shader/identity.vert
> index 6d6f7551017e..12c41377cfe7 100644
> --- a/src/qcam/assets/shader/identity.vert
> +++ b/src/qcam/assets/shader/identity.vert
> @@ -9,8 +9,10 @@ attribute vec4 vertexIn;
>  attribute vec2 textureIn;
>  varying vec2 textureOut;
>  
> +uniform float stride_factor;
> +
>  void main(void)
>  {
>  	gl_Position = vertexIn;
> -	textureOut = textureIn;
> +	textureOut = vec2(textureIn.x * stride_factor, textureIn.y);
>  }
> diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp
> index aeb1ea02d2d5..3ae8b03accb5 100644
> --- a/src/qcam/viewfinder_gl.cpp
> +++ b/src/qcam/viewfinder_gl.cpp
> @@ -395,6 +395,7 @@ bool ViewFinderGL::createFragmentShader()
>  	textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
>  	textureUniformStep_ = shaderProgram_.uniformLocation("tex_step");
>  	textureUniformSize_ = shaderProgram_.uniformLocation("tex_size");
> +	textureUniformStrideFactor_ = shaderProgram_.uniformLocation("stride_factor");
>  	textureUniformBayerFirstRed_ = shaderProgram_.uniformLocation("tex_bayer_first_red");
>  
>  	/* Create the textures. */
> @@ -464,6 +465,9 @@ void ViewFinderGL::initializeGL()
>  
>  void ViewFinderGL::doRender()
>  {
> +	/* Stride of the first plane, in pixels. */
> +	unsigned int stridePixels;
> +
>  	switch (format_) {
>  	case libcamera::formats::NV12:
>  	case libcamera::formats::NV21:
> @@ -477,7 +481,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width(),
> +			     stride_,
>  			     size_.height(),
>  			     0,
>  			     GL_LUMINANCE,
> @@ -491,13 +495,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE_ALPHA,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE_ALPHA,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(1).data());
>  		shaderProgram_.setUniformValue(textureUniformU_, 1);
> +
> +		stridePixels = stride_;
>  		break;
>  
>  	case libcamera::formats::YUV420:
> @@ -507,7 +513,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width(),
> +			     stride_,
>  			     size_.height(),
>  			     0,
>  			     GL_LUMINANCE,
> @@ -521,7 +527,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
> @@ -535,13 +541,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(2).data());
>  		shaderProgram_.setUniformValue(textureUniformV_, 2);
> +
> +		stridePixels = stride_;
>  		break;
>  
>  	case libcamera::formats::YVU420:
> @@ -551,7 +559,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width(),
> +			     stride_,
>  			     size_.height(),
>  			     0,
>  			     GL_LUMINANCE,
> @@ -565,7 +573,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
> @@ -579,13 +587,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(2).data());
>  		shaderProgram_.setUniformValue(textureUniformU_, 1);
> +
> +		stridePixels = stride_;
>  		break;
>  
>  	case libcamera::formats::UYVY:
> @@ -602,7 +612,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_RGBA,
> -			     size_.width() / 2,
> +			     stride_ / 4,
>  			     size_.height(),
>  			     0,
>  			     GL_RGBA,
> @@ -619,6 +629,8 @@ void ViewFinderGL::doRender()
>  		shaderProgram_.setUniformValue(textureUniformStep_,
>  					       1.0f / (size_.width() / 2 - 1),
>  					       1.0f /* not used */);
> +
> +		stridePixels = stride_ / 2;
>  		break;
>  
>  	case libcamera::formats::ABGR8888:
> @@ -630,13 +642,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_RGBA,
> -			     size_.width(),
> +			     stride_ / 4,
>  			     size_.height(),
>  			     0,
>  			     GL_RGBA,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(0).data());
>  		shaderProgram_.setUniformValue(textureUniformY_, 0);
> +
> +		stridePixels = stride_ / 4;
>  		break;
>  
>  	case libcamera::formats::BGR888:
> @@ -646,13 +660,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_RGB,
> -			     size_.width(),
> +			     stride_ / 3,
>  			     size_.height(),
>  			     0,
>  			     GL_RGB,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(0).data());
>  		shaderProgram_.setUniformValue(textureUniformY_, 0);
> +
> +		stridePixels = stride_ / 3;
>  		break;
>  
>  	case libcamera::formats::SBGGR8:
> @@ -692,11 +708,27 @@ void ViewFinderGL::doRender()
>  		shaderProgram_.setUniformValue(textureUniformStep_,
>  					       1.0f / (stride_ - 1),
>  					       1.0f / (size_.height() - 1));
> +
> +		/*
> +		 * The stride is already taken into account in the shaders, set
> +		 * the generic stride factor to 1.0.
> +		 */
> +		stridePixels = size_.width();
>  		break;
>  
>  	default:
> +		stridePixels = size_.width();
>  		break;
>  	};
> +
> +	/*
> +	 * Compute the stride factor for the vertex shader, to map the
> +	 * horizontal texture coordinate range [0.0, 1.0] to the active portion
> +	 * of the image.
> +	 */
> +	shaderProgram_.setUniformValue(textureUniformStrideFactor_,
> +				       static_cast<float>(size_.width() - 1) /
> +				       (stridePixels - 1));
>  }
>  
>  void ViewFinderGL::paintGL()
> diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h
> index 2b2b1e86035a..37b1ddd04b1d 100644
> --- a/src/qcam/viewfinder_gl.h
> +++ b/src/qcam/viewfinder_gl.h
> @@ -97,6 +97,7 @@ private:
>  
>  	/* Raw Bayer texture parameters */
>  	GLuint textureUniformSize_;
> +	GLuint textureUniformStrideFactor_;
>  	GLuint textureUniformBayerFirstRed_;
>  	QPointF firstRed_;
>  
>
Paul Elder Sept. 22, 2021, 8:10 a.m. UTC | #2
Hi Laurent,

On Tue, Sep 07, 2021 at 03:20:44AM +0300, Laurent Pinchart wrote:
> The RGB and YUV conversion doesn't take the stride into account, neither
> when creating the textures, nor when sampling them. Fix it by using the
> stride as the texture width, and multiplying the x coordinate in the
> vertex shaders by a factor to only sample the active portion of the
> image.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>

> ---
>  src/qcam/assets/shader/identity.vert |  4 ++-
>  src/qcam/viewfinder_gl.cpp           | 54 ++++++++++++++++++++++------
>  src/qcam/viewfinder_gl.h             |  1 +
>  3 files changed, 47 insertions(+), 12 deletions(-)
> 
> diff --git a/src/qcam/assets/shader/identity.vert b/src/qcam/assets/shader/identity.vert
> index 6d6f7551017e..12c41377cfe7 100644
> --- a/src/qcam/assets/shader/identity.vert
> +++ b/src/qcam/assets/shader/identity.vert
> @@ -9,8 +9,10 @@ attribute vec4 vertexIn;
>  attribute vec2 textureIn;
>  varying vec2 textureOut;
>  
> +uniform float stride_factor;
> +
>  void main(void)
>  {
>  	gl_Position = vertexIn;
> -	textureOut = textureIn;
> +	textureOut = vec2(textureIn.x * stride_factor, textureIn.y);
>  }
> diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp
> index aeb1ea02d2d5..3ae8b03accb5 100644
> --- a/src/qcam/viewfinder_gl.cpp
> +++ b/src/qcam/viewfinder_gl.cpp
> @@ -395,6 +395,7 @@ bool ViewFinderGL::createFragmentShader()
>  	textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
>  	textureUniformStep_ = shaderProgram_.uniformLocation("tex_step");
>  	textureUniformSize_ = shaderProgram_.uniformLocation("tex_size");
> +	textureUniformStrideFactor_ = shaderProgram_.uniformLocation("stride_factor");
>  	textureUniformBayerFirstRed_ = shaderProgram_.uniformLocation("tex_bayer_first_red");
>  
>  	/* Create the textures. */
> @@ -464,6 +465,9 @@ void ViewFinderGL::initializeGL()
>  
>  void ViewFinderGL::doRender()
>  {
> +	/* Stride of the first plane, in pixels. */
> +	unsigned int stridePixels;
> +
>  	switch (format_) {
>  	case libcamera::formats::NV12:
>  	case libcamera::formats::NV21:
> @@ -477,7 +481,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width(),
> +			     stride_,
>  			     size_.height(),
>  			     0,
>  			     GL_LUMINANCE,
> @@ -491,13 +495,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE_ALPHA,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE_ALPHA,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(1).data());
>  		shaderProgram_.setUniformValue(textureUniformU_, 1);
> +
> +		stridePixels = stride_;
>  		break;
>  
>  	case libcamera::formats::YUV420:
> @@ -507,7 +513,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width(),
> +			     stride_,
>  			     size_.height(),
>  			     0,
>  			     GL_LUMINANCE,
> @@ -521,7 +527,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
> @@ -535,13 +541,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(2).data());
>  		shaderProgram_.setUniformValue(textureUniformV_, 2);
> +
> +		stridePixels = stride_;
>  		break;
>  
>  	case libcamera::formats::YVU420:
> @@ -551,7 +559,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width(),
> +			     stride_,
>  			     size_.height(),
>  			     0,
>  			     GL_LUMINANCE,
> @@ -565,7 +573,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
> @@ -579,13 +587,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_LUMINANCE,
> -			     size_.width() / horzSubSample_,
> +			     stride_ / horzSubSample_,
>  			     size_.height() / vertSubSample_,
>  			     0,
>  			     GL_LUMINANCE,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(2).data());
>  		shaderProgram_.setUniformValue(textureUniformU_, 1);
> +
> +		stridePixels = stride_;
>  		break;
>  
>  	case libcamera::formats::UYVY:
> @@ -602,7 +612,7 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_RGBA,
> -			     size_.width() / 2,
> +			     stride_ / 4,
>  			     size_.height(),
>  			     0,
>  			     GL_RGBA,
> @@ -619,6 +629,8 @@ void ViewFinderGL::doRender()
>  		shaderProgram_.setUniformValue(textureUniformStep_,
>  					       1.0f / (size_.width() / 2 - 1),
>  					       1.0f /* not used */);
> +
> +		stridePixels = stride_ / 2;
>  		break;
>  
>  	case libcamera::formats::ABGR8888:
> @@ -630,13 +642,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_RGBA,
> -			     size_.width(),
> +			     stride_ / 4,
>  			     size_.height(),
>  			     0,
>  			     GL_RGBA,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(0).data());
>  		shaderProgram_.setUniformValue(textureUniformY_, 0);
> +
> +		stridePixels = stride_ / 4;
>  		break;
>  
>  	case libcamera::formats::BGR888:
> @@ -646,13 +660,15 @@ void ViewFinderGL::doRender()
>  		glTexImage2D(GL_TEXTURE_2D,
>  			     0,
>  			     GL_RGB,
> -			     size_.width(),
> +			     stride_ / 3,
>  			     size_.height(),
>  			     0,
>  			     GL_RGB,
>  			     GL_UNSIGNED_BYTE,
>  			     image_->data(0).data());
>  		shaderProgram_.setUniformValue(textureUniformY_, 0);
> +
> +		stridePixels = stride_ / 3;
>  		break;
>  
>  	case libcamera::formats::SBGGR8:
> @@ -692,11 +708,27 @@ void ViewFinderGL::doRender()
>  		shaderProgram_.setUniformValue(textureUniformStep_,
>  					       1.0f / (stride_ - 1),
>  					       1.0f / (size_.height() - 1));
> +
> +		/*
> +		 * The stride is already taken into account in the shaders, set
> +		 * the generic stride factor to 1.0.
> +		 */
> +		stridePixels = size_.width();
>  		break;
>  
>  	default:
> +		stridePixels = size_.width();
>  		break;
>  	};
> +
> +	/*
> +	 * Compute the stride factor for the vertex shader, to map the
> +	 * horizontal texture coordinate range [0.0, 1.0] to the active portion
> +	 * of the image.
> +	 */
> +	shaderProgram_.setUniformValue(textureUniformStrideFactor_,
> +				       static_cast<float>(size_.width() - 1) /
> +				       (stridePixels - 1));
>  }
>  
>  void ViewFinderGL::paintGL()
> diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h
> index 2b2b1e86035a..37b1ddd04b1d 100644
> --- a/src/qcam/viewfinder_gl.h
> +++ b/src/qcam/viewfinder_gl.h
> @@ -97,6 +97,7 @@ private:
>  
>  	/* Raw Bayer texture parameters */
>  	GLuint textureUniformSize_;
> +	GLuint textureUniformStrideFactor_;
>  	GLuint textureUniformBayerFirstRed_;
>  	QPointF firstRed_;
>  
> -- 
> Regards,
> 
> Laurent Pinchart
>

Patch
diff mbox series

diff --git a/src/qcam/assets/shader/identity.vert b/src/qcam/assets/shader/identity.vert
index 6d6f7551017e..12c41377cfe7 100644
--- a/src/qcam/assets/shader/identity.vert
+++ b/src/qcam/assets/shader/identity.vert
@@ -9,8 +9,10 @@  attribute vec4 vertexIn;
 attribute vec2 textureIn;
 varying vec2 textureOut;
 
+uniform float stride_factor;
+
 void main(void)
 {
 	gl_Position = vertexIn;
-	textureOut = textureIn;
+	textureOut = vec2(textureIn.x * stride_factor, textureIn.y);
 }
diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp
index aeb1ea02d2d5..3ae8b03accb5 100644
--- a/src/qcam/viewfinder_gl.cpp
+++ b/src/qcam/viewfinder_gl.cpp
@@ -395,6 +395,7 @@  bool ViewFinderGL::createFragmentShader()
 	textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
 	textureUniformStep_ = shaderProgram_.uniformLocation("tex_step");
 	textureUniformSize_ = shaderProgram_.uniformLocation("tex_size");
+	textureUniformStrideFactor_ = shaderProgram_.uniformLocation("stride_factor");
 	textureUniformBayerFirstRed_ = shaderProgram_.uniformLocation("tex_bayer_first_red");
 
 	/* Create the textures. */
@@ -464,6 +465,9 @@  void ViewFinderGL::initializeGL()
 
 void ViewFinderGL::doRender()
 {
+	/* Stride of the first plane, in pixels. */
+	unsigned int stridePixels;
+
 	switch (format_) {
 	case libcamera::formats::NV12:
 	case libcamera::formats::NV21:
@@ -477,7 +481,7 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width(),
+			     stride_,
 			     size_.height(),
 			     0,
 			     GL_LUMINANCE,
@@ -491,13 +495,15 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE_ALPHA,
-			     size_.width() / horzSubSample_,
+			     stride_ / horzSubSample_,
 			     size_.height() / vertSubSample_,
 			     0,
 			     GL_LUMINANCE_ALPHA,
 			     GL_UNSIGNED_BYTE,
 			     image_->data(1).data());
 		shaderProgram_.setUniformValue(textureUniformU_, 1);
+
+		stridePixels = stride_;
 		break;
 
 	case libcamera::formats::YUV420:
@@ -507,7 +513,7 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width(),
+			     stride_,
 			     size_.height(),
 			     0,
 			     GL_LUMINANCE,
@@ -521,7 +527,7 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width() / horzSubSample_,
+			     stride_ / horzSubSample_,
 			     size_.height() / vertSubSample_,
 			     0,
 			     GL_LUMINANCE,
@@ -535,13 +541,15 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width() / horzSubSample_,
+			     stride_ / horzSubSample_,
 			     size_.height() / vertSubSample_,
 			     0,
 			     GL_LUMINANCE,
 			     GL_UNSIGNED_BYTE,
 			     image_->data(2).data());
 		shaderProgram_.setUniformValue(textureUniformV_, 2);
+
+		stridePixels = stride_;
 		break;
 
 	case libcamera::formats::YVU420:
@@ -551,7 +559,7 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width(),
+			     stride_,
 			     size_.height(),
 			     0,
 			     GL_LUMINANCE,
@@ -565,7 +573,7 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width() / horzSubSample_,
+			     stride_ / horzSubSample_,
 			     size_.height() / vertSubSample_,
 			     0,
 			     GL_LUMINANCE,
@@ -579,13 +587,15 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_LUMINANCE,
-			     size_.width() / horzSubSample_,
+			     stride_ / horzSubSample_,
 			     size_.height() / vertSubSample_,
 			     0,
 			     GL_LUMINANCE,
 			     GL_UNSIGNED_BYTE,
 			     image_->data(2).data());
 		shaderProgram_.setUniformValue(textureUniformU_, 1);
+
+		stridePixels = stride_;
 		break;
 
 	case libcamera::formats::UYVY:
@@ -602,7 +612,7 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_RGBA,
-			     size_.width() / 2,
+			     stride_ / 4,
 			     size_.height(),
 			     0,
 			     GL_RGBA,
@@ -619,6 +629,8 @@  void ViewFinderGL::doRender()
 		shaderProgram_.setUniformValue(textureUniformStep_,
 					       1.0f / (size_.width() / 2 - 1),
 					       1.0f /* not used */);
+
+		stridePixels = stride_ / 2;
 		break;
 
 	case libcamera::formats::ABGR8888:
@@ -630,13 +642,15 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_RGBA,
-			     size_.width(),
+			     stride_ / 4,
 			     size_.height(),
 			     0,
 			     GL_RGBA,
 			     GL_UNSIGNED_BYTE,
 			     image_->data(0).data());
 		shaderProgram_.setUniformValue(textureUniformY_, 0);
+
+		stridePixels = stride_ / 4;
 		break;
 
 	case libcamera::formats::BGR888:
@@ -646,13 +660,15 @@  void ViewFinderGL::doRender()
 		glTexImage2D(GL_TEXTURE_2D,
 			     0,
 			     GL_RGB,
-			     size_.width(),
+			     stride_ / 3,
 			     size_.height(),
 			     0,
 			     GL_RGB,
 			     GL_UNSIGNED_BYTE,
 			     image_->data(0).data());
 		shaderProgram_.setUniformValue(textureUniformY_, 0);
+
+		stridePixels = stride_ / 3;
 		break;
 
 	case libcamera::formats::SBGGR8:
@@ -692,11 +708,27 @@  void ViewFinderGL::doRender()
 		shaderProgram_.setUniformValue(textureUniformStep_,
 					       1.0f / (stride_ - 1),
 					       1.0f / (size_.height() - 1));
+
+		/*
+		 * The stride is already taken into account in the shaders, set
+		 * the generic stride factor to 1.0.
+		 */
+		stridePixels = size_.width();
 		break;
 
 	default:
+		stridePixels = size_.width();
 		break;
 	};
+
+	/*
+	 * Compute the stride factor for the vertex shader, to map the
+	 * horizontal texture coordinate range [0.0, 1.0] to the active portion
+	 * of the image.
+	 */
+	shaderProgram_.setUniformValue(textureUniformStrideFactor_,
+				       static_cast<float>(size_.width() - 1) /
+				       (stridePixels - 1));
 }
 
 void ViewFinderGL::paintGL()
diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h
index 2b2b1e86035a..37b1ddd04b1d 100644
--- a/src/qcam/viewfinder_gl.h
+++ b/src/qcam/viewfinder_gl.h
@@ -97,6 +97,7 @@  private:
 
 	/* Raw Bayer texture parameters */
 	GLuint textureUniformSize_;
+	GLuint textureUniformStrideFactor_;
 	GLuint textureUniformBayerFirstRed_;
 	QPointF firstRed_;