From 6773a9672a39bc975471a706e50ad60ce02a69a4 Mon Sep 17 00:00:00 2001 From: Quantum Date: Sat, 4 Dec 2021 00:24:36 -0500 Subject: [PATCH] Support 10-bit screenshots by downsampling to 8-bit This commit introduces support for all eight 10-bit colour formats supported by wl_shm. le32toh is used to convert little endian pixels to host endianness. This function is available on Linux in and FreeBSD in . --- background-image.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/background-image.c b/background-image.c index a7021c9c..6674512e 100644 --- a/background-image.c +++ b/background-image.c @@ -1,9 +1,16 @@ +#define _DEFAULT_SOURCE #include #include "background-image.h" #include "cairo.h" #include "log.h" #include "swaylock.h" +#ifdef __FreeBSD__ +# include +#else +# include +#endif + // Cairo RGB24 uses 32 bits per pixel, as XRGB, in native endianness. // xrgb32_le uses 32 bits per pixel, as XRGB, little endian (BGRX big endian). void cairo_rgb24_from_xrgb32_le(unsigned char *buf, int width, int height, int stride) { @@ -32,6 +39,58 @@ void cairo_rgb24_from_xbgr32_le(unsigned char *buf, int width, int height, int s } } +void cairo_rgb24_from_xrgb2101010_le(unsigned char *buf, int width, int height, int stride) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + uint32_t *pix = (uint32_t *) (buf + y * stride + x * 4); + uint32_t color = le32toh(*pix); + *pix = 0 | + ((color >> 22) & 0xFF) << 16 | + ((color >> 12) & 0xFF) << 8 | + ((color >> 2) & 0xFF); + } + } +} + +void cairo_rgb24_from_xbgr2101010_le(unsigned char *buf, int width, int height, int stride) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + uint32_t *pix = (uint32_t *) (buf + y * stride + x * 4); + uint32_t color = le32toh(*pix); + *pix = 0 | + ((color >> 2) & 0xFF) << 16 | + ((color >> 12) & 0xFF) << 8 | + ((color >> 22) & 0xFF); + } + } +} + +void cairo_rgb24_from_rgbx1010102_le(unsigned char *buf, int width, int height, int stride) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + uint32_t *pix = (uint32_t *) (buf + y * stride + x * 4); + uint32_t color = le32toh(*pix); + *pix = 0 | + ((color >> 24) & 0xFF) << 16 | + ((color >> 14) & 0xFF) << 8 | + ((color >> 4) & 0xFF); + } + } +} + +void cairo_rgb24_from_bgrx1010102_le(unsigned char *buf, int width, int height, int stride) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + uint32_t *pix = (uint32_t *) (buf + y * stride + x * 4); + uint32_t color = le32toh(*pix); + *pix = 0 | + ((color >> 4) & 0xFF) << 16 | + ((color >> 14) & 0xFF) << 8 | + ((color >> 24) & 0xFF); + } + } +} + enum background_mode parse_background_mode(const char *mode) { if (strcmp(mode, "stretch") == 0) { return BACKGROUND_MODE_STRETCH; @@ -169,6 +228,30 @@ cairo_surface_t *load_background_from_buffer(void *buf, uint32_t format, cairo_image_surface_get_width(image), cairo_image_surface_get_height(image), cairo_image_surface_get_stride(image)); + } else if (format == WL_SHM_FORMAT_XRGB2101010 || format == WL_SHM_FORMAT_ARGB2101010) { + cairo_rgb24_from_xrgb2101010_le( + cairo_image_surface_get_data(image), + cairo_image_surface_get_width(image), + cairo_image_surface_get_height(image), + cairo_image_surface_get_stride(image)); + } else if (format == WL_SHM_FORMAT_XBGR2101010 || format == WL_SHM_FORMAT_ABGR2101010) { + cairo_rgb24_from_xbgr2101010_le( + cairo_image_surface_get_data(image), + cairo_image_surface_get_width(image), + cairo_image_surface_get_height(image), + cairo_image_surface_get_stride(image)); + } else if (format == WL_SHM_FORMAT_RGBX1010102 || format == WL_SHM_FORMAT_RGBA1010102) { + cairo_rgb24_from_rgbx1010102_le( + cairo_image_surface_get_data(image), + cairo_image_surface_get_width(image), + cairo_image_surface_get_height(image), + cairo_image_surface_get_stride(image)); + } else if (format == WL_SHM_FORMAT_BGRX1010102 || format == WL_SHM_FORMAT_BGRA1010102) { + cairo_rgb24_from_bgrx1010102_le( + cairo_image_surface_get_data(image), + cairo_image_surface_get_width(image), + cairo_image_surface_get_height(image), + cairo_image_surface_get_stride(image)); } else { if (format != WL_SHM_FORMAT_XRGB8888 && format != WL_SHM_FORMAT_ARGB8888) { swaylock_log(LOG_ERROR,