It appears that the Adreno 320 GL 3.0 uses fixed point instead of floating point for mediump float.
My blur shader works fine on the 225 and is attenuated (truncated) on the 320,
when using mediump both on the coefficient generator (GPU Gems 3, p. 877) and the accumulator.
However, when I change them to highp, the shader passes my tests.
My coefficients range between 0.002 and 0.97.
Querying glGetShaderPrecisionFormat() on the 320 and 225 yield the same specs for both devices:
<high_fragment_flt precision="23" range0="127" range1="127"/>
<med_fragment_flt precision="10" range0="15" range1="15"/>
<low_fragment_flt precision="10" range0="15" range1="15"/>
<high_fragment_int precision="0" range0="31" range1="30"/>
<med_fragment_int precision="0" range0="15" range1="14"/>
<low_fragment_int precision="0" range0="15" range1="14"/>
Half float should be able to have full 11 bit precision for numbers as small as 6.1e-5.
This is obviously a bug, either in glGetShaderPrecisionFormat(), or in your GLSL compiler, or in the driver.
I just updated my US Samsung Galaxy S4 SGH-M919 a few days ago, and it hasn't fixed the bug.
The working 225 is
<system manufacturer="samsung" model="SAMSUNG-SGH-I747" name="d2uc" brand="samsung" language="en" region="US" abi="armeabi-v7a" version="4.4.2"/>
<opengl vendor="Qualcomm" renderer="Adreno (TM) 225" version="OpenGL ES 2.0 [email protected] [email protected] (CL@3869936)" GLSL_version="OpenGL ES GLSL ES 1.00"/>
and the broken devices are:
<system manufacturer="samsung" model="SM-N900P" name="hltespr" brand="samsung" language="en" region="US" abi="armeabi-v7a" version="4.4.2"/>
<opengl vendor="Qualcomm" renderer="Adreno (TM) 330" version="OpenGL ES 3.0 [email protected] AU@ (CL@)" GLSL_version="OpenGL ES GLSL ES 3.00"/>
<system manufacturer="samsung" model="SGH-M919" name="jfltetmo" brand="samsung" language="en" region="US" abi="armeabi-v7a" version="4.4.2"/>
<opengl vendor="Qualcomm" renderer="Adreno (TM) 320" version="OpenGL ES 3.0 [email protected] AU@ (CL@3869936)" GLSL_version="OpenGL ES GLSL ES 3.00"/>
<system manufacturer="HTC" model="HTC6435LVW" name="dlx" brand="verizon_wwe" language="xxhdpi" region="" abi="armeabi-v7a" version="4.1.1"/>
<opengl vendor="Qualcomm" renderer="Adreno (TM) 320" version="OpenGL ES 2.0 [email protected] AU@ (CL@2814726)" GLSL_version="OpenGL ES GLSL ES 1.00"/>
The bug does not seem to be limited to the 320, as the 330 exhibits this bug as well. Also, it does not seem to be limited to GLSL 3.0, as a device running GLSL 1.0 also exhibits this bug. It appears to be associated with the 300 series GPUs.
Has anyone else experienced this bug?
Thanks for reporting this issue. Can we get a bit more information?
1) Regarding "half float should be able to have full 11 bit precision for numbers as small as 6.1e-5. Curious where that value comes from? - note that as per the IEEE-754 standard, the precision is 11 bits though 10 bits are explicity stored (and thus the value returned by glGetShaderPrecisionFormat
2) Would you be able to share your shader code and perhaps a sample apk that demonstates the difference between Adreno 225 and Adreno 320/330?
Thank you for your response.
The 6.104e-5 comes from setting the exponent to 1 and the mantissa to 0. This is the smallest normalized number in the half float representation. The smallest denorm is 5.960e-8, obtained by setting the exponent to 0 and the significand to 1. Similarly, the largest representable number is 65504.
I have written a half float simulator in software, and have determined that the problem is with the 225, not the 320&330. The software simulation of the half float blur shader has consistent results with the 320&330.
The problem is that the 225 is returning the wrong information in the glGetShaderPrecisionFormat() query. It says that it has 10 bits of medium precision whereas in fact it has 23, as determined by the shaders given at the end of this post. I have at least 4 different shaders that are chosen based upon various extension and other queries. I would really rather not have to compile and run a shader to determine which other shaders to configure at launch time. Luckily, for the 225, I can just query GL_OES_fragment_precision_high and deploy a high precision shader. However, for other functions, there may be performance differences between medium and high precision, and I would like to choose the fastest shader that produces the correct results.
Thank you for your response.
The 6.104e-5 comes from setting the exponent to 1 and the significand to 0. This is the smallest normalized number in the half float representation. The smallest denorm is 5.960e-8, obtained by setting the exponent to 0 and the significand to 1, but I doubt that many GPUs would implement denorms. Similarly, the largest representable half float number is 65504.
I have written a half float simulator in software, and have since determined that the problem is with the 225, not the 320&330. The software simulation of the half float blur shader has consistent results with the 320&330.
The problem is that the 225 is returning the wrong information in the glGetShaderPrecisionFormat() query. It says that it has 10 bits of medium precision whereas in fact it has 23, as determined by the shaders given at the end of this post. I have at least 4 different shaders that are chosen based upon various extension and other queries. I would really rather not have to compile and run a shader to determine which other shaders to configure at launch time. Luckily, for the 225, I can just query GL_OES_fragment_precision_high and deploy a high precision shader. However, for other functions, there may be performance differences between medium and high precision, and I would like to choose the fastest shader that produces the correct results.
So, the title of this thread should really be "glGetShaderPrecisionFormat() bug in Adreno 225".
We'll reach out directly to you to better understand your findings.
Hey,
I'd be really interested in hearing the outcome of this discussion as I have a very similar situation, I have a pixel shader which gets truncated values for one of its calculations when using precision mediump float; but with precision highp float; everything is fine.
It only happens on Samsung Galaxy S4, the same code runs fine on a Google Nexus 7 (2012).
I can give more information if required but it sounds like whatever the answer was here is probably the answer for me.
Thanks
This issue turned out to be a mismatch of the build that was installed on the specific Samsung Galaxy S3 device being used. The problem was fixed shortly thereafter with a software updated from Samsung.
If you have more details, feel free to share...