Commit ad6dfb01 authored by Michel Dänzer's avatar Michel Dänzer Committed by Michel Dänzer
Browse files

Detect and fix up non-premultiplied cursor data

X server >= 1.18 already had code for this, but it only caught cases
where some pixels have 0 for alpha and non-0 for a non-alpha component.
Turns out some apps (e.g. the Civilization VI game) use
non-premultiplied cursor data which doesn't have such pixels, but can
still result in visual artifacts.

This uses the method suggested by Kamil in
https://bugs.freedesktop.org/92309#c19: check for pixels where any
colour component value is larger than the alpha value, which isn't
possible with premultiplied alpha.

There can still be non-premultiplied data which won't be caught by this,
but that should result in slightly incorrect colours and/or blending at
the worst, not wildly incorrect colours such as shown in the bug report
below.

v2:
* Disable the check with current xserver Git master, which already does
  the same check now.

Bugzilla: https://bugs.freedesktop.org/108355

Suggested-by: default avatarKamil Páral <kamil.paral@gmail.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent c9d43c1d
Pipeline #7052 passed with stage
in 2 minutes and 8 seconds
......@@ -1500,49 +1500,65 @@ drmmode_cursor_src_offset(Rotation rotation, int width, int height,
#endif
static uint32_t
drmmode_cursor_gamma_passthrough(xf86CrtcPtr crtc, uint32_t argb)
{
uint32_t alpha = argb >> 24;
if (!alpha)
return 0;
return argb;
}
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, 20, 99, 0, 0)
if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24))
/* Doesn't look like premultiplied alpha */
return FALSE;
#endif
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;
/* 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;
if (premultiplied) {
/* Un-premultiply alpha */
for (i = 0; i < 3; i++)
rgb[i] = rgb[i] * 0xff / alpha;
}
return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
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;
}
/* Premultiply alpha */
for (i = 0; i < 3; i++)
rgb[i] = rgb[i] * alpha / 0xff;
*argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
return TRUE;
}
static void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr)
{
ScrnInfoPtr pScrn = crtc->scrn;
AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
uint32_t (*cursor_gamma)(xf86CrtcPtr crtc, uint32_t argb) =
drmmode_cursor_gamma;
Bool premultiplied = TRUE;
Bool apply_gamma = TRUE;
uint32_t argb;
if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) ||
drmmode_cm_enabled(&info->drmmode))
cursor_gamma = drmmode_cursor_gamma_passthrough;
apply_gamma = FALSE;
#if XF86_CRTC_VERSION < 7
if (crtc->driverIsPerformingTransform) {
......@@ -1550,15 +1566,20 @@ static void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_
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(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
......@@ -1567,8 +1588,16 @@ static void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_
uint32_t cursor_size = info->cursor_w * info->cursor_h;
int i;
for (i = 0; i < cursor_size; i++)
ptr[i] = cpu_to_le32(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);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment