Bug 22770

Summary: Zero-width lines drawn differently than vesa driver (but consistent with line width 1)
Product: xorg Reporter: Bryce Harrington <bryce>
Component: Driver/intelAssignee: Carl Worth <cworth>
Status: RESOLVED INVALID QA Contact: Xorg Project Team <xorg-team>
Severity: normal    
Priority: low CC: jaimerave
Version: 7.4 (2008.09)   
Hardware: x86 (IA32)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments:
Description Flags
Xorg.0.log
none
dialog img
none
closeup img
none
buttons img
none
The problem With the intel Driver
none
The same program using Vesa driver
none
Test program
none
Test program to demonstrate differing zero-width-line algorithms none

Description Bryce Harrington 2009-07-14 15:44:58 UTC
Created attachment 27691 [details]
Xorg.0.log

Forwarding this bug from Ubuntu reporter Jaime Rave:
https://bugs.edge.launchpad.net/xserver-xorg-video-intel/+bug/398244

[Problem]
Corner shadow pixels are missing in gui widgets on Intel X4500HD when -intel used (-vesa displays properly).  Wine upstream indicates this is a driver bug, not wine.

[Original Report]
While using wine there are some missing pixels in the widgets. This is while using Intel Driver, if i change the driver to Vesa the problem doesn't appear.

You can check more information and screenshots at: http://bugs.winehq.org/show_bug.cgi?id=19082

I also have tried using the latest drivers from http://ppa.launchpad.net/xorg-edgers/ppa/ubuntu, but still the same problem.

I'm using Ubuntu 9.04, Wine 1.1.25 and my video card is a Intel X4500HD

00:02.0 VGA compatible controller [0300]: Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller [8086:2a42] (rev 07).
Comment 1 Bryce Harrington 2009-07-14 15:45:37 UTC
Created attachment 27692 [details]
dialog img
Comment 2 Bryce Harrington 2009-07-14 15:45:53 UTC
Created attachment 27693 [details]
closeup img
Comment 3 Bryce Harrington 2009-07-14 15:46:09 UTC
Created attachment 27694 [details]
buttons img
Comment 4 Bryce Harrington 2009-07-30 13:27:53 UTC
(I'm dropping the priority on this a notch since it's a cosmetic issue, which apparently only affects wine.  I think I set it too high when initially filed, apologies if you do think it should be major/high.)
Comment 5 Carl Worth 2009-07-31 11:03:37 UTC
Hi Bryce,

I have to agree that it's hard to prioritize this bug over things that cause lockups of the GPU or failure to login. But at the same time, I do have a part of me that is anxious to make every last pixel correct. :-)

Jaime,

I think what we'll need next is a smaller test case to help us know exactly what operation is resulting in the missing pixel. It's a bit too much for us as driver hackers to hear "wine dialog" and know what the problem might be. Could you perhaps do some investigation to find out as much as you can about what is actually being drawn here? Is it lines? Filled rectangles? Outlined rectangles? And how it's being drawn: Is wine using XDrawLines? XDrawRectangle? cairo calls?

Ideally we could get this down to a single call, (say one XDrawLines request), where the vesa driver and the intel driver behave differently. If we had that, I would guess that it should be quite easy to identify and fix the bug.

One very good approach to getting this information might be to run an X protocol capture tool and capture a trace. For example:

    xtrace &
    DISPLAY=:9 wine ./whatever/program/shows/the/bug

There will be a lot of output, (but the more simple program you can use, the better of course). But hopefully by knowing where on the screen the missing pixel is, you can grep through the trace and find where the problem is.

Oh, another thing you might try is to instead run "xtrace -i" in a separate terminal rather than running it in the background. This puts xtrace into an "interactive" mode where you have to press Enter before it forwards each request. This way you can control how slowly the application runs and know when the right range of output is appearing in the protocol trace.

I hope that helps and that we can track down your missing pixel for you.

-Carl

Comment 6 Jaime Rave 2009-07-31 23:26:02 UTC
Well I've made some researching, I'm not a XServer guru but this is what I found using xtrace. When is going to draw the button (that shows the bug) in a example program this is the code that is been called.

001:<:0119: 20: Request(59): SetClipRectangles ordering=YXBanded(0x03) gc=0x0560000b clip-x-origin=36 clip-y-origin=16 rectangles ={x=0 y=0 w=76 h=26};
001:<:011a: 20: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00d4d0c8 background=0x00d4d0c8}
001:<:011b: 20: Request(70): PolyFillRectangle drawable=0x05e00006 gc=0x0560000b rectangles={x=36 y=16 w=75 h=25};
001:<:011c: 20: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00000000 join-style=Miter(0x00)}
001:<:011d: 20: Request(67): PolyRectangle drawable=0x05e00006 gc=0x0560000b rectangles={x=36 y=16 w=75 h=25};
001:<:011e: 20: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00ffffff join-style=Round(0x01)}
001:<:011f: 28: Request(66): PolySegment drawable=0x05e00006 gc=0x0560000b segments={x1=37 y1=17 x2=111 y2=17},{x1=37 y1=17 x2=37 y2=41};
001:<:0120: 16: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00404040}
001:<:0121: 28: Request(66): PolySegment drawable=0x05e00006 gc=0x0560000b segments={x1=110 y1=40 x2=36 y2=40},{x1=110 y1=40 x2=110 y2=16};
001:<:0122: 16: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00d4d0c8}
001:<:0123: 28: Request(66): PolySegment drawable=0x05e00006 gc=0x0560000b segments={x1=38 y1=18 x2=110 y2=18},{x1=38 y1=18 x2=38 y2=40};
001:<:0124: 16: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00808080}
001:<:0125: 28: Request(66): PolySegment drawable=0x05e00006 gc=0x0560000b segments={x1=109 y1=39 x2=37 y2=39},{x1=109 y1=39 x2=109 y2=17};
001:<:0126: 16: Request(56): ChangeGC gc=0x0560000b  values={foreground=0x00d4d0c8}
001:<:0127: 20: Request(70): PolyFillRectangle drawable=0x05e00006 gc=0x0560000b rectangles={x=39 y=19 w=70 h=20};

I have made the tests with a small program showing a dialog box just with a button. If you need more information, or if this is not enough just ask for more info, I'll be more than glad to help with this bug. If you need the source code of the test program or the complete output of the xtrace I'll attach it.
Comment 7 Jaime Rave 2009-07-31 23:56:03 UTC
Created attachment 28240 [details]
The problem With the intel Driver

Ok, I think I found the problem. Is in the PolySegment call. When the X1 or Y1 is bigger than X2 or Y2 the function is drawing the segments one pixel less than is supposed to be. I think the images will explain better.
Comment 8 Jaime Rave 2009-07-31 23:56:40 UTC
Created attachment 28241 [details]
The same program using Vesa driver
Comment 9 Carl Worth 2009-08-01 06:13:19 UTC
(In reply to comment #7)

> Ok, I think I found the problem. Is in the PolySegment call. When the X1 or Y1
> is bigger than X2 or Y2 the function is drawing the segments one pixel less
> than is supposed to be. I think the images will explain better.

Excellent!

Thank you very much for your careful research on this one. The ball is definitely in my court now to see what our driver is doing wrong.

Please ping me if you don't hear any progress from me in the next week or two.

-Carl
Comment 10 Jaime Rave 2009-08-14 16:18:51 UTC
Hi Carl, any progress in this bug??
Comment 11 Jaime Rave 2009-08-30 23:07:48 UTC
This is still a problem. Is there any additional information I can give to quickly fix this bug?. Carl you told me to ping you in 2 weeks but I haven't heard anything from you in a month.
Comment 12 Carl Worth 2009-09-02 11:37:48 UTC
(In reply to comment #11)
> This is still a problem. Is there any additional information I can give to
> quickly fix this bug?. Carl you told me to ping you in 2 weeks but I haven't
> heard anything from you in a month.

Hi Jaime,

I apologize that I missed your first ping. I appreciated the second
one, (it mentioned that I had actually *asked* for it so it was easier
to notice).

Anyway, I tried writing a test program based on your xtrace output,
but I couldn't reproduce the bug exactly. I did succeed in getting the
intel driver to generate results like in your output, but my test
program achieved the same results with the vesa driver as well.

Could you send me your test program? One source of differences is that
your xtrace output doesn't have all of the GC settings and there are
several that are relevant here, (such as line-width and cap-style).

Thanks,

-Carl

Comment 13 Jaime Rave 2009-09-02 23:27:23 UTC
Created attachment 29156 [details]
Test program

Hi Carl. This is the program i used to get the xtrace. It just create a message window with a button that show the bug in the right bottom corner. Anything else just ask for it.
Comment 14 Carl Worth 2009-09-03 16:52:20 UTC
Created attachment 29196 [details]
Test program to demonstrate differing zero-width-line algorithms

(In reply to comment #13)
> Created an attachment (id=29156) [details]
> Test program
> 
> Hi Carl. This is the program i used to get the xtrace. It just create a message
> window with a button that show the bug in the right bottom corner. Anything
> else just ask for it.

Hi Jaime,

Thanks for the test program.

I'm now attaching a test program that is as minimal as possible and
that shows different behavior with either the vesa or xf86-video-intel
drivers.

However, this isn't actually a driver bug.

Instead, the test program (and wine) are drawing lines with width of
0, (known as "thin lines" in the X protocol description). And such
lines can be implemented with a device-specific algorithm that can
differ from driver to driver[*].

So it's not actually surprising that there are differences
here---that's perfectly allowable. What is a bit surprising is that
the results with the intel driver are equivalent to the results that
would be obtained by using a line width of 1, (where the protocol
specifies an algorithm that defines precisely which pixels must be
affected). I would have expected the vesa driver to match that
behavior.

The "wide lines" (such as line_width=1) specification requires that
drawing a segment (x1,y1)-(x2,y2) be equivalent to drawing from
(x2,y2)-(x1,y1). The protocol specification recommends, (but does not
require), that "thin lines" also meet this same
constraint. Interestingly, the intel driver appears to meet this
constraint, but the vesa driver does not.

So, according to what I can read of the X protocol specification,
neither the vesa nor intel drivers have a bug here. They are allowed
to differ in these details of which pixels get lit. (And if anything,
vesa is the odd one for not matching the algorithm of line_width=1.)

So, to fix the bug, wine is going to have to change its code to not
rely on the pixelization of zero-width lines, (which can differ from
one driver to the next), and should instead use lines with
width=1. Making this change will require making some adjustments to
how the segment endpoint coordinates are computed to still achieve the
desired result.

I hope this helps, (and that my test program is useful for anyone
looking into this problem).

And of course, another option is to stop using things like
XDrawSegment entirely and instead use something like cairo
(http://cairographics.org) which always provides consistent
pixelization regardless of drivers.

Good luck!

[*] Here are some of the details from the specification:

Wide lines are drawn centered on the path described by the graphics
request. Unless otherwise specified by the join-style or cap-style,
the bounding box of a wide line with endpoints [x1, y1], [x2, y2] and
width w is a rectangle with vertices at the following real
coordinates:

[x1-(w*sn/2), y1+(w*cs/2)], [x1+(w*sn/2), y1-(w*cs/2)],
[x2-(w*sn/2), y2+(w*cs/2)], [x2+(w*sn/2), y2-(w*cs/2)]

Here sn is the sine of the angle of the line, and cs is the cosine of
the angle of the line. A pixel is part of the line and so is drawn if
the center of the pixel is fully inside the bounding box (which is
viewed as having infinitely thin edges). If the center of the pixel is
exactly on the bounding box, it is part of the line if and only if the
interior is immediately to its right (x increasing direction). Pixels
with centers on a horizontal edge are a special case and are part of
the line if and only if the interior or the boundary is immediately
below (y increasing direction) and the interior or the boundary is
immediately to the right (x increasing direction).

Thin lines (zero line-width) are one-pixel-wide lines drawn using an
unspecified, device-dependent algorithm. There are only two
constraints on this algorithm.

   1. If a line is drawn unclipped from [x1,y1] to [x2,y2] and if
   another line is drawn unclipped from [x1+dx,y1+dy] to
   [x2+dx,y2+dy], a point [x,y] is touched by drawing the first line
   if and only if the point [x+dx,y+dy] is touched by drawing the
   second line.

   2. The effective set of points comprising a line cannot be affected
   by clipping. That is, a point is touched in a clipped line if and
   only if the point lies inside the clipping region and the point
   would be touched by the line when drawn unclipped.

A wide line drawn from [x1,y1] to [x2,y2] always draws the same pixels
as a wide line drawn from [x2,y2] to [x1,y1], not counting cap-style
and join-style. It is recommended that this property be true for thin
lines, but this is not required. A line-width of zero may differ from
a line-width of one in which pixels are drawn. This permits the use of
many manufacturers' line drawing hardware, which may run many times
faster than the more precisely specified wide lines.

http://tronche.com/gui/x/xlib/GC/manipulating.html
Comment 15 Carl Worth 2009-09-03 16:53:42 UTC
Retitling the bug report now that it has been investigated more closely, and resolving as not a bug.

Thanks again for the report,

-Carl
Comment 16 Jaime Rave 2009-10-08 14:47:40 UTC
Hi Carl, I know that this bug is already resolved as "not a bug", but I've been testing in other PC with Nvidia cards and the bug is not there either. And also changing the line with to 1 in wine looks like it doesn't fix the bug. I've been rechecking and the problem seems to be that when Wine make this call: 

001:<:0121: 28: Request(66): PolySegment drawable=0x05e00006 gc=0x0560000b segments={x1=110 y1=40 x2=36 y2=40},{x1=110 y1=40 x2=110 y2=16}; 

It specs the line to be drawn from x1=110 to x2=36 and not drawing the last pixel in x=36 as when line_with is 0 or 1 in Wine they are using the CapStyle as CapNotLast [1]. But it's been draw from x=36 to x=110 and the one that is missing is the one at x=110. 

So looks like it is a bug in the driver after all. Thanks in advance for the help.

[1]http://source.winehq.org/source/dlls/winex11.drv/graphics.c#L321
Comment 17 Jaime Rave 2010-04-20 10:02:09 UTC
Fixed in Wine.

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.