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 // ClipDistanceTest.cpp: Test cases for GL_APPLE_clip_distance/GL_EXT_clip_cull_distance extension.
7 //
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 #include "util/EGLWindow.h"
12 #include "util/test_utils.h"
13
14 using namespace angle;
15
16 class ClipDistanceTest : public ANGLETest
17 {
18 protected:
ClipDistanceTest()19 ClipDistanceTest()
20 {
21 setWindowWidth(16);
22 setWindowHeight(16);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27 setConfigDepthBits(24);
28 }
29 };
30
31 // Query max clip distances and enable, disable states of clip distances
TEST_P(ClipDistanceTest,StateQuery)32 TEST_P(ClipDistanceTest, StateQuery)
33 {
34 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_APPLE_clip_distance"));
35
36 GLint maxClipDistances = 0;
37 glGetIntegerv(GL_MAX_CLIP_DISTANCES_APPLE, &maxClipDistances);
38
39 EXPECT_GL_NO_ERROR();
40 EXPECT_GE(maxClipDistances, 8);
41
42 GLboolean enabled = glIsEnabled(GL_CLIP_DISTANCE1_APPLE);
43 EXPECT_GL_NO_ERROR();
44 EXPECT_EQ(enabled, GL_FALSE);
45
46 glEnable(GL_CLIP_DISTANCE1_APPLE);
47 EXPECT_GL_NO_ERROR();
48 glEnable(GL_CLIP_DISTANCE7_APPLE);
49 EXPECT_GL_NO_ERROR();
50 enabled = glIsEnabled(GL_CLIP_DISTANCE1_APPLE);
51 EXPECT_EQ(enabled, GL_TRUE);
52
53 glDisable(GL_CLIP_DISTANCE1_APPLE);
54 EXPECT_GL_NO_ERROR();
55 enabled = glIsEnabled(GL_CLIP_DISTANCE1_APPLE);
56 EXPECT_EQ(enabled, GL_FALSE);
57
58 EXPECT_EQ(glIsEnabled(GL_CLIP_DISTANCE7_APPLE), GL_TRUE);
59 }
60
61 // Write to one gl_ClipDistance element
TEST_P(ClipDistanceTest,OneClipDistance)62 TEST_P(ClipDistanceTest, OneClipDistance)
63 {
64 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_APPLE_clip_distance"));
65
66 constexpr char kVS[] = R"(
67 #extension GL_APPLE_clip_distance : require
68
69 uniform vec4 u_plane;
70
71 attribute vec2 a_position;
72
73 void main()
74 {
75 gl_Position = vec4(a_position, 0.0, 1.0);
76
77 gl_ClipDistance[0] = dot(gl_Position, u_plane);
78 })";
79
80 ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
81 glLinkProgram(programRed);
82 glUseProgram(programRed);
83 ASSERT_GL_NO_ERROR();
84
85 glEnable(GL_CLIP_DISTANCE0_APPLE);
86
87 // Clear to blue
88 glClearColor(0, 0, 1, 1);
89 glClear(GL_COLOR_BUFFER_BIT);
90
91 // Draw full screen quad with color red
92 glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
93 EXPECT_GL_NO_ERROR();
94 drawQuad(programRed, "a_position", 0);
95 EXPECT_GL_NO_ERROR();
96
97 // All pixels on the left of the plane x = -0.5 must be blue
98 for (int x = 0; x < getWindowWidth() / 4 - 1; ++x)
99 {
100 for (int y = 0; y < getWindowHeight(); ++y)
101 {
102 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::blue);
103 }
104 }
105
106 // All pixels on the right of the plane x = -0.5 must be red
107 for (int x = getWindowWidth() / 4 + 2; x < getWindowWidth(); ++x)
108 {
109 for (int y = 0; y < getWindowHeight(); ++y)
110 {
111 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
112 }
113 }
114
115 // Clear to green
116 glClearColor(0, 1, 0, 1);
117 glClear(GL_COLOR_BUFFER_BIT);
118
119 // Draw full screen quad with color red
120 glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
121 EXPECT_GL_NO_ERROR();
122 drawQuad(programRed, "a_position", 0);
123 EXPECT_GL_NO_ERROR();
124
125 // All pixels on the left of the plane x = -0.5 must be red
126 for (int x = 0; x < getWindowWidth() / 4 - 1; ++x)
127 {
128 for (int y = 0; y < getWindowHeight(); ++y)
129 {
130 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
131 }
132 }
133
134 // All pixels on the right of the plane x = -0.5 must be green
135 for (int x = getWindowWidth() / 4 + 2; x < getWindowWidth(); ++x)
136 {
137 for (int y = 0; y < getWindowHeight(); ++y)
138 {
139 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
140 }
141 }
142
143 // Disable GL_CLIP_DISTANCE
144 glDisable(GL_CLIP_DISTANCE0_APPLE);
145 drawQuad(programRed, "a_position", 0);
146
147 // All pixels must be red
148 for (int x = 0; x < getWindowWidth(); ++x)
149 {
150 for (int y = 0; y < getWindowHeight(); ++y)
151 {
152 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
153 }
154 }
155 }
156
157 // Write to 3 clip distances
TEST_P(ClipDistanceTest,ThreeClipDistances)158 TEST_P(ClipDistanceTest, ThreeClipDistances)
159 {
160 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_APPLE_clip_distance"));
161
162 constexpr char kVS[] = R"(
163 #extension GL_APPLE_clip_distance : require
164
165 uniform vec4 u_plane[3];
166
167 attribute vec2 a_position;
168
169 void main()
170 {
171 gl_Position = vec4(a_position, 0.0, 1.0);
172
173 gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
174 gl_ClipDistance[3] = dot(gl_Position, u_plane[1]);
175 gl_ClipDistance[7] = dot(gl_Position, u_plane[2]);
176 })";
177
178 ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
179 glLinkProgram(programRed);
180 glUseProgram(programRed);
181 ASSERT_GL_NO_ERROR();
182
183 // Enable 3 clip distances
184 glEnable(GL_CLIP_DISTANCE0_APPLE);
185 glEnable(GL_CLIP_DISTANCE3_APPLE);
186 glEnable(GL_CLIP_DISTANCE7_APPLE);
187 ASSERT_GL_NO_ERROR();
188
189 // Clear to blue
190 glClearColor(0, 0, 1, 1);
191 glClear(GL_COLOR_BUFFER_BIT);
192
193 // Draw full screen quad with color red
194 // x = -0.5
195 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
196 // x = 0.5
197 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
198 // x + y = 1
199 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
200 EXPECT_GL_NO_ERROR();
201 drawQuad(programRed, "a_position", 0);
202 EXPECT_GL_NO_ERROR();
203
204 // All pixels on the left of the plane x = -0.5 must be blue
205 for (int x = 0; x < getWindowWidth() / 4 - 1; ++x)
206 {
207 for (int y = 0; y < getWindowHeight(); ++y)
208 {
209 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::blue);
210 }
211 }
212
213 // All pixels on the right of the plane x = -0.5 must be red, except those in the upper right
214 // triangle
215 for (int x = getWindowWidth() / 4 + 2; x < getWindowWidth() / 2; ++x)
216 {
217 for (int y = 0; y < getWindowHeight(); ++y)
218 {
219 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
220 }
221 }
222
223 for (int y = 0; y < getWindowHeight(); ++y)
224 {
225 for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
226 {
227 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
228 {
229 // bottom left triangle clipped by x=0.5 plane
230 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
231 }
232 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
233 {
234 // upper right triangle plus right of x=0.5 plane
235 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::blue);
236 }
237 }
238 }
239
240 // Clear to green
241 glClearColor(0, 1, 0, 1);
242 glClear(GL_COLOR_BUFFER_BIT);
243
244 // Disable gl_ClipDistance[3]
245 glDisable(GL_CLIP_DISTANCE3_APPLE);
246
247 // Draw full screen quad with color red
248 EXPECT_GL_NO_ERROR();
249 drawQuad(programRed, "a_position", 0);
250 EXPECT_GL_NO_ERROR();
251
252 // All pixels on the left of the plane x = -0.5 must be green
253 for (int x = 0; x < getWindowWidth() / 4 - 1; ++x)
254 {
255 for (int y = 0; y < getWindowHeight(); ++y)
256 {
257 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
258 }
259 }
260
261 // All pixels on the right of the plane x = -0.5 must be red, except those in the upper right
262 // triangle
263 for (int x = getWindowWidth() / 4 + 2; x < getWindowWidth() / 2; ++x)
264 {
265 for (int y = 0; y < getWindowHeight(); ++y)
266 {
267 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
268 }
269 }
270
271 for (int y = 0; y < getWindowHeight(); ++y)
272 {
273 for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
274 {
275 if (x < getWindowWidth() * 3 / 2 - y - 1)
276 {
277 // bottom left triangle
278 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
279 }
280 else if (x > getWindowWidth() * 3 / 2 - y + 1)
281 {
282 // upper right triangle
283 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
284 }
285 }
286 }
287 }
288
289 // Redeclare gl_ClipDistance in shader with explitcit size, also use it in a global function
290 // outside main()
TEST_P(ClipDistanceTest,ThreeClipDistancesRedeclared)291 TEST_P(ClipDistanceTest, ThreeClipDistancesRedeclared)
292 {
293 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_APPLE_clip_distance"));
294
295 constexpr char kVS[] = R"(
296 #extension GL_APPLE_clip_distance : require
297
298 varying highp float gl_ClipDistance[3];
299
300 void computeClipDistances(in vec4 position, in vec4 plane[3])
301 {
302 gl_ClipDistance[0] = dot(position, plane[0]);
303 gl_ClipDistance[1] = dot(position, plane[1]);
304 gl_ClipDistance[2] = dot(position, plane[2]);
305 }
306
307 uniform vec4 u_plane[3];
308
309 attribute vec2 a_position;
310
311 void main()
312 {
313 gl_Position = vec4(a_position, 0.0, 1.0);
314
315 computeClipDistances(gl_Position, u_plane);
316 })";
317
318 ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
319 glLinkProgram(programRed);
320 glUseProgram(programRed);
321 ASSERT_GL_NO_ERROR();
322
323 // Enable 3 clip distances
324 glEnable(GL_CLIP_DISTANCE0_APPLE);
325 glEnable(GL_CLIP_DISTANCE1_APPLE);
326 glEnable(GL_CLIP_DISTANCE2_APPLE);
327 ASSERT_GL_NO_ERROR();
328
329 // Clear to blue
330 glClearColor(0, 0, 1, 1);
331 glClear(GL_COLOR_BUFFER_BIT);
332
333 // Draw full screen quad with color red
334 // x = -0.5
335 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
336 // x = 0.5
337 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
338 // x + y = 1
339 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
340 EXPECT_GL_NO_ERROR();
341 drawQuad(programRed, "a_position", 0);
342 EXPECT_GL_NO_ERROR();
343
344 // All pixels on the left of the plane x = -0.5 must be blue
345 for (int x = 0; x < getWindowWidth() / 4 - 1; ++x)
346 {
347 for (int y = 0; y < getWindowHeight(); ++y)
348 {
349 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::blue);
350 }
351 }
352
353 // All pixels on the right of the plane x = -0.5 must be red, except those in the upper right
354 // triangle
355 for (int x = getWindowWidth() / 4 + 2; x < getWindowWidth() / 2; ++x)
356 {
357 for (int y = 0; y < getWindowHeight(); ++y)
358 {
359 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
360 }
361 }
362
363 for (int y = 0; y < getWindowHeight(); ++y)
364 {
365 for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
366 {
367 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
368 {
369 // bottom left triangle clipped by x=0.5 plane
370 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
371 }
372 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
373 {
374 // upper right triangle plus right of x=0.5 plane
375 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::blue);
376 }
377 }
378 }
379 }
380
381 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
382 // tests should be run against.
383 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClipDistanceTest);
384