gdk: add endian-aware 30-bit RGB converters

Add specialized converters for both 10:10:10 channel layouts and both X image byte orders.

Preserve depth-30 padding bits, avoid invalid negative shifts in the generic converter and select endian conversion at compile time.

Validated with a real Xvfb 30-bit A/B pixel test and cross-target endian store checks.

Derived from downstream commit 02a2c61f2d.

Co-authored-by: Daemonratte <daemonratte@daemonratte.net>
This commit is contained in:
Daemonratte 2026-08-04 15:34:12 +02:00
commit 71023e0333

View file

@ -2242,6 +2242,68 @@ gdk_rgb_convert_8880_br (GdkRgbInfo *image_info, GdkImage *image,
}
}
#define DEFINE_GDK_RGB_CONVERT_101010(name, high, low, to_order) \
static void \
name (GdkRgbInfo *image_info, GdkImage *image, \
gint x0, gint y0, gint width, gint height, \
const guchar *buf, int rowstride, \
gint x_align, gint y_align, GdkRgbCmap *cmap) \
{ \
int y, w; \
guchar *obuf, *p; \
gint bpl; \
const guchar *bptr, *bp2; \
guint32 r, g, b; \
guint32 pixel; \
guint32 alpha_mask; \
\
alpha_mask = image_info->visual->depth == 32 ? 0xc0000000U : 0; \
\
bptr = buf; \
bpl = image->bpl; \
obuf = ((guchar *) image->mem) + y0 * bpl + x0 * 4; \
\
for (y = 0; y < height; y++) \
{ \
bp2 = bptr; \
p = obuf; \
w = width; \
\
while (w--) \
{ \
r = *bp2++; \
g = *bp2++; \
b = *bp2++; \
\
r = (r << 2) | (r >> 6); \
g = (g << 2) | (g >> 6); \
b = (b << 2) | (b >> 6); \
\
pixel = alpha_mask | \
(high << 20) | \
(g << 10) | \
low; \
\
*((guint32 *) p) = to_order (pixel); \
p += 4; \
} \
\
bptr += rowstride; \
obuf += bpl; \
} \
}
DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_r_low_lsb,
b, r, GUINT32_TO_LE)
DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_b_low_lsb,
r, b, GUINT32_TO_LE)
DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_r_low_msb,
b, r, GUINT32_TO_BE)
DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_b_low_msb,
r, b, GUINT32_TO_BE)
#undef DEFINE_GDK_RGB_CONVERT_101010
/* Generic truecolor/directcolor conversion function. Slow, but these
are oddball modes. */
static void
@ -3195,6 +3257,34 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info)
#endif
}
#endif
else if (bpp == 32 && (depth == 30 || depth == 32) &&
vtype == GDK_VISUAL_TRUE_COLOR &&
byte_order == GDK_LSB_FIRST &&
red_mask == 0x000003ff &&
green_mask == 0x000ffc00 &&
blue_mask == 0x3ff00000)
conv = gdk_rgb_convert_101010_r_low_lsb;
else if (bpp == 32 && (depth == 30 || depth == 32) &&
vtype == GDK_VISUAL_TRUE_COLOR &&
byte_order == GDK_LSB_FIRST &&
red_mask == 0x3ff00000 &&
green_mask == 0x000ffc00 &&
blue_mask == 0x000003ff)
conv = gdk_rgb_convert_101010_b_low_lsb;
else if (bpp == 32 && (depth == 30 || depth == 32) &&
vtype == GDK_VISUAL_TRUE_COLOR &&
byte_order == GDK_MSB_FIRST &&
red_mask == 0x000003ff &&
green_mask == 0x000ffc00 &&
blue_mask == 0x3ff00000)
conv = gdk_rgb_convert_101010_r_low_msb;
else if (bpp == 32 && (depth == 30 || depth == 32) &&
vtype == GDK_VISUAL_TRUE_COLOR &&
byte_order == GDK_MSB_FIRST &&
red_mask == 0x3ff00000 &&
green_mask == 0x000ffc00 &&
blue_mask == 0x000003ff)
conv = gdk_rgb_convert_101010_b_low_msb;
else if (vtype == GDK_VISUAL_TRUE_COLOR && byte_order == GDK_LSB_FIRST)
{
conv = gdk_rgb_convert_truecolor_lsb;