On Sat, Mar 02, 2019 at 10:24:22PM +0200, Mihai Popescu wrote:
> Hello,
> 
> I am able to generate a segmentation fault on X with chromium help.
> This is happening each time I visit the web page at [1]. Basically,
> there is a picture of a product and whenever I hover the mouse over
> it, X gets a segmentation fault and exits at xenodm login prompt.
> Sometimes, if I repeat this procedure over and over, I get an offset
> for the image on my display, making things hard to see.
> 
> [1] 
> https://computers.woot.com/offers/lenovo-thinkcentre-m78-amd-a4-sff-desktop-1
> 
> I have inspected the web page in question with firefox, and I can tell
> the page loads a special image cursor when I hover on the picture in
> question. No segmentation fault for X this time.
> 

Hi,

Thanks for the bug report. Can you try the attached patch (from
upstream) ?

Index: src/drmmode_display.c
===================================================================
RCS file: /cvs/OpenBSD/xenocara/driver/xf86-video-ati/src/drmmode_display.c,v
retrieving revision 1.18
diff -u -p -u -r1.18 drmmode_display.c
--- src/drmmode_display.c       13 Jan 2019 07:16:48 -0000      1.18
+++ src/drmmode_display.c       4 Mar 2019 08:12:30 -0000
@@ -1038,29 +1038,62 @@ drmmode_cursor_src_offset(Rotation rotat
 
 #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 */
+                       *premultiplied = FALSE;
+                       return FALSE;
+               }
+#endif
 
-       if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
-               return argb;
+               if (!(*apply_gamma))
+                       return TRUE;
+
+               if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) {
+                       /* Un-premultiplied R/G/B would overflow gamma LUT,
+                        * don't apply gamma correction
+                        */
+                       *apply_gamma = FALSE;
+                       return FALSE;
+               }
+       }
+
+       if (!alpha) {
+               *argb = 0;
+               return TRUE;
+       }
 
-       /* Un-premultiply alpha */
+       /* 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;
+       }
+
+       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;
+       }
 
-       return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
+       /* 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
@@ -1069,27 +1102,36 @@ drmmode_load_cursor_argb (xf86CrtcPtr cr
        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);
+                               argb = image[srcoffset];
+                               if (!drmmode_cursor_pixel(crtc, &argb, 
&premultiplied,
+                                                         &apply_gamma))
+                                       goto retry_transform;
 
-                               ptr[dsty * info->cursor_w + dstx] =
-                                       cpu_to_le32(drmmode_cursor_gamma(crtc,
-                                                                        
image[srcoffset]));
+                               ptr[dsty * info->cursor_w + dstx] = 
cpu_to_le32(argb);
                        }
                }
        } else
@@ -1098,8 +1140,15 @@ drmmode_load_cursor_argb (xf86CrtcPtr cr
                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))
+                               goto retry;
+
+                       ptr[i] = cpu_to_le32(argb);
+               }
        }
 }
 

-- 
Matthieu Herrb

Reply via email to