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