xref: /aosp_15_r20/external/angle/src/tests/compiler_tests/EXT_clip_cull_distance_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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_clip_cull_distance_test.cpp:
7 //   Test for EXT_clip_cull_distance
8 //
9 
10 #include "tests/test_utils/ShaderExtensionTest.h"
11 
12 namespace
13 {
14 const char EXTPragma[] = "#extension GL_EXT_clip_cull_distance : require\n";
15 
16 const char ANGLEPragma[] = "#extension GL_ANGLE_clip_cull_distance : require\n";
17 
18 // Shader using gl_ClipDistance and gl_CullDistance
19 const char VertexShaderCompileSucceeds1[] =
20     R"(
21     uniform vec4 uPlane;
22 
23     in vec4 aPosition;
24 
25     void main()
26     {
27         gl_Position = aPosition;
28         gl_ClipDistance[1] = dot(aPosition, uPlane);
29         gl_CullDistance[1] = dot(aPosition, uPlane);
30     })";
31 
32 // Shader redeclares gl_ClipDistance and gl_CullDistance
33 const char VertexShaderCompileSucceeds2[] =
34     R"(
35     uniform vec4 uPlane;
36 
37     in vec4 aPosition;
38 
39     out highp float gl_ClipDistance[4];
40     out highp float gl_CullDistance[4];
41 
42     void main()
43     {
44         gl_Position = aPosition;
45         gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
46         gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
47         gl_ClipDistance[gl_MaxCombinedClipAndCullDistances - 5] = dot(aPosition, uPlane);
48         gl_CullDistance[gl_MaxCullDistances - 6 + 1] = dot(aPosition, uPlane);
49         gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)] = dot(aPosition, uPlane);
50     })";
51 
52 #if defined(ANGLE_ENABLE_VULKAN)
53 // Shader using gl_ClipDistance and gl_CullDistance
54 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
55 const char VertexShaderCompileFails1[] =
56     R"(
57     uniform vec4 uPlane;
58 
59     in vec4 aPosition;
60 
61     void main()
62     {
63         gl_Position = aPosition;
64         gl_ClipDistance[5] = dot(aPosition, uPlane);
65         gl_CullDistance[4] = dot(aPosition, uPlane);
66     })";
67 
68 // Shader redeclares gl_ClipDistance and gl_CullDistance
69 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
70 const char VertexShaderCompileFails2[] =
71     R"(
72     uniform vec4 uPlane;
73 
74     in vec4 aPosition;
75 
76     out highp float gl_ClipDistance[5];
77     out highp float gl_CullDistance[4];
78 
79     void main()
80     {
81         gl_Position = aPosition;
82         gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
83         gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
84         gl_CullDistance[gl_MaxCullDistances - 6 + 1] = dot(aPosition, uPlane);
85         gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)] = dot(aPosition, uPlane);
86     })";
87 
88 // Shader redeclares gl_ClipDistance
89 // But, the array size is greater than gl_MaxClipDistances
90 const char VertexShaderCompileFails3[] =
91     R"(
92     uniform vec4 uPlane;
93 
94     in vec4 aPosition;
95 
96     out highp float gl_ClipDistance[gl_MaxClipDistances + 1];
97 
98     void main()
99     {
100         gl_Position = aPosition;
101         gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
102         gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
103     })";
104 
105 // Access gl_CullDistance with integral constant index
106 // But, the index is greater than gl_MaxCullDistances
107 const char VertexShaderCompileFails4[] =
108     R"(
109     uniform vec4 uPlane;
110 
111     in vec4 aPosition;
112 
113     void main()
114     {
115         gl_Position = aPosition;
116         gl_CullDistance[gl_MaxCullDistances] = dot(aPosition, uPlane);
117     })";
118 
119 // Simple ESSL1 vertex shader that should still fail because of incompatible
120 // #extension require
121 const char VertexShaderCompileFails5[] =
122     R"(
123     attribute vec4 aPosition;
124 
125     void main()
126     {
127         gl_Position = aPosition;
128     })";
129 #endif
130 
131 // Shader using gl_ClipDistance and gl_CullDistance
132 const char FragmentShaderCompileSucceeds1[] =
133     R"(
134     out highp vec4 fragColor;
135 
136     void main()
137     {
138         fragColor = vec4(gl_ClipDistance[0], gl_CullDistance[0], 0, 1);
139     })";
140 
141 // Shader redeclares gl_ClipDistance and gl_CullDistance
142 const char FragmentShaderCompileSucceeds2[] =
143     R"(
144     in highp float gl_ClipDistance[4];
145     in highp float gl_CullDistance[4];
146 
147     in highp vec4 aPosition;
148 
149     out highp vec4 fragColor;
150 
151     void main()
152     {
153         fragColor.x = gl_ClipDistance[gl_MaxClipDistances - 6 + 1];
154         fragColor.y = gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)];
155         fragColor.z = gl_CullDistance[gl_MaxCullDistances - 6 + 1];
156         fragColor.w = gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)];
157         fragColor *= gl_CullDistance[gl_MaxCombinedClipAndCullDistances - 5];
158     })";
159 
160 #if defined(ANGLE_ENABLE_VULKAN)
161 // Shader using gl_ClipDistance and gl_CullDistance
162 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
163 const char FragmentShaderCompileFails1[] =
164     R"(
165     out highp vec4 fragColor;
166 
167     void main()
168     {
169         fragColor = vec4(gl_ClipDistance[4], gl_CullDistance[5], 0, 1);
170     })";
171 
172 // Shader redeclares gl_ClipDistance and gl_CullDistance
173 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
174 const char FragmentShaderCompileFails2[] =
175     R"(
176     in highp float gl_ClipDistance[5];
177     in highp float gl_CullDistance[4];
178 
179     in highp vec4 aPosition;
180 
181     out highp vec4 fragColor;
182 
183     void main()
184     {
185         fragColor.x = gl_ClipDistance[gl_MaxClipDistances - 6 + 1];
186         fragColor.y = gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)];
187         fragColor.z = gl_CullDistance[gl_MaxCullDistances - 6 + 1];
188         fragColor.w = gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)];
189     })";
190 
191 // In fragment shader, writing to gl_ClipDistance should be denied.
192 const char FragmentShaderCompileFails3[] =
193     R"(
194     out highp vec4 fragColor;
195 
196     void main()
197     {
198         gl_ClipDistance[0] = 0.0f;
199         fragColor = vec4(1, gl_ClipDistance[0], 0, 1);
200     })";
201 
202 // In fragment shader, writing to gl_CullDistance should be denied even if redeclaring it with the
203 // array size
204 const char FragmentShaderCompileFails4[] =
205     R"(
206     out highp vec4 fragColor;
207 
208     in highp float gl_CullDistance[1];
209 
210     void main()
211     {
212         gl_CullDistance[0] = 0.0f;
213         fragColor = vec4(1, gl_CullDistance[0], 0, 1);
214     })";
215 
216 // Accessing to gl_Clip/CullDistance with non-const index should be denied if the size of
217 // gl_Clip/CullDistance is not decided.
218 const char FragmentShaderCompileFails5[] =
219     R"(
220     out highp vec4 fragColor;
221 
222     void main()
223     {
224         medium float color[3];
225         for(int i = 0 ; i < 3 ; i++)
226         {
227             color[i] = gl_CullDistance[i];
228         }
229         fragColor = vec4(color[0], color[1], color[2], 1.0f);
230     })";
231 
232 // In compute shader, redeclaring gl_ClipDistance should be denied.
233 const char ComputeShaderCompileFails1[] =
234     R"(
235     layout(local_size_x = 1) in;
236     highp float gl_ClipDistance[1];
237     void main() {})";
238 
239 // In compute shader, writing to gl_ClipDistance should be denied.
240 const char ComputeShaderCompileFails2[] =
241     R"(
242     layout(local_size_x = 1) in;
243     void main() { gl_ClipDistance[0] = 1.0; })";
244 
245 // In compute shader, reading gl_ClipDistance should be denied.
246 const char ComputeShaderCompileFails3[] =
247     R"(
248     layout(local_size_x = 1) in;
249     void main() { highp float c = gl_ClipDistance[0]; })";
250 
251 // In compute shader, redeclaring gl_CullDistance should be denied.
252 const char ComputeShaderCompileFails4[] =
253     R"(
254     layout(local_size_x = 1) in;
255     highp float gl_CullDistance[1];
256     void main() {})";
257 
258 // In compute shader, writing to gl_CullDistance should be denied.
259 const char ComputeShaderCompileFails5[] =
260     R"(
261     layout(local_size_x = 1) in;
262     void main() { gl_CullDistance[0] = 1.0; })";
263 
264 // In compute shader, reading gl_CullDistance should be denied.
265 const char ComputeShaderCompileFails6[] =
266     R"(
267     layout(local_size_x = 1) in;
268     void main() { highp float c = gl_CullDistance[0]; })";
269 #endif
270 
271 class EXTClipCullDistanceTest : public sh::ShaderExtensionTest
272 {
273   public:
InitializeCompiler(ShShaderOutput shaderOutputType,GLenum shaderType)274     void InitializeCompiler(ShShaderOutput shaderOutputType, GLenum shaderType)
275     {
276         DestroyCompiler();
277 
278         mCompiler = sh::ConstructCompiler(shaderType, testing::get<0>(GetParam()), shaderOutputType,
279                                           &mResources);
280         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
281     }
282 
TestShaderCompile(const char * pragma)283     testing::AssertionResult TestShaderCompile(const char *pragma)
284     {
285         ShCompileOptions compileOptions = {};
286         compileOptions.objectCode       = true;
287 
288         const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
289                                        testing::get<2>(GetParam())};
290         bool success                = sh::Compile(mCompiler, shaderStrings, 3, compileOptions);
291         if (success)
292         {
293             return ::testing::AssertionSuccess() << "Compilation success";
294         }
295         return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
296     }
297 
SetExtensionEnable(bool enable)298     void SetExtensionEnable(bool enable)
299     {
300         // GL_APPLE_clip_distance is implicitly enabled when GL_EXT_clip_cull_distance or
301         // GL_ANGLE_clip_cull_distance are enabled
302 #if defined(ANGLE_ENABLE_VULKAN)
303         mResources.APPLE_clip_distance = enable;
304 #endif
305         mResources.EXT_clip_cull_distance = enable;
306 
307         mResources.ANGLE_clip_cull_distance = enable;
308     }
309 };
310 
311 class EXTClipCullDistanceForVertexShaderTest : public EXTClipCullDistanceTest
312 {
313   public:
InitializeCompiler()314     void InitializeCompiler() { InitializeCompiler(SH_GLSL_450_CORE_OUTPUT); }
InitializeCompiler(ShShaderOutput shaderOutputType)315     void InitializeCompiler(ShShaderOutput shaderOutputType)
316     {
317         EXTClipCullDistanceTest::InitializeCompiler(shaderOutputType, GL_VERTEX_SHADER);
318     }
319 };
320 
321 class EXTClipCullDistanceForFragmentShaderTest : public EXTClipCullDistanceTest
322 {
323   public:
InitializeCompiler()324     void InitializeCompiler() { InitializeCompiler(SH_GLSL_450_CORE_OUTPUT); }
InitializeCompiler(ShShaderOutput shaderOutputType)325     void InitializeCompiler(ShShaderOutput shaderOutputType)
326     {
327         EXTClipCullDistanceTest::InitializeCompiler(shaderOutputType, GL_FRAGMENT_SHADER);
328     }
329 };
330 
331 class EXTClipCullDistanceForComputeShaderTest : public EXTClipCullDistanceTest
332 {
333   public:
InitializeCompiler()334     void InitializeCompiler() { InitializeCompiler(SH_GLSL_450_CORE_OUTPUT); }
InitializeCompiler(ShShaderOutput shaderOutputType)335     void InitializeCompiler(ShShaderOutput shaderOutputType)
336     {
337         EXTClipCullDistanceTest::InitializeCompiler(shaderOutputType, GL_COMPUTE_SHADER);
338     }
339 };
340 
341 // Extension flag is required to compile properly. Expect failure when it is
342 // not present.
TEST_P(EXTClipCullDistanceForVertexShaderTest,CompileFailsWithoutExtension)343 TEST_P(EXTClipCullDistanceForVertexShaderTest, CompileFailsWithoutExtension)
344 {
345     SetExtensionEnable(false);
346     InitializeCompiler();
347     EXPECT_FALSE(TestShaderCompile(EXTPragma));
348     InitializeCompiler();
349     EXPECT_FALSE(TestShaderCompile(ANGLEPragma));
350 }
351 
352 // Extension directive is required to compile properly. Expect failure when
353 // it is not present.
TEST_P(EXTClipCullDistanceForVertexShaderTest,CompileFailsWithExtensionWithoutPragma)354 TEST_P(EXTClipCullDistanceForVertexShaderTest, CompileFailsWithExtensionWithoutPragma)
355 {
356     SetExtensionEnable(true);
357     InitializeCompiler();
358     EXPECT_FALSE(TestShaderCompile(""));
359 }
360 
361 #if defined(ANGLE_ENABLE_VULKAN)
362 // With extension flag and extension directive, compiling using TranslatorVulkan succeeds.
TEST_P(EXTClipCullDistanceForVertexShaderTest,CompileSucceedsVulkan)363 TEST_P(EXTClipCullDistanceForVertexShaderTest, CompileSucceedsVulkan)
364 {
365     SetExtensionEnable(true);
366 
367     mResources.MaxClipDistances                = 8;
368     mResources.MaxCullDistances                = 8;
369     mResources.MaxCombinedClipAndCullDistances = 8;
370 
371     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
372     EXPECT_TRUE(TestShaderCompile(EXTPragma));
373     EXPECT_FALSE(TestShaderCompile(""));
374     EXPECT_TRUE(TestShaderCompile(EXTPragma));
375     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
376     EXPECT_TRUE(TestShaderCompile(ANGLEPragma));
377     EXPECT_FALSE(TestShaderCompile(""));
378     EXPECT_TRUE(TestShaderCompile(ANGLEPragma));
379 }
380 #endif
381 
382 // Extension flag is required to compile properly. Expect failure when it is
383 // not present.
TEST_P(EXTClipCullDistanceForFragmentShaderTest,CompileFailsWithoutExtension)384 TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileFailsWithoutExtension)
385 {
386     SetExtensionEnable(false);
387     InitializeCompiler();
388     EXPECT_FALSE(TestShaderCompile(EXTPragma));
389     InitializeCompiler();
390     EXPECT_FALSE(TestShaderCompile(ANGLEPragma));
391 }
392 
393 // Extension directive is required to compile properly. Expect failure when
394 // it is not present.
TEST_P(EXTClipCullDistanceForFragmentShaderTest,CompileFailsWithExtensionWithoutPragma)395 TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileFailsWithExtensionWithoutPragma)
396 {
397     SetExtensionEnable(true);
398     InitializeCompiler();
399     EXPECT_FALSE(TestShaderCompile(""));
400 }
401 
402 #if defined(ANGLE_ENABLE_VULKAN)
403 // With extension flag and extension directive, compiling using TranslatorVulkan succeeds.
TEST_P(EXTClipCullDistanceForFragmentShaderTest,CompileSucceedsVulkan)404 TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileSucceedsVulkan)
405 {
406     SetExtensionEnable(true);
407 
408     mResources.MaxClipDistances                = 8;
409     mResources.MaxCullDistances                = 8;
410     mResources.MaxCombinedClipAndCullDistances = 8;
411 
412     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
413     EXPECT_TRUE(TestShaderCompile(EXTPragma));
414     EXPECT_FALSE(TestShaderCompile(""));
415     EXPECT_TRUE(TestShaderCompile(EXTPragma));
416     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
417     EXPECT_TRUE(TestShaderCompile(ANGLEPragma));
418     EXPECT_FALSE(TestShaderCompile(""));
419     EXPECT_TRUE(TestShaderCompile(ANGLEPragma));
420 }
421 
422 class EXTClipCullDistanceForVertexShaderCompileFailureTest
423     : public EXTClipCullDistanceForVertexShaderTest
424 {};
425 
426 class EXTClipCullDistanceForFragmentShaderCompileFailureTest
427     : public EXTClipCullDistanceForFragmentShaderTest
428 {};
429 
430 class EXTClipCullDistanceForComputeShaderCompileFailureTest
431     : public EXTClipCullDistanceForComputeShaderTest
432 {};
433 
TEST_P(EXTClipCullDistanceForVertexShaderCompileFailureTest,CompileFails)434 TEST_P(EXTClipCullDistanceForVertexShaderCompileFailureTest, CompileFails)
435 {
436     SetExtensionEnable(true);
437 
438     mResources.MaxClipDistances                = 8;
439     mResources.MaxCullDistances                = 8;
440     mResources.MaxCombinedClipAndCullDistances = 8;
441 
442     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
443     EXPECT_FALSE(TestShaderCompile(EXTPragma));
444     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
445     EXPECT_FALSE(TestShaderCompile(ANGLEPragma));
446 }
447 
TEST_P(EXTClipCullDistanceForFragmentShaderCompileFailureTest,CompileFails)448 TEST_P(EXTClipCullDistanceForFragmentShaderCompileFailureTest, CompileFails)
449 {
450     SetExtensionEnable(true);
451 
452     mResources.MaxClipDistances                = 8;
453     mResources.MaxCullDistances                = 8;
454     mResources.MaxCombinedClipAndCullDistances = 8;
455 
456     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
457     EXPECT_FALSE(TestShaderCompile(EXTPragma));
458     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
459     EXPECT_FALSE(TestShaderCompile(ANGLEPragma));
460 }
461 
462 // Test that the clip and cull distance built-ins are not defined for compute shaders.
TEST_P(EXTClipCullDistanceForComputeShaderCompileFailureTest,CompileFails)463 TEST_P(EXTClipCullDistanceForComputeShaderCompileFailureTest, CompileFails)
464 {
465     SetExtensionEnable(true);
466 
467     mResources.MaxClipDistances                = 8;
468     mResources.MaxCullDistances                = 8;
469     mResources.MaxCombinedClipAndCullDistances = 8;
470 
471     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
472     EXPECT_FALSE(TestShaderCompile(EXTPragma));
473     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
474     EXPECT_FALSE(TestShaderCompile(ANGLEPragma));
475 }
476 #endif
477 
478 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
479                          EXTClipCullDistanceForVertexShaderTest,
480                          Combine(Values(SH_GLES3_SPEC),
481                                  Values(sh::ESSLVersion300),
482                                  Values(VertexShaderCompileSucceeds1,
483                                         VertexShaderCompileSucceeds2)));
484 
485 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
486                          EXTClipCullDistanceForFragmentShaderTest,
487                          Combine(Values(SH_GLES3_SPEC),
488                                  Values(sh::ESSLVersion300),
489                                  Values(FragmentShaderCompileSucceeds1,
490                                         FragmentShaderCompileSucceeds2)));
491 
492 // The corresponding TEST_Ps are defined only when ANGLE_ENABLE_VULKAN is
493 // defined.
494 #if defined(ANGLE_ENABLE_VULKAN)
495 INSTANTIATE_TEST_SUITE_P(IncorrectESSL100Shaders,
496                          EXTClipCullDistanceForVertexShaderCompileFailureTest,
497                          Combine(Values(SH_GLES2_SPEC),
498                                  Values(sh::ESSLVersion100),
499                                  Values(VertexShaderCompileFails5)));
500 
501 INSTANTIATE_TEST_SUITE_P(IncorrectESSL300Shaders,
502                          EXTClipCullDistanceForVertexShaderCompileFailureTest,
503                          Combine(Values(SH_GLES3_SPEC),
504                                  Values(sh::ESSLVersion300),
505                                  Values(VertexShaderCompileFails1,
506                                         VertexShaderCompileFails2,
507                                         VertexShaderCompileFails3,
508                                         VertexShaderCompileFails4)));
509 
510 INSTANTIATE_TEST_SUITE_P(IncorrectESSL300Shaders,
511                          EXTClipCullDistanceForFragmentShaderCompileFailureTest,
512                          Combine(Values(SH_GLES3_SPEC),
513                                  Values(sh::ESSLVersion300),
514                                  Values(FragmentShaderCompileFails1,
515                                         FragmentShaderCompileFails2,
516                                         FragmentShaderCompileFails3,
517                                         FragmentShaderCompileFails4,
518                                         FragmentShaderCompileFails5)));
519 
520 INSTANTIATE_TEST_SUITE_P(IncorrectESSL310Shaders,
521                          EXTClipCullDistanceForComputeShaderCompileFailureTest,
522                          Combine(Values(SH_GLES3_1_SPEC),
523                                  Values(sh::ESSLVersion310),
524                                  Values(ComputeShaderCompileFails1,
525                                         ComputeShaderCompileFails2,
526                                         ComputeShaderCompileFails3,
527                                         ComputeShaderCompileFails4,
528                                         ComputeShaderCompileFails5,
529                                         ComputeShaderCompileFails6)));
530 #endif
531 
532 }  // anonymous namespace
533