pex-gl / pex-context

Modern WebGL state wrapper for PEX: allocate GPU resources (textures, buffers), setup state pipelines and passes, and combine them into commands.
http://pex-gl.github.io/pex-context/
MIT License
160 stars 12 forks source link

Add shader precision #60

Open dmnsgn opened 5 years ago

dmnsgn commented 5 years ago

Ground work for: https://github.com/pex-gl/pex-renderer/issues/122

vorg commented 5 years ago

Couple of notes:

getMaxPrecision is one of a kind API (getSomething), what about exposing capabilities.maxPrecision and letting the user handle that for now? What would be better pex-context way?

It seems that the getMaxPrecision(precision) function is coming from ThreeJS where they issue a warning if the max precision doesn't match the requested material precision.

Are we sure our aim is to support such devices with no highp? Can we do some more research when using mediump is beneficial?

dmnsgn commented 5 years ago

I exposed the getMaxPrecision as the user needs it when overriding a material with a certain precision. See:

I agree it feels slightly weird because it is one of a kind but I couldn't find a better way to make it accessible to pex-renderer without having to duplicate the gl precision check code. Only other acceptable way I see so far would be to make the function a separate package.

Are we sure our aim is to support such devices with no highp? Can we do some more research when using mediump is beneficial?

We encountered some mobile devices with only mediump available on cx.

It seems that the getMaxPrecision(precision) function is coming from ThreeJS where they issue a warning if the max precision doesn't match the requested material precision.

We can add a warning as well or use a debug feature somehow.

vorg commented 5 years ago

I feel like we are trying to make things complicated here. In somehow controversial discussions like this one it's useful to think i case of scenarios.

From my understanding some older devices might not support highp. I've never heard of a device not supporting mediump. I would imagine the getShaderPrecisionFormat for all precisions is there only for completeness.

I would suggest leaving only capabilities.maxPrecision renamed tocapabilities.maxFragmentPrecision. One issue with that is we introduce string values e.g. "highp". Those while same as glsl code should probably be enums (pex-context way). I assume strings are use for pex-renderer convenience.

There is actually built-in glsl constant GL_FRAGMENT_PRECISION_HIGH as explained in "How to write portable WebGL". So you can query highp availability in the shader:

#if GL_FRAGMENT_PRECISION_HIGH == 1
    // highp is supported
#else
    // high is not supported
#endif

That means we could potentially have matching

capabilities.fragmentPrecisionHigh = true/false
dmnsgn commented 5 years ago

From my understanding some older devices might not support highp. I've never heard of a device not supporting mediump. I would imagine the getShaderPrecisionFormat for all precisions is there only for completeness.

We can get rid of 'lowp'.


I would suggest leaving only capabilities.maxPrecision renamed tocapabilities.maxFragmentPrecision. One issue with that is we introduce string values e.g. "highp". Those while same as glsl code should probably be enums (pex-context way). I assume strings are use for pex-renderer convenience.

getMaxPrecision actually checks for both vertex and fragment precision (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 && gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT)) so I would keep maxPrecision. I am not aware of any case where it would be different from vert to frag but then why does the API exists in this way?


There is actually built-in glsl constant GL_FRAGMENT_PRECISION_HIGH as explained in "How to write portable WebGL". So you can query highp availability in the shader:

#if GL_FRAGMENT_PRECISION_HIGH == 1
    // highp is supported
#else
    // high is not supported
#endif

So that kind of make useless to have it in pex-context? We could just add a direct replacement if highp is not supported in pex-renderer shaders:

#ifndef GL_FRAGMENT_PRECISION_HIGH
#define highp mediump
#endif

varying highp vec3 vPositionWorld;
// would become
varying mediump vec3 vPositionWorld;

That means we could potentially have matching

capabilities.fragmentPrecisionHigh = true/false

You mean no ctx. capabilities.maxPrecision but just ctx. capabilities.fragmentPrecisionHigh instead?

vorg commented 5 years ago

https://google.github.io/filament/webgl/suzanne.html

No checks in GLSL but it doesn't mean they don't do them in JS. As mentioned in docs they default to mediump but specify highp for position related data attributes

#version 300 es
precision mediump float;
precision mediump int;
layout(std140) uniform FrameUniforms
{
highp mat4 viewFromWorldMatrix;
highp mat4 worldFromViewMatrix;
highp mat4 clipFromViewMatrix;
highp mat4 viewFromClipMatrix;
highp mat4 clipFromWorldMatrix;
highp mat4 worldFromClipMatrix;
highp mat4 lightFromWorldMatrix;
highp vec4 resolution;
highp vec3 cameraPosition;
highp float time;
vorg commented 5 years ago

Yes, only fragmentPrecisionHigh=true/false. Eg. BabylonJS has highPrecisionShaderSupported. This avoids confusion with maxFragmentPrecision as gl.getShaderPrecisionFormat is precision is not just high/med/low but high with 32 bits or high with 24 bits etc..

We would then use GL_FRAGMENT_PRECISION_HIGH to fallback to mediump when we write cross platform code in pex-renderer.

This flag would be used more for low end device sniffing than overwriting shader precisions as doing it automatically and globally most likely will not work and just cause artifacts to show up.