Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POINTS clipping not working correctly on several drivers #2888

Open
greggman opened this issue May 11, 2019 · 7 comments
Open

POINTS clipping not working correctly on several drivers #2888

greggman opened this issue May 11, 2019 · 7 comments
Assignees

Comments

@greggman
Copy link
Contributor

greggman commented May 11, 2019

If I understand the spec correctly POINTS are not clipped in the vertex shader. From the spec section 2.13

If the primitive under consideration is a point, then clipping discards it if it lies outside the near or far clip plane; otherwise it is passed unchanged.

There's a kind of conformance test for this here

https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/clipping-wide-points.html?webglVersion=1&quiet=0&quick=1

But it only tests if the center of the point is slightly off the right and top sides.

I wrote a test to try all four sides and to move the center as far as possible off each side. It should be possible to set the center of the point basically the max point size from gl.getParameter(ALIASED_POINT_SIZE_RANGE)[1] divided by 2 - 0.6 or so (-0.50000001?) off of any side. The spec says

Point rasterization produces a fragment for each framebuffer pixel whose center lies inside a square centered at the point’s (xw, yw), with side length equal to the point size

Here's the test

https://jsfiddle.net/greggman/beqptu8r/

It fails on my iPhone6+, My Pixel 2 XL, My 2014 MBP NVIDIA GeForce GT 750M
It passes on My 2014 MBP Intel Iris Pro, and on a Windows HD Graphics 630, and Windows NVidia 1060

It's possible my math is wrong but it doesn't seem wrong at a glance.

@greggman
Copy link
Contributor Author

greggman commented May 12, 2019

Follow up: The test canvas above is 1x1 pixels. If I increase the canvas size to 9x9 or greater it starts working on my MBP NVidia. It still fails on my iPhone.

So, writing a test to print what the effective max point size is for different canvas sizes shows that on my MBP NVidia it goes

canvas: 1x1 effective max point size 255
canvas: 2x2 effective max point size 511
canvas: 3x3 effective max point size 765
canvas: 4x4 effective max point size 1021
canvas: 5x5 effective max point size 1275
canvas: 7x7 effective max point size 1785
canvas: 8x8 effective max point size 2041
canvas: 9x9 effective max point size 2047   // the advertised max point size

on my iPhone6+ it's apparently floor(canvas.size / 2) + 1 up to max advertised size

on my Pixel XL 2 it's

canvas: 1x1 effective max point size 253
canvas: 2x2 effective max point size 507
canvas: 3x3 effective max point size 759
canvas: 4x4 effective max point size 1013
canvas: 5x5 effective max point size 1023  // the advertised max point size

https://jsfiddle.net/greggman/qbre4ztp/

@kenrussell
Copy link
Member

TBH I'm not optimistic that WebGL will be able to smooth over the differences between OpenGL (ES) drivers in this area. AMD GPUs have a long history of clipping points if the centroid of the point goes outside the viewport. There is no trivial change that can be done to the OpenGL state machine that will give identical point clipping results on all GPUs. The only workaround is to emulate points with a geometry shader. We might do this inside ANGLE on all platforms, which would take care of most if not all browsers in the long run.

@greggman
Copy link
Contributor Author

Unfortunately I don't have an AMD GPU to test with but it certainly would be nice if the OpenGL ES conformance tests tested these drivers (AMD, Android, iOS) actually passed the spec. The driver can either fix the bug or change their max size to 1.0

ANGLE fixing it would be good.

PS: I don't go looking for these bugs. People run into issues, post them on Stack Overflow looking for answers, which I see and then investigate

@MarkCallow
Copy link
Collaborator

MarkCallow commented May 16, 2019

The heart of this issue is a difference between the OpenGL and OpenGL ES specifications. OpenGL:

If the primitive under consideration is a point, then clipping passes it unchanged if it lies within the clip volume; otherwise, it is discarded.

OpenGL ES, as @greggman quoted:

If the primitive under consideration is a point, then clipping passes it unchanged if it lies within the near and far clip planes; otherwise, it is discarded.

The difference is subtle and hard to spot, even when you are looking for it, especially if you do not have the 2 statements side by side. The bottom line is that OpenGL ES has pop-free point clipping while in OpenGL they pop in and out. That is to say once the center of the point is outside the clip volume it disappears, even if part of the point is still inside. Pop-free point clipping was introduced in OpenGL ES 2.0.

This difference is what @kenrussell was alluding to though the fact there is a spec difference isn't clear in his comment.

So neither the OpenGL ES conformance tests nor the AMD drivers are buggy. They are following different specifications. AMD, as far as I know, makes no claim to support an OpenGL ES context.

Regrettably, as I have just discovered, none of the ARB_ES*_compatibility specs mention this difference in behavior.

The only ways to get pop-free behavior when running on OpenGL are to limit the max point size to 1 or else emulate points with a geometry shader.

@greggman
Copy link
Contributor Author

greggman commented May 17, 2019

Maybe if this is not going to be fixed it should be mentioned in the WebGL specs? That whether or not points are clipped is undefined and that if you want unclipped points you need to draw quads yourself? I suppose that's already true to some extent in that the max point size can be as low as 1.0 but in reality it looks like 97% of devices support a max point size of 255 and 100% support at least 60

@greggman
Copy link
Contributor Author

greggman commented May 17, 2019

I should also mention if that really is the OpenGL 4.5 spec then it sounds like OpenGL needs tests that the points are clipped. Clearly they aren't in lots of driver. Either that or the spec needs to change to say it's undefined.

@kdashg
Copy link
Contributor

kdashg commented May 17, 2019

Thanks for finding the prose, @MarkCallow!

I agree with @kenrussell: Since I don't expect this to be a major/common portability pain, think we're best off leaving this behavior as 'or'd, rather than mandating a geometry shader pass on non-ES.

Thanks for reporting this divergence!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants