[Mesa-dev] Expected wide line rendering with clipping

Erik Faye-Lund kusmabite at gmail.com
Mon Feb 9 06:58:29 PST 2015


On Mon, Feb 9, 2015 at 12:35 PM, Roland Scheidegger <sroland at vmware.com> wrote:
> Am 09.02.2015 um 09:53 schrieb Iago Toral:
>> On Fri, 2015-02-06 at 21:27 +0100, Roland Scheidegger wrote:
>>> Am 06.02.2015 um 13:11 schrieb Iago Toral:
>>>> Hi,
>>>>
>>>> Eduardo and I have been looking into a few dEQP test failures that deal
>>>> with wide line rendering. There are a few of them that fail because of
>>>> how clipping is implemented for this case.
>>>>
>>>> The problem in these cases seems to be that the hw renders the wide line
>>>> as a parallelogram so that if an edge of the parallelogram is partially
>>>> clipped, the other parallel edge will also be clipped at the same
>>>> height/width so that the resulting wide line stays a parallelogram. The
>>>> dEQP renders as if a wide line where a collection of 1px lines, so
>>>> cliping one edge of the resulting line does not have implications for
>>>> the other edge.
>>>>
>>>> This ASCII art illustrates the problem (* represent line pixels, |
>>>> represents the viewport's rightmost edge):
>>>>
>>>>  Expected by dEQP          i965 rendering
>>>>          |                      |
>>>>         *|                      |
>>>>        **|                      |
>>>>       ***|                      |
>>>>      ****|                  ****|
>>>>     **** |                 **** |
>>>>    ****  |                ****  |
>>>>
>>>> We can make the rendering result match dEQP's expectation by enabling
>>>> the GuardBand in the clip stage (GEN6_CLIP_GB_TEST). This is being
>>>> disabled by the driver for gen7 in this scenario because the underlying
>>>> framebuffer surface is larger than the viewport, and per the comment in
>>>> the code, in gen7 that would make it render beyond the viewport limits
>>>> in that surface, while it notes that gen8 hw fixes this. So I guess that
>>>> we do not want to do this in any case in gen7.
>>>>
>>>> Then, I have been reviewing the OpenGL specs to see if they clarify what
>>>> should happen when clipping wide lines and I think the spec does not
>>>> make a clear point, since when it talks about line clipping it does not
>>>> cover the case of wide lines specifically:
>>>>
>>>> "13.5. PRIMITIVE CLIPPING
>>>> ...
>>>> If part of the line segment lies in the volume and part lies outside,
>>>> then the line segment is clipped and new vertex coordinates are computed
>>>> for one or both vertices. A clipped line segment endpoint lies on both
>>>> the original line segment and the boundary of the clip volume.
>>>> ...
>>>> "
>>>>
>>>> The above description is clear for 1px lines, but where should the new
>>>> vertex be generated exactly for wide lines, where many points could be
>>>> at the boundary of the clip volume? Is any point valid? (that would mean
>>>> the dEQP test is bogus because there are multiple accepted renderings),
>>>> should the new vertex be exactly at the center of the line? (that would
>>>> make both deqp and intel rendering bogus).
>>>>
>>>> Then there is also this comment in "14.5.2.2 Wide Lines" inside the
>>>> non-AA line rasterization chapter:
>>>>
>>>> "Non-antialiased line segments of width other than one are rasterized by
>>>> off-setting them in the minor direction (for an x-major line, the minor
>>>> direction is y, and for a y-major line, the minor direction is x) and
>>>> replicating fragments in the minor direction (see figure 14.3). Let w be
>>>> the width rounded to the nearest integer (if w = 0, then it is as if w =
>>>> 1). If the line segment has endpoints given by (x 0 , y 0 ) and (x 1 , y
>>>> 1 ) in window coordinates, the segment with endpoints (x 0 , y 0 − (w −
>>>> 1)/2) and (x 1 , y 1 − (w − 1)/2) is rasterized, but instead of a single
>>>> fragment, a column of fragments of height w (a row of fragments of
>>>> length w for a y-major segment) is produced at each x (y for y-major)
>>>> location. The lowest fragment of this column is the fragment that would
>>>> be produced by rasterizing the segment of width 1 with the modified
>>>> coordinates."
>>>>
>>>> This "suggests" that wide line rendering should be equivalent to
>>>> rendering multiple lines of width=1 and if we actually did that then the
>>>> expected rendering result after clipping would be what dEQP expects.
>>>>
>>>> I think the whole thing isn't 100% clear. Does anyone have any thoughts
>>>> on what should be considered correct behavior in this case?
>>>>
>>>> Iago
>>>>
>>>>
>>>
>>> I am quite sure that i965 rendering is what (at least legacy GL)
>>> expects. This is because the wide-line expansion is defined to be
>>> happening at rasterization time, i.e. past clipping. Thus, at clipping
>>> time, no matter if a line is wide or not, it is still really a line,
>>> hence clipping will produce a single new endpoint at the viewport edge
>>> and in rasterization this is then what will be used as the endpoint.
>>
>> That makes sense, but in that case I think i965 rendering would still be
>> incorrect, the expected result would look something like this:
>>
>>           |
>>           |
>>         **|
>>        ***|
>>       ****|
>>      **** |
>>     ****  |
>>
>> However, as far as I can tell, since i965 hardware renders wide lines as
>> parallelograms, it can't render something like this.
>>
>> Actually, the rendering result looks more like something we would obtain
>> if we did line expansion before clipping:
>>
>>           |
>>           |
>>           |
>>           |
>>       ****|
>>      **** |
>>     ****  |
>
> Ok that seems incorrect then - I thought this was merely the inprecision
> of the ascii art.
> I think though I didn't really get all the details of wide line
> rendering previously, in particular the major/minor axis bits, which are
> again sort of surprising (naively you would expect wide lines to be a
> rectangle, not reproduce replicated fragments along the minor axis, but
> that's only true for antialiased lines). Due to that it could be that
> what i965 produces is indeed correct - the spec says render with a line
> which is essentially offset from the real line with width/2 and
> replicate fragments in the minor direction, and I'm not really sure it
> should produce fragments then if the "virtual endpoint" lies outside the
> viewport (though I would still suspect yes since this ought to still be
> happening after clipping).
> But maybe i965 just renders wide (non-antialiased lines) by offsetting
> them at primitive setup time, then clips them, and does the wide-line
> thing at rasterization, which would lead to this result. Though in this
> case this would make it asysmmetrical wrt to left/right edges right? So
> this would happen only on the right edge, at the left edge with the same
> line it would render them until it touches the viewport, that is it
> would look like this:
>
> |           |
> |           |
> |           |
> |       ****|
> |      **** |
> |     ****  |
> |    ****   |
> |   ****    |
> |  ****     |
> | ****      |
> |***        |
> |**         |
> |*          |
> |           |
>
> Whereas I suspect it should indeed be:
>
> |           |
> |           |
> |         **|
> |       ****|
> |      **** |
> |     ****  |
> |    ****   |
> |   ****    |
> |  ****     |
> | ****      |
> |***        |
> |**         |
> |           |
> |           |
>
> I don't know if it's really worth bothering though, I bet what everybody
> really wants to see for wide lines is rectangles anyway (which you
> clearly won't get according to the spec with non-antialiased lines).
> Wide line rendering along with points is really messed up imho.

My understanding of wide non-antialiased lines is like this:

1) They get clipped in their "ideal line" representation ("After a
primitive is formed, it is clipped to a viewing volume" GLES2 spec,
section 2.6)
2) The ideal line gets rasterized according to the diamond-exit rule
(or similar) as a 1 pixel wide line (GLES2 spec, section 3.4.1)
3) The spans in the line's minor direction gets expanded to match the
width. This includes replicating varyings interpolation weights
("Non-antialiased line segments of width other than one are rasterized
by offsetting them in the minor direction (for an x-major line, the
minor direction is y, and for a y-major line, the minor direction is
x) and replicating fragments in the minor direction" GLES2 spec,
section 3.4.2)

This means:
A) wide lines can produce fragments outside of the viewport, and
"missing" fragments around the viewport-border
B) Lines have axis oriented end-points *and* interpolants, both which
"pop" when changing major axis.
C) Interpolation weights also pop when changing major axis, so manual
stipple-patterns etc should also follow the minor-direction.

However, during the development of OpenGL ES 2.0, IIRC one vendor was
unhappy with the line rasterization rules. Said vendor proposed an
extension to allow different rasterization, but IIRC in the end result
was that we decided to not conformance test these details.

AFAIK, this works the same in OpenGL versions before 3.0 (where wide
lines were deprecated), however OpenGL hasn't traditionally had a very
complete conformance test suite (unlike GLES 2).

A quick test on NVIDIA hardware reveals that they follow these rules
on on-screen endpoint, but not when clipping to the viewport.


More information about the mesa-dev mailing list