yangqiaosheng / angleproject

Automatically exported from code.google.com/p/angleproject
Other
0 stars 0 forks source link

ANGLE introduces subtle artifacts for 2D rendering that are not present in canvas or native GL #340

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Load http://hildr.luminance.org/GameType/GameType.html

What is the expected output? What do you see instead?
Rendering of text and other 2D images in ANGLE should roughly match native 
OpenGL or canvas

What version of the product are you using? On what operating system?
Appears in all tested builds of Firefox and Chrome (when using ANGLE+WebGL for 
rendering) on my Windows 7 64-bit machine with a NVIDIA Geforce GTX 670 (Driver 
version 301.42, the latest).

Please provide any additional information below.
I've tested this in multiple versions of FF and Chrome and it seems to have 
been around for a while. Apparently it may have something to do with my 
hardware configuration, because other users of these browsers don't see it. If 
I force Firefox to use native OpenGL, the issue goes away, and if I use Chrome 
or Firefox's canvas backends, the issue also goes away, so something about 
ANGLE's pipeline is introducing the artifacts.

Specifically, the artifacts cause a 'grainy' appearance in textures due to a 
small number of pixels being distorted or displaced. It's most obvious on text 
(I'll attach screenshots showing the output from individual backends in FF in 
one demo). It shows up in all of the demos for my particular application, but 
I've also seen it in other WebGL demos (emscripten's Bananabread demo, for 
example).

Original issue reported on code.google.com by kevin.g...@gmail.com on 17 Jun 2012 at 9:31

Attachments:

GoogleCodeExporter commented 9 years ago
Two more screenshots from other rendering backends. If you zoom in, you can see 
the distortion in the ANGLE version.

Original comment by kevin.g...@gmail.com on 17 Jun 2012 at 9:32

Attachments:

GoogleCodeExporter commented 9 years ago
Possibly related to some other reports by the MapsGL team about blurred text 
rendering on some hardware.

Original comment by kbr@chromium.org on 17 Jun 2012 at 10:42

GoogleCodeExporter commented 9 years ago
This could be caused by not sampling at texel centers. ANGLE uses a different 
rounding for texture coordinates (which is completely within spec). The 
solution is to add (0.5 / <texture width>, 0.5 / <texture height>) to your 
texture coordinates. Does that fix the issue?

Original comment by nicolas....@gmail.com on 18 Jun 2012 at 1:02

GoogleCodeExporter commented 9 years ago
Unfortunately it does not.

I have another demo that tries to do pixel-perfect rendering and renders 
EXTREMELY broken on this machine under WebGL. I spent two days or so on and off 
experimenting with various texture coordinate biases, sampling parameters, etc 
to try and get correct rendering and no reasonable combination I could think of 
worked.

Off the top of my head, I remember trying:

Offsetting all pixel coordinates by a certain number of texels (0.1, 0.5, 1.0, 
-0.1, -0.5, -1.0)
Offsetting the total dimensions of the texture rectangle by a certain number of 
texels (-1, -2, +1, +2, +0.5, -0.5)

All of those just made the problem worse - for example, offsetting the 
coordinates gave me the texel bleeding on the edges of quads that I would 
expect of my texel coordinates were wrong.

As you can see, the bleeding in this demo only occurs in one pixel of each quad 
(in the corner) and the pixel bleeding in is from an adjacent texel. This is 
similar to how only a few pixels of the text quads in my text rendering are 
mangled - it's not consistently off by some quantity of texels, and it's not 
blurry as it would be if I were sampling at the wrong texel coordinates.

Original comment by kevin.g...@gmail.com on 18 Jun 2012 at 1:17

Attachments:

GoogleCodeExporter commented 9 years ago
Is mipmapping and multi-sampling enabled? ANGLE uses centroid sampling on some 
hardware, which can cause pixels near edges or corners of triangles to use a 
different mipmap level. It might be causing more harm than good so we're 
looking into disabling this feature.

Original comment by nicolas....@gmail.com on 18 Jun 2012 at 1:28

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
For reference, here is the setup code from the library I use (webgl-2d) that 
sets texture states:

      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

      // Enable Mip mapping on power-of-2 textures
      if (isPOT(image.width) && isPOT(image.height)) {
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
        gl.generateMipmap(gl.TEXTURE_2D);
      } else {
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      }

Since I think these textures are all power of two, that means it's using 
LINEAR_MIPMAP_LINEAR. I kind of want mip-mapping here, so that scaling bitmaps 
down looks good.

I don't think it's doing anything else to enable multisampling, but I'm not 
sure if it defaults to on - I think it does in modern versions of chrome and 
firefox?

Original comment by kevin.g...@gmail.com on 18 Jun 2012 at 1:31

GoogleCodeExporter commented 9 years ago
Indeed multisampling is on by default, and since you're using mipmapping as 
well I'll check whether the centroid sampling is causing the stray pixels...

Original comment by nicolas....@gmail.com on 18 Jun 2012 at 1:42

GoogleCodeExporter commented 9 years ago
Aha, if I do:

          var contextParameters = {
            antialias: false,
          };

and then pass that as the second parameter to getContext (when was the second 
parameter added? I had no idea it existed, or that the default was antialiasing 
on...), then these artifacts go away.

Original comment by kevin.g...@gmail.com on 18 Jun 2012 at 1:42

GoogleCodeExporter commented 9 years ago
I've just confirmed that forcing centroid sampling off makes the issue go away.

Thanks for testing with antialiasing off. That further confirms the cause.

Since centroid sampling is supposed to be a useful feature I'll check whether 
the right solution is to turn antialiasing off or whether centroid sampling 
should be disabled (perhaps only in certain cases)...

Original comment by nicolas....@gmail.com on 18 Jun 2012 at 1:55

GoogleCodeExporter commented 9 years ago
FYI, I've updated my version of webgl-2d to disable antialiasing, so if you 
need to reproduce this issue, let me know and I can change it back.

Original comment by kevin.g...@gmail.com on 18 Jun 2012 at 2:06

GoogleCodeExporter commented 9 years ago
Unfortunately disabling centroid sampling might not be straightforward. It 
depends on the use of COLOR and TEXCOORD semantics for varyings in the 
translated HLSL shader. We use COLOR, which enables centroid sampling, because 
for point sprites it ensures that the varying values for the single vertex are 
replicated for each fragment. TEXCOORD causes the coordinates to range from 0 
to 1 for point sprite rendering (which we use to implement gl_PointCoord).

That said, the OpenGL ES 2.0 specification section 4.3.5 on varyings states 
that: "If single-sampling, the interpolated value is for the fragment center. 
If multi-sampling, the interpolated value can be anywhere within the pixel, 
including the fragment center or one of the fragment samples."

So using centroid sampling is clearly within spec. It may just surprise people 
to see a difference between WebGL using desktop OpenGL versus ANGLE. Part of 
the problem is that WebGL defaults to enabling anti-aliasing.

Even if we only use COLOR semantics when rendering point sprites, so every 
other primitive doesn't use centroid sampling, point sprites can still cause 
unexpected results. Plus it's actually a big complication to use different 
shaders depending on the primitive type. The other alternative would be to 
render point sprites as quads, but this is also quite complex and could have 
performance implications.

Original comment by nicolas....@gmail.com on 18 Jun 2012 at 3:43

GoogleCodeExporter commented 9 years ago
I think leaving centroid sampling on would be fine, provided there's a way to 
work around the texture sampling artifacts when rendering 2D quads with 
antialiasing enabled. Is there such a workaround? If it exists, documenting it 
is probably enough - I was unable to find a workaround that was adequate, but I 
hadn't considered the mip-mapping component.

Original comment by kevin.g...@gmail.com on 18 Jun 2012 at 3:45

GoogleCodeExporter commented 9 years ago
Yes this does look like artifacts we've seen on some machines using ANGLE.  I 
wrote these two variations on conformance tests that fail on the affected 
machines:
http://www.billbaxter.com/samplertest/3.html (tests pixel precise rendering 
with LINEAR filtering on)
http://www.billbaxter.com/samplertest/4.html (tests pixel precise rendering 
with NEAREST and NPOT texture)

And also this mip-map with bias test also fails on that machine:
https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/tests/conforma
nce/glsl/samplers/glsl-function-texture2d-bias.html
(a green line from mip-level 1 appears along the seam between triangles which 
should be rendered at mip level 0)

But these issues don't seem to affect all machines using ANGLE.  I think we've 
only seen it on ATI.

Original comment by wbax...@google.com on 18 Jun 2012 at 4:43

GoogleCodeExporter commented 9 years ago
... Note about the 3.html and 4.html tests above, currently they generate 
output for every failed pixel so if your machine fails it horribly, it may 
appear that the test just hangs.

Original comment by wbax...@google.com on 18 Jun 2012 at 4:44

GoogleCodeExporter commented 9 years ago
For my machine (GeForce GTX 670, latest drivers, W7, as mentioned above), 
billbaxter test #3 and the khronos test both fail, but billbaxter #4 passes.

Original comment by kevin.g...@gmail.com on 18 Jun 2012 at 4:45

GoogleCodeExporter commented 9 years ago
That's what I've seen most commonly.  NEAREST sampling is ok, but trying to do 
LINEAR filtering with pixel precision fails.  We've seen that on a ThinkPad 
T400 with ATI Mobility Radeon HD 3400 Series, Windows 7.

But we have one machine, a ThinkPad X220 with Intel HD 3000 gpu running Windows 
7, which fails test #4 as well (with every test pixel coming out as some 
combination of red and green).

Original comment by wbax...@google.com on 18 Jun 2012 at 5:07

GoogleCodeExporter commented 9 years ago

Original comment by kbr@chromium.org on 19 Jun 2012 at 1:29

GoogleCodeExporter commented 9 years ago
On my laptop with a GeForce GT 330M, only test #3 doesn't succeed. When I force 
anti-aliasing off or when forcing centroid sampling off, it succeed.

The issue is that WebGL enables anti-aliasing by default, and there is a lot of 
"freedom" in how devices/drivers implement it. As quoted above, the spec allows 
the interpolated [varying] value to be anywhere in the pixel! And this can 
obviously affect texture sampling.

ANGLE is, as far as I can tell, a compliant implementation. And centroid 
sampling can actually avoid multi-sampling artifacts in some cases.

Original comment by nicolas....@gmail.com on 19 Jun 2012 at 2:27

GoogleCodeExporter commented 9 years ago
The conformance tests have been updated to always disable anti-aliasing.

But we've decided to still go ahead and try to disable centroid sampling in 
ANGLE to prevent unexpected artifacts when anti-aliasing is desired (such as 
with MapsGL). The only other alternative we could think of was to render text 
with a single triangle large enough to cover the text's enclosing rectangle (so 
no edges cross the text and hence centroid sampling doesn't affect it). But 
that's obviously a significant application side complication.

I will look into the feasibility of rewriting the binary shader to use COLOR 
semantics only when rendering point sprites...

Original comment by nicolas....@gmail.com on 28 Jun 2012 at 3:11

GoogleCodeExporter commented 9 years ago
Thanks for disabling the centroid sampling -- is there a bug to track for the 
implementation of that change?

Also -- I'm not sure the definition of centroid sampling but it seems odd that 
any sampling strategy would cause a the green from level 1 of the mip-chain to 
be chosen when a quad is being rendered at 1:1 texel:pixel scale and 0 lod 
bias.   (I.e. the first test case here: 
https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/tests/conforma
nce/glsl/samplers/glsl-function-texture2d-bias.html)
Does that, in fact, make sense when using centroid sampling? 
This page: 
http://msdn.microsoft.com/en-us/library/windows/desktop/cc627092(v=vs.85).aspx#C
entroid_Sampling
says "it is recommended that you do not combine derivatives and centroid 
sampling", but mip level calculations are essentially texCoord derivative 
calculations.  Should the derivatives for calculating texture LOD perhaps be 
calculated without using centroidal sampling in any case?

Original comment by wbax...@google.com on 28 Jun 2012 at 5:15

GoogleCodeExporter commented 9 years ago
I'll keep you updated on the progress here.

I think I found an even simpler way to fix (improve) this issue: Shaders used 
for point rendering write to gl_PointCoord, and since we already detect this it 
will be straightforward to select between COLOR/TEXCOORD semantics based on 
that. I will test this shortly.

Indeed centroid sampling and derivatives don't mix well. But it's not possible 
to separate the two because the derivatives simply compute the difference 
between the same variable's value of neighboring pixels. And this can be any 
variable; a varying, a value computed from a varying, a sampled texture color, 
etc. Centroid sampling affects varying interpolation only. So everything 
between the varying interpolation and derivative would have to be recomputed. 
This might be possible with the latest hardware, but only when done explicitly 
in the shader.

Anyway, simply ensuring that centroid sampling is not used fixes the 
derivatives. It means we don't benefit from centroid sampling's advantages for 
some cases, but it appears this is a desirable compromise.

Original comment by nicolas....@gmail.com on 4 Jul 2012 at 1:29

GoogleCodeExporter commented 9 years ago
Fixed in r1192.

Original comment by nicolas....@gmail.com on 4 Jul 2012 at 8:15