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 class EXTShaderFramebufferFetchNoncoherentTest : public sh::ShaderExtensionTest
108 {
109 public:
SetUp()110 void SetUp() override
111 {
112 std::map<ShShaderOutput, std::string> shaderOutputList = {
113 {SH_GLSL_450_CORE_OUTPUT, "SH_GLSL_450_CORE_OUTPUT"},
114 #if defined(ANGLE_ENABLE_VULKAN)
115 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}
116 #endif
117 };
118
119 Initialize(shaderOutputList);
120 }
121
TearDown()122 void TearDown() override
123 {
124 for (auto shaderOutputType : mShaderOutputList)
125 {
126 DestroyCompiler(shaderOutputType.first);
127 }
128 }
129
Initialize(std::map<ShShaderOutput,std::string> & shaderOutputList)130 void Initialize(std::map<ShShaderOutput, std::string> &shaderOutputList)
131 {
132 mShaderOutputList = std::move(shaderOutputList);
133
134 for (auto shaderOutputType : mShaderOutputList)
135 {
136 sh::InitBuiltInResources(&mResourceList[shaderOutputType.first]);
137 mCompilerList[shaderOutputType.first] = nullptr;
138 }
139 }
140
DestroyCompiler(ShShaderOutput shaderOutputType)141 void DestroyCompiler(ShShaderOutput shaderOutputType)
142 {
143 if (mCompilerList[shaderOutputType])
144 {
145 sh::Destruct(mCompilerList[shaderOutputType]);
146 mCompilerList[shaderOutputType] = nullptr;
147 }
148 }
149
InitializeCompiler()150 void InitializeCompiler()
151 {
152 for (auto shaderOutputType : mShaderOutputList)
153 {
154 InitializeCompiler(shaderOutputType.first);
155 }
156 }
157
InitializeCompiler(ShShaderOutput shaderOutputType)158 void InitializeCompiler(ShShaderOutput shaderOutputType)
159 {
160 DestroyCompiler(shaderOutputType);
161
162 mCompilerList[shaderOutputType] =
163 sh::ConstructCompiler(GL_FRAGMENT_SHADER, testing::get<0>(GetParam()), shaderOutputType,
164 &mResourceList[shaderOutputType]);
165 ASSERT_TRUE(mCompilerList[shaderOutputType] != nullptr)
166 << "Compiler for " << mShaderOutputList[shaderOutputType]
167 << " could not be constructed.";
168 }
169
TestShaderCompile(ShShaderOutput shaderOutputType,const char * pragma)170 testing::AssertionResult TestShaderCompile(ShShaderOutput shaderOutputType, const char *pragma)
171 {
172 ShCompileOptions compileOptions = {};
173 compileOptions.objectCode = true;
174
175 const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
176 testing::get<2>(GetParam())};
177
178 bool success =
179 sh::Compile(mCompilerList[shaderOutputType], shaderStrings, 3, compileOptions);
180 if (success)
181 {
182 return ::testing::AssertionSuccess()
183 << "Compilation success(" << mShaderOutputList[shaderOutputType] << ")";
184 }
185 return ::testing::AssertionFailure() << sh::GetInfoLog(mCompilerList[shaderOutputType]);
186 }
187
TestShaderCompile(bool expectation,const char * pragma)188 void TestShaderCompile(bool expectation, const char *pragma)
189 {
190 for (auto shaderOutputType : mShaderOutputList)
191 {
192 if (expectation)
193 {
194 EXPECT_TRUE(TestShaderCompile(shaderOutputType.first, pragma));
195 }
196 else
197 {
198 EXPECT_FALSE(TestShaderCompile(shaderOutputType.first, pragma));
199 }
200 }
201 }
202
SetExtensionEnable(bool enable)203 void SetExtensionEnable(bool enable)
204 {
205 for (auto shaderOutputType : mShaderOutputList)
206 {
207 mResourceList[shaderOutputType.first].MaxDrawBuffers = 8;
208 mResourceList[shaderOutputType.first].EXT_shader_framebuffer_fetch_non_coherent =
209 enable;
210 }
211 }
212
213 private:
214 std::map<ShShaderOutput, std::string> mShaderOutputList;
215 std::map<ShShaderOutput, ShHandle> mCompilerList;
216 std::map<ShShaderOutput, ShBuiltInResources> mResourceList;
217 };
218
219 class EXTShaderFramebufferFetchNoncoherentES100Test
220 : public EXTShaderFramebufferFetchNoncoherentTest
221 {};
222
223 // Extension flag is required to compile properly. Expect failure when it is
224 // not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test,CompileFailsWithoutExtension)225 TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test, CompileFailsWithoutExtension)
226 {
227 SetExtensionEnable(false);
228 InitializeCompiler();
229 TestShaderCompile(false, EXTPragma);
230 }
231
232 // Extension directive is required to compile properly. Expect failure when
233 // it is not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test,CompileFailsWithExtensionWithoutPragma)234 TEST_P(EXTShaderFramebufferFetchNoncoherentES100Test, CompileFailsWithExtensionWithoutPragma)
235 {
236 SetExtensionEnable(true);
237 InitializeCompiler();
238 TestShaderCompile(false, "");
239 }
240
241 class EXTShaderFramebufferFetchNoncoherentES300Test
242 : public EXTShaderFramebufferFetchNoncoherentTest
243 {};
244
245 // Extension flag is required to compile properly. Expect failure when it is
246 // not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test,CompileFailsWithoutExtension)247 TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test, CompileFailsWithoutExtension)
248 {
249 SetExtensionEnable(false);
250 InitializeCompiler();
251 TestShaderCompile(false, EXTPragma);
252 }
253
254 // Extension directive is required to compile properly. Expect failure when
255 // it is not present.
TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test,CompileFailsWithExtensionWithoutPragma)256 TEST_P(EXTShaderFramebufferFetchNoncoherentES300Test, CompileFailsWithExtensionWithoutPragma)
257 {
258 SetExtensionEnable(true);
259 InitializeCompiler();
260 TestShaderCompile(false, "");
261 }
262
263 INSTANTIATE_TEST_SUITE_P(CorrectESSL100Shaders,
264 EXTShaderFramebufferFetchNoncoherentES100Test,
265 Combine(Values(SH_GLES2_SPEC),
266 Values(sh::ESSLVersion100),
267 Values(ESSL100_LastFragDataRedeclared1)));
268
269 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
270 EXTShaderFramebufferFetchNoncoherentES300Test,
271 Combine(Values(SH_GLES3_SPEC),
272 Values(sh::ESSLVersion300),
273 Values(ESSL300_InOut,
274 ESSL300_InOut2,
275 ESSL300_InOut3,
276 ESSL300_InOut4,
277 ESSL300_InOut5,
278 ESSL300_InOut6)));
279
280 #if defined(ANGLE_ENABLE_VULKAN)
281
282 // Use gl_LastFragData without redeclaration of gl_LastFragData with noncoherent qualifier
283 const char ESSL100_LastFragDataWithoutRedeclaration[] =
284 R"(
285 uniform highp vec4 u_color;
286
287 void main (void)
288 {
289 gl_FragColor = u_color + gl_LastFragData[0];
290 })";
291
292 // Redeclare gl_LastFragData without noncoherent qualifier
293 const char ESSL100_LastFragDataRedeclaredWithoutNoncoherent[] =
294 R"(
295 uniform highp vec4 u_color;
296 highp vec4 gl_LastFragData[gl_MaxDrawBuffers];
297
298 void main (void)
299 {
300 gl_FragColor = u_color + gl_LastFragData[0];
301 })";
302
303 // Use inout variable without noncoherent qualifier
304 const char ESSL300_InOutWithoutNoncoherent[] =
305 R"(
306 layout(location = 0) inout highp vec4 o_color;
307 uniform highp vec4 u_color;
308
309 void main (void)
310 {
311 o_color = clamp(o_color + u_color, vec4(0.0f), vec4(1.0f));
312 })";
313
314 class EXTShaderFramebufferFetchNoncoherentSuccessTest
315 : public EXTShaderFramebufferFetchNoncoherentTest
316 {
317 public:
SetUp()318 void SetUp() override
319 {
320 std::map<ShShaderOutput, std::string> shaderOutputList = {
321 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}};
322
323 Initialize(shaderOutputList);
324 }
325 };
326
327 class EXTShaderFramebufferFetchNoncoherentFailureTest
328 : public EXTShaderFramebufferFetchNoncoherentSuccessTest
329 {};
330
331 class EXTShaderFramebufferFetchNoncoherentES100SuccessTest
332 : public EXTShaderFramebufferFetchNoncoherentSuccessTest
333 {};
334
335 class EXTShaderFramebufferFetchNoncoherentES100FailureTest
336 : public EXTShaderFramebufferFetchNoncoherentFailureTest
337 {};
338
339 // With extension flag and extension directive, compiling succeeds.
340 // Also test that the extension directive state is reset correctly.
TEST_P(EXTShaderFramebufferFetchNoncoherentES100SuccessTest,CompileSucceedsWithExtensionAndPragma)341 TEST_P(EXTShaderFramebufferFetchNoncoherentES100SuccessTest, CompileSucceedsWithExtensionAndPragma)
342 {
343 SetExtensionEnable(true);
344 InitializeCompiler();
345 TestShaderCompile(true, EXTPragma);
346 // Test reset functionality.
347 TestShaderCompile(false, "");
348 TestShaderCompile(true, EXTPragma);
349 }
350
351 //
TEST_P(EXTShaderFramebufferFetchNoncoherentES100FailureTest,CompileFailsWithoutNoncoherent)352 TEST_P(EXTShaderFramebufferFetchNoncoherentES100FailureTest, CompileFailsWithoutNoncoherent)
353 {
354 SetExtensionEnable(true);
355 InitializeCompiler();
356 TestShaderCompile(false, EXTPragma);
357 }
358
359 class EXTShaderFramebufferFetchNoncoherentES300SuccessTest
360 : public EXTShaderFramebufferFetchNoncoherentSuccessTest
361 {};
362
363 class EXTShaderFramebufferFetchNoncoherentES300FailureTest
364 : public EXTShaderFramebufferFetchNoncoherentFailureTest
365 {};
366
367 // With extension flag and extension directive, compiling succeeds.
368 // Also test that the extension directive state is reset correctly.
TEST_P(EXTShaderFramebufferFetchNoncoherentES300SuccessTest,CompileSucceedsWithExtensionAndPragma)369 TEST_P(EXTShaderFramebufferFetchNoncoherentES300SuccessTest, CompileSucceedsWithExtensionAndPragma)
370 {
371 SetExtensionEnable(true);
372 InitializeCompiler();
373 TestShaderCompile(true, EXTPragma);
374 // Test reset functionality.
375 TestShaderCompile(false, "");
376 TestShaderCompile(true, EXTPragma);
377 }
378
379 //
TEST_P(EXTShaderFramebufferFetchNoncoherentES300FailureTest,CompileFailsWithoutNoncoherent)380 TEST_P(EXTShaderFramebufferFetchNoncoherentES300FailureTest, CompileFailsWithoutNoncoherent)
381 {
382 SetExtensionEnable(true);
383 InitializeCompiler();
384 TestShaderCompile(false, EXTPragma);
385 }
386
387 // The SL #version 100 shaders that are correct work similarly
388 // in both GL2 and GL3, with and without the version string.
389 INSTANTIATE_TEST_SUITE_P(CorrectESSL100Shaders,
390 EXTShaderFramebufferFetchNoncoherentES100SuccessTest,
391 Combine(Values(SH_GLES2_SPEC),
392 Values(sh::ESSLVersion100),
393 Values(ESSL100_LastFragDataRedeclared1)));
394
395 INSTANTIATE_TEST_SUITE_P(IncorrectESSL100Shaders,
396 EXTShaderFramebufferFetchNoncoherentES100FailureTest,
397 Combine(Values(SH_GLES2_SPEC),
398 Values(sh::ESSLVersion100),
399 Values(ESSL100_LastFragDataWithoutRedeclaration,
400 ESSL100_LastFragDataRedeclaredWithoutNoncoherent)));
401
402 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
403 EXTShaderFramebufferFetchNoncoherentES300SuccessTest,
404 Combine(Values(SH_GLES3_SPEC),
405 Values(sh::ESSLVersion300),
406 Values(ESSL300_InOut,
407 ESSL300_InOut2,
408 ESSL300_InOut3,
409 ESSL300_InOut4,
410 ESSL300_InOut5,
411 ESSL300_InOut6)));
412
413 INSTANTIATE_TEST_SUITE_P(IncorrectESSL300Shaders,
414 EXTShaderFramebufferFetchNoncoherentES300FailureTest,
415 Combine(Values(SH_GLES3_SPEC),
416 Values(sh::ESSLVersion300),
417 Values(ESSL300_InOutWithoutNoncoherent)));
418 #endif
419
420 } // anonymous namespace
421