summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2018-12-20 18:25:21 +0100
committerMichel Dänzer <michel.daenzer@amd.com>2018-12-20 18:25:21 +0100
commit0c40a76d1c050d018e6d59bebb5efc9c62be308c (patch)
tree854dbd98e7a92ab055452f2af0c590833ceb9347
parent0058fd2ebf4c900b12f129984e98886a7ac84b2f (diff)
Detect and fix up non-premultiplied cursor data
X server >= 1.18 already has code for this, but handle it with older X servers as well. (Ported from amdgpu commits ad6dfb0124860cf67730bde85867f81d9258c84d & 426f9a49655f01863cf4d898f525e5f95984e0c4)
-rw-r--r--src/drmmode_display.c81
1 files changed, 61 insertions, 20 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 00d94449..9a9e092a 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1049,29 +1049,52 @@ drmmode_cursor_src_offset(Rotation rotation, int width, int height,
#endif
-static uint32_t
-drmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb)
+static Bool
+drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool premultiplied,
+ Bool apply_gamma)
{
- uint32_t alpha = argb >> 24;
+ uint32_t alpha = *argb >> 24;
uint32_t rgb[3];
int i;
- if (!alpha)
- return 0;
+ if (premultiplied) {
+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0)
+ if (alpha == 0 && (*argb & 0xffffff) != 0)
+ /* Doesn't look like premultiplied alpha */
+ return FALSE;
+#endif
- if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
- return argb;
+ if (!apply_gamma)
+ return TRUE;
+ }
- /* Un-premultiply alpha */
+ if (!alpha) {
+ *argb = 0;
+ return TRUE;
+ }
+
+ /* Extract RGB */
for (i = 0; i < 3; i++)
- rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha;
+ rgb[i] = (*argb >> (i * 8)) & 0xff;
+
+ if (premultiplied) {
+ /* Un-premultiply alpha */
+ for (i = 0; i < 3; i++)
+ rgb[i] = rgb[i] * 0xff / alpha;
+ }
+
+ if (apply_gamma) {
+ rgb[0] = crtc->gamma_blue[rgb[0]] >> 8;
+ rgb[1] = crtc->gamma_green[rgb[1]] >> 8;
+ rgb[2] = crtc->gamma_red[rgb[2]] >> 8;
+ }
- /* Apply gamma correction and pre-multiply alpha */
- rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff;
- rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff;
- rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff;
+ /* Premultiply alpha */
+ for (i = 0; i < 3; i++)
+ rgb[i] = rgb[i] * alpha / 0xff;
- return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
+ *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
+ return TRUE;
}
static void
@@ -1080,27 +1103,37 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
ScrnInfoPtr pScrn = crtc->scrn;
RADEONInfoPtr info = RADEONPTR(pScrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ Bool premultiplied = TRUE;
+ Bool apply_gamma = TRUE;
+ uint32_t argb;
uint32_t *ptr;
/* cursor should be mapped already */
ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
+ if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
+ apply_gamma = FALSE;
+
#if XF86_CRTC_VERSION < 7
if (crtc->driverIsPerformingTransform) {
uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
int dstx, dsty;
int srcoffset;
+retry_transform:
for (dsty = 0; dsty < cursor_h; dsty++) {
for (dstx = 0; dstx < cursor_w; dstx++) {
srcoffset = drmmode_cursor_src_offset(crtc->rotation,
cursor_w,
cursor_h,
dstx, dsty);
-
- ptr[dsty * info->cursor_w + dstx] =
- cpu_to_le32(drmmode_cursor_gamma(crtc,
- image[srcoffset]));
+ argb = image[srcoffset];
+ if (!drmmode_cursor_pixel(crtc, &argb, premultiplied,
+ apply_gamma)) {
+ premultiplied = FALSE;
+ goto retry_transform;
+ }
+ ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb);
}
}
} else
@@ -1109,8 +1142,16 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
uint32_t cursor_size = info->cursor_w * info->cursor_h;
int i;
- for (i = 0; i < cursor_size; i++)
- ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i]));
+retry:
+ for (i = 0; i < cursor_size; i++) {
+ argb = image[i];
+ if (!drmmode_cursor_pixel(crtc, &argb, premultiplied,
+ apply_gamma)) {
+ premultiplied = FALSE;
+ goto retry;
+ }
+ ptr[i] = cpu_to_le32(argb);
+ }
}
}