[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] The miserable state of affairs of floating point support



On Fri, Mar 24, 2017 at 12:47 PM, Maksims Mihejevs <max@playcanvas.com> wrote:
Regarding float32 precision issues.
I've made two examples one using WebGL 1.0 context and another WebGL 2.0 context.

Thanks Max for putting this together.
 

There are 5 boxes with colors.

Top-left: float texture can render - if webgl2, this is always green, and if webgl1, then it actually tests if can render and read back to float texture.
Top-right: half-float texture can render - if webgl2, this is always green, and if webgl1, then it actually tests if can render and read back to half-float texture.
middle-left: float texture precision test - it writes float data, and reads back. If value has lost a precision, then box will be yellow. If value persisted then box will be green. If float texture not supported box will be red.
middle-right: half-float texture precision test - it writes half-float data, and reads back. If value has lost a precision, then box will be yellow. If value persisted then box will be green. If float texture not supported box will be red.
bottom-left: same as middle-left (float texture) but it is green if precision is all-good and will be red if precision is not right or float textures are not supported.


So from One Plus 2 device, I am getting no half-float support at all, and not right precision on float textures. Although device has Qualcomm MSM8994 Snapdragon 810 on it, which is decent GPU.

Results on a Google Pixel with Chrome Dev:

WebGL 1.0:
Top-left: green
Top-right: red
Middle-left: yellow
Middle-right: red
Bottom-left: red

WebGL 2.0:
All boxes green.

In Chrome it looks like the WebGL 1.0 extension OES_texture_half_float isn't allowing these textures to be renderable. This looks like an accident and I've filed http://crbug.com/705083 about it. Sorry about that.

For the floating-point texture precision issue in WebGL 1.0: could you please reduce this a little further and provide a standalone test case outside PlayCanvas? Maybe https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/oes-texture-float.html would be a good starting point. I'll be glad to file this bug then, or feel free to yourself and email me the bug ID. Just want to make sure that it isn't a bug in the shader (like using mediump for float instead of highp), and it's difficult to tell that with your current example.

Chrome's using OpenGL ES 3.0 contexts internally, so it would be trivial to upgrade the internalformat of these textures from "RGBA" to "RGBA32F", if that's all that's needed to give a hint to the driver to actually allocate it with 32-bit precision per channel.

Thanks,

-Ken

P.S. I tried both your test cases and the oes-texture-half-float.html conformance test in Firefox and Firefox Aurora on Android, but didn't get good results for any of them.


Please verify on some mobile devices this as well in order to identify the devices with not full float texture precision, I do believe they are not that rare exceptions, which means that float textures are might be not suitable for many use cases.
We in PlayCanvas engine test texture float precision and if it is not full precision, we assume that this exception is not supported at all then. Otherwise we had loads of artifacts and rendering issues of features that relied on float textures with false precision.

Kind Regards,
Max

On 23 March 2017 at 01:19, Kenneth Russell <kbr@google.com> wrote:


On Wed, Mar 22, 2017 at 10:48 AM, Maksims Mihejevs <max@playcanvas.com> wrote:
We have experienced another issue.

On one mobile platform it was advertised that Float 32 texture is supported. And after actually testing it (because you have to test regardless of what is advertised by extension), it did "worked".
But there was a weird catch: writing float 32 pixel, and then reading it, it would loose precision. So even it worked, it actually was changed. Either due to some emulation and repacking to different formats there was some issues and data gets modified, or by some other bug, where we literally missing some bytes or actual values are modified.

This was a surprise for us and did lead to some time figuring out, what is actually a problem. We were trying to implement Variance Shadow Maps with float32 textures, and some data got modified breaking the feature only on some devices.

This is of course not acceptable at all, and renders feature unusable in many scenarios where precision of data should persist.

Does this behavior persist in WebGL 2.0 if you use EXT_color_buffer_float and explicitly render to an FP32 texture, using highp precision variables in your shaders? I'm not sure what the guarantees were in older OpenGL ES versions, but since ES 3.0 provides exact control over textures' internal formats, I would expect this round-trip to be guaranteed.


 

Cheers,
Max

On 22 March 2017 at 17:12, Florian Bösch <pyalot@gmail.com> wrote:
Having looked supporting different formats for rendering to and sampling from, I'd like to share my observations.

Extensions are claimed that are not supported

On iOS the implementation claims to support OES_texture_float_linear but this does not actually work and it defaults (silently) to nearest.


Could you please submit a conformance test verifying this behavior?

 

Float16Array still does not exist

It's still a major pain to deal with generating data to upload to Half-Float textures because despite repeated prodding on the ECMA-ML as well as here, we still don't have a Float16Array.

Can't help with this. Sorry.


Some implementations do not accept Uint16Array upload to half-float textures

Safari and iOS refuse to accept an array for texImage2D to upload to half-float textures. Even though it's now in the specification that this is permissible. We talked about this. It was agreed we would allow that.

I confirm that Safari on macOS is failing https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/oes-texture-half-float.html . Please confirm that it's failing on iOS and file a bug on bugs.webkit.org.


Setting linear blending mode on textures that don't support it generates no error

The UA complains about an unrenderable texture when you draw sampling from it, so it knows that the blending mode isn't supported. But you can't get an error from it either at texParameter or draw*. This is extremely awkward, because apparently (see above) the linear extensions have no meaning whatsoever, so you have to actually draw to figure out if blending works and then readback the results. If you (the UA) already knows that linear doesn't work, please don't make developers integrate a unit test to figure it out?

Please file an issue about this on https://github.com/KhronosGroup/WebGL . The browser vendors can discuss making this change.


The color_buffer extensions have no meaning

Platforms (such as Chrome) that support drawing to floating point textures do not expose these extensions, leaving you no choice but to getExtension it and then promptly ignore anything you got and test if you can actually construct an FBO that is indicated as valid and draw to it and then read the drawn texture (trough another FBO because see blow).

This behavior is much clarified and simpler in WebGL 2.0. There's only one extension: EXT_color_buffer_float, and it provides a strong guarantee about renderability without adding a lot of feature detection code to the WebGL implementation itself and impacting startup time of all WebGL apps. Please try WebGL 2.0. If you see issues in this area in that version then please file bugs.


readPixels of floats may or may not work

Some platforms do not implement readPixels from a floating point texture. Some do. Because of that, you can't directly test some of the more interesting properties of floating point textures (such as blending, filtering, clamping, etc.) but you have to do it trough a proxy unsigned byte FBO because you can't rely on readPixels.

This should again be much clarified in WebGL 2.0 and there should be strong guarantees about readPixels' behavior there.


Some devices do not expose floating point textures even though they support them

For reasons that completely boggle me, the fairly new Samsung S7 (just a year old) which has perfectly fine and working support for a variety of floating point textures/operations do not expose that to WebGL (by some combination of unlucky ES config and whatnot). That's a fairly big problem. Because samsung devices are fairly popular, it means floating point support on mobiles is actually retrograde, mean reverting slowly back to somewhere anno 2012 or so.

We just tested Chrome Dev on a Samsung Galaxy S7 Edge and it passes the render-to-RGBA-texture portion of https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/oes-texture-float.html . (RGB textures are not renderable.) It also seems to support EXT_color_buffer_float for WebGL 2.0. If you have a scenario on a newer device like this where render-to-FP-texture is not working at all then please file a bug.

If you're trying to save memory, then rendering to R32F and RG32F textures is available as of WebGL 2.0.


The only qualifier I can find for the situation is miserable and utterly broken. It's hurting WebGL. It should be addressed. It should have been addressed long ago, and most of these things came up in the past years at one point or another. I don't understand why they are not addressed.

WebGL 2.0 should solve many longstanding issues with rendering to floating-point textures. It's supported in Firefox on Android now and will be in Chrome 58 on Android. Please help us make sure that these issues are addressed in the most recent version, and we can work on backporting some of the fixes to WebGL 1.0 + extensions.

-Ken