Closed GoogleCodeExporter closed 9 years ago
Your patch causes lots of WebGL 1.0.2 regressions
(https://www.khronos.org/registry/webgl/conformance-suites/1.0.2/webgl-conforman
ce-tests.html).
halfPixelSize is not a full pixel in size. Remember that OpenGL's NDC space
ranges from -1 to 1 in each dimension.
Perhaps your line is right at the edge of the clipping volume, and DX11 rounds
the other way?
Original comment by nico...@transgaming.com
on 10 Jun 2013 at 6:58
The test sample works on all other OpenGL ES implementations we have tested on,
except ANGLE. Yes the line is at the edge of the clipping volume. Do the tests
that regress with my patch, when run without my patch give the same results on
OpenGL and ANGLE?
Where this half-pixel difference applied in the pipeline? The only
documentation of the D3D 9 viewport transformation that I could find - at
http://msdn.microsoft.com/en-us/library/windows/desktop/bb206341%28v=vs.85%29.as
px - shows an identical transformation to OpenGL (for x and y) except for
scaling y by -height/2 instead of height/2.
There are many mentions of the half-pixel difference in words and even one
diagram but the above was the only mathematical expression of the viewport
transform that I could find.
Original comment by callow.m...@artspark.co.jp
on 11 Jun 2013 at 2:28
The transformed endpoints of the missing line prior to division by w are (-40,
-40, 38.039016, 40) and (40, -40, 38.039016, 40).
The original GL viewport settings are x=0, y=80, width=624, height=381. The
resulting dx viewport settings are x=0, y=80, width=624, height=341. The
drawable size is 624 x 421.
Original comment by callow.m...@artspark.co.jp
on 11 Jun 2013 at 2:42
You shouldn't rely on a line that's right at the edge of the clipping volume to
be visible (or not). A slight difference in floating-point rounding can change
the result, and OpenGL ES 2.0 does not specify how rounding is handled. Even if
the line is not actually clipped, the OpenGL ES 2.0 rasterization rules are not
very strict and the pixels may still fall outside the viewport. The best
guarantee for consistent results across different GL implementations is to have
endpoints that are close to pixel centers.
Of course we don't deliberately deviate from what most implementations would
produce, but it doesn't seem to me that the math in ANGLE's GL to DX
transformations is incorrect. You can read more about it in the ANGLE article
in the OpenGL Insights book, which happens to be freely available:
http://openglinsights.com/
Original comment by nico...@transgaming.com
on 11 Jun 2013 at 5:08
There shouldn't be any rounding in this case. The actual point values are
({+,-}40.000000, -40.000000, 38.039016, 40.000000). Obviously the line is not
being clipped, since it appears with my change to the viewport adjustment.
I looked at the article. It states that
"One last interesting effect of the different viewport trans
formations is that it also affects the fill convention."
Maybe I'm just being thick but I don't see how multiplying y by -1 affects the
fill convention. That is set by the specification of how rasterization works.
It also says
"OpenGL does not require a specific fill convention, only that a
well-defined convention is used consistently"
but the rasterization section of OpenGL ES 2.0 spec. says that fragment centers
that lie inside the (triangle) are produced by rasterization. Earlier it
defined the fragment center as being offset by (1/2, 1/2) from its lower-left
corner. That sounds like a fill convention to me. The only bit left unspecified
is which (triangle) rasterizes a fragment whose center is on a common edge.
I will try more OpenGL ES implementations and see if any of the ones we have
not yet tried, fail to emit this line.
Original comment by callow.m...@artspark.co.jp
on 11 Jun 2013 at 6:38
I agree that my proposed fix is incorrect but there is a real problem here.
According to the OpenGL spec rules a line at y_d = -1, y_w = 0, (_d: NDC, _w:
window) will be rasterized. I not aware of any OpenGL implementation that fails
to do this. The missing line in this sample is at y_d=-1. Therefore ANGLE is
not reproducing the same result at OpenGL.
When ANGLE applies the half-pixel offset, y_w becomes -0.5 and D3D9 does not
rasterize the line. D3D9 line rasterization follows the same rules as GDI and
"GDI does not round to the nearest integer." Therefore I believe the half-pixel
offset is unnecessary and should not be applied when drawing aliased lines.
One way to fix this is to compute a second viewAdjust value in setViewport and
prior to line drawing set the dx_ViewAdjust uniforms to the non-adjusted value.
Original comment by callow.m...@artspark.co.jp
on 12 Jun 2013 at 6:52
I'm sorry but I couldn't find any such guarantee in the OpenGL spec (neither in
ES 2.0 nor in GL 4.3). In fact it says the following in the 'Basic Line Segment
Rasterization' section: "The coordinates of a fragment produced by the
algorithm may not deviate by more than one unit in either x or y window
coordinates from a corresponding fragment produced by the diamond-exit rule."
In other words, it may deviate by a full pixel.
But even when adhering to the diamond-exit rule, there is no guarantee that a
line at the edge of your viewport will get rasterized. It is equivalent to
rasterizing the six-sided polygon formed by the convex hull of two pixel sized
diamond shapes centered at the endpoints. When your endpoints are on the edge
of the viewport, the edges of this polygon intersect the centers of the edge
pixels. But whether these are considered covered by the polygon or not depends
on the fill convention.
The fill convention isn't about defining what point in the pixel is used for
determining coverage. It's about if a polygon edge intersects this point,
whether it's considered covered or not. It must prevent gaps and overlap
between polygons that share an edge. And this is affected by flipping the y
direction. ANGLE effectively renders things 'upside down', and then flips is
back on present, to deal with the difference in texture orientation as detailed
in the OpenGL Insights article.
So it's not as if we're making use of the GL spec's pretty massive 1 pixel
leeway in line rasterization to justify the difference you're observing. It's
caused by a minute difference in rounding determined by the fill convention,
which is fully consistent and therefore conforms to the strict GL spec. It is
only by chance that you haven't encountered any other OpenGL implementation
where the line isn't visible.
The same problem occurs when people render a rectangle that's aligned to pixel
centers. There's no guarantee whether the top or bottom row of pixels gets
rasterized, or the left or right column. Rectangles like that should be aligned
to pixel edges instead for predictable results. For lines to show up
consistently you should align the endpoints to pixel centers.
For your case moving the line up a fraction of a pixel should make it visible.
If it has to be moved up half a pixel or more, that would be an actual bug.
Original comment by nico...@transgaming.com
on 12 Jun 2013 at 2:48
It has to be moved up half a pixel.
In init3D_GLLog after the call to glViewport, add the following line to move
the line up half a pixel.
vtxatt_IDX_1_ID_3006[1] = vtxatt_IDX_1_ID_3006[4] += 10.0f/(m_height - 40);
You will also need to remove "const" from the declaration of the array in
angle/log?gles_pointer.txt.
This gives an NDC position for Y of -0.997375325. To verify the calculation,
the half-pixel height in NDC is 1.0f/(m_height - 40) = 0.0026246719.
Subtracting this from -1.0 and you get the above value. Viewport height is set
to (m_height - 40). With this adjustment, the line will be drawn.
If you change 10.0 in the adjustment to 9.999 the line will disappear.
Original comment by callow.m...@artspark.co.jp
on 13 Jun 2013 at 4:22
Here is a partial patch based on avoiding the half-pixel viewport adjustment
when drawing lines. The patch is only partial in that it does not differentiate
anti-aliased lines which are rasterized differently and probably still need the
viewport adjustment.
Original comment by callow.m...@artspark.co.jp
on 13 Jun 2013 at 4:40
RE comment #8, I should have noted that m_height = 421.
Original comment by callow.m...@artspark.co.jp
on 13 Jun 2013 at 5:52
On my system I merely have to move the vertices up by 0.0395269413f/(m_height -
40) to make the line appear. Considering that z is at 10.0, this is just
1/506th of a pixel. This is most probably a rounding error by itself of 1/512th
of a pixel, which is what you need to make a card with 8-bit subpixel accuracy
round to the next value. So this perfectly supports my thesis that this is just
a fill convention difference.
Original comment by nico...@transgaming.com
on 13 Jun 2013 at 2:51
I wonder why get such different results than you.
I have tried on 2 different systems and for any value less than 9.999, i.e, a
half-pixel adjustment, the line does not appear. Both systems have AMD cards,
one mobile & 1 desktop. The desktop one has a much newer driver but I see there
is an even newer driver available. I'll try that.
Original comment by callow.m...@artspark.co.jp
on 14 Jun 2013 at 7:07
There is no change in behavior with the latest driver.
The required adjustment seems too large for line to be missing simply due to a
rounding issue.
Original comment by callow.m...@artspark.co.jp
on 14 Jun 2013 at 7:38
This still looks like a valid variation in rasterization rules for lines near
the edge of the viewport to me. Please file a new bug if you have additional
indications that this might be an ANGLE bug instead.
Original comment by c...@chromium.org
on 2 Dec 2013 at 6:58
Original issue reported on code.google.com by
callow.m...@artspark.co.jp
on 7 Jun 2013 at 6:21Attachments: