• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Shader using gl_ClipDistance and gl_CullDistance
17 const char VertexShaderCompileSucceeds1[] =
18     R"(
19     uniform vec4 uPlane;
20 
21     in vec4 aPosition;
22 
23     void main()
24     {
25         gl_Position = aPosition;
26         gl_ClipDistance[1] = dot(aPosition, uPlane);
27         gl_CullDistance[1] = dot(aPosition, uPlane);
28     })";
29 
30 // Shader redeclares gl_ClipDistance and gl_CullDistance
31 const char VertexShaderCompileSucceeds2[] =
32     R"(
33     uniform vec4 uPlane;
34 
35     in vec4 aPosition;
36 
37     out highp float gl_ClipDistance[4];
38     out highp float gl_CullDistance[4];
39 
40     void main()
41     {
42         gl_Position = aPosition;
43         gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
44         gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
45         gl_CullDistance[gl_MaxCullDistances - 6 + 1] = dot(aPosition, uPlane);
46         gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)] = dot(aPosition, uPlane);
47     })";
48 
49 #if defined(ANGLE_ENABLE_VULKAN)
50 // Shader using gl_ClipDistance and gl_CullDistance
51 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
52 const char VertexShaderCompileFails1[] =
53     R"(
54     uniform vec4 uPlane;
55 
56     in vec4 aPosition;
57 
58     void main()
59     {
60         gl_Position = aPosition;
61         gl_ClipDistance[5] = dot(aPosition, uPlane);
62         gl_CullDistance[4] = dot(aPosition, uPlane);
63     })";
64 
65 // Shader redeclares gl_ClipDistance and gl_CullDistance
66 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
67 const char VertexShaderCompileFails2[] =
68     R"(
69     uniform vec4 uPlane;
70 
71     in vec4 aPosition;
72 
73     out highp float gl_ClipDistance[5];
74     out highp float gl_CullDistance[4];
75 
76     void main()
77     {
78         gl_Position = aPosition;
79         gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
80         gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
81         gl_CullDistance[gl_MaxCullDistances - 6 + 1] = dot(aPosition, uPlane);
82         gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)] = dot(aPosition, uPlane);
83     })";
84 
85 // Shader redeclares gl_ClipDistance
86 // But, the array size is greater than gl_MaxClipDistances
87 const char VertexShaderCompileFails3[] =
88     R"(
89     uniform vec4 uPlane;
90 
91     in vec4 aPosition;
92 
93     out highp float gl_ClipDistance[gl_MaxClipDistances + 1];
94 
95     void main()
96     {
97         gl_Position = aPosition;
98         gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
99         gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
100     })";
101 
102 // Access gl_CullDistance with integral constant index
103 // But, the index is greater than gl_MaxCullDistances
104 const char VertexShaderCompileFails4[] =
105     R"(
106     uniform vec4 uPlane;
107 
108     in vec4 aPosition;
109 
110     void main()
111     {
112         gl_Position = aPosition;
113         gl_CullDistance[gl_MaxCullDistances] = dot(aPosition, uPlane);
114     })";
115 
116 const char VertexShaderCompileFails5[] =
117     R"(
118     uniform vec4 uPlane;
119 
120     attribute vec4 aPosition;
121 
122     void main()
123     {
124         gl_Position = aPosition;
125         gl_CullDistance[0] = 0.0;
126     })";
127 
128 const char VertexShaderCompileFailes6[] =
129     R"(
130     uniform vec4 uPlane;
131 
132     attribute vec4 aPosition;
133 
134     varying float gl_ClipDistance[1];
135 
136     void main()
137     {
138         gl_Position = aPosition;
139         gl_ClipDistance[0] = 0.0;
140     })";
141 #endif
142 
143 // Shader using gl_ClipDistance and gl_CullDistance
144 const char FragmentShaderCompileSucceeds1[] =
145     R"(
146     out highp vec4 fragColor;
147 
148     void main()
149     {
150         fragColor = vec4(gl_ClipDistance[0], gl_CullDistance[0], 0, 1);
151     })";
152 
153 // Shader redeclares gl_ClipDistance and gl_CullDistance
154 const char FragmentShaderCompileSucceeds2[] =
155     R"(
156     in highp float gl_ClipDistance[4];
157     in highp float gl_CullDistance[4];
158 
159     in highp vec4 aPosition;
160 
161     out highp vec4 fragColor;
162 
163     void main()
164     {
165         fragColor.x = gl_ClipDistance[gl_MaxClipDistances - 6 + 1];
166         fragColor.y = gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)];
167         fragColor.z = gl_CullDistance[gl_MaxCullDistances - 6 + 1];
168         fragColor.w = gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)];
169     })";
170 
171 #if defined(ANGLE_ENABLE_VULKAN)
172 // Shader using gl_ClipDistance and gl_CullDistance
173 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
174 const char FragmentShaderCompileFails1[] =
175     R"(
176     out highp vec4 fragColor;
177 
178     void main()
179     {
180         fragColor = vec4(gl_ClipDistance[4], gl_CullDistance[5], 0, 1);
181     })";
182 
183 // Shader redeclares gl_ClipDistance and gl_CullDistance
184 // But, the sum of the sizes is greater than gl_MaxCombinedClipAndCullDistances
185 const char FragmentShaderCompileFails2[] =
186     R"(
187     in highp float gl_ClipDistance[5];
188     in highp float gl_CullDistance[4];
189 
190     in highp vec4 aPosition;
191 
192     out highp vec4 fragColor;
193 
194     void main()
195     {
196         fragColor.x = gl_ClipDistance[gl_MaxClipDistances - 6 + 1];
197         fragColor.y = gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)];
198         fragColor.z = gl_CullDistance[gl_MaxCullDistances - 6 + 1];
199         fragColor.w = gl_CullDistance[gl_MaxCullDistances - int(aPosition.x)];
200     })";
201 
202 // In fragment shader, writing to gl_ClipDistance should be denied.
203 const char FragmentShaderCompileFails3[] =
204     R"(
205     out highp vec4 fragColor;
206 
207     void main()
208     {
209         gl_ClipDistance[0] = 0.0f;
210         fragColor = vec4(1, gl_ClipDistance[0], 0, 1);
211     })";
212 
213 // In fragment shader, writing to gl_CullDistance should be denied even if redeclaring it with the
214 // array size
215 const char FragmentShaderCompileFails4[] =
216     R"(
217     out highp vec4 fragColor;
218 
219     in highp float gl_CullDistance[1];
220 
221     void main()
222     {
223         gl_CullDistance[0] = 0.0f;
224         fragColor = vec4(1, gl_CullDistance[0], 0, 1);
225     })";
226 
227 // Accessing to gl_Clip/CullDistance with non-const index should be denied if the size of
228 // gl_Clip/CullDistance is not decided.
229 const char FragmentShaderCompileFails5[] =
230     R"(
231     out highp vec4 fragColor;
232 
233     void main()
234     {
235         medium float color[3];
236         for(int i = 0 ; i < 3 ; i++)
237         {
238             color[i] = gl_CullDistance[i];
239         }
240         fragColor = vec4(color[0], color[1], color[2], 1.0f);
241     })";
242 #endif
243 
244 class EXTClipCullDistanceTest : public sh::ShaderExtensionTest
245 {
246   public:
InitializeCompiler(ShShaderOutput shaderOutputType,GLenum shaderType)247     void InitializeCompiler(ShShaderOutput shaderOutputType, GLenum shaderType)
248     {
249         DestroyCompiler();
250 
251         mCompiler = sh::ConstructCompiler(shaderType, testing::get<0>(GetParam()), shaderOutputType,
252                                           &mResources);
253         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
254     }
255 
TestShaderCompile(const char * pragma)256     testing::AssertionResult TestShaderCompile(const char *pragma)
257     {
258         const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
259                                        testing::get<2>(GetParam())};
260         bool success = sh::Compile(mCompiler, shaderStrings, 3, SH_VARIABLES | SH_OBJECT_CODE);
261         if (success)
262         {
263             return ::testing::AssertionSuccess() << "Compilation success";
264         }
265         return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
266     }
267 
SetExtensionEnable(bool enable)268     void SetExtensionEnable(bool enable)
269     {
270         // GL_APPLE_clip_distance is implicitly enabled when GL_EXT_clip_cull_distance is enabled
271 #if defined(ANGLE_ENABLE_VULKAN)
272         mResources.APPLE_clip_distance = enable;
273 #endif
274         mResources.EXT_clip_cull_distance = enable;
275     }
276 };
277 
278 class EXTClipCullDistanceForVertexShaderTest : public EXTClipCullDistanceTest
279 {
280   public:
InitializeCompiler()281     void InitializeCompiler() { InitializeCompiler(SH_GLSL_450_CORE_OUTPUT); }
InitializeCompiler(ShShaderOutput shaderOutputType)282     void InitializeCompiler(ShShaderOutput shaderOutputType)
283     {
284         EXTClipCullDistanceTest::InitializeCompiler(shaderOutputType, GL_VERTEX_SHADER);
285     }
286 };
287 
288 class EXTClipCullDistanceForFragmentShaderTest : public EXTClipCullDistanceTest
289 {
290   public:
InitializeCompiler()291     void InitializeCompiler() { InitializeCompiler(SH_GLSL_450_CORE_OUTPUT); }
InitializeCompiler(ShShaderOutput shaderOutputType)292     void InitializeCompiler(ShShaderOutput shaderOutputType)
293     {
294         EXTClipCullDistanceTest::InitializeCompiler(shaderOutputType, GL_FRAGMENT_SHADER);
295     }
296 };
297 
298 // Extension flag is required to compile properly. Expect failure when it is
299 // not present.
TEST_P(EXTClipCullDistanceForVertexShaderTest,CompileFailsWithoutExtension)300 TEST_P(EXTClipCullDistanceForVertexShaderTest, CompileFailsWithoutExtension)
301 {
302     SetExtensionEnable(false);
303     InitializeCompiler();
304     EXPECT_FALSE(TestShaderCompile(EXTPragma));
305 }
306 
307 // Extension directive is required to compile properly. Expect failure when
308 // it is not present.
TEST_P(EXTClipCullDistanceForVertexShaderTest,CompileFailsWithExtensionWithoutPragma)309 TEST_P(EXTClipCullDistanceForVertexShaderTest, CompileFailsWithExtensionWithoutPragma)
310 {
311     SetExtensionEnable(true);
312     InitializeCompiler();
313     EXPECT_FALSE(TestShaderCompile(""));
314 }
315 
316 #if defined(ANGLE_ENABLE_VULKAN)
317 // With extension flag and extension directive, compiling using TranslatorVulkan succeeds.
TEST_P(EXTClipCullDistanceForVertexShaderTest,CompileSucceedsVulkan)318 TEST_P(EXTClipCullDistanceForVertexShaderTest, CompileSucceedsVulkan)
319 {
320     SetExtensionEnable(true);
321 
322     mResources.MaxClipDistances                = 8;
323     mResources.MaxCullDistances                = 8;
324     mResources.MaxCombinedClipAndCullDistances = 8;
325 
326     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
327     EXPECT_TRUE(TestShaderCompile(EXTPragma));
328     EXPECT_FALSE(TestShaderCompile(""));
329     EXPECT_TRUE(TestShaderCompile(EXTPragma));
330 }
331 #endif
332 
333 // Extension flag is required to compile properly. Expect failure when it is
334 // not present.
TEST_P(EXTClipCullDistanceForFragmentShaderTest,CompileFailsWithoutExtension)335 TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileFailsWithoutExtension)
336 {
337     SetExtensionEnable(false);
338     InitializeCompiler();
339     EXPECT_FALSE(TestShaderCompile(EXTPragma));
340 }
341 
342 // Extension directive is required to compile properly. Expect failure when
343 // it is not present.
TEST_P(EXTClipCullDistanceForFragmentShaderTest,CompileFailsWithExtensionWithoutPragma)344 TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileFailsWithExtensionWithoutPragma)
345 {
346     SetExtensionEnable(true);
347     InitializeCompiler();
348     EXPECT_FALSE(TestShaderCompile(""));
349 }
350 
351 #if defined(ANGLE_ENABLE_VULKAN)
352 // With extension flag and extension directive, compiling using TranslatorVulkan succeeds.
353 //
354 // Test is disabled due to translation bug.  http://anglebug.com/5747
TEST_P(EXTClipCullDistanceForFragmentShaderTest,DISABLED_CompileSucceedsVulkan)355 TEST_P(EXTClipCullDistanceForFragmentShaderTest, DISABLED_CompileSucceedsVulkan)
356 {
357     SetExtensionEnable(true);
358 
359     mResources.MaxClipDistances                = 8;
360     mResources.MaxCullDistances                = 8;
361     mResources.MaxCombinedClipAndCullDistances = 8;
362 
363     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
364     EXPECT_TRUE(TestShaderCompile(EXTPragma));
365     EXPECT_FALSE(TestShaderCompile(""));
366     EXPECT_TRUE(TestShaderCompile(EXTPragma));
367 }
368 
369 class EXTClipCullDistanceForVertexShaderCompileFailureTest
370     : public EXTClipCullDistanceForVertexShaderTest
371 {};
372 
373 class EXTClipCullDistanceForFragmentShaderCompileFailureTest
374     : public EXTClipCullDistanceForFragmentShaderTest
375 {};
376 
TEST_P(EXTClipCullDistanceForVertexShaderCompileFailureTest,CompileFails)377 TEST_P(EXTClipCullDistanceForVertexShaderCompileFailureTest, CompileFails)
378 {
379     SetExtensionEnable(true);
380 
381     mResources.MaxClipDistances                = 8;
382     mResources.MaxCullDistances                = 8;
383     mResources.MaxCombinedClipAndCullDistances = 8;
384 
385     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
386     EXPECT_FALSE(TestShaderCompile(EXTPragma));
387 }
388 
TEST_P(EXTClipCullDistanceForFragmentShaderCompileFailureTest,CompileFails)389 TEST_P(EXTClipCullDistanceForFragmentShaderCompileFailureTest, CompileFails)
390 {
391     SetExtensionEnable(true);
392 
393     mResources.MaxClipDistances                = 8;
394     mResources.MaxCullDistances                = 8;
395     mResources.MaxCombinedClipAndCullDistances = 8;
396 
397     InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
398     EXPECT_FALSE(TestShaderCompile(EXTPragma));
399 }
400 #endif
401 
402 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
403                          EXTClipCullDistanceForVertexShaderTest,
404                          Combine(Values(SH_GLES3_SPEC),
405                                  Values(sh::ESSLVersion300),
406                                  Values(VertexShaderCompileSucceeds1,
407                                         VertexShaderCompileSucceeds2)));
408 
409 INSTANTIATE_TEST_SUITE_P(CorrectESSL300Shaders,
410                          EXTClipCullDistanceForFragmentShaderTest,
411                          Combine(Values(SH_GLES3_SPEC),
412                                  Values(sh::ESSLVersion300),
413                                  Values(FragmentShaderCompileSucceeds1,
414                                         FragmentShaderCompileSucceeds2)));
415 
416 // The corresponding TEST_Ps are defined only when ANGLE_ENABLE_VULKAN is
417 // defined.
418 #if defined(ANGLE_ENABLE_VULKAN)
419 INSTANTIATE_TEST_SUITE_P(IncorrectESSL100Shaders,
420                          EXTClipCullDistanceForVertexShaderCompileFailureTest,
421                          Combine(Values(SH_GLES2_SPEC),
422                                  Values(sh::ESSLVersion100),
423                                  Values(VertexShaderCompileFails5, VertexShaderCompileFailes6)));
424 
425 INSTANTIATE_TEST_SUITE_P(IncorrectESSL300Shaders,
426                          EXTClipCullDistanceForVertexShaderCompileFailureTest,
427                          Combine(Values(SH_GLES3_SPEC),
428                                  Values(sh::ESSLVersion300),
429                                  Values(VertexShaderCompileFails1,
430                                         VertexShaderCompileFails2,
431                                         VertexShaderCompileFails3,
432                                         VertexShaderCompileFails4)));
433 
434 INSTANTIATE_TEST_SUITE_P(IncorrectESSL300Shaders,
435                          EXTClipCullDistanceForFragmentShaderCompileFailureTest,
436                          Combine(Values(SH_GLES3_SPEC),
437                                  Values(sh::ESSLVersion300),
438                                  Values(FragmentShaderCompileFails1,
439                                         FragmentShaderCompileFails2,
440                                         FragmentShaderCompileFails3,
441                                         FragmentShaderCompileFails4,
442                                         FragmentShaderCompileFails5)));
443 #endif
444 
445 }  // anonymous namespace
446