Precision error in shaders

Hallo Everyone!

I’ve been blocked into some error, that I couldn’t find a solution since weeks. So maybe you maybe you’ve already faced this problem or you have an idea how to rescue it:
In my project, I have two version:
** One that runs entirely on CPU that works great.
** And another one computed on shaders, but has some issue:
The precision of built-in functions in shaders (e.g. acos(x) ) are pretty bad, when two values are very close to each other, and therefore it totally spoils my visualization. I tried to add ‘highp’ in every function/variable but no improvement has been detected.
image
Here is the more interesting part: When I run my project on Ubuntu on my Virtual Machine (Windows as host), the precision error does not occur! Otherwise, the project run on shader does not seem to do better on all other machines that I tried on.
I tried to investigate on my own at that precision error: it seems to be that the Virtual Machine assign a virtual graphic card (that works actually on CPU) and thereby the work is correctly done. Shaders on GPU otherwise can receive only 32-bit float value, while I’m working on very precise value such as (x=1.0937385142696257, y= -1.8403266919216732), which are not handled in 32-bit float correctly but suited for 64-bit float such as in javascript and it seems that the GPU architecture does not handle this type of float.
I tried as well to send a typed float Foat64Array using the 64Buffer but it seems that WebGL does not support it.
Thereby I’m in an impasse.

So here is my question:
Are there any solution to improve precision on built-in function such as cos or acos (eventually better than ‘highp’)?
Are there any possible solution to mimic 64-float on WebGL shaders?
I looked in the web for various solution for this kind of case, and it seems to be that all solutions that I saw handle only very basics math operation for the minimal decimal of the float such as addition or multiplication.

If is it not possible, can on in his app create a virtual graphics card (by suggesting to install plugins or extension in the browser) and force operation to be done in this part instead of the real GPU?

Thank you for your help!

32-bit single precision floating point is the highest possible shader precision. This should be sufficient for all algorithms in the area of interactive 3D graphics. In many cases, it’s not even necessary to use 32-bit but lower precision like 16-bit (half float). This approach is faster, more energy efficient and more robust since certain older mobile devices can’t handle 32-bit at all or only with bugs (see https://github.com/mrdoob/three.js/issues/14137).

I suggest you have a look at GPGPU via Cuda or OpenCL. But keep in mind that most GPUs are not optimized for 64-bit floating point.You need GPUs intended for HPC (like Nvidia’s Teslas) to get a really good 64-bit performance.

More information:

https://devtalk.nvidia.com/default/topic/624598/double-precision-and-cuda/

1 Like

Thanks for the suggestion!

EDIT: Is it possible to embedd such tools in the browser? Do you mean that I can implement shaders that should be rendered by browsers using OpenCL for example?

Unfortunately no, that does not work.

So there are no possibility to use OpenCL in a WebApp run under the browser?

No, it’s not possible.

Thanks for the help! :slight_smile:

You can still emulate 64bit though i wonder how much precision you need. I’ve made a CPU renderer which is specifically made to render GLSL on a quad for procedural generation, to generate the same results as the GPU (for realscale planetary rendering), i had to use several and different tricks to avoid 32bit or 16bit limitations, specifically for simplex noise any default angle functions causing issues for too large numbers.

By using numbers which fit the precision it solved this case, with fbm this wasn’t really a big issue, but it really depends on the case, maybe there is a work around that might be less expensive in the end. If there are exact results required, not just in visual appearance, then it’s a different scenario.

That’s exactly the point. I need something that allow me to do angle trigonometrique operation with 64-float instead of 32-floats which will result in bad rendering at some points.
Besides that, I need a very performant tool which allow operations to be done parallely.

I considered the possibility to implement a c++ OpenCl backend therefore, but ‘Post’ request will be in this case much costly. I heard about a certain WebCl, a framework equivalent to WebGl but on CPU level. But again, browsers do not support it for now…

Last chance to get the performance that I intend to have is to move the parallel operations on javascript, but I don’t think that it is really possible…

Could you tell me how did you succeded to avoid 32-float limitations?

Thanks!

What is your actual scenario, for what are those calculations?

I’m actually transforming euclidean distances to hyperbolic distances. The later one will help me as well to calculate new angles of points. (Here is a quick overview: https://en.m.wikipedia.org/wiki/Hyperbolic_geometry)
So I need pratically most of standard trigonometrique operations such as sin/cos/acos/sinh…

When those operation are done with 32-floats, each operation will round the result and thereby I may end with wrong values at the end.

I cannot also do those operation on cpu level, because at each rendering I send the new origin of the graph, and thereby all distances will be calculated with to respect to that origin…

With graphs that have 10.000 points, there are no performance issues. But if I want to render graphs with 1 millions nodes, that would be problematic in term of performance…