Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 10-bit screenshots by downsampling to 8-bit #18

Merged
merged 1 commit into from
Nov 27, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 103 additions & 8 deletions background-image.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
#define _DEFAULT_SOURCE
#include <assert.h>
#include "background-image.h"
#include "cairo.h"
#include "log.h"
#include "swaylock.h"

#ifdef __FreeBSD__
# include <sys/endian.h>
#else
# include <endian.h>
#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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -163,19 +222,54 @@ cairo_surface_t *load_background_from_buffer(void *buf, uint32_t format,
break;
}

if (format == WL_SHM_FORMAT_XBGR8888 || format == WL_SHM_FORMAT_ABGR8888) {
switch (format) {
case WL_SHM_FORMAT_XBGR8888:
case WL_SHM_FORMAT_ABGR8888:
cairo_rgb24_from_xbgr32_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,
"Unknown pixel format: %u. Assuming XRGB32. Colors may look wrong.",
format);
}

break;
case WL_SHM_FORMAT_XRGB2101010:
case 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));
break;
case WL_SHM_FORMAT_XBGR2101010:
case 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));
break;
case WL_SHM_FORMAT_RGBX1010102:
case 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));
break;
case WL_SHM_FORMAT_BGRX1010102:
case 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));
break;
default:
swaylock_log(LOG_ERROR,
"Unknown pixel format: %u. Assuming XRGB32. Colors may look wrong.",
format);
// fallthrough
case WL_SHM_FORMAT_XRGB8888:
case WL_SHM_FORMAT_ARGB8888: {
// If we're little endian, we don't have to do anything
int test = 1;
bool is_little_endian = *(char *)&test == 1;
Expand All @@ -187,6 +281,7 @@ cairo_surface_t *load_background_from_buffer(void *buf, uint32_t format,
cairo_image_surface_get_stride(image));
}
}
}

return image;
}
Expand Down