Bug 237434 - Precision issue in in Vertex Shader on iPads/M1 (but work on Intel Mac)
Summary: Precision issue in in Vertex Shader on iPads/M1 (but work on Intel Mac)
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebGL (show other bugs)
Version: Safari 15
Hardware: Mac (Apple Silicon) iOS 15
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks: anglemetalregr
  Show dependency treegraph
 
Reported: 2022-03-03 10:09 PST by Jean-Sylvestre Zirani
Modified: 2023-12-18 23:01 PST (History)
11 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jean-Sylvestre Zirani 2022-03-03 10:09:12 PST
Hi, 


We are developing a geo-positioning application that uses WASM and WebGL. 

We have encountered a strange precision issue in the vertex shader. It happens only on Mac that are not using Intel chip and it happens in every browser that uses Webkit WebGL. 

The easiest way to reproduce the issue is to go to: 

https://prideout.net/emulating-double-precision

If you zoom on San-Francisco and tries to move the dogs around, on Apple M1/iOS you will encounter jittering in both views.

We don't have encountered the issue outside of Mac platforms. The right view is always smooth.



Cheers,
Jean-Sylvestre
Comment 1 Kenneth Russell 2022-03-03 10:49:00 PST
Can confirm that when zooming in and dragging around the picture of the dogs, the right canvas's crosshairs jitter on an M1 MacBook Pro with both:

Safari Version 15.3 (17612.4.9.1.8)
Safari Technology Preview Release 140 (Safari 15.4, WebKit 17614.1.1.5)

However, somewhat suprisingly, it renders smoothly with:
Chrome 101.0.4921.0 (Official Build) canary (arm64)

when launched from the command line forcing ANGLE's Metal backend via:

/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --user-data-dir=/tmp/c1 --use-cmd-decoder=passthrough --use-angle=metal

This might imply that this was just fixed in top-of-tree ANGLE, but I don't remember a significant change to the shader translator in this area.
Comment 2 Gregg Tavares 2022-03-03 11:35:36 PST
I don't think this has anything to do with it but there are differences in vertex handling for certain cases in

src/libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.metal

In upstream ANGLE vs WebKit. No idea why those differences exist and have not been merged.
Comment 3 Daniel Balog 2022-03-09 23:56:50 PST
Am I correct in understanding that this is potentially already fixed, but simply needs to be merged?
Comment 4 Radar WebKit Bug Importer 2022-03-10 10:10:17 PST
<rdar://problem/90105952>
Comment 5 Daniel Balog 2022-03-31 01:31:49 PDT
I can confirm that launching chrome canary with the aforementioned command line parameters:

/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --user-data-dir=/tmp/c1 --use-cmd-decoder=passthrough --use-angle=metal

Fixes this problem + all similar problems that we've been experiencing in our applications. It's mostly about jittering vertices.
Comment 6 Kenneth Russell 2022-03-31 17:36:11 PDT
Hmm. I'm still seeing the jittery crosshairs in the right-hand view of:
https://prideout.net/emulating-double-precision

with:
./Tools/Scripts/run-minibrowser --debug

with a top-of-tree build of WebKit + ANGLE as of yesterday.

Surprisingly, Chrome Canary with the Metal backend still displays the right-hand-side crosshairs smoothly.
Comment 7 Gabby Getz 2022-11-03 08:05:58 PDT
Hi all,

Any updates on this issue?

We're seeing a similar issue in CesiumJS to may be related - https://github.com/CesiumGS/cesium/issues/9417.

The problem we're seeing should be reproducible at the following link. On non-M1 machines, the line is static as the camera moves. On M1 devices, the line is jagged/jumpy.
 https://sandcastle.cesium.com/standalone.html#c=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).

It may be worth noting we use a similar implementation of emulating double precision as https://prideout.net/emulating-double-precision.
Comment 8 Daniel Balog 2022-11-03 08:31:51 PDT
We're still having this issue with the new releases of iOS 16, iPadOS 16 and MacOS Ventura. Was secretly hoping the latest version of safari would maybe fix something but it doesn't seem to.
Comment 9 Kimmo Kinnunen 2022-12-22 03:27:17 PST
Thank you for the report.

This is due to "ffast-math" feature of compiling the Metal shaders generated by the WebGL GLSL shaders. At the time Chrome ANGLE/Metal does not do ffast-math but Safari does.

This can be worked around by adding

  invariant gl_Position;

in your shader.

The precision in which the GLSL expressions are calculated is defined. However, the each math formula can be reordered due to optimisation.

Some reorderings are not invariant with each other due to the float precision in the shader.

Common problem is the case where big values cause float saturation in the optimised version, whereas the unoptimised version might not saturate an intermediate expression.

Example of the saturation problem could be a reordering of:
    vec3 p = a_position - u_eyepos - u_eyepos_lowpart;
     ->
    vec3 p = a_position - (u_eyepos + u_eyepos_lowpart [saturated]);
    vec3 p = a_position - u_eyepos;
 

This is the explanation of invariance in GLSL spec:
4.6 Variance and the Invariant Qualifier

In this section, variance refers to the possibility of getting different values from the same expression in different programs. For example, say two vertex shaders, in different programs, each set gl_Position with the same expression in both shaders, and the input values into that expression are the same when both shaders run. It is possible, due to independent compilation of the two shaders, that the values assigned to gl_Position are not exactly the same when the two shaders run. In this example, this can cause problems with alignment of geometry in a multi-pass algorithm.
In general, such variance between shaders is allowed. When such variance does not exist for a particular output variable, that variable is said to be invariant.
Comment 10 Daniel Balog 2023-01-31 01:15:16 PST
Hey Kimmo,

Thank you for your advice. We tried it and it works. Adding invariant gl_Position actually fixes this for M1 Safari.

However, it doesn't seem to be a solution for Chrome or Firefox. Any idea why those browsers are not picking up the invariant flag?
Comment 11 swoorupj 2023-07-15 05:47:08 PDT
Adding `invariant gl_Position` fixed for me using chrome. 

I am using Version 114.0.5735.198 (Official Build) (arm64)
Comment 12 Kimmo Kinnunen 2023-07-31 04:19:00 PDT
> However, it doesn't seem to be a solution for Chrome or Firefox. Any idea why those browsers are not picking up the invariant flag?

Chrome is sometimes using OpenGL ES "backend" sometimes, sometimes Metal backend. The invariant fix is implemented only for Metal. Firefox is using OpenGL ES.

The OpenGL ES drivers do not have the invariance feature and have different kinds of optimizations. Thus the solution does not work on these implementations, unfortunately.

The better fix could be to ensure the values of the intermediate computations stay within the 32-bit float value domain.
Comment 13 Don McCurdy 2023-12-15 11:33:53 PST
> The OpenGL ES drivers do not have the invariance feature and have different kinds of optimizations. Thus the solution does not work on these implementations, unfortunately.

Somehow I'm seeing the opposite behavior while debugging some vertex shader precision issues in the luma.gl (https://luma.gl/) test suite. Tests pass (Chrome 120.0.6099.109) under the OpenGL ANGLE backend — but only if I add the 'invariant' specifier, and tests fail without the specifier. Under the Metal ANGLE backend, the tests always fail on Apple M1/M2. The tests fail with or without the `invariant` specifier in Safari on Apple M1/M2.

Longer writeup and complete GLSL code in:

https://github.com/visgl/luma.gl/issues/1764#issuecomment-1858162100
Comment 14 Don McCurdy 2023-12-18 17:21:45 PST
Here's a small, reproducible example:

- Demo: https://fp64-arithmetic.donmccurdy.com/
- Code: https://github.com/donmccurdy/fp64-arithmetic

An additional finding, for which I've added a GUI dropdown in the example, is that using GLSL 1.0 gives much more accurate results than GLSL 3.0 in Chromium-based browsers, unless the selected backend is Metal. In Safari, there are significant precision issues regardless of the GLSL version.
Comment 15 Kenneth Russell 2023-12-18 23:01:26 PST
In Chromium with ANGLE's Metal backend, force-disabling fast math here:
https://source.chromium.org/chromium/chromium/src/+/main:third_party/angle/src/libANGLE/renderer/metal/mtl_utils.mm;l=907?q=mtl_utils.mm

fixes most of the test failures in:

- Demo: https://fp64-arithmetic.donmccurdy.com/
- Code: https://github.com/donmccurdy/fp64-arithmetic

I didn't study the generated shaders to see whether the "invariant" keyword is being applied broadly enough to prevent all of the intermediate expressions from being optimized by the Metal shader compiler. It looks like the math operations in this FP64 emulation are highly sensitive to shader compiler optimizations.

Currently there's no global way to force-disable the use of fast math, and fast math is required for acceptable performance of shaders in general. If you find it's not possible or feasible to use "invariant" to get the needed results, we could consider adding a #pragma to the shading language, an API extension to disable fast-math optimization for shaders/programs, or something similar.