1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // RecordConstantPrecision_test.cpp:
7 // Test for recording constant variable precision when it affects consuming expression.
8 //
9
10 #include "GLSLANG/ShaderLang.h"
11 #include "angle_gl.h"
12 #include "gtest/gtest.h"
13 #include "tests/test_utils/compiler_test.h"
14
15 using namespace sh;
16
17 class RecordConstantPrecisionTest : public MatchOutputCodeTest
18 {
19 public:
RecordConstantPrecisionTest()20 RecordConstantPrecisionTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT) {}
21 };
22
23 // The constant's precision must be specified if its precision is higher than the other operands,
24 // since it increases the precision of the consuming expression.
TEST_F(RecordConstantPrecisionTest,HigherPrecisionConstantAsParameter)25 TEST_F(RecordConstantPrecisionTest, HigherPrecisionConstantAsParameter)
26 {
27 const std::string &shaderString = R"(
28 uniform mediump float u;
29 void main()
30 {
31 const highp float a = 4096.5;
32 mediump float b = fract(a + u);
33 gl_FragColor = vec4(b);
34 })";
35 compile(shaderString);
36 ASSERT_TRUE(foundInCode("const highp float s"));
37 ASSERT_FALSE(foundInCode("fract(4096.5"));
38 ASSERT_FALSE(foundInCode("fract((4096.5"));
39 }
40
41 // The constant's precision does not need to be specified if its precision is equal to the other
42 // operands, as it does not increase the precision of the consuming expression. For simplicity
43 // however, the constant's precision is specified anyway.
TEST_F(RecordConstantPrecisionTest,EqualPrecisionConstantAsParameter)44 TEST_F(RecordConstantPrecisionTest, EqualPrecisionConstantAsParameter)
45 {
46 const std::string &shaderString = R"(
47 uniform mediump float u;
48 void main()
49 {
50 const mediump float a = 4096.5;
51 mediump float b = fract(a + u);
52 gl_FragColor = vec4(b);
53 })";
54 compile(shaderString);
55 ASSERT_TRUE(foundInCode("const mediump float s"));
56 ASSERT_FALSE(foundInCode("fract((4096.5"));
57 }
58
59 // The constant's precision must be specified if its precision is higher than the other operands,
60 // since it increases the precision of the consuming expression. This applies also when the
61 // constant is part of a constant expression that can be folded.
TEST_F(RecordConstantPrecisionTest,FoldedBinaryConstantPrecisionIsHigher)62 TEST_F(RecordConstantPrecisionTest, FoldedBinaryConstantPrecisionIsHigher)
63 {
64 const std::string &shaderString = R"(
65 uniform mediump float u;
66 void main()
67 {
68 const highp float a = 4095.5;
69 mediump float b = fract((a + 1.0) + u);
70 gl_FragColor = vec4(b);
71 })";
72 compile(shaderString);
73 ASSERT_TRUE(foundInCode("const highp float s"));
74 ASSERT_FALSE(foundInCode("fract(4096.5"));
75 ASSERT_FALSE(foundInCode("fract((4096.5"));
76 }
77
78 // The constant's precision must be specified if its precision is higher than the other operands,
79 // since it increases the precision of the consuming expression. This applies also when the
80 // constant is part of a constant expression that can be folded.
TEST_F(RecordConstantPrecisionTest,FoldedUnaryConstantPrecisionIsHigher)81 TEST_F(RecordConstantPrecisionTest, FoldedUnaryConstantPrecisionIsHigher)
82 {
83 const std::string &shaderString = R"(
84 uniform mediump float u;
85 void main()
86 {
87 const highp float a = 0.5;
88 mediump float b = sin(fract(a) + u);
89 gl_FragColor = vec4(b);
90 })";
91 compile(shaderString);
92 ASSERT_TRUE(foundInCode("const highp float s"));
93 ASSERT_FALSE(foundInCode("sin(0.5"));
94 ASSERT_FALSE(foundInCode("sin((0.5"));
95 }
96
97 // The constant's precision must be specified if its precision is higher than the other operands,
98 // since it increases the precision of the consuming expression. This applies also when the
99 // constant is part of a constructor expression. Note that lowp constants never need their
100 // precision specified.
TEST_F(RecordConstantPrecisionTest,HigherPrecisionConstantInConstructor)101 TEST_F(RecordConstantPrecisionTest, HigherPrecisionConstantInConstructor)
102 {
103 const std::string &shaderString = R"(
104 uniform mediump float u;
105 void main()
106 {
107 const highp float a = 4096.5;
108 const lowp float b = 1.0;
109 lowp vec4 result = vec4(b, a, b, u);
110 gl_FragColor = result;
111 })";
112 compile(shaderString);
113 ASSERT_TRUE(foundInCode("const highp float s"));
114 ASSERT_FALSE(foundInCode("const lowp float s"));
115 ASSERT_TRUE(foundInCode("vec4(1.0, s"));
116 }
117
118 // The constant's precision does not need to be specified if its used to initialize a variable.
TEST_F(RecordConstantPrecisionTest,HigherPrecisionConstantInAssignment)119 TEST_F(RecordConstantPrecisionTest, HigherPrecisionConstantInAssignment)
120 {
121 const std::string &shaderString = R"(
122 uniform mediump float u;
123 void main()
124 {
125 const highp float a = 4096.5;
126 mediump float b = a;
127 mediump float c;
128 c = a;
129 gl_FragColor = vec4(b, b, c, c);
130 })";
131 compile(shaderString);
132 ASSERT_FALSE(foundInCode("const highp float s"));
133 ASSERT_TRUE(foundInCode("b = 4096.5"));
134 ASSERT_TRUE(foundInCode("c = 4096.5"));
135 }
136
137 // The constant's precision does not need to be specified if its used as an index.
TEST_F(RecordConstantPrecisionTest,HigherPrecisionConstantInIndex)138 TEST_F(RecordConstantPrecisionTest, HigherPrecisionConstantInIndex)
139 {
140 const std::string &shaderString = R"(
141 uniform mediump float u;
142 void main()
143 {
144 const highp int a = 330;
145 mediump float b[340];
146 gl_FragColor = vec4(b[a]);
147 })";
148 compile(shaderString);
149 ASSERT_FALSE(foundInCode("const highp int s"));
150 ASSERT_TRUE(foundInCode("b[330]"));
151 }
152