• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 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 // HLSLOutput_test.cpp:
7 //   Tests for HLSL output.
8 //
9 
10 #include <regex>
11 #include "GLSLANG/ShaderLang.h"
12 #include "angle_gl.h"
13 #include "gtest/gtest.h"
14 #include "tests/test_utils/compiler_test.h"
15 
16 using namespace sh;
17 
18 class HLSLOutputTest : public MatchOutputCodeTest
19 {
20   public:
HLSLOutputTest()21     HLSLOutputTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_HLSL_4_1_OUTPUT) {}
22 };
23 
24 class HLSL30VertexOutputTest : public MatchOutputCodeTest
25 {
26   public:
HLSL30VertexOutputTest()27     HLSL30VertexOutputTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_HLSL_3_0_OUTPUT) {}
28 };
29 
30 class HLSL41VertexOutputTest : public MatchOutputCodeTest
31 {
32   public:
HLSL41VertexOutputTest()33     HLSL41VertexOutputTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_HLSL_4_1_OUTPUT) {}
34 };
35 
36 // Test that having dynamic indexing of a vector inside the right hand side of logical or doesn't
37 // trigger asserts in HLSL output.
TEST_F(HLSLOutputTest,DynamicIndexingOfVectorOnRightSideOfLogicalOr)38 TEST_F(HLSLOutputTest, DynamicIndexingOfVectorOnRightSideOfLogicalOr)
39 {
40     const std::string &shaderString =
41         "#version 300 es\n"
42         "precision highp float;\n"
43         "out vec4 my_FragColor;\n"
44         "uniform int u1;\n"
45         "void main() {\n"
46         "   bvec4 v = bvec4(true, true, true, false);\n"
47         "   my_FragColor = vec4(v[u1 + 1] || v[u1]);\n"
48         "}\n";
49     compile(shaderString);
50 }
51 
52 // Test that rewriting else blocks in a function that returns a struct doesn't use the struct name
53 // without a prefix.
TEST_F(HLSL30VertexOutputTest,RewriteElseBlockReturningStruct)54 TEST_F(HLSL30VertexOutputTest, RewriteElseBlockReturningStruct)
55 {
56     const std::string &shaderString =
57         "struct foo\n"
58         "{\n"
59         "    float member;\n"
60         "};\n"
61         "uniform bool b;\n"
62         "foo getFoo()\n"
63         "{\n"
64         "    if (b)\n"
65         "    {\n"
66         "        return foo(0.0);\n"
67         "    }\n"
68         "    else\n"
69         "    {\n"
70         "        return foo(1.0);\n"
71         "    }\n"
72         "}\n"
73         "void main()\n"
74         "{\n"
75         "   gl_Position = vec4(getFoo().member);\n"
76         "}\n";
77     compile(shaderString);
78     EXPECT_TRUE(foundInCode("_foo"));
79     EXPECT_FALSE(foundInCode("(foo)"));
80     EXPECT_FALSE(foundInCode(" foo"));
81 }
82 
83 // Regression test for RemoveDynamicIndexing transformation producing invalid AST, based on fuzzer
84 // test.
TEST_F(HLSL41VertexOutputTest,RemoveDynamicingIndexIndexPrecisionBug)85 TEST_F(HLSL41VertexOutputTest, RemoveDynamicingIndexIndexPrecisionBug)
86 {
87     const char shaderString[] = R"(void main()
88 {
89     mat3 tmp;
90     vec3 res = vec3(0);
91     for (int i = 0; res += 0., ivec3(0)[i], ivec3(tmp)[i], i < 0;);
92 })";
93     compile(shaderString);
94 }
95 
96 // Test that having an array constructor as a statement doesn't trigger an assert in HLSL output.
97 // This test has a constant array constructor statement.
TEST_F(HLSLOutputTest,ConstArrayConstructorStatement)98 TEST_F(HLSLOutputTest, ConstArrayConstructorStatement)
99 {
100     const std::string &shaderString =
101         R"(#version 300 es
102         void main()
103         {
104             int[1](0);
105         })";
106     compile(shaderString);
107 }
108 
109 // Test that having an array constructor as a statement doesn't trigger an assert in HLSL output.
TEST_F(HLSLOutputTest,ArrayConstructorStatement)110 TEST_F(HLSLOutputTest, ArrayConstructorStatement)
111 {
112     const std::string &shaderString =
113         R"(#version 300 es
114         precision mediump float;
115         out vec4 outColor;
116         void main()
117         {
118             outColor = vec4(0.0, 0.0, 0.0, 1.0);
119             float[1](outColor[1]++);
120         })";
121     compile(shaderString);
122 }
123 
124 // Test an array of arrays constructor as a statement.
TEST_F(HLSLOutputTest,ArrayOfArraysStatement)125 TEST_F(HLSLOutputTest, ArrayOfArraysStatement)
126 {
127     const std::string &shaderString =
128         R"(#version 310 es
129         precision mediump float;
130         out vec4 outColor;
131         void main()
132         {
133             outColor = vec4(0.0, 0.0, 0.0, 1.0);
134             float[2][2](float[2](outColor[1]++, 0.0), float[2](1.0, 2.0));
135         })";
136     compile(shaderString);
137 }
138 
139 // Test dynamic indexing of a vector. This makes sure that helper functions added for dynamic
140 // indexing have correct data that subsequent traversal steps rely on.
TEST_F(HLSLOutputTest,VectorDynamicIndexing)141 TEST_F(HLSLOutputTest, VectorDynamicIndexing)
142 {
143     const std::string &shaderString =
144         R"(#version 300 es
145         precision mediump float;
146         out vec4 outColor;
147         uniform int i;
148         void main()
149         {
150             vec4 foo = vec4(0.0, 0.0, 0.0, 1.0);
151             foo[i] = foo[i + 1];
152             outColor = foo;
153         })";
154     compile(shaderString);
155 }
156 
157 // Test returning an array from a user-defined function. This makes sure that function symbols are
158 // changed consistently when the user-defined function is changed to have an array out parameter.
TEST_F(HLSLOutputTest,ArrayReturnValue)159 TEST_F(HLSLOutputTest, ArrayReturnValue)
160 {
161     const std::string &shaderString =
162         R"(#version 300 es
163         precision mediump float;
164         uniform float u;
165         out vec4 outColor;
166 
167         float[2] getArray(float f)
168         {
169             return float[2](f, f + 1.0);
170         }
171 
172         void main()
173         {
174             float[2] arr = getArray(u);
175             outColor = vec4(arr[0], arr[1], 0.0, 1.0);
176         })";
177     compile(shaderString);
178 }
179 
180 // Test that writing parameters without a name doesn't assert.
TEST_F(HLSLOutputTest,ParameterWithNoName)181 TEST_F(HLSLOutputTest, ParameterWithNoName)
182 {
183     const std::string &shaderString =
184         R"(precision mediump float;
185 
186         uniform vec4 v;
187 
188         vec4 s(vec4)
189         {
190             return v;
191         }
192         void main()
193         {
194             gl_FragColor = s(v);
195         })";
196     compile(shaderString);
197 }
198 
199 // Test that array dimensions are written out correctly.
TEST_F(HLSLOutputTest,Array)200 TEST_F(HLSLOutputTest, Array)
201 {
202     const std::string &shaderString =
203         R"(#version 300 es
204         precision mediump float;
205 
206         uniform float uf;
207 
208         out vec4 my_FragColor;
209 
210         void main()
211         {
212             my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
213             float arr[2];
214             for (int i = 0; i < 2; ++i) {
215                 arr[i] = uf * 2.0;
216                 my_FragColor.x += arr[i];
217             }
218         })";
219     compile(shaderString);
220     EXPECT_TRUE(foundInCodeRegex(std::regex("_arr(\\d)*\\[2\\]")));
221 }
222 
223 // Test that initializing array with previously declared array will not be overwritten
TEST_F(HLSLOutputTest,SameNameArray)224 TEST_F(HLSLOutputTest, SameNameArray)
225 {
226     const std::string &shaderString =
227         R"(#version 300 es
228         precision highp float;
229         out vec4 my_FragColor;
230 
231         void main()
232         {
233           float arr[2] = float[2](1.0, 1.0);
234           {
235             float arr[2] = arr;
236             my_FragColor = vec4(0.0, arr[0], 0.0, arr[1]);
237           }
238         })";
239     compile(shaderString);
240     // There should be two different arr defined, e.g. _arr1000 and _arr1001
241     // Use Workaround for now.
242     // Once the build team fixes libc++ we could use the following one line solution instead.
243     // EXPECT_TRUE(foundInCodeRegex(std::regex("_arr(\\d*)\\[2\\](.|\\r|\\n)*_arr(?!\\1)\\d*\\[2\\]")));
244     std::smatch m;
245     EXPECT_TRUE(foundInCodeRegex(std::regex("_arr(\\d)*\\[2\\]"), &m));
246     EXPECT_TRUE(m.size() == 2);
247     EXPECT_TRUE(m[0].str() != m[1].str());
248 }
249 
250 // Test that passing a non-struct member of a std140 structure to a function won't trigger the
251 // struct mapping.
TEST_F(HLSLOutputTest,NonStructMemberAsFunctionArgument)252 TEST_F(HLSLOutputTest, NonStructMemberAsFunctionArgument)
253 {
254     constexpr char shaderString[] = R"(#version 300 es
255 precision highp float;
256 out vec4 my_FragColor;
257 
258 struct InstancingData
259 {
260     vec4 data;
261 };
262 
263 layout(std140) uniform InstanceBlock
264 {
265     InstancingData instances[8];
266 };
267 
268 void main()
269 {
270     int index = int(gl_FragCoord.x);
271     float result = dot(instances[index].data, vec4(1.0, 1.0, 1.0, 1.0));
272     my_FragColor = vec4(result, 0.0, 0.0, 1.0);
273 })";
274 
275     compile(shaderString);
276     EXPECT_FALSE(foundInCode("map_instances"));
277 }
278