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 // APPLE_clip_distance_test.cpp:
7 // Test for APPLE_clip_distance
8 //
9
10 #include "tests/test_utils/ShaderExtensionTest.h"
11
12 namespace
13 {
14 const char EXTPragma[] = "#extension GL_APPLE_clip_distance : require\n";
15
16 // Shader using gl_ClipDistance
17 const char ESSL100_APPLEClipDistanceShader1[] =
18 R"(
19 uniform vec4 uPlane;
20
21 attribute vec4 aPosition;
22
23 void main()
24 {
25 gl_Position = aPosition;
26 gl_ClipDistance[1] = dot(aPosition, uPlane);
27 })";
28
29 // Shader redeclares gl_ClipDistance
30 const char ESSL100_APPLEClipDistanceShader2[] =
31 R"(
32 uniform vec4 uPlane;
33
34 attribute vec4 aPosition;
35
36 varying highp float gl_ClipDistance[4];
37
38 void main()
39 {
40 gl_Position = aPosition;
41 gl_ClipDistance[gl_MaxClipDistances - 6 + 1] = dot(aPosition, uPlane);
42 gl_ClipDistance[gl_MaxClipDistances - int(aPosition.x)] = dot(aPosition, uPlane);
43 })";
44
45 class APPLEClipDistanceTest : public sh::ShaderExtensionTest
46 {
47 public:
InitializeCompiler()48 void InitializeCompiler() { InitializeCompiler(SH_GLSL_130_OUTPUT); }
InitializeCompiler(ShShaderOutput shaderOutputType)49 void InitializeCompiler(ShShaderOutput shaderOutputType)
50 {
51 DestroyCompiler();
52
53 mCompiler = sh::ConstructCompiler(GL_VERTEX_SHADER, testing::get<0>(GetParam()),
54 shaderOutputType, &mResources);
55 ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
56 }
57
TestShaderCompile(const char * pragma)58 testing::AssertionResult TestShaderCompile(const char *pragma)
59 {
60 const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
61 testing::get<2>(GetParam())};
62 bool success = sh::Compile(mCompiler, shaderStrings, 3, SH_VARIABLES | SH_OBJECT_CODE);
63 if (success)
64 {
65 return ::testing::AssertionSuccess() << "Compilation success";
66 }
67 return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
68 }
69 };
70
71 // Extension flag is required to compile properly. Expect failure when it is
72 // not present.
TEST_P(APPLEClipDistanceTest,CompileFailsWithoutExtension)73 TEST_P(APPLEClipDistanceTest, CompileFailsWithoutExtension)
74 {
75 mResources.APPLE_clip_distance = 0;
76 InitializeCompiler();
77 EXPECT_FALSE(TestShaderCompile(EXTPragma));
78 }
79
80 // Extension directive is required to compile properly. Expect failure when
81 // it is not present.
TEST_P(APPLEClipDistanceTest,CompileFailsWithExtensionWithoutPragma)82 TEST_P(APPLEClipDistanceTest, CompileFailsWithExtensionWithoutPragma)
83 {
84 mResources.APPLE_clip_distance = 1;
85 InitializeCompiler();
86 EXPECT_FALSE(TestShaderCompile(""));
87 }
88
89 // With extension flag and extension directive, compiling succeeds.
90 // Also test that the extension directive state is reset correctly.
TEST_P(APPLEClipDistanceTest,CompileSucceedsWithExtensionAndPragma)91 TEST_P(APPLEClipDistanceTest, CompileSucceedsWithExtensionAndPragma)
92 {
93 mResources.APPLE_clip_distance = 1;
94 mResources.MaxClipDistances = 8;
95 InitializeCompiler();
96 EXPECT_TRUE(TestShaderCompile(EXTPragma));
97 // Test reset functionality.
98 EXPECT_FALSE(TestShaderCompile(""));
99 EXPECT_TRUE(TestShaderCompile(EXTPragma));
100 }
101
102 #if defined(ANGLE_ENABLE_VULKAN)
103 // With extension flag and extension directive, compiling using TranslatorVulkan succeeds.
TEST_P(APPLEClipDistanceTest,CompileSucceedsVulkan)104 TEST_P(APPLEClipDistanceTest, CompileSucceedsVulkan)
105 {
106 mResources.APPLE_clip_distance = 1;
107 mResources.MaxClipDistances = 8;
108
109 InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
110 EXPECT_TRUE(TestShaderCompile(EXTPragma));
111 }
112
113 // Test that the SPIR-V gen path can compile a shader when this extension is not supported.
TEST_P(APPLEClipDistanceTest,CompileSucceedsWithoutExtSupportVulkan)114 TEST_P(APPLEClipDistanceTest, CompileSucceedsWithoutExtSupportVulkan)
115 {
116 mResources.APPLE_clip_distance = 0;
117 mResources.MaxClipDistances = 0;
118 mResources.MaxCullDistances = 0;
119
120 InitializeCompiler(SH_SPIRV_VULKAN_OUTPUT);
121
122 constexpr char kNoClipCull[] = R"(
123 void main()
124 {
125 gl_Position = vec4(0);
126 })";
127 const char *shaderStrings[] = {kNoClipCull};
128
129 bool success = sh::Compile(mCompiler, shaderStrings, 1, SH_OBJECT_CODE);
130 if (success)
131 {
132 ::testing::AssertionSuccess() << "Compilation success";
133 }
134 else
135 {
136 ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
137 }
138
139 EXPECT_TRUE(success);
140 }
141 #endif
142
143 #if defined(ANGLE_ENABLE_METAL)
144 // With extension flag and extension directive, compiling using TranslatorMetal succeeds.
TEST_P(APPLEClipDistanceTest,CompileSucceedsMetal)145 TEST_P(APPLEClipDistanceTest, CompileSucceedsMetal)
146 {
147 mResources.APPLE_clip_distance = 1;
148 mResources.MaxClipDistances = 8;
149
150 InitializeCompiler(SH_SPIRV_METAL_OUTPUT);
151 EXPECT_TRUE(TestShaderCompile(EXTPragma));
152 }
153 #endif
154
155 // The SL #version 100 shaders that are correct work similarly
156 // in both GL2 and GL3, with and without the version string.
157 INSTANTIATE_TEST_SUITE_P(CorrectESSL100Shaders,
158 APPLEClipDistanceTest,
159 Combine(Values(SH_GLES2_SPEC),
160 Values(sh::ESSLVersion100),
161 Values(ESSL100_APPLEClipDistanceShader1,
162 ESSL100_APPLEClipDistanceShader2)));
163
164 } // anonymous namespace
165