Vulkan: Retain precision of uniform variables

When gathering in a uniform block, the precision of default uniforms was
dropped.

Bug: angleproject:4889
Bug: angleproject:6132
Change-Id: Ie6a8e2e7cef7cd3808cee08d20f886fc4e762cd5
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3076124
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler.gni b/src/compiler.gni
index 24bb387..a4cf350 100644
--- a/src/compiler.gni
+++ b/src/compiler.gni
@@ -149,6 +149,8 @@
   "src/compiler/translator/tree_ops/PruneEmptyCases.h",
   "src/compiler/translator/tree_ops/PruneNoOps.cpp",
   "src/compiler/translator/tree_ops/PruneNoOps.h",
+  "src/compiler/translator/tree_ops/RecordConstantPrecision.cpp",
+  "src/compiler/translator/tree_ops/RecordConstantPrecision.h",
   "src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp",
   "src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h",
   "src/compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.cpp",
@@ -248,8 +250,6 @@
   "src/compiler/translator/OutputESSL.cpp",
   "src/compiler/translator/OutputESSL.h",
   "src/compiler/translator/TranslatorESSL.cpp",
-  "src/compiler/translator/tree_ops/gl/RecordConstantPrecision.cpp",
-  "src/compiler/translator/tree_ops/gl/RecordConstantPrecision.h",
 ]
 angle_translator_glsl_sources = [
   "src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp",
diff --git a/src/compiler/translator/TranslatorESSL.cpp b/src/compiler/translator/TranslatorESSL.cpp
index 80afd04..f315233 100644
--- a/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/compiler/translator/TranslatorESSL.cpp
@@ -9,7 +9,7 @@
 #include "angle_gl.h"
 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "compiler/translator/OutputESSL.h"
-#include "compiler/translator/tree_ops/gl/RecordConstantPrecision.h"
+#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/TranslatorVulkan.cpp b/src/compiler/translator/TranslatorVulkan.cpp
index 8ddcf06..c482cd6 100644
--- a/src/compiler/translator/TranslatorVulkan.cpp
+++ b/src/compiler/translator/TranslatorVulkan.cpp
@@ -22,6 +22,7 @@
 #include "compiler/translator/StaticType.h"
 #include "compiler/translator/glslang_wrapper.h"
 #include "compiler/translator/tree_ops/MonomorphizeUnsupportedFunctions.h"
+#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
 #include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
 #include "compiler/translator/tree_ops/RewriteArrayOfArrayOfOpaqueUniforms.h"
@@ -146,7 +147,6 @@
         if (IsDefaultUniform(type))
         {
             TType *fieldType = new TType(type);
-            fieldType->setPrecision(EbpUndefined);
 
             uniformList->push_back(new TField(fieldType, symbol->getName(), symbol->getLine(),
                                               symbol->variable().symbolType()));
@@ -168,7 +168,6 @@
         const TVariable *variable = uniformVars[fieldIndex];
 
         TType *replacementType = new TType(variable->getType());
-        replacementType->setPrecision(EbpUndefined);
         replacementType->setInterfaceBlockField(uniformBlock->getType().getInterfaceBlock(),
                                                 fieldIndex);
 
@@ -1382,6 +1381,15 @@
     }
 #endif
 
+    // When generating text, glslang cannot know the precision of folded constants so it may infer
+    // the wrong precisions.  The following transformation gives constants names with precision to
+    // guide glslang.  This is not an issue for SPIR-V generation because the precision information
+    // is present in the tree already.
+    if (!RecordConstantPrecision(this, root, &getSymbolTable()))
+    {
+        return false;
+    }
+
     // Write translated shader.
     TOutputVulkanGLSL outputGLSL(this, sink, enablePrecision, compileOptions);
     root->traverse(&outputGLSL);
diff --git a/src/compiler/translator/tree_ops/gl/RecordConstantPrecision.cpp b/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
similarity index 98%
rename from src/compiler/translator/tree_ops/gl/RecordConstantPrecision.cpp
rename to src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
index e08d16b..ea15ab7 100644
--- a/src/compiler/translator/tree_ops/gl/RecordConstantPrecision.cpp
+++ b/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
@@ -14,7 +14,7 @@
 // in case that is required for correct precision propagation.
 //
 
-#include "compiler/translator/tree_ops/gl/RecordConstantPrecision.h"
+#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
 
 #include "compiler/translator/InfoSink.h"
 #include "compiler/translator/tree_util/IntermNode_util.h"
diff --git a/src/compiler/translator/tree_ops/gl/RecordConstantPrecision.h b/src/compiler/translator/tree_ops/RecordConstantPrecision.h
similarity index 85%
rename from src/compiler/translator/tree_ops/gl/RecordConstantPrecision.h
rename to src/compiler/translator/tree_ops/RecordConstantPrecision.h
index bf37100..b3ebb8c 100644
--- a/src/compiler/translator/tree_ops/gl/RecordConstantPrecision.h
+++ b/src/compiler/translator/tree_ops/RecordConstantPrecision.h
@@ -14,8 +14,8 @@
 // in case that is required for correct precision propagation.
 //
 
-#ifndef COMPILER_TRANSLATOR_TREEOPS_GL_RECORDCONSTANTPRECISION_H_
-#define COMPILER_TRANSLATOR_TREEOPS_GL_RECORDCONSTANTPRECISION_H_
+#ifndef COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_
+#define COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_
 
 #include "common/angleutils.h"
 
@@ -30,4 +30,4 @@
                                               TSymbolTable *symbolTable);
 }  // namespace sh
 
-#endif  // COMPILER_TRANSLATOR_TREEOPS_GL_RECORDCONSTANTPRECISION_H_
+#endif  // COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 1cfbd32..9c64493 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -13102,6 +13102,36 @@
     runTest(kFS);
 }
 
+TEST_P(GLSLTest, AAA)
+{
+    constexpr char kFS[] = R"(
+// It is assumed that uTest is set to 0. It's here to make the expression not constant.
+uniform mediump float uTest;
+void main() {
+    // exact representation of 4096.5 requires 13 bits of relative precision.
+    const highp float c = 4096.5;
+    mediump float a = 0.0;
+    // Below, addition should be evaluated at highp, since one of the operands has the highp qualifier.
+    // Thus fract should also be evaluated at highp.
+    // See OpenGL ES Shading Language spec section 4.5.2.
+    // This should make the result 0.5, since highp provides at least 16 bits of relative precision.
+    // (exceptions for operation precision are allowed for a small number of computationally
+    // intensive built-in functions, but it is reasonable to think that fract is not one of those).
+    // However, if fract() is incorrectly evaluated at minimum precision fulfilling mediump criteria,
+    // or at IEEE half float precision, the result is 0.0.
+    a = fract(c + uTest);
+    // Multiply by 2.0 to make the color green.
+    gl_FragColor = vec4(0.0, 2.0 * a, 0.0, 1.0);
+})";
+
+    ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
+
+    drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
+    EXPECT_GL_NO_ERROR();
+
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
 }  // anonymous namespace
 
 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(GLSLTest, WithDirectSPIRVGeneration(ES2_VULKAN()));