🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445
From: PaganDE <dev@paganlinux.org>
Subject: [PATCH] gles2: fix R/B swap when reading DRM_FORMAT_BGR888
GLES2 has no GL_BGR, so wlroots maps DRM_FORMAT_BGR888 to
glReadPixels(GL_RGB, GL_UNSIGNED_BYTE). GL_RGB returns bytes in
R,G,B order while the BGR888 layout expects B,G,R - the resulting
buffer ends up with red and blue swapped.
On llvmpipe the implementation read format is GL_RGB, so
wlr_output_preferred_read_format() reports BGR888 and screencopy
clients receive a buffer with inverted channels.
Origin: PaganDE fork of wlroots 0.20.2
---
render/gles2/texture.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
--- a/render/gles2/texture.c 2026-07-07 23:46:09.000000000 +0200
+++ b/render/gles2/texture.c 2026-08-31 14:04:58.836879583 +0200
@@ -225,6 +225,25 @@
}
}
+ /*
+ * DRM_FORMAT_BGR888 has no GLES2 equivalent: we read it as GL_RGB,
+ * which returns bytes in R,G,B order, while the BGR888 layout
+ * expects B,G,R. Swap the channels so the buffer actually contains
+ * BGR data. Otherwise screencopy/screenshot clients see red and
+ * blue swapped (visible on llvmpipe, where the preferred read
+ * format is BGR888).
+ */
+ if (drm_fmt->drm_format == DRM_FORMAT_BGR888) {
+ for (int32_t i = 0; i < src.height; ++i) {
+ unsigned char *row = p + (size_t)i * options->stride;
+ for (int32_t x = 0; x < src.width; ++x) {
+ unsigned char tmp = row[x * 3];
+ row[x * 3] = row[x * 3 + 2];
+ row[x * 3 + 2] = tmp;
+ }
+ }
+ }
+
wlr_egl_restore_context(&prev_ctx);
pop_gles2_debug(texture->renderer);