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 explicit 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 class ClipCullDistanceTest : public ClipDistanceTest
382 {};
383
384 // Query max clip distances and enable, disable states of clip distances
TEST_P(ClipCullDistanceTest,StateQuery)385 TEST_P(ClipCullDistanceTest, StateQuery)
386 {
387 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
388
389 GLint maxClipDistances = 0;
390 glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
391
392 EXPECT_GL_NO_ERROR();
393 EXPECT_GE(maxClipDistances, 8);
394
395 GLint maxCullDistances = 0;
396 glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
397
398 EXPECT_GL_NO_ERROR();
399 EXPECT_GE(maxCullDistances, 8);
400
401 GLint maxCombinedClipAndCullDistances = 0;
402 glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT, &maxCombinedClipAndCullDistances);
403
404 EXPECT_GL_NO_ERROR();
405 EXPECT_GE(maxCombinedClipAndCullDistances, 8);
406
407 GLboolean enabled = glIsEnabled(GL_CLIP_DISTANCE1_EXT);
408 EXPECT_GL_NO_ERROR();
409 EXPECT_EQ(enabled, GL_FALSE);
410
411 glEnable(GL_CLIP_DISTANCE1_EXT);
412 EXPECT_GL_NO_ERROR();
413 glEnable(GL_CLIP_DISTANCE7_EXT);
414 EXPECT_GL_NO_ERROR();
415 enabled = glIsEnabled(GL_CLIP_DISTANCE1_EXT);
416 EXPECT_EQ(enabled, GL_TRUE);
417
418 glDisable(GL_CLIP_DISTANCE1_EXT);
419 EXPECT_GL_NO_ERROR();
420 enabled = glIsEnabled(GL_CLIP_DISTANCE1_EXT);
421 EXPECT_EQ(enabled, GL_FALSE);
422
423 EXPECT_EQ(glIsEnabled(GL_CLIP_DISTANCE7_EXT), GL_TRUE);
424 }
425
426 // Check that the validation for EXT_clip_cull_distance extension is correct
427 // If gl_ClipDistance or gl_CullDistance is redeclared in some shader stages, the array size of the
428 // redeclared variables should match
TEST_P(ClipCullDistanceTest,SizeCheck)429 TEST_P(ClipCullDistanceTest, SizeCheck)
430 {
431 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
432
433 // Validate array size match of redeclared ClipDistance built-in
434 constexpr char kVSErrorClipDistance[] = R"(#version 300 es
435 #extension GL_EXT_clip_cull_distance : require
436
437 out highp float gl_ClipDistance[1];
438
439 uniform vec4 u_plane;
440
441 in vec2 a_position;
442
443 void main()
444 {
445 gl_Position = vec4(a_position, 0.0, 1.0);
446
447 gl_ClipDistance[0] = dot(gl_Position, u_plane);
448
449 gl_CullDistance[0] = dot(gl_Position, u_plane);
450 gl_CullDistance[1] = dot(gl_Position, u_plane);
451 })";
452
453 constexpr char kFSErrorClipDistance[] = R"(#version 300 es
454 #extension GL_EXT_clip_cull_distance : require
455 in highp float gl_ClipDistance[2];
456 precision highp float;
457 out vec4 my_FragColor;
458 void main()
459 {
460 my_FragColor = vec4(gl_ClipDistance[0], gl_ClipDistance[1], gl_CullDistance[0], 1.0f);
461 })";
462
463 GLProgram programClipDistance;
464 programClipDistance.makeRaster(kVSErrorClipDistance, kFSErrorClipDistance);
465 EXPECT_GL_FALSE(programClipDistance.valid());
466
467 // Validate array size match of redeclared CullDistance built-in
468 constexpr char kVSErrorCullDistance[] = R"(#version 300 es
469 #extension GL_EXT_clip_cull_distance : require
470
471 out highp float gl_CullDistance[1];
472
473 uniform vec4 u_plane;
474
475 in vec2 a_position;
476
477 void main()
478 {
479 gl_Position = vec4(a_position, 0.0, 1.0);
480
481 gl_CullDistance[0] = dot(gl_Position, u_plane);
482
483 gl_ClipDistance[0] = dot(gl_Position, u_plane);
484 gl_ClipDistance[1] = dot(gl_Position, u_plane);
485 })";
486
487 constexpr char kFSErrorCullDistance[] = R"(#version 300 es
488 #extension GL_EXT_clip_cull_distance : require
489 in highp float gl_CullDistance[2];
490 precision highp float;
491 out vec4 my_FragColor;
492 void main()
493 {
494 my_FragColor = vec4(gl_CullDistance[0], gl_CullDistance[1], gl_ClipDistance[0], 1.0f);
495 })";
496
497 GLProgram programCullDistance;
498 programCullDistance.makeRaster(kVSErrorCullDistance, kFSErrorCullDistance);
499 EXPECT_GL_FALSE(programCullDistance.valid());
500 }
501
502 // Write to one gl_ClipDistance element
TEST_P(ClipCullDistanceTest,OneClipDistance)503 TEST_P(ClipCullDistanceTest, OneClipDistance)
504 {
505 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
506
507 constexpr char kVS[] = R"(#version 300 es
508 #extension GL_EXT_clip_cull_distance : require
509
510 uniform vec4 u_plane;
511
512 in vec2 a_position;
513
514 void main()
515 {
516 gl_Position = vec4(a_position, 0.0, 1.0);
517
518 gl_ClipDistance[0] = dot(gl_Position, u_plane);
519 })";
520
521 ANGLE_GL_PROGRAM(programRed, kVS, essl3_shaders::fs::Red());
522 glLinkProgram(programRed);
523 glUseProgram(programRed);
524 ASSERT_GL_NO_ERROR();
525
526 glEnable(GL_CLIP_DISTANCE0_EXT);
527
528 // Clear to blue
529 glClearColor(0, 0, 1, 1);
530 glClear(GL_COLOR_BUFFER_BIT);
531
532 // Draw full screen quad with color red
533 glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
534 EXPECT_GL_NO_ERROR();
535 drawQuad(programRed, "a_position", 0);
536 EXPECT_GL_NO_ERROR();
537
538 // All pixels on the left of the plane x = -0.5 must be blue
539 GLuint x = 0;
540 GLuint y = 0;
541 GLuint width = getWindowWidth() / 4 - 1;
542 GLuint height = getWindowHeight();
543 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
544
545 // All pixels on the right of the plane x = -0.5 must be red
546 x = getWindowWidth() / 4 + 2;
547 y = 0;
548 width = getWindowWidth() - x;
549 height = getWindowHeight();
550 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
551
552 // Clear to green
553 glClearColor(0, 1, 0, 1);
554 glClear(GL_COLOR_BUFFER_BIT);
555
556 // Draw full screen quad with color red
557 glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
558 EXPECT_GL_NO_ERROR();
559 drawQuad(programRed, "a_position", 0);
560 EXPECT_GL_NO_ERROR();
561
562 // All pixels on the left of the plane x = -0.5 must be red
563 x = 0;
564 y = 0;
565 width = getWindowWidth() / 4 - 1;
566 height = getWindowHeight();
567 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
568
569 // All pixels on the right of the plane x = -0.5 must be green
570 x = getWindowWidth() / 4 + 2;
571 y = 0;
572 width = getWindowWidth() - x;
573 height = getWindowHeight();
574 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
575
576 // Disable GL_CLIP_DISTANCE
577 glDisable(GL_CLIP_DISTANCE0_EXT);
578 drawQuad(programRed, "a_position", 0);
579
580 // All pixels must be red
581 x = 0;
582 y = 0;
583 width = getWindowWidth();
584 height = getWindowHeight();
585 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
586 }
587
588 // Write to 3 clip distances
TEST_P(ClipCullDistanceTest,ThreeClipDistances)589 TEST_P(ClipCullDistanceTest, ThreeClipDistances)
590 {
591 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
592
593 constexpr char kVS[] = R"(#version 300 es
594 #extension GL_EXT_clip_cull_distance : require
595
596 uniform vec4 u_plane[3];
597
598 in vec2 a_position;
599
600 void main()
601 {
602 gl_Position = vec4(a_position, 0.0, 1.0);
603
604 gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
605 gl_ClipDistance[3] = dot(gl_Position, u_plane[1]);
606 gl_ClipDistance[7] = dot(gl_Position, u_plane[2]);
607 })";
608
609 ANGLE_GL_PROGRAM(programRed, kVS, essl3_shaders::fs::Red());
610 glLinkProgram(programRed);
611 glUseProgram(programRed);
612 ASSERT_GL_NO_ERROR();
613
614 // Enable 3 clip distances
615 glEnable(GL_CLIP_DISTANCE0_EXT);
616 glEnable(GL_CLIP_DISTANCE3_EXT);
617 glEnable(GL_CLIP_DISTANCE7_EXT);
618 ASSERT_GL_NO_ERROR();
619
620 // Clear to blue
621 glClearColor(0, 0, 1, 1);
622 glClear(GL_COLOR_BUFFER_BIT);
623
624 // Draw full screen quad with color red
625 // x = -0.5
626 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
627 // x = 0.5
628 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
629 // x + y = 1
630 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
631 EXPECT_GL_NO_ERROR();
632 drawQuad(programRed, "a_position", 0);
633 EXPECT_GL_NO_ERROR();
634
635 {
636 // All pixels on the left of the plane x = -0.5 must be blue
637 GLuint x = 0;
638 GLuint y = 0;
639 GLuint width = getWindowWidth() / 4 - 1;
640 GLuint height = getWindowHeight();
641 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
642
643 // All pixels on the right of the plane x = -0.5 must be red, except those in the upper
644 // right triangle
645 x = getWindowWidth() / 4 + 2;
646 y = 0;
647 width = getWindowWidth() / 2 - x;
648 height = getWindowHeight();
649 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
650 }
651
652 {
653 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
654 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
655 actualColors.data());
656 for (int y = 0; y < getWindowHeight(); ++y)
657 {
658 for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
659 {
660 const int currentPosition = y * getWindowHeight() + x;
661
662 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
663 {
664 // bottom left triangle clipped by x=0.5 plane
665 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
666 }
667 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
668 {
669 // upper right triangle plus right of x=0.5 plane
670 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
671 }
672 }
673 }
674 }
675
676 // Clear to green
677 glClearColor(0, 1, 0, 1);
678 glClear(GL_COLOR_BUFFER_BIT);
679
680 // Disable gl_ClipDistance[3]
681 glDisable(GL_CLIP_DISTANCE3_EXT);
682
683 // Draw full screen quad with color red
684 EXPECT_GL_NO_ERROR();
685 drawQuad(programRed, "a_position", 0);
686 EXPECT_GL_NO_ERROR();
687
688 // All pixels on the left of the plane x = -0.5 must be green
689 for (int x = 0; x < getWindowWidth() / 4 - 1; ++x)
690 {
691 for (int y = 0; y < getWindowHeight(); ++y)
692 {
693 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
694 }
695 }
696
697 {
698 // All pixels on the right of the plane x = -0.5 must be red, except those in the upper
699 // right triangle
700 GLuint x = getWindowWidth() / 4 + 2;
701 GLuint y = 0;
702 GLuint width = getWindowWidth() / 2 - x;
703 GLuint height = getWindowHeight();
704 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
705 }
706
707 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
708 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
709 actualColors.data());
710 for (int y = 0; y < getWindowHeight(); ++y)
711 {
712 for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
713 {
714 const int currentPosition = y * getWindowHeight() + x;
715
716 if (x < getWindowWidth() * 3 / 2 - y - 1)
717 {
718 // bottom left triangle
719 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
720 }
721 else if (x > getWindowWidth() * 3 / 2 - y + 1)
722 {
723 // upper right triangle
724 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
725 }
726 }
727 }
728 }
729
730 // Redeclare gl_ClipDistance in shader with explicit size, also use it in a global function
731 // outside main()
TEST_P(ClipCullDistanceTest,ThreeClipDistancesRedeclared)732 TEST_P(ClipCullDistanceTest, ThreeClipDistancesRedeclared)
733 {
734 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
735
736 constexpr char kVS[] = R"(#version 300 es
737 #extension GL_EXT_clip_cull_distance : require
738
739 out highp float gl_ClipDistance[3];
740
741 void computeClipDistances(in vec4 position, in vec4 plane[3])
742 {
743 gl_ClipDistance[0] = dot(position, plane[0]);
744 gl_ClipDistance[1] = dot(position, plane[1]);
745 gl_ClipDistance[2] = dot(position, plane[2]);
746 }
747
748 uniform vec4 u_plane[3];
749
750 in vec2 a_position;
751
752 void main()
753 {
754 gl_Position = vec4(a_position, 0.0, 1.0);
755
756 computeClipDistances(gl_Position, u_plane);
757 })";
758
759 ANGLE_GL_PROGRAM(programRed, kVS, essl3_shaders::fs::Red());
760 glLinkProgram(programRed);
761 glUseProgram(programRed);
762 ASSERT_GL_NO_ERROR();
763
764 // Enable 3 clip distances
765 glEnable(GL_CLIP_DISTANCE0_EXT);
766 glEnable(GL_CLIP_DISTANCE1_EXT);
767 glEnable(GL_CLIP_DISTANCE2_EXT);
768 ASSERT_GL_NO_ERROR();
769
770 // Clear to blue
771 glClearColor(0, 0, 1, 1);
772 glClear(GL_COLOR_BUFFER_BIT);
773
774 // Draw full screen quad with color red
775 // x = -0.5
776 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
777 // x = 0.5
778 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
779 // x + y = 1
780 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
781 EXPECT_GL_NO_ERROR();
782 drawQuad(programRed, "a_position", 0);
783 EXPECT_GL_NO_ERROR();
784
785 {
786 // All pixels on the left of the plane x = -0.5 must be blue
787 GLuint x = 0;
788 GLuint y = 0;
789 GLuint width = getWindowWidth() / 4 - 1;
790 GLuint height = getWindowHeight();
791 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
792
793 // All pixels on the right of the plane x = -0.5 must be red, except those in the upper
794 // right triangle
795 x = getWindowWidth() / 4 + 2;
796 y = 0;
797 width = getWindowWidth() / 2 - x;
798 height = getWindowHeight();
799 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
800 }
801
802 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
803 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
804 actualColors.data());
805 for (int y = 0; y < getWindowHeight(); ++y)
806 {
807 for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
808 {
809 const int currentPosition = y * getWindowHeight() + x;
810
811 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
812 {
813 // bottom left triangle clipped by x=0.5 plane
814 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
815 }
816 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
817 {
818 // upper right triangle plus right of x=0.5 plane
819 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
820 }
821 }
822 }
823 }
824
825 // Write to one gl_CullDistance element
TEST_P(ClipCullDistanceTest,OneCullDistance)826 TEST_P(ClipCullDistanceTest, OneCullDistance)
827 {
828 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
829
830 constexpr char kVS[] = R"(#version 300 es
831 #extension GL_EXT_clip_cull_distance : require
832
833 uniform vec4 u_plane;
834
835 in vec2 a_position;
836
837 void main()
838 {
839 gl_Position = vec4(a_position, 0.0, 1.0);
840
841 gl_CullDistance[0] = dot(gl_Position, u_plane);
842 })";
843
844 ANGLE_GL_PROGRAM(programRed, kVS, essl3_shaders::fs::Red());
845 glLinkProgram(programRed);
846 glUseProgram(programRed);
847 ASSERT_GL_NO_ERROR();
848
849 // Clear to blue
850 glClearColor(0, 0, 1, 1);
851 glClear(GL_COLOR_BUFFER_BIT);
852
853 // Draw full screen quad with color red
854 glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
855 EXPECT_GL_NO_ERROR();
856 drawQuad(programRed, "a_position", 0);
857 EXPECT_GL_NO_ERROR();
858
859 {
860 // All pixels must be red
861 GLuint x = 0;
862 GLuint y = 0;
863 GLuint width = getWindowWidth();
864 GLuint height = getWindowHeight();
865 EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
866 }
867
868 // Clear to green
869 glClearColor(0, 1, 0, 1);
870 glClear(GL_COLOR_BUFFER_BIT);
871
872 // Draw full screen quad with color red
873 glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 1, 0, 0);
874 EXPECT_GL_NO_ERROR();
875 drawQuad(programRed, "a_position", 0);
876 EXPECT_GL_NO_ERROR();
877
878 // All pixels on the plane y >= -x must be red
879 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
880 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
881 actualColors.data());
882 for (int x = 0; x < getWindowWidth(); ++x)
883 {
884 for (int y = 0; y < getWindowHeight(); ++y)
885 {
886 const int currentPosition = y * getWindowHeight() + x;
887
888 if ((x + y) >= 0)
889 {
890 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
891 }
892 else
893 {
894 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
895 }
896 }
897 }
898 }
899
900 // Write to 4 clip distances
TEST_P(ClipCullDistanceTest,FourClipDistances)901 TEST_P(ClipCullDistanceTest, FourClipDistances)
902 {
903 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
904
905 constexpr char kVS[] = R"(#version 300 es
906 #extension GL_EXT_clip_cull_distance : require
907
908 in vec2 a_position;
909 uniform vec4 u_plane[4];
910
911 void main()
912 {
913 gl_Position = vec4(a_position, 0.0, 1.0);
914
915 gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
916 gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
917 gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
918 gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
919 })";
920
921 ANGLE_GL_PROGRAM(programRed, kVS, essl3_shaders::fs::Red());
922 glUseProgram(programRed);
923 ASSERT_GL_NO_ERROR();
924
925 // Enable 3 clip distances
926 glEnable(GL_CLIP_DISTANCE0_EXT);
927 glEnable(GL_CLIP_DISTANCE2_EXT);
928 glEnable(GL_CLIP_DISTANCE3_EXT);
929 ASSERT_GL_NO_ERROR();
930
931 // Disable 1 clip distances
932 glDisable(GL_CLIP_DISTANCE1_EXT);
933 ASSERT_GL_NO_ERROR();
934
935 // Clear to blue
936 glClearColor(0, 0, 1, 1);
937 glClear(GL_COLOR_BUFFER_BIT);
938
939 constexpr unsigned int kNumVertices = 12;
940 const std::array<Vector3, kNumVertices> quadVertices = {
941 {Vector3(-1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f),
942 Vector3(1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, -1.0f, 0.0f),
943 Vector3(1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, -1.0f, 0.0f),
944 Vector3(-1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, 1.0f, 0.0f)}};
945
946 GLBuffer vertexBuffer;
947 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
948 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
949 GL_STATIC_DRAW);
950 ASSERT_GL_NO_ERROR();
951
952 GLint positionLocation = glGetAttribLocation(programRed, "a_position");
953 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
954 ASSERT_GL_NO_ERROR();
955
956 glEnableVertexAttribArray(positionLocation);
957 ASSERT_GL_NO_ERROR();
958
959 // Draw full screen quad and small size triangle with color red
960 // y <= 1.0f
961 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
962 // y >= 0.5f
963 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
964 // y >= 3x-0.5f
965 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
966 // y >= -3x-0.5f
967 glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
968 EXPECT_GL_NO_ERROR();
969
970 glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
971 EXPECT_GL_NO_ERROR();
972
973 const int windowWidth = getWindowWidth();
974 const int windowHeight = getWindowHeight();
975 auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
976 return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
977 };
978 auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
979 return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
980 };
981
982 // Only pixels in the triangle must be red
983 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
984 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
985 actualColors.data());
986 for (int x = 0; x < getWindowWidth(); ++x)
987 {
988 for (int y = 0; y < getWindowHeight(); ++y)
989 {
990 // The drawing method of Swiftshader and Native graphic card is different. So the
991 // compare function doesn't check the value on the line.
992 const int currentPosition = y * getWindowHeight() + x;
993
994 if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
995 {
996 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
997 }
998 else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
999 {
1000 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1001 }
1002 }
1003 }
1004 }
1005
1006 // Write to 4 cull distances
TEST_P(ClipCullDistanceTest,FourCullDistances)1007 TEST_P(ClipCullDistanceTest, FourCullDistances)
1008 {
1009 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance"));
1010
1011 // SwiftShader bug: http://anglebug.com/5451
1012 ANGLE_SKIP_TEST_IF(isSwiftshader());
1013
1014 constexpr char kVS[] = R"(#version 300 es
1015 #extension GL_EXT_clip_cull_distance : require
1016
1017 uniform vec4 u_plane[4];
1018
1019 in vec2 a_position;
1020
1021 void main()
1022 {
1023 gl_Position = vec4(a_position, 0.0, 1.0);
1024
1025 gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
1026 gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
1027 gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
1028 gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
1029 })";
1030
1031 ANGLE_GL_PROGRAM(programRed, kVS, essl3_shaders::fs::Red());
1032 glLinkProgram(programRed);
1033 glUseProgram(programRed);
1034 ASSERT_GL_NO_ERROR();
1035
1036 // Clear to blue
1037 glClearColor(0, 0, 1, 1);
1038 glClear(GL_COLOR_BUFFER_BIT);
1039
1040 constexpr unsigned int kNumVertices = 12;
1041 const std::array<Vector3, kNumVertices> quadVertices = {
1042 {Vector3(-1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f),
1043 Vector3(1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, -1.0f, 0.0f),
1044 Vector3(1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, -1.0f, 0.0f),
1045 Vector3(-1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, 1.0f, 0.0f)}};
1046
1047 GLBuffer vertexBuffer;
1048 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1049 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
1050 GL_STATIC_DRAW);
1051 ASSERT_GL_NO_ERROR();
1052
1053 GLint positionLocation = glGetAttribLocation(programRed, "a_position");
1054 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1055 ASSERT_GL_NO_ERROR();
1056
1057 glEnableVertexAttribArray(positionLocation);
1058 ASSERT_GL_NO_ERROR();
1059
1060 // Draw full screen quad and small size triangle with color red
1061 // y <= 1.0f
1062 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
1063 // y >= 0.5f
1064 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
1065 // y >= 3x-0.5f
1066 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
1067 // y >= -3x-0.5f
1068 glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
1069 EXPECT_GL_NO_ERROR();
1070
1071 glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
1072 EXPECT_GL_NO_ERROR();
1073
1074 // Only pixels in the triangle must be red
1075 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1076 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1077 actualColors.data());
1078 for (int x = 0; x < getWindowWidth(); ++x)
1079 {
1080 for (int y = 0; y < getWindowHeight(); ++y)
1081 {
1082 const int currentPosition = y * getWindowHeight() + x;
1083
1084 if (y > x || y >= -x + getWindowHeight() - 1)
1085 {
1086 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1087 }
1088 else
1089 {
1090 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1091 }
1092 }
1093 }
1094 }
1095
1096 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,ClipDistanceInteractWithGeometryShader)1097 TEST_P(ClipCullDistanceTest, ClipDistanceInteractWithGeometryShader)
1098 {
1099 // TODO: http://anglebug.com/5466
1100 // After implementing EXT_geometry_shader, EXT_clip_cull_distance should be additionally
1101 // implemented to support the geometry shader. And then, this skip can be removed.
1102 ANGLE_SKIP_TEST_IF(IsVulkan());
1103
1104 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance") ||
1105 !IsGLExtensionEnabled("GL_EXT_geometry_shader"));
1106
1107 constexpr char kVS[] = R"(#version 310 es
1108 #extension GL_EXT_clip_cull_distance : require
1109 #extension GL_EXT_geometry_shader : require
1110
1111 in vec2 a_position;
1112 uniform vec4 u_plane[4];
1113
1114 void main()
1115 {
1116 gl_Position = vec4(a_position, 0.0, 1.0);
1117
1118 gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
1119 gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
1120 gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
1121 gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
1122 })";
1123
1124 constexpr char kGS[] = R"(#version 310 es
1125 #extension GL_EXT_clip_cull_distance : require
1126 #extension GL_EXT_geometry_shader : require
1127
1128 layout (triangles) in;
1129 layout (triangle_strip, max_vertices = 3) out;
1130
1131 in gl_PerVertex {
1132 highp vec4 gl_Position;
1133 highp float gl_ClipDistance[];
1134 } gl_in[];
1135
1136 out gl_PerVertex {
1137 highp vec4 gl_Position;
1138 highp float gl_ClipDistance[];
1139 };
1140
1141 uniform vec4 u_plane[4];
1142
1143 void GetNewPosition(int i)
1144 {
1145 gl_Position = 2.0f * gl_in[i].gl_Position;
1146
1147 for (int index = 0 ; index < 4 ; index++)
1148 {
1149 if (gl_in[i].gl_ClipDistance[index] < 0.0f)
1150 {
1151 gl_ClipDistance[index] = dot(gl_Position, u_plane[index]);
1152 }
1153 }
1154 EmitVertex();
1155 }
1156
1157 void main()
1158 {
1159 for (int i = 0 ; i < 3 ; i++)
1160 {
1161 GetNewPosition(i);
1162 }
1163 EndPrimitive();
1164 })";
1165
1166 ANGLE_GL_PROGRAM_WITH_GS(programRed, kVS, kGS, essl31_shaders::fs::Red());
1167 glUseProgram(programRed);
1168 ASSERT_GL_NO_ERROR();
1169
1170 // Enable 3 clip distances
1171 glEnable(GL_CLIP_DISTANCE0_EXT);
1172 glEnable(GL_CLIP_DISTANCE2_EXT);
1173 glEnable(GL_CLIP_DISTANCE3_EXT);
1174 ASSERT_GL_NO_ERROR();
1175
1176 // Disable 1 clip distances
1177 glDisable(GL_CLIP_DISTANCE1_EXT);
1178 ASSERT_GL_NO_ERROR();
1179
1180 // Clear to blue
1181 glClearColor(0, 0, 1, 1);
1182 glClear(GL_COLOR_BUFFER_BIT);
1183
1184 constexpr unsigned int kNumVertices = 12;
1185 const std::array<Vector3, kNumVertices> quadVertices = {
1186 {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
1187 Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
1188 Vector3(0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f),
1189 Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, 0.5f, 0.0f)}};
1190
1191 GLBuffer vertexBuffer;
1192 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1193 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
1194 GL_STATIC_DRAW);
1195 ASSERT_GL_NO_ERROR();
1196
1197 GLint positionLocation = glGetAttribLocation(programRed, "a_position");
1198 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1199 ASSERT_GL_NO_ERROR();
1200
1201 glEnableVertexAttribArray(positionLocation);
1202 ASSERT_GL_NO_ERROR();
1203
1204 // Draw full screen quad and small size triangle with color red
1205 // y <= 1.0f
1206 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
1207 // y >= 0.5f
1208 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
1209 // y >= 3x-0.5f
1210 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
1211 // y >= -3x-0.5f
1212 glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
1213 EXPECT_GL_NO_ERROR();
1214
1215 glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
1216 EXPECT_GL_NO_ERROR();
1217
1218 const int windowWidth = getWindowWidth();
1219 const int windowHeight = getWindowHeight();
1220 auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
1221 return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
1222 };
1223 auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
1224 return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
1225 };
1226
1227 // Only pixels in the triangle must be red
1228 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1229 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1230 actualColors.data());
1231 for (int x = 0; x < getWindowWidth(); ++x)
1232 {
1233 for (int y = 0; y < getWindowHeight(); ++y)
1234 {
1235 // The drawing method of Swiftshader and Native graphic card is different. So the
1236 // compare function doesn't check the value on the line.
1237 const int currentPosition = y * getWindowHeight() + x;
1238
1239 if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
1240 {
1241 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1242 }
1243 else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
1244 {
1245 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1246 }
1247 }
1248 }
1249 }
1250
1251 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,CullDistanceInteractWithGeometryShader)1252 TEST_P(ClipCullDistanceTest, CullDistanceInteractWithGeometryShader)
1253 {
1254 // TODO: http://anglebug.com/5466
1255 // After implementing EXT_geometry_shader, EXT_clip_cull_distance should be additionally
1256 // implemented to support the geometry shader. And then, this skip can be removed.
1257 ANGLE_SKIP_TEST_IF(IsVulkan());
1258
1259 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clip_cull_distance") ||
1260 !IsGLExtensionEnabled("GL_EXT_geometry_shader"));
1261
1262 constexpr char kVS[] = R"(#version 310 es
1263 #extension GL_EXT_clip_cull_distance : require
1264 #extension GL_EXT_geometry_shader : require
1265
1266 in vec2 a_position;
1267 uniform vec4 u_plane[4];
1268
1269 void main()
1270 {
1271 gl_Position = vec4(a_position, 0.0, 1.0);
1272
1273 gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
1274 gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
1275 gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
1276 gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
1277 })";
1278
1279 constexpr char kGS[] = R"(#version 310 es
1280 #extension GL_EXT_clip_cull_distance : require
1281 #extension GL_EXT_geometry_shader : require
1282
1283 layout (triangles) in;
1284 layout (triangle_strip, max_vertices = 3) out;
1285
1286 in gl_PerVertex {
1287 highp vec4 gl_Position;
1288 highp float gl_CullDistance[];
1289 } gl_in[];
1290
1291 out gl_PerVertex {
1292 highp vec4 gl_Position;
1293 highp float gl_CullDistance[];
1294 };
1295
1296 uniform vec4 u_plane[4];
1297
1298 void GetNewPosition(int i)
1299 {
1300 gl_Position = 2.0f * gl_in[i].gl_Position;
1301
1302 for (int index = 0 ; index < 4 ; index++)
1303 {
1304 if (gl_in[i].gl_CullDistance[index] < 0.0f)
1305 {
1306 gl_CullDistance[index] = dot(gl_Position, u_plane[index]);
1307 }
1308 }
1309 EmitVertex();
1310 }
1311
1312 void main()
1313 {
1314 for (int i = 0 ; i < 3 ; i++)
1315 {
1316 GetNewPosition(i);
1317 }
1318 EndPrimitive();
1319 })";
1320
1321 ANGLE_GL_PROGRAM_WITH_GS(programRed, kVS, kGS, essl31_shaders::fs::Red());
1322 glUseProgram(programRed);
1323 ASSERT_GL_NO_ERROR();
1324
1325 // Clear to blue
1326 glClearColor(0, 0, 1, 1);
1327 glClear(GL_COLOR_BUFFER_BIT);
1328
1329 constexpr unsigned int kNumVertices = 12;
1330 const std::array<Vector3, kNumVertices> quadVertices = {
1331 {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
1332 Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
1333 Vector3(0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f),
1334 Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, 0.5f, 0.0f)}};
1335
1336 GLBuffer vertexBuffer;
1337 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1338 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
1339 GL_STATIC_DRAW);
1340 ASSERT_GL_NO_ERROR();
1341
1342 GLint positionLocation = glGetAttribLocation(programRed, "a_position");
1343 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1344 ASSERT_GL_NO_ERROR();
1345
1346 glEnableVertexAttribArray(positionLocation);
1347 ASSERT_GL_NO_ERROR();
1348
1349 // Draw full screen quad and small size triangle with color red
1350 // y <= 1.0f
1351 glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
1352 // y >= 0.5f
1353 glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
1354 // y >= 3x-0.5f
1355 glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
1356 // y >= -3x-0.5f
1357 glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
1358 EXPECT_GL_NO_ERROR();
1359
1360 glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
1361 EXPECT_GL_NO_ERROR();
1362
1363 // Only pixels in the triangle must be red
1364 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1365 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1366 actualColors.data());
1367 for (int x = 0; x < getWindowWidth(); ++x)
1368 {
1369 for (int y = 0; y < getWindowHeight(); ++y)
1370 {
1371 const int currentPosition = y * getWindowHeight() + x;
1372
1373 if (y > x || y >= -x + getWindowHeight() - 1)
1374 {
1375 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1376 }
1377 else
1378 {
1379 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1380 }
1381 }
1382 }
1383 }
1384
1385 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClipDistanceTest);
1386
1387 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClipCullDistanceTest);
1388 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(ClipCullDistanceTest);
1389