1 //
2 // Copyright 2020 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 // EXT_shader_framebuffer_fetch_test.cpp:
7 // Test for EXT_shader_framebuffer_fetch and EXT_shader_framebuffer_fetch_non_coherent
8 //
9
10 #include "tests/test_utils/ShaderExtensionTest.h"
11
12 namespace
13 {
14 const char EXTPragma[] = "#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require\n";
15
16 // Redeclare gl_LastFragData with noncoherent qualifier
17 const char ESSL100_LastFragDataRedeclared1[] =
18 R"(
19 uniform highp vec4 u_color;
20 layout(noncoherent) highp vec4 gl_LastFragData[gl_MaxDrawBuffers];
21
22 void main (void)
23 {
24 gl_FragColor = u_color + gl_LastFragData[0] + gl_LastFragData[2];
25 })";
26
27 // Use inout variable with noncoherent qualifier
28 const char ESSL300_InOut[] =
29 R"(
30 layout(noncoherent, location = 0) inout highp vec4 o_color;
31 uniform highp vec4 u_color;
32
33 void main (void)
34 {
35 o_color = clamp(o_color + u_color, vec4(0.0f), vec4(1.0f));
36 })";
37
38 // Use inout variable with noncoherent qualifier and 3-components vector
39 const char ESSL300_InOut2[] =
40 R"(
41 layout(noncoherent, location = 0) inout highp vec3 o_color;
42 uniform highp vec3 u_color;
43
44 void main (void)
45 {
46 o_color = clamp(o_color + u_color, vec3(0.0f), vec3(1.0f));
47 })";
48
49 // Use inout variable with noncoherent qualifier and integer type qualifier
50 const char ESSL300_InOut3[] =
51 R"(
52 layout(noncoherent, location = 0) inout highp ivec4 o_color;
53 uniform highp ivec4 u_color;
54
55 void main (void)
56 {
57 o_color = clamp(o_color + u_color, ivec4(0), ivec4(1));
58 })";
59
60 // Use inout variable with noncoherent qualifier and unsigned integer type qualifier
61 const char ESSL300_InOut4[] =
62 R"(
63 layout(noncoherent, location = 0) inout highp uvec4 o_color;
64 uniform highp uvec4 u_color;
65
66 void main (void)
67 {
68 o_color = clamp(o_color + u_color, uvec4(0), uvec4(1));
69 })";
70
71 // Use inout variable with noncoherent qualifier and inout function parameter
72 const char ESSL300_InOut5[] =
73 R"(
74 layout(noncoherent, location = 0) inout highp vec4 o_color;
75 uniform highp vec4 u_color;
76
77 void getClampValue(inout highp mat4 io_color, highp vec4 i_color)
78 {
79 io_color[0] = clamp(io_color[0] + i_color, vec4(0.0f), vec4(1.0f));
80 }
81
82 void main (void)
83 {
84 highp mat4 o_color_mat = mat4(0);
85 o_color_mat[0] = o_color;
86 getClampValue(o_color_mat, u_color);
87 o_color = o_color_mat[0];
88 })";
89
90 // Use multiple inout variables with noncoherent qualifier
91 const char ESSL300_InOut6[] =
92 R"(
93 layout(noncoherent, location = 0) inout highp vec4 o_color0;
94 layout(noncoherent, location = 1) inout highp vec4 o_color1;
95 layout(noncoherent, location = 2) inout highp vec4 o_color2;
96 layout(noncoherent, location = 3) inout highp vec4 o_color3;
97 uniform highp vec4 u_color;
98
99 void main (void)
100 {
101 o_color0 = clamp(o_color0 + u_color, vec4(0.0f), vec4(1.0f));
102 o_color1 = clamp(o_color1 + u_color, vec4(0.0f), vec4(1.0f));
103 o_color2 = clamp(o_color2 + u_color, vec4(0.0f), vec4(1.0f));
104 o_color3 = clamp(o_color3 + u_color, vec4(0.0f), vec4(1.0f));
105 })";
106
107 // Use the array of inout variable with noncoherent qualifier
108 const char ESSL300_InOut7[] =
109 R"(
110 layout(noncoherent, location = 0) inout highp vec4 o_color[4];
111 uniform highp vec4 u_color;
112
113 void main (void)
114 {
115 for (int i = 0 ; i < 4 ; i++)
116 {
117 o_color[i] = clamp(o_color[i] + u_color, vec4(0.0f), vec4(1.0f));
118 }
119 })";
120
121 class EXTShaderFramebufferFetchNoncoherentTest : public sh::ShaderExtensionTest
122 {
123 public:
SetUp()124 void SetUp() override
125 {
126 std::map<ShShaderOutput, std::string> shaderOutputList = {
127 {SH_GLSL_450_CORE_OUTPUT, "SH_GLSL_450_CORE_OUTPUT"},
128 #if defined(ANGLE_ENABLE_VULKAN)
129 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}
130 #endif
131 };
132
133 Initialize(shaderOutputList);
134 }
135
TearDown()136 void TearDown() override
137 {
138 for (auto shaderOutputType : mShaderOutputList)
139 {
140 DestroyCompiler(shaderOutputType.first);
141 }
142 }
143
Initialize(std::map<ShShaderOutput,std::string> & shaderOutputList)144 void Initialize(std::map<ShShaderOutput, std::string> &shaderOutputList)
145 {
146 mShaderOutputList = std::move(shaderOutputList);
147
148 for (auto shaderOutputType : mShaderOutputList)
149 {
150 sh::InitBuiltInResources(&mResourceList[shaderOutputType.first]);
151 mCompilerList[shaderOutputType.first] = nullptr;
152 }
153 }
154
DestroyCompiler(ShShaderOutput shaderOutputType)155 void DestroyCompiler(ShShaderOutput shaderOutputType)
156 {
157 if (mCompilerList[shaderOutputType])
158 {
159 sh::Destruct(mCompilerList[shaderOutputType]);
160 mCompilerList[shaderOutputType] = nullptr;
161 }
162 }
163
InitializeCompiler()164 void InitializeCompiler()
165 {
166 for (auto shaderOutputType : mShaderOutputList)
167 {
168 InitializeCompiler(shaderOutputType.first);
169 }
170 }
171
InitializeCompiler(ShShaderOutput shaderOutputType)172 void InitializeCompiler(ShShaderOutput shaderOutputType)
173 {
174 DestroyCompiler(shaderOutputType);
175
176 mCompilerList[shaderOutputType] =
177 sh::ConstructCompiler(GL_FRAGMENT_SHADER, testing::get<0>(GetParam()), shaderOutputType,
178 &mResourceList[shaderOutputType]);
179 ASSERT_TRUE(mCompilerList[shaderOutputType] != nullptr)
180 << "Compiler for " << mShaderOutputList[shaderOutputType]
181 << " could not be constructed.";
182 }
183
TestShaderCompile(ShShaderOutput shaderOutputType,const char * pragma)184 testing::AssertionResult TestShaderCompile(ShShaderOutput shaderOutputType, const char *pragma)
185 {
186 const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
187 testing::get<2>(GetParam())};
188
189 bool success = sh::Compile(mCompilerList[shaderOutputType], shaderStrings, 3,
190 SH_VARIABLES | SH_OBJECT_CODE);
191 if (success)
192 {
193 return ::testing::AssertionSuccess()
194 << "Compilation success(" << mShaderOutputList[shaderOutputType] << ")";
195 }
196 return ::testing::AssertionFailure() << sh::GetInfoLog(mCompilerList[shaderOutputType]);
197 }
198
TestShaderCompile(bool expectation,const char * pragma)199 void TestShaderCompile(bool expectation, const char *pragma)
200 {
201 for (auto shaderOutputType : mShaderOutputList)
202 {
203 if (expectation)
204 {
205 EXPECT_TRUE(TestShaderCompile(shaderOutputType.first, pragma));
206 }
207 else
208 {
209 EXPECT_FALSE(TestShaderCompile(shaderOutputType.first, pragma));
210 }
211 }
212 }
213
SetExtensionEnable(bool enable)214 void SetExtensionEnable(bool enable)
215 {
216 for (auto shaderOutputType : mShaderOutputList)
217 {
218 mResourceList[shaderOutputType.first].MaxDrawBuffers = 8;
219 mResourceList[shaderOutputType.first].EXT_shader_framebuffer_fetch_non_coherent =
220 enable;
221 }
222 }
223
224 private:
225 std::map<ShShaderOutput, std::string> mShaderOutputList;
226 std::map<ShShaderOutput, ShHandle> mCompilerList;
227 std::map<ShShaderOutput, ShBuiltInResources> mResourceList;
228 };
229
230 class EXTShaderFramebufferFetchNoncoherentES100Test
231 : public EXTShaderFramebufferFetchNoncoherentTest
232 {};
233
234 // Extension flag is required to compile properly. Expect failure when it is
235 // not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test,CompileFailsWithoutExtension)236 TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test, CompileFailsWithoutExtension)
237 {
238 SetExtensionEnable(false);
239 InitializeCompiler();
240 TestShaderCompile(false, EXTPragma);
241 }
242
243 // Extension directive is required to compile properly. Expect failure when
244 // it is not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test,CompileFailsWithExtensionWithoutPragma)245 TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test, CompileFailsWithExtensionWithoutPragma)
246 {
247 SetExtensionEnable(true);
248 InitializeCompiler();
249 TestShaderCompile(false, "");
250 }
251
252 class EXTShaderFramebufferFetchNoncoherentES300Test
253 : public EXTShaderFramebufferFetchNoncoherentTest
254 {};
255
256 // Extension flag is required to compile properly. Expect failure when it is
257 // not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test,CompileFailsWithoutExtension)258 TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test, CompileFailsWithoutExtension)
259 {
260 SetExtensionEnable(false);
261 InitializeCompiler();
262 TestShaderCompile(false, EXTPragma);
263 }
264
265 // Extension directive is required to compile properly. Expect failure when
266 // it is not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test,CompileFailsWithExtensionWithoutPragma)267 TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test, CompileFailsWithExtensionWithoutPragma)
268 {
269 SetExtensionEnable(true);
270 InitializeCompiler();
271 TestShaderCompile(false, "");
272 }
273
274 INSTANTIATE_TEST_SUITE_P(CorrectESSL100Shaders,
275 EXTShaderFramebufferFetchNoncoherentES100Test,
276 Combine(Values(SH_GLES2_SPEC),
277 Values(sh::ESSLVersion100),
278 Values(ESSL100_LastFragDataRedeclared1)));
279
280 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
281 EXTShaderFramebufferFetchNoncoherentES300Test,
282 Combine(Values(SH_GLES3_SPEC),
283 Values(sh::ESSLVersion300),
284 Values(ESSL300_InOut,
285 ESSL300_InOut2,
286 ESSL300_InOut3,
287 ESSL300_InOut4,
288 ESSL300_InOut5,
289 ESSL300_InOut6,
290 ESSL300_InOut7)));
291
292 #if defined(ANGLE_ENABLE_VULKAN)
293
294 // Use gl_LastFragData without redeclaration of gl_LastFragData with noncoherent qualifier
295 const char ESSL100_LastFragDataWithoutRedeclaration[] =
296 R"(
297 uniform highp vec4 u_color;
298
299 void main (void)
300 {
301 gl_FragColor = u_color + gl_LastFragData[0];
302 })";
303
304 // Redeclare gl_LastFragData without noncoherent qualifier
305 const char ESSL100_LastFragDataRedeclaredWithoutNoncoherent[] =
306 R"(
307 uniform highp vec4 u_color;
308 highp vec4 gl_LastFragData[gl_MaxDrawBuffers];
309
310 void main (void)
311 {
312 gl_FragColor = u_color + gl_LastFragData[0];
313 })";
314
315 // Use inout variable without noncoherent qualifier
316 const char ESSL300_InOutWithoutNoncoherent[] =
317 R"(
318 layout(location = 0) inout highp vec4 o_color;
319 uniform highp vec4 u_color;
320
321 void main (void)
322 {
323 o_color = clamp(o_color + u_color, vec4(0.0f), vec4(1.0f));
324 })";
325
326 class EXTShaderFramebufferFetchNoncoherentSuccessTest
327 : public EXTShaderFramebufferFetchNoncoherentTest
328 {
329 public:
SetUp()330 void SetUp() override
331 {
332 std::map<ShShaderOutput, std::string> shaderOutputList = {
333 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}};
334
335 Initialize(shaderOutputList);
336 }
337 };
338
339 class EXTShaderFramebufferFetchNoncoherentFailureTest
340 : public EXTShaderFramebufferFetchNoncoherentSuccessTest
341 {};
342
343 class EXTShaderFramebufferFetchNoncoherentES100SuccessTest
344 : public EXTShaderFramebufferFetchNoncoherentSuccessTest
345 {};
346
347 class EXTShaderFramebufferFetchNoncoherentES100FailureTest
348 : public EXTShaderFramebufferFetchNoncoherentFailureTest
349 {};
350
351 // With extension flag and extension directive, compiling succeeds.
352 // Also test that the extension directive state is reset correctly.
TEST_P(EXTShaderFramebufferFetchNoncoherentES100SuccessTest,CompileSucceedsWithExtensionAndPragma)353 TEST_P(EXTShaderFramebufferFetchNoncoherentES100SuccessTest, CompileSucceedsWithExtensionAndPragma)
354 {
355 SetExtensionEnable(true);
356 InitializeCompiler();
357 TestShaderCompile(true, EXTPragma);
358 // Test reset functionality.
359 TestShaderCompile(false, "");
360 TestShaderCompile(true, EXTPragma);
361 }
362
363 //
TEST_P(EXTShaderFramebufferFetchNoncoherentES100FailureTest,CompileFailsWithoutNoncoherent)364 TEST_P(EXTShaderFramebufferFetchNoncoherentES100FailureTest, CompileFailsWithoutNoncoherent)
365 {
366 SetExtensionEnable(true);
367 InitializeCompiler();
368 TestShaderCompile(false, EXTPragma);
369 }
370
371 class EXTShaderFramebufferFetchNoncoherentES300SuccessTest
372 : public EXTShaderFramebufferFetchNoncoherentSuccessTest
373 {};
374
375 class EXTShaderFramebufferFetchNoncoherentES300FailureTest
376 : public EXTShaderFramebufferFetchNoncoherentFailureTest
377 {};
378
379 // With extension flag and extension directive, compiling succeeds.
380 // Also test that the extension directive state is reset correctly.
TEST_P(EXTShaderFramebufferFetchNoncoherentES300SuccessTest,CompileSucceedsWithExtensionAndPragma)381 TEST_P(EXTShaderFramebufferFetchNoncoherentES300SuccessTest, CompileSucceedsWithExtensionAndPragma)
382 {
383 SetExtensionEnable(true);
384 InitializeCompiler();
385 TestShaderCompile(true, EXTPragma);
386 // Test reset functionality.
387 TestShaderCompile(false, "");
388 TestShaderCompile(true, EXTPragma);
389 }
390
391 //
TEST_P(EXTShaderFramebufferFetchNoncoherentES300FailureTest,CompileFailsWithoutNoncoherent)392 TEST_P(EXTShaderFramebufferFetchNoncoherentES300FailureTest, CompileFailsWithoutNoncoherent)
393 {
394 SetExtensionEnable(true);
395 InitializeCompiler();
396 TestShaderCompile(false, EXTPragma);
397 }
398
399 // The SL #version 100 shaders that are correct work similarly
400 // in both GL2 and GL3, with and without the version string.
401 INSTANTIATE_TEST_SUITE_P(CorrectESSL100Shaders,
402 EXTShaderFramebufferFetchNoncoherentES100SuccessTest,
403 Combine(Values(SH_GLES2_SPEC),
404 Values(sh::ESSLVersion100),
405 Values(ESSL100_LastFragDataRedeclared1)));
406
407 INSTANTIATE_TEST_SUITE_P(IncorrectESSL100Shaders,
408 EXTShaderFramebufferFetchNoncoherentES100FailureTest,
409 Combine(Values(SH_GLES2_SPEC),
410 Values(sh::ESSLVersion100),
411 Values(ESSL100_LastFragDataWithoutRedeclaration,
412 ESSL100_LastFragDataRedeclaredWithoutNoncoherent)));
413
414 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
415 EXTShaderFramebufferFetchNoncoherentES300SuccessTest,
416 Combine(Values(SH_GLES3_SPEC),
417 Values(sh::ESSLVersion300),
418 Values(ESSL300_InOut,
419 ESSL300_InOut2,
420 ESSL300_InOut3,
421 ESSL300_InOut4,
422 ESSL300_InOut5,
423 ESSL300_InOut6,
424 ESSL300_InOut7)));
425
426 INSTANTIATE_TEST_SUITE_P(IncorrectESSL300Shaders,
427 EXTShaderFramebufferFetchNoncoherentES300FailureTest,
428 Combine(Values(SH_GLES3_SPEC),
429 Values(sh::ESSLVersion300),
430 Values(ESSL300_InOutWithoutNoncoherent)));
431 #endif
432
433 } // anonymous namespace
434