Bug 10508

Summary: Transformed image source surfaces sometimes misrender to xlib surface target
Product: cairo Reporter: Damon Chaplin <damon>
Component: generalAssignee: Carl Worth <cworth>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: blocker    
Priority: medium    
Version: 1.4.2   
Hardware: Other   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments: screenshot
test case
xlib test case
workaround version of test case

Description Damon Chaplin 2007-04-02 12:58:27 UTC
In the GooCanvas demo if I set the zoom to 5.0 and scroll around I am
getting painting artifacts on the image items (e.g. the big pixmap under
"Images").

This problem occurs in 1.4.0/1.4.2 but not in 1.2.4. (The GTK+ version
is the same.)

It could be a bug in my code, but it is a fairly simple fill operation:

  cairo_set_source (cr, image_data->pattern);
  cairo_matrix_init_translate (&matrix, -image_data->x, -image_data->y);
  cairo_pattern_set_matrix (image_data->pattern, &matrix);
  cairo_rectangle (cr, image_data->x, image_data->y,
		   image_data->width, image_data->height);
  cairo_fill (cr);

I'll attach a screenshot in a minute.
Comment 1 Damon Chaplin 2007-04-02 13:16:29 UTC
Created attachment 9441 [details]
screenshot
Comment 2 Damon Chaplin 2007-04-02 13:18:55 UTC
Comment on attachment 9441 [details]
screenshot

The screenshot shows the results of scrolling the canvas vertically slowly.
So it is only redrawing a few rows of pixels at a time as the canvas is
scrolled, and it seems to be messing up one or two of the rows.
Comment 3 Behdad Esfahbod 2007-04-02 13:20:18 UTC
What if you call cairo_pattern_set_matrix() before cairo_set_source()?  The pattern CTM is locked when you call set_source(), as opposed to when you call fill().  So I'd not be surprised if the same happens about pattern matrix.
Comment 4 Damon Chaplin 2007-04-02 13:43:58 UTC
No, calling cairo_pattern_set_matrix() before cairo_set_source() doesn't seem to help.
Comment 5 Damon Chaplin 2007-04-02 14:04:02 UTC
The problem was introduced in 1.3.12. (1.3.10 is OK)

I might try a git bisect later, though I'm not familiar with git.
Comment 6 Behdad Esfahbod 2007-04-03 12:48:32 UTC
Damon, any progress?  We'd like to fix this in 1.4.4 which will be out on Monday.  Can you do the bisect and let us know where this was introduced?  Alternatively, if you can write a simple test showing the problem, we can do the rest, but I guess bisecting would be easier for you.

Thanks,
Comment 7 Damon Chaplin 2007-04-03 14:56:06 UTC
This is what I got with git-bisect. This is the first time I've used that
so there is a slight chance I messed it up.

But it is the result I expected - the change that restricted the painting
seems to have restricted it a bit too much:


c96a71e709e537f690da6d4a184aa4c64fe11028 is first bad commit
commit c96a71e709e537f690da6d4a184aa4c64fe11028
Author: Carl Worth <cworth@cworth.org>
Date:   Fri Jan 5 15:56:06 2007 -0800

    Restrict _clip_and_composite_trapezoids to destination extents
    
    This is a fix for a huge performance bug (as measured by perf/long-lines).
    Previously, if no explicit clip was set, _clip_and_composite_trapezoids
    would allocate a mask as large as the trapezoids and rasterize into it.
    With this fix, it restricts the mask by the extents of the destination
    surface.
    
    This doesn't address the identical performance problem with the xlib
    backend, which is due to a very similar bug in the X server.
    
    image-rgb  long-lines-uncropped-100 465.42 -> 5.03: 92.66x speedup
    █████████████████████████████████████████████▉
    image-rgba long-lines-uncropped-100 460.80 -> 5.02: 91.87x speedup
    █████████████████████████████████████████████▍

:040000 040000 e883e75a0c6d25dcf65ec2f97752de537d2b8ab2 beb7a548759406fc19348476b701c292d8f44fa6 M      src
Comment 8 Behdad Esfahbod 2007-04-03 16:10:39 UTC
Carl, your stuff.
Comment 9 Damon Chaplin 2007-04-03 16:12:48 UTC
Note that the problem only occurs when images are scaled by cairo. It may be
a bug in the image scaling code that was triggered by the performance
improvements. (Maybe it has trouble handling only one row/column of output.)
Comment 10 Damon Chaplin 2007-04-04 03:03:50 UTC
Actually it isn't just a scaled image problem. I can also see the problem if
I place an unscaled image at a non-integer position, e.g. (100.5,100.5).
(Probably the same code though.)
Comment 11 Carl Worth 2007-04-05 13:10:39 UTC
OK, I've replicated this with the goocanvas demo. Smells like a rounding bug somewhere. I'll look closer now.

-Carl
Comment 12 Carl Worth 2007-04-05 17:20:47 UTC
(In reply to comment #10)
> Actually it isn't just a scaled image problem. I can also see the problem if
> I place an unscaled image at a non-integer position, e.g. (100.5,100.5).
> (Probably the same code though.)

That's encouraging. Do you have minimal program to demonstrate the bug?

I'm fine if it uses goocanvas, but if it can demonstrate the bug without any user interaction that would be ideal.

Thanks,

-Carl
Comment 13 Damon Chaplin 2007-04-06 08:11:06 UTC
Created attachment 9499 [details]
test case
Comment 14 Damon Chaplin 2007-04-06 08:13:33 UTC
To use the test case run it and then drag another window around on top of it,
so that the image needs to be partially redrawn.
You should see painting errors.
Comment 15 Carl Worth 2007-04-13 10:59:33 UTC
Adding some details to the bug title, (the bug only affects code targeting the xlib backend, and only with an image-surface source that is transformed).
Comment 16 Carl Worth 2007-04-13 11:06:15 UTC
Created attachment 9595 [details]
xlib test case

Here's a slightly more minimal test case. It uses only cairo and Xlib, not GTK+. And it continuously redraws so there's no need to drag another window over the program's window to see the bug.

Note: Dragging windows, or otherwise keeping your X server busy, does make the bug manifest itself more regularly. If I leave my X server pretty much alone, this test case stops triggering the bug, (instead of sweeping, miscolored lines, the window contents become static).

-Carl
Comment 17 Carl Worth 2007-04-13 11:12:32 UTC
Created attachment 9596 [details]
workaround version of test case

I don't have a fix for the bug yet, but I do have one workaround to suggest.

Instead of using an image surface as the source pattern, copy the unscaled image contents to an xlib surface, and then use that as the pattern to be transformed.

This attachment is the same as the previous test case, but with this workaround applied, demonstrating that it is effective at eliminating the bug.

-Carl
Comment 18 Behdad Esfahbod 2007-04-18 09:55:29 UTC
Oh, I fixed this right before 1.4.4 btw.

commit 84c10a79ffd233a953434bd787dcfe57787552f8
Author: Behdad Esfahbod <behdad@behdad.org>
Date:   Fri Apr 13 16:33:07 2007 -0400

    [cairo-pattern] Slightly hackish fix for bug #10508
    
    The so-attributed-to-X-server bug was that cairo maps the drawing
    region to the pattern space, rounds the box, and uploads only that
    part of the source surface to the X server.  Well, this only works for
    NEAREST filter as any more sophisticated filter needs to sneak a peek
    at the neighboring pixels around the edges too.
    
    The right fix involves taking into account the filter used, and the
    pattern matrix, but for most cases, a single pixel should be enough.
    Not sure about scaling down...
    
    Anyway, this is just a workaround to get 1.4.4 out of the door.  I'll
    commit a proper fix soon.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.