diff --git a/src/libcamera/shaders/bayer_glr16_to_rgba.frag b/src/libcamera/shaders/bayer_glr16_to_rgba.frag
index f3883a82b..4a2e5af87 100644
--- a/src/libcamera/shaders/bayer_glr16_to_rgba.frag
+++ b/src/libcamera/shaders/bayer_glr16_to_rgba.frag
@@ -44,81 +44,53 @@ void main(void) {
 	#define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
 
 	float C = fetch(center.x, center.y); // ( 0, 0)
-	const vec4 kC = vec4( 4.0,  6.0,  5.0,  5.0) / 8.0;
 
-	// Determine which of four types of pixels we are on.
+	/* Which of the four CFA phases are we on (0 = even). Same as McGuire. */
 	vec2 alternate = mod(floor(center.zw), 2.0);
+	bool even_col = alternate.x < 1.0;
+	bool even_row = alternate.y < 1.0;
 
-	vec4 Dvec = vec4(
-		fetch(xCoord[1], yCoord[1]),  // (-1,-1)
-		fetch(xCoord[1], yCoord[2]),  // (-1, 1)
-		fetch(xCoord[2], yCoord[1]),  // ( 1,-1)
-		fetch(xCoord[2], yCoord[2])); // ( 1, 1)
-
-	vec4 PATTERN = (kC.xyz * C).xyzz;
-
-	// Can also be a dot product with (1,1,1,1) on hardware where that is
-	// specially optimized.
-	// Equivalent to: D = Dvec[0] + Dvec[1] + Dvec[2] + Dvec[3];
-	Dvec.xy += Dvec.zw;
-	Dvec.x  += Dvec.y;
-
-	vec4 value = vec4(
-		fetch(center.x, yCoord[0]),   // ( 0,-2)
-		fetch(center.x, yCoord[1]),   // ( 0,-1)
-		fetch(xCoord[0], center.y),   // (-2, 0)
-		fetch(xCoord[1], center.y));  // (-1, 0)
-
+	/*
+	 *   +----+----+----+
+	 *   | D2 | A1 | D3 |
+	 *   +----+----+----+
+	 *   | B0 |  C | B1 |
+	 *   +----+----+----+
+	 *   | D0 | A0 | D1 |
+	 *   +----+----+----+
+	 *
+	 * patterns.x = (A0 + A1) / 2      vertical neighbours
+	 * patterns.y = (B0 + B1) / 2      horizontal neighbours
+	 * patterns.z = (A0+A1+B0+B1) / 4  cross average  (green at R/B sites)
+	 * patterns.w = (D0+D1+D2+D3) / 4  diagonal average (other colour at R/B sites)
+	 *
+	 * xCoord[1] = -1, xCoord[2] = +1, yCoord[1] = -1, yCoord[2] = +1
+	 * (xCoord[0]/[3] and yCoord[0]/[3] = +-2 are unused here; the vertex
+	 *  shader still emits them so the VS is identical to the McGuire path).
+	 */
+	vec4 patterns = vec4(
+		fetch(center.x,  yCoord[1]),	/* A0: ( 0,-1) */
+		fetch(xCoord[1], center.y),	/* B0: (-1, 0) */
+		fetch(xCoord[1], yCoord[1]),	/* D0: (-1,-1) */
+		fetch(xCoord[2], yCoord[1]));	/* D1: ( 1,-1) */
 	vec4 temp = vec4(
-		fetch(center.x, yCoord[3]),   // ( 0, 2)
-		fetch(center.x, yCoord[2]),   // ( 0, 1)
-		fetch(xCoord[3], center.y),   // ( 2, 0)
-		fetch(xCoord[2], center.y));  // ( 1, 0)
-
-	// Even the simplest compilers should be able to constant-fold these to
-	// avoid the division.
-	// Note that on scalar processors these constants force computation of some
-	// identical products twice.
-	const vec4 kA = vec4(-1.0, -1.5,  0.5, -1.0) / 8.0;
-	const vec4 kB = vec4( 2.0,  0.0,  0.0,  4.0) / 8.0;
-	const vec4 kD = vec4( 0.0,  2.0, -1.0, -1.0) / 8.0;
-
-	// Conserve constant registers and take advantage of free swizzle on load
-	#define kE (kA.xywz)
-	#define kF (kB.xywz)
-
-	value += temp;
-
-	// There are five filter patterns (identity, cross, checker,
-	// theta, phi).  Precompute the terms from all of them and then
-	// use swizzles to assign to color channels.
-	//
-	// Channel   Matches
-	//   x       cross   (e.g., EE G)
-	//   y       checker (e.g., EE B)
-	//   z       theta   (e.g., EO R)
-	//   w       phi     (e.g., EO R)
-	#define A (value[0])
-	#define B (value[1])
-	#define D (Dvec.x)
-	#define E (value[2])
-	#define F (value[3])
-
-	// Avoid zero elements. On a scalar processor this saves two MADDs
-	// and it has no effect on a vector processor.
-	PATTERN.yzw += (kD.yz * D).xyy;
-
-	PATTERN += (kA.xyz * A).xyzx + (kE.xyw * E).xyxz;
-	PATTERN.xw  += kB.xw * B;
-	PATTERN.xz  += kF.xz * F;
-
-	rgb =  (alternate.y == 0.0) ?
-	((alternate.x == 0.0) ?
-		vec3(C, PATTERN.xy) :
-		vec3(PATTERN.z, C, PATTERN.w)) :
-	((alternate.x == 0.0) ?
-		vec3(PATTERN.w, C, PATTERN.z) :
-		vec3(PATTERN.yx, C));
+		fetch(center.x,  yCoord[2]),	/* A1: ( 0, 1) */
+		fetch(xCoord[2], center.y),	/* B1: ( 1, 0) */
+		fetch(xCoord[2], yCoord[2]),	/* D3: ( 1, 1) */
+		fetch(xCoord[1], yCoord[2]));	/* D2: (-1, 1) */
+
+	patterns = (patterns + temp) * 0.5;
+		/* .x=(A0+A1)/2  .y=(B0+B1)/2  .z=(D0+D3)/2  .w=(D1+D2)/2 */
+	patterns.w = (patterns.z + patterns.w) * 0.5;	/* diagonal avg */
+	patterns.z = (patterns.x + patterns.y) * 0.5;	/* cross avg */
+
+	rgb = even_col ?
+		(even_row ?
+			vec3(C, patterns.zw) :
+			vec3(patterns.x, C, patterns.y)) :
+		(even_row ?
+			vec3(patterns.y, C, patterns.x) :
+			vec3(patterns.wz, C));
 
 	/*
 	*   CCM is a 3x3 in the format
