• 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 // 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