compositor: make GL_EXT_read_format_bgra optional
Some GL implementations do not provide GL_EXT_read_format_bgra
extension.
Set a glReadPixels format based on whether the extensions is supported
or not, and use that format in all backends.
Add RGBA->BGRA swapping copy to screenshooter to keep the shm buffer
data format as BGRA.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 1b0fbd0..d2a2ea1 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -1052,8 +1052,9 @@
eglMakeCurrent(compositor->base.display, output->egl_surface,
output->egl_surface, compositor->base.context);
- glReadPixels(0, 0, output_base->current->width, output_base->current->height,
- GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
+ glReadPixels(0, 0, output_base->current->width,
+ output_base->current->height,
+ compositor->base.read_format, GL_UNSIGNED_BYTE, data);
}
static int
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 7a9ebde..c9d599d 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -387,8 +387,9 @@
eglMakeCurrent(compositor->base.display, output->egl_surface,
output->egl_surface, compositor->base.context);
- glReadPixels(0, 0, output_base->current->width, output_base->current->height,
- GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
+ glReadPixels(0, 0, output_base->current->width,
+ output_base->current->height,
+ compositor->base.read_format, GL_UNSIGNED_BYTE, data);
}
static int
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 9822c2c..4361a01 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -354,8 +354,9 @@
eglMakeCurrent(compositor->base.display, output->egl_surface,
output->egl_surface, compositor->base.context);
- glReadPixels(0, 0, output_base->current->width, output_base->current->height,
- GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
+ glReadPixels(0, 0, output_base->current->width,
+ output_base->current->height,
+ compositor->base.read_format, GL_UNSIGNED_BYTE, data);
}
static int
diff --git a/src/compositor.c b/src/compositor.c
index ac5e91c..17daac4 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2391,10 +2391,10 @@
return -1;
}
- if (!strstr(extensions, "GL_EXT_read_format_bgra")) {
- fprintf(stderr, "GL_EXT_read_format_bgra not available\n");
- return -1;
- }
+ if (strstr(extensions, "GL_EXT_read_format_bgra"))
+ ec->read_format = GL_BGRA_EXT;
+ else
+ ec->read_format = GL_RGBA;
if (strstr(extensions, "GL_EXT_unpack_subimage"))
ec->has_unpack_subimage = 1;
diff --git a/src/compositor.h b/src/compositor.h
index e381e66..93284c5 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -223,6 +223,7 @@
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
int has_unpack_subimage;
+ GLenum read_format;
PFNEGLBINDWAYLANDDISPLAYWL bind_display;
PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
diff --git a/src/screenshooter.c b/src/screenshooter.c
index 835e175..b4b341b 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -51,6 +51,37 @@
}
static void
+copy_row_swap_RB(void *vdst, void *vsrc, int bytes)
+{
+ uint32_t *dst = vdst;
+ uint32_t *src = vsrc;
+ uint32_t *end = dst + bytes / 4;
+
+ while (dst < end) {
+ uint32_t v = *src++;
+ /* A R G B */
+ uint32_t tmp = v & 0xff00ff00;
+ tmp |= (v >> 16) & 0x000000ff;
+ tmp |= (v << 16) & 0x00ff0000;
+ *dst++ = tmp;
+ }
+}
+
+static void
+copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height,
+ int dst_stride, int src_stride)
+{
+ uint8_t *end;
+
+ end = dst + height * dst_stride;
+ while (dst < end) {
+ copy_row_swap_RB(dst, src, src_stride);
+ dst += dst_stride;
+ src -= src_stride;
+ }
+}
+
+static void
screenshooter_shoot(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *output_resource,
@@ -82,8 +113,19 @@
d = wl_shm_buffer_get_data(buffer) + output->y * buffer_stride +
output->x * 4;
s = tmp + output_stride * (output->current->height - 1);
- copy_bgra_yflip(d, s, output->current->height,
- buffer_stride, output_stride);
+
+ switch (output->compositor->read_format) {
+ case GL_BGRA_EXT:
+ copy_bgra_yflip(d, s, output->current->height,
+ buffer_stride, output_stride);
+ break;
+ case GL_RGBA:
+ copy_rgba_yflip(d, s, output->current->height,
+ buffer_stride, output_stride);
+ break;
+ default:
+ break;
+ }
free(tmp);
}