xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ClipDistanceTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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
7 // GL_APPLE_clip_distance / GL_EXT_clip_cull_distance / GL_ANGLE_clip_cull_distance extensions.
8 //
9 
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12 #include "util/EGLWindow.h"
13 #include "util/test_utils.h"
14 
15 using namespace angle;
16 
17 class ClipDistanceAPPLETest : public ANGLETest<>
18 {
19   protected:
ClipDistanceAPPLETest()20     ClipDistanceAPPLETest()
21     {
22         setWindowWidth(64);
23         setWindowHeight(64);
24         setConfigRedBits(8);
25         setConfigGreenBits(8);
26         setConfigBlueBits(8);
27         setConfigAlphaBits(8);
28         setConfigDepthBits(24);
29         setExtensionsEnabled(false);
30     }
31 };
32 
33 // Query max clip distances and enable, disable states of clip distances
TEST_P(ClipDistanceAPPLETest,StateQuery)34 TEST_P(ClipDistanceAPPLETest, StateQuery)
35 {
36     GLint maxClipDistances = 0;
37     glGetIntegerv(GL_MAX_CLIP_DISTANCES_APPLE, &maxClipDistances);
38     EXPECT_EQ(maxClipDistances, 0);
39     EXPECT_GL_ERROR(GL_INVALID_ENUM);
40 
41     auto assertState = [](GLenum pname, bool valid, bool expectedState) {
42         EXPECT_EQ(glIsEnabled(pname), valid ? expectedState : false);
43         EXPECT_GL_ERROR(valid ? GL_NO_ERROR : GL_INVALID_ENUM);
44 
45         GLboolean result = false;
46         glGetBooleanv(pname, &result);
47         EXPECT_EQ(result, valid ? expectedState : false);
48         EXPECT_GL_ERROR(valid ? GL_NO_ERROR : GL_INVALID_ENUM);
49     };
50 
51     for (size_t i = 0; i < 8; i++)
52     {
53         assertState(GL_CLIP_DISTANCE0_APPLE + i, false, false);
54 
55         glEnable(GL_CLIP_DISTANCE0_APPLE + i);
56         EXPECT_GL_ERROR(GL_INVALID_ENUM);
57 
58         assertState(GL_CLIP_DISTANCE0_APPLE + i, false, false);
59 
60         glDisable(GL_CLIP_DISTANCE0_APPLE + i);
61         EXPECT_GL_ERROR(GL_INVALID_ENUM);
62 
63         assertState(GL_CLIP_DISTANCE0_APPLE + i, false, false);
64     }
65 
66     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
67 
68     ASSERT_GL_NO_ERROR();
69 
70     glGetIntegerv(GL_MAX_CLIP_DISTANCES_APPLE, &maxClipDistances);
71     EXPECT_EQ(maxClipDistances, 8);
72     EXPECT_GL_NO_ERROR();
73 
74     for (size_t i = 0; i < 8; i++)
75     {
76         assertState(GL_CLIP_DISTANCE0_APPLE + i, true, false);
77 
78         glEnable(GL_CLIP_DISTANCE0_APPLE + i);
79         EXPECT_GL_NO_ERROR();
80 
81         assertState(GL_CLIP_DISTANCE0_APPLE + i, true, true);
82 
83         glDisable(GL_CLIP_DISTANCE0_APPLE + i);
84         EXPECT_GL_NO_ERROR();
85 
86         assertState(GL_CLIP_DISTANCE0_APPLE + i, true, false);
87     }
88 }
89 
90 // Check that gl_ClipDistance is not defined for fragment shaders
TEST_P(ClipDistanceAPPLETest,FragmentShader)91 TEST_P(ClipDistanceAPPLETest, FragmentShader)
92 {
93     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
94 
95     constexpr char kVS[] = R"(
96 #extension GL_APPLE_clip_distance : require
97 
98 void main()
99 {
100     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
101 
102     gl_ClipDistance[0] = gl_Position.w;
103 })";
104 
105     constexpr char kFS[] = R"(
106 #extension GL_APPLE_clip_distance : require
107 
108 void main()
109 {
110     gl_FragColor = vec4(gl_ClipDistance[0], 1.0, 1.0, 1.0);
111 })";
112 
113     GLProgram prg;
114     prg.makeRaster(kVS, kFS);
115     EXPECT_FALSE(prg.valid());
116 }
117 
118 // Check that gl_ClipDistance cannot be redeclared as a global
TEST_P(ClipDistanceAPPLETest,NotVarying)119 TEST_P(ClipDistanceAPPLETest, NotVarying)
120 {
121     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
122 
123     constexpr char kVS[] = R"(
124 #extension GL_APPLE_clip_distance : require
125 
126 highp float gl_ClipDistance[1];
127 
128 void main()
129 {
130     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
131 
132     gl_ClipDistance[0] = gl_Position.w;
133 })";
134 
135     GLProgram prg;
136     prg.makeRaster(kVS, essl1_shaders::fs::Red());
137     EXPECT_FALSE(prg.valid());
138 }
139 
140 // Check that gl_ClipDistance size cannot be undefined
TEST_P(ClipDistanceAPPLETest,UndefinedArraySize)141 TEST_P(ClipDistanceAPPLETest, UndefinedArraySize)
142 {
143     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
144 
145     constexpr char kVS[] = R"(
146 #extension GL_APPLE_clip_distance : require
147 
148 void main()
149 {
150     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
151     for (int i = 0; i < 8; i++)
152     {
153         gl_ClipDistance[i] = gl_Position.w;
154     }
155 })";
156 
157     GLProgram prg;
158     prg.makeRaster(kVS, essl1_shaders::fs::Red());
159     EXPECT_FALSE(prg.valid());
160 }
161 
162 // Check that gl_ClipDistance size cannot be more than maximum
TEST_P(ClipDistanceAPPLETest,OutOfRangeArraySize)163 TEST_P(ClipDistanceAPPLETest, OutOfRangeArraySize)
164 {
165     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
166 
167     GLint maxClipDistances = 0;
168     glGetIntegerv(GL_MAX_CLIP_DISTANCES_APPLE, &maxClipDistances);
169 
170     std::stringstream vsImplicit;
171     vsImplicit << R"(#extension GL_APPLE_clip_distance : require
172 void main()
173 {
174     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
175     gl_ClipDistance[)"
176                << maxClipDistances << R"(] = gl_Position.w;
177 })";
178 
179     std::stringstream vsRedeclared;
180     vsRedeclared << R"(#extension GL_APPLE_clip_distance : require
181 varying highp float gl_ClipDistance[)"
182                  << (maxClipDistances + 1) << R"(];
183 void main()
184 {
185     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
186     gl_ClipDistance[)"
187                  << (maxClipDistances - 1) << R"(] = gl_Position.w;
188 })";
189 
190     std::stringstream vsRedeclaredInvalidIndex;
191     vsRedeclaredInvalidIndex << R"(#extension GL_APPLE_clip_distance : require
192 varying highp float gl_ClipDistance[)"
193                              << (maxClipDistances - 2) << R"(];
194 void main()
195 {
196     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
197     gl_ClipDistance[)" << (maxClipDistances - 1)
198                              << R"(] = gl_Position.w;
199 })";
200 
201     for (auto stream : {&vsImplicit, &vsRedeclared, &vsRedeclaredInvalidIndex})
202     {
203         GLProgram prg;
204         prg.makeRaster(stream->str().c_str(), essl1_shaders::fs::Red());
205         EXPECT_FALSE(prg.valid());
206     }
207 }
208 
209 // Write to one gl_ClipDistance element
TEST_P(ClipDistanceAPPLETest,OneClipDistance)210 TEST_P(ClipDistanceAPPLETest, OneClipDistance)
211 {
212     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
213 
214     constexpr char kVS[] = R"(
215 #extension GL_APPLE_clip_distance : require
216 
217 uniform vec4 u_plane;
218 
219 attribute vec2 a_position;
220 
221 void main()
222 {
223     gl_Position = vec4(a_position, 0.0, 1.0);
224 
225     gl_ClipDistance[0] = dot(gl_Position, u_plane);
226 })";
227 
228     ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
229     glUseProgram(programRed);
230     ASSERT_GL_NO_ERROR();
231 
232     glEnable(GL_CLIP_DISTANCE0_APPLE);
233 
234     // Clear to blue
235     glClearColor(0, 0, 1, 1);
236     glClear(GL_COLOR_BUFFER_BIT);
237 
238     // Draw full screen quad with color red
239     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
240     EXPECT_GL_NO_ERROR();
241     drawQuad(programRed, "a_position", 0);
242     EXPECT_GL_NO_ERROR();
243 
244     // All pixels on the left of the plane x = -0.5 must be blue
245     GLuint x      = 0;
246     GLuint y      = 0;
247     GLuint width  = getWindowWidth() / 4 - 1;
248     GLuint height = getWindowHeight();
249     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
250 
251     // All pixels on the right of the plane x = -0.5 must be red
252     x      = getWindowWidth() / 4 + 2;
253     y      = 0;
254     width  = getWindowWidth() - x;
255     height = getWindowHeight();
256     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
257 
258     // Clear to green
259     glClearColor(0, 1, 0, 1);
260     glClear(GL_COLOR_BUFFER_BIT);
261 
262     // Draw full screen quad with color red
263     glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
264     EXPECT_GL_NO_ERROR();
265     drawQuad(programRed, "a_position", 0);
266     EXPECT_GL_NO_ERROR();
267 
268     // All pixels on the left of the plane x = -0.5 must be red
269     x      = 0;
270     y      = 0;
271     width  = getWindowWidth() / 4 - 1;
272     height = getWindowHeight();
273     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
274 
275     // All pixels on the right of the plane x = -0.5 must be green
276     x      = getWindowWidth() / 4 + 2;
277     y      = 0;
278     width  = getWindowWidth() - x;
279     height = getWindowHeight();
280     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
281 
282     // Disable GL_CLIP_DISTANCE
283     glDisable(GL_CLIP_DISTANCE0_APPLE);
284     drawQuad(programRed, "a_position", 0);
285 
286     // All pixels must be red
287     x      = 0;
288     y      = 0;
289     width  = getWindowWidth();
290     height = getWindowHeight();
291     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
292 }
293 
294 // Write to each gl_ClipDistance element
TEST_P(ClipDistanceAPPLETest,EachClipDistance)295 TEST_P(ClipDistanceAPPLETest, EachClipDistance)
296 {
297     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
298 
299     for (size_t i = 0; i < 8; i++)
300     {
301         std::stringstream vertexShaderStr;
302         vertexShaderStr << "#extension GL_APPLE_clip_distance : require\n"
303                         << "uniform vec4 u_plane;\n"
304                         << "attribute vec2 a_position;\n"
305                         << "void main()\n"
306                         << "{\n"
307                         << "    gl_Position = vec4(a_position, 0.0, 1.0);\n"
308                         << "    gl_ClipDistance[" << i << "] = dot(gl_Position, u_plane);\n"
309                         << "}";
310 
311         ANGLE_GL_PROGRAM(programRed, vertexShaderStr.str().c_str(), essl1_shaders::fs::Red());
312         glUseProgram(programRed);
313         ASSERT_GL_NO_ERROR();
314 
315         // Enable the current clip distance, disable all others.
316         for (size_t j = 0; j < 8; j++)
317         {
318             if (j == i)
319                 glEnable(GL_CLIP_DISTANCE0_APPLE + j);
320             else
321                 glDisable(GL_CLIP_DISTANCE0_APPLE + j);
322         }
323 
324         // Clear to blue
325         glClearColor(0, 0, 1, 1);
326         glClear(GL_COLOR_BUFFER_BIT);
327 
328         // Draw full screen quad with color red
329         glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
330         EXPECT_GL_NO_ERROR();
331         drawQuad(programRed, "a_position", 0);
332         EXPECT_GL_NO_ERROR();
333 
334         // All pixels on the left of the plane x = -0.5 must be blue
335         GLuint x      = 0;
336         GLuint y      = 0;
337         GLuint width  = getWindowWidth() / 4 - 1;
338         GLuint height = getWindowHeight();
339         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
340 
341         // All pixels on the right of the plane x = -0.5 must be red
342         x      = getWindowWidth() / 4 + 2;
343         y      = 0;
344         width  = getWindowWidth() - x;
345         height = getWindowHeight();
346         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
347 
348         // Clear to green
349         glClearColor(0, 1, 0, 1);
350         glClear(GL_COLOR_BUFFER_BIT);
351 
352         // Draw full screen quad with color red
353         glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
354         EXPECT_GL_NO_ERROR();
355         drawQuad(programRed, "a_position", 0);
356         EXPECT_GL_NO_ERROR();
357 
358         // All pixels on the left of the plane x = -0.5 must be red
359         x      = 0;
360         y      = 0;
361         width  = getWindowWidth() / 4 - 1;
362         height = getWindowHeight();
363         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
364 
365         // All pixels on the right of the plane x = -0.5 must be green
366         x      = getWindowWidth() / 4 + 2;
367         y      = 0;
368         width  = getWindowWidth() - x;
369         height = getWindowHeight();
370         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
371 
372         // Disable GL_CLIP_DISTANCE
373         glDisable(GL_CLIP_DISTANCE0_APPLE + i);
374         drawQuad(programRed, "a_position", 0);
375 
376         // All pixels must be red
377         x      = 0;
378         y      = 0;
379         width  = getWindowWidth();
380         height = getWindowHeight();
381         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
382     }
383 }
384 
385 // Use 8 clip distances to draw an octagon
TEST_P(ClipDistanceAPPLETest,Octagon)386 TEST_P(ClipDistanceAPPLETest, Octagon)
387 {
388     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
389 
390     constexpr char kVS[] = R"(
391 #extension GL_APPLE_clip_distance : require
392 
393 attribute vec2 a_position;
394 
395 void main()
396 {
397     gl_Position = vec4(a_position, 0.0, 1.0);
398 
399     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
400     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
401     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
402     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
403     gl_ClipDistance[4] = dot(gl_Position, vec4( 1,  1, 0, 0.70710678));
404     gl_ClipDistance[5] = dot(gl_Position, vec4( 1, -1, 0, 0.70710678));
405     gl_ClipDistance[6] = dot(gl_Position, vec4(-1,  1, 0, 0.70710678));
406     gl_ClipDistance[7] = dot(gl_Position, vec4(-1, -1, 0, 0.70710678));
407 })";
408 
409     ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
410     glUseProgram(programRed);
411     ASSERT_GL_NO_ERROR();
412 
413     glEnable(GL_CLIP_DISTANCE0_APPLE);
414     glEnable(GL_CLIP_DISTANCE1_APPLE);
415     glEnable(GL_CLIP_DISTANCE2_APPLE);
416     glEnable(GL_CLIP_DISTANCE3_APPLE);
417     glEnable(GL_CLIP_DISTANCE4_APPLE);
418     glEnable(GL_CLIP_DISTANCE5_APPLE);
419     glEnable(GL_CLIP_DISTANCE6_APPLE);
420     glEnable(GL_CLIP_DISTANCE7_APPLE);
421 
422     // Clear to blue
423     glClearColor(0, 0, 1, 1);
424     glClear(GL_COLOR_BUFFER_BIT);
425 
426     // Draw full screen quad with color red
427     drawQuad(programRed, "a_position", 0);
428     EXPECT_GL_NO_ERROR();
429 
430     // Top edge
431     EXPECT_PIXEL_COLOR_EQ(32, 56, GLColor::blue);
432     EXPECT_PIXEL_COLOR_EQ(32, 40, GLColor::red);
433 
434     // Top-right edge
435     EXPECT_PIXEL_COLOR_EQ(48, 48, GLColor::blue);
436     EXPECT_PIXEL_COLOR_EQ(40, 40, GLColor::red);
437 
438     // Right edge
439     EXPECT_PIXEL_COLOR_EQ(56, 32, GLColor::blue);
440     EXPECT_PIXEL_COLOR_EQ(40, 32, GLColor::red);
441 
442     // Bottom-right edge
443     EXPECT_PIXEL_COLOR_EQ(48, 16, GLColor::blue);
444     EXPECT_PIXEL_COLOR_EQ(40, 24, GLColor::red);
445 
446     // Bottom edge
447     EXPECT_PIXEL_COLOR_EQ(32, 8, GLColor::blue);
448     EXPECT_PIXEL_COLOR_EQ(32, 24, GLColor::red);
449 
450     // Bottom-left edge
451     EXPECT_PIXEL_COLOR_EQ(16, 16, GLColor::blue);
452     EXPECT_PIXEL_COLOR_EQ(24, 24, GLColor::red);
453 
454     // Left edge
455     EXPECT_PIXEL_COLOR_EQ(8, 32, GLColor::blue);
456     EXPECT_PIXEL_COLOR_EQ(24, 32, GLColor::red);
457 
458     // Top-left edge
459     EXPECT_PIXEL_COLOR_EQ(16, 48, GLColor::blue);
460     EXPECT_PIXEL_COLOR_EQ(24, 40, GLColor::red);
461 }
462 
463 // Write to 3 clip distances
TEST_P(ClipDistanceAPPLETest,ThreeClipDistances)464 TEST_P(ClipDistanceAPPLETest, ThreeClipDistances)
465 {
466     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
467 
468     constexpr char kVS[] = R"(
469 #extension GL_APPLE_clip_distance : require
470 
471 uniform vec4 u_plane[3];
472 
473 attribute vec2 a_position;
474 
475 void main()
476 {
477     gl_Position = vec4(a_position, 0.0, 1.0);
478 
479     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
480     gl_ClipDistance[3] = dot(gl_Position, u_plane[1]);
481     gl_ClipDistance[7] = dot(gl_Position, u_plane[2]);
482 })";
483 
484     ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
485     glUseProgram(programRed);
486     ASSERT_GL_NO_ERROR();
487 
488     // Enable 3 clip distances
489     glEnable(GL_CLIP_DISTANCE0_APPLE);
490     glEnable(GL_CLIP_DISTANCE3_APPLE);
491     glEnable(GL_CLIP_DISTANCE7_APPLE);
492     ASSERT_GL_NO_ERROR();
493 
494     // Clear to blue
495     glClearColor(0, 0, 1, 1);
496     glClear(GL_COLOR_BUFFER_BIT);
497 
498     // Draw full screen quad with color red
499     // x = -0.5
500     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
501     // x = 0.5
502     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
503     // x + y = 1
504     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
505     EXPECT_GL_NO_ERROR();
506     drawQuad(programRed, "a_position", 0);
507     EXPECT_GL_NO_ERROR();
508 
509     {
510         // All pixels on the left of the plane x = -0.5 must be blue
511         GLuint x      = 0;
512         GLuint y      = 0;
513         GLuint width  = getWindowWidth() / 4 - 1;
514         GLuint height = getWindowHeight();
515         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
516 
517         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
518         x      = getWindowWidth() / 4 + 2;
519         y      = 0;
520         width  = getWindowWidth() / 2 - x;
521         height = getWindowHeight();
522         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
523     }
524 
525     {
526         // Check pixels to the right of the plane x = 0
527         std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
528         glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
529                      actualColors.data());
530         for (int y = 0; y < getWindowHeight(); ++y)
531         {
532             for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
533             {
534                 const int currentPosition = y * getWindowHeight() + x;
535 
536                 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
537                 {
538                     // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
539                     EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
540                 }
541                 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
542                 {
543                     // Top of the plane x + y = 1 plus right of x = 0.5 plane
544                     EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
545                 }
546             }
547         }
548     }
549 
550     // Clear to green
551     glClearColor(0, 1, 0, 1);
552     glClear(GL_COLOR_BUFFER_BIT);
553 
554     // Disable gl_ClipDistance[3]
555     glDisable(GL_CLIP_DISTANCE3_APPLE);
556 
557     // Draw full screen quad with color red
558     EXPECT_GL_NO_ERROR();
559     drawQuad(programRed, "a_position", 0);
560     EXPECT_GL_NO_ERROR();
561 
562     {
563         // All pixels on the left of the plane x = -0.5 must be green
564         GLuint x      = 0;
565         GLuint y      = 0;
566         GLuint width  = getWindowWidth() / 4 - 1;
567         GLuint height = getWindowHeight();
568         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
569 
570         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
571         x      = getWindowWidth() / 4 + 2;
572         y      = 0;
573         width  = getWindowWidth() / 2 - x;
574         height = getWindowHeight();
575         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
576     }
577 
578     // Check pixels to the right of the plane x = 0
579     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
580     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
581                  actualColors.data());
582     for (int y = 0; y < getWindowHeight(); ++y)
583     {
584         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
585         {
586             const int currentPosition = y * getWindowHeight() + x;
587 
588             if (x < getWindowWidth() * 3 / 2 - y - 1)
589             {
590                 // Bottom of the plane x + y = 1
591                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
592             }
593             else if (x > getWindowWidth() * 3 / 2 - y + 1)
594             {
595                 // Top of the plane x + y = 1
596                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
597             }
598         }
599     }
600 }
601 
602 // Redeclare gl_ClipDistance in shader with explicit size, also use it in a global function
603 // outside main()
TEST_P(ClipDistanceAPPLETest,ThreeClipDistancesRedeclared)604 TEST_P(ClipDistanceAPPLETest, ThreeClipDistancesRedeclared)
605 {
606     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_APPLE_clip_distance"));
607 
608     constexpr char kVS[] = R"(
609 #extension GL_APPLE_clip_distance : require
610 
611 varying highp float gl_ClipDistance[3];
612 
613 void computeClipDistances(in vec4 position, in vec4 plane[3])
614 {
615     gl_ClipDistance[0] = dot(position, plane[0]);
616     gl_ClipDistance[1] = dot(position, plane[1]);
617     gl_ClipDistance[2] = dot(position, plane[2]);
618 }
619 
620 uniform vec4 u_plane[3];
621 
622 attribute vec2 a_position;
623 
624 void main()
625 {
626     gl_Position = vec4(a_position, 0.0, 1.0);
627 
628     computeClipDistances(gl_Position, u_plane);
629 })";
630 
631     ANGLE_GL_PROGRAM(programRed, kVS, essl1_shaders::fs::Red());
632     glUseProgram(programRed);
633     ASSERT_GL_NO_ERROR();
634 
635     // Enable 3 clip distances
636     glEnable(GL_CLIP_DISTANCE0_APPLE);
637     glEnable(GL_CLIP_DISTANCE1_APPLE);
638     glEnable(GL_CLIP_DISTANCE2_APPLE);
639     ASSERT_GL_NO_ERROR();
640 
641     // Clear to blue
642     glClearColor(0, 0, 1, 1);
643     glClear(GL_COLOR_BUFFER_BIT);
644 
645     // Draw full screen quad with color red
646     // x = -0.5
647     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
648     // x = 0.5
649     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
650     // x + y = 1
651     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
652     EXPECT_GL_NO_ERROR();
653     drawQuad(programRed, "a_position", 0);
654     EXPECT_GL_NO_ERROR();
655 
656     {
657         // All pixels on the left of the plane x = -0.5 must be blue
658         GLuint x      = 0;
659         GLuint y      = 0;
660         GLuint width  = getWindowWidth() / 4 - 1;
661         GLuint height = getWindowHeight();
662         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
663 
664         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
665         x      = getWindowWidth() / 4 + 2;
666         y      = 0;
667         width  = getWindowWidth() / 2 - x;
668         height = getWindowHeight();
669         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
670     }
671 
672     // Check pixels to the right of the plane x = 0
673     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
674     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
675                  actualColors.data());
676     for (int y = 0; y < getWindowHeight(); ++y)
677     {
678         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
679         {
680             const int currentPosition = y * getWindowHeight() + x;
681 
682             if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
683             {
684                 // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
685                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
686             }
687             else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
688             {
689                 // Top of the plane x + y = 1 plus right of x = 0.5 plane
690                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
691             }
692         }
693     }
694 }
695 
696 using ClipCullDistanceTestParams = std::tuple<angle::PlatformParameters, bool>;
697 
PrintToStringParamName(const::testing::TestParamInfo<ClipCullDistanceTestParams> & info)698 std::string PrintToStringParamName(const ::testing::TestParamInfo<ClipCullDistanceTestParams> &info)
699 {
700     std::stringstream ss;
701     ss << std::get<0>(info.param);
702     if (std::get<1>(info.param))
703     {
704         ss << "__EXT";
705     }
706     else
707     {
708         ss << "__ANGLE";
709     }
710     return ss.str();
711 }
712 
713 class ClipCullDistanceTest : public ANGLETest<ClipCullDistanceTestParams>
714 {
715   protected:
716     const bool mCullDistanceSupportRequired;
717     const std::string kExtensionName;
718 
ClipCullDistanceTest()719     ClipCullDistanceTest()
720         : mCullDistanceSupportRequired(::testing::get<1>(GetParam())),
721           kExtensionName(::testing::get<1>(GetParam()) ? "GL_EXT_clip_cull_distance"
722                                                        : "GL_ANGLE_clip_cull_distance")
723     {
724         setWindowWidth(64);
725         setWindowHeight(64);
726         setConfigRedBits(8);
727         setConfigGreenBits(8);
728         setConfigBlueBits(8);
729         setConfigAlphaBits(8);
730         setConfigDepthBits(24);
731         setExtensionsEnabled(false);
732     }
733 };
734 
735 // Query max clip distances and enable, disable states of clip distances
TEST_P(ClipCullDistanceTest,StateQuery)736 TEST_P(ClipCullDistanceTest, StateQuery)
737 {
738     GLint maxClipDistances = 0;
739     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
740     EXPECT_EQ(maxClipDistances, 0);
741     EXPECT_GL_ERROR(GL_INVALID_ENUM);
742 
743     GLint maxCullDistances = 0;
744     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
745     EXPECT_EQ(maxCullDistances, 0);
746     EXPECT_GL_ERROR(GL_INVALID_ENUM);
747 
748     GLint maxCombinedClipAndCullDistances = 0;
749     glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT, &maxCombinedClipAndCullDistances);
750     EXPECT_EQ(maxCombinedClipAndCullDistances, 0);
751     EXPECT_GL_ERROR(GL_INVALID_ENUM);
752 
753     auto assertState = [](GLenum pname, bool valid, bool expectedState) {
754         EXPECT_EQ(glIsEnabled(pname), valid ? expectedState : false);
755         EXPECT_GL_ERROR(valid ? GL_NO_ERROR : GL_INVALID_ENUM);
756 
757         GLboolean result = false;
758         glGetBooleanv(pname, &result);
759         EXPECT_EQ(result, valid ? expectedState : false);
760         EXPECT_GL_ERROR(valid ? GL_NO_ERROR : GL_INVALID_ENUM);
761     };
762 
763     for (size_t i = 0; i < 8; i++)
764     {
765         assertState(GL_CLIP_DISTANCE0_EXT + i, false, false);
766 
767         glEnable(GL_CLIP_DISTANCE0_EXT + i);
768         EXPECT_GL_ERROR(GL_INVALID_ENUM);
769 
770         assertState(GL_CLIP_DISTANCE0_EXT + i, false, false);
771 
772         glDisable(GL_CLIP_DISTANCE0_EXT + i);
773         EXPECT_GL_ERROR(GL_INVALID_ENUM);
774 
775         assertState(GL_CLIP_DISTANCE0_EXT + i, false, false);
776     }
777 
778     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
779 
780     ASSERT_GL_NO_ERROR();
781 
782     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
783     EXPECT_GE(maxClipDistances, 8);
784     EXPECT_GL_NO_ERROR();
785 
786     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
787     if (mCullDistanceSupportRequired)
788     {
789         EXPECT_GE(maxCullDistances, 8);
790     }
791     else
792     {
793         EXPECT_TRUE(maxCullDistances == 0 || maxCullDistances >= 8);
794     }
795     EXPECT_GL_NO_ERROR();
796 
797     glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT, &maxCombinedClipAndCullDistances);
798     if (mCullDistanceSupportRequired)
799     {
800         EXPECT_GE(maxCombinedClipAndCullDistances, 8);
801     }
802     else
803     {
804         EXPECT_TRUE(maxCombinedClipAndCullDistances == 0 || maxCombinedClipAndCullDistances >= 8);
805     }
806     EXPECT_GL_NO_ERROR();
807 
808     for (size_t i = 0; i < 8; i++)
809     {
810         assertState(GL_CLIP_DISTANCE0_EXT + i, true, false);
811 
812         glEnable(GL_CLIP_DISTANCE0_EXT + i);
813         EXPECT_GL_NO_ERROR();
814 
815         assertState(GL_CLIP_DISTANCE0_EXT + i, true, true);
816 
817         glDisable(GL_CLIP_DISTANCE0_EXT + i);
818         EXPECT_GL_NO_ERROR();
819 
820         assertState(GL_CLIP_DISTANCE0_EXT + i, true, false);
821     }
822 }
823 
824 // Check that gl_ClipDistance and gl_CullDistance sizes cannot be undefined
TEST_P(ClipCullDistanceTest,UndefinedArraySize)825 TEST_P(ClipCullDistanceTest, UndefinedArraySize)
826 {
827     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
828 
829     std::string kVSClip = R"(#version 300 es
830 #extension )" + kExtensionName +
831                           R"( : require
832 
833 void main()
834 {
835     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
836     for (int i = 0; i < gl_MaxClipDistances; i++)
837     {
838         gl_ClipDistance[i] = gl_Position.w;
839     }
840 })";
841 
842     std::string kVSCull = R"(#version 300 es
843 #extension )" + kExtensionName +
844                           R"( : require
845 
846 void main()
847 {
848     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
849     for (int i = 0; i < gl_MaxCullDistances; i++)
850     {
851         gl_CullDistance[i] = gl_Position.w;
852     }
853 })";
854 
855     for (auto vs : {kVSClip, kVSCull})
856     {
857         GLProgram prg;
858         prg.makeRaster(vs.c_str(), essl1_shaders::fs::Red());
859         EXPECT_FALSE(prg.valid());
860     }
861 }
862 
863 // Check that shaders with invalid or missing storage qualifiers are rejected
TEST_P(ClipCullDistanceTest,StorageQualifiers)864 TEST_P(ClipCullDistanceTest, StorageQualifiers)
865 {
866     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
867 
868     std::stringstream vertexSource;
869     auto vs = [this, &vertexSource](std::string name, std::string qualifier) {
870         vertexSource.str(std::string());
871         vertexSource.clear();
872         vertexSource << "#version 300 es\n"
873                      << "#extension " << kExtensionName << " : require\n"
874                      << qualifier << " highp float " << name << "[1];\n"
875                      << "void main()\n"
876                      << "{\n"
877                      << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
878                      << "    " << name << "[0] = 1.0;\n"
879                      << "}";
880     };
881 
882     std::stringstream fragmentSource;
883     auto fs = [this, &fragmentSource](std::string name, std::string qualifier) {
884         fragmentSource.str(std::string());
885         fragmentSource.clear();
886         fragmentSource << "#version 300 es\n"
887                        << "#extension " << kExtensionName << " : require\n"
888                        << qualifier << " highp float " << name << "[1];\n"
889                        << "out highp vec4 my_FragColor;\n"
890                        << "void main()\n"
891                        << "{\n"
892                        << "    my_FragColor = vec4(" << name << "[0], 0.0, 0.0, 1.0);\n"
893                        << "}";
894     };
895 
896     auto checkProgram = [=, &vertexSource, &fragmentSource](std::string name,
897                                                             std::string qualifierVertex,
898                                                             std::string qualifierFragment) {
899         GLProgram program;
900         vs(name, qualifierVertex);
901         fs(name, qualifierFragment);
902         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
903         return program.valid();
904     };
905 
906     GLint maxClipDistances = 0;
907     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
908     ASSERT_GT(maxClipDistances, 0);
909 
910     GLint maxCullDistances = 0;
911     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
912     if (mCullDistanceSupportRequired)
913     {
914         ASSERT_GT(maxCullDistances, 0);
915     }
916     else
917     {
918         ASSERT_GE(maxCullDistances, 0);
919     }
920 
921     std::pair<std::string, int> entries[2] = {{"gl_ClipDistance", maxClipDistances},
922                                               {"gl_CullDistance", maxCullDistances}};
923     for (auto entry : entries)
924     {
925         if (entry.second == 0)
926             continue;
927 
928         EXPECT_TRUE(checkProgram(entry.first, "out", "in"));
929 
930         EXPECT_FALSE(checkProgram(entry.first, "", ""));
931         EXPECT_FALSE(checkProgram(entry.first, "", "in"));
932         EXPECT_FALSE(checkProgram(entry.first, "", "out"));
933         EXPECT_FALSE(checkProgram(entry.first, "in", ""));
934         EXPECT_FALSE(checkProgram(entry.first, "in", "in"));
935         EXPECT_FALSE(checkProgram(entry.first, "in", "out"));
936         EXPECT_FALSE(checkProgram(entry.first, "out", ""));
937         EXPECT_FALSE(checkProgram(entry.first, "out", "out"));
938     }
939 }
940 
941 // Check that array sizes cannot be more than maximum
TEST_P(ClipCullDistanceTest,OutOfRangeArraySize)942 TEST_P(ClipCullDistanceTest, OutOfRangeArraySize)
943 {
944     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
945 
946     auto test = [this](std::string name, int maxSize) {
947         std::stringstream vsImplicit;
948         vsImplicit << R"(#version 300 es
949         #extension )"
950                    << kExtensionName << R"( : require
951 void main()
952 {
953     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
954     )" << name << "["
955                    << maxSize << R"(] = gl_Position.w;
956 })";
957 
958         std::stringstream vsRedeclared;
959         vsRedeclared << R"(#version 300 es
960 #extension )" << kExtensionName
961                      << R"( : require
962 out highp float )" << name
963                      << "[" << (maxSize + 1) << R"(];
964 void main()
965 {
966     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
967     )" << name << "[" << (maxSize ? maxSize - 1 : 0)
968                      << R"(] = gl_Position.w;
969 })";
970 
971         std::stringstream vsRedeclaredInvalidIndex;
972         vsRedeclaredInvalidIndex << R"(#version 300 es
973 #extension )" << kExtensionName << R"( : require
974 out highp float )" << name << "[" << (maxSize ? maxSize - 2 : 0)
975                                  << R"(];
976 void main()
977 {
978     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
979     )" << name << "[" << (maxSize ? maxSize - 1 : 0)
980                                  << R"(] = gl_Position.w;
981 })";
982 
983         for (auto stream : {&vsImplicit, &vsRedeclared, &vsRedeclaredInvalidIndex})
984         {
985             GLProgram prg;
986             prg.makeRaster(stream->str().c_str(), essl1_shaders::fs::Red());
987             EXPECT_FALSE(prg.valid());
988         }
989     };
990 
991     GLint maxClipDistances = 0;
992     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
993     ASSERT_GT(maxClipDistances, 0);
994 
995     GLint maxCullDistances = 0;
996     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
997     if (mCullDistanceSupportRequired)
998     {
999         ASSERT_GT(maxCullDistances, 0);
1000     }
1001     else
1002     {
1003         ASSERT_GE(maxCullDistances, 0);
1004     }
1005 
1006     test("gl_ClipDistance", maxClipDistances);
1007     test("gl_CullDistance", maxCullDistances);
1008 }
1009 
1010 // Check that shader validation enforces matching array sizes between shader stages
TEST_P(ClipCullDistanceTest,SizeCheck)1011 TEST_P(ClipCullDistanceTest, SizeCheck)
1012 {
1013     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1014 
1015     std::stringstream vertexSource;
1016     auto vs = [this, &vertexSource](std::string name, bool declare, int size) {
1017         vertexSource.str(std::string());
1018         vertexSource.clear();
1019         vertexSource << "#version 300 es\n";
1020         vertexSource << "#extension " << kExtensionName << " : require\n";
1021         if (declare)
1022         {
1023             ASSERT(size);
1024             vertexSource << "out highp float " << name << "[" << size << "];\n";
1025         }
1026         vertexSource << "void main()\n";
1027         vertexSource << "{\n";
1028         vertexSource << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n";
1029         if (size)
1030         {
1031             vertexSource << "    " << name << "[" << (size - 1) << "] = 1.0;\n";
1032         }
1033         vertexSource << "}";
1034     };
1035 
1036     std::stringstream fragmentSource;
1037     auto fs = [this, &fragmentSource](std::string name, bool declare, int size) {
1038         fragmentSource.str(std::string());
1039         fragmentSource.clear();
1040         fragmentSource << "#version 300 es\n";
1041         fragmentSource << "#extension " << kExtensionName << " : require\n";
1042         if (declare)
1043         {
1044             ASSERT(size);
1045             fragmentSource << "in highp float " << name << "[" << size << "];\n";
1046         }
1047         fragmentSource << "out highp vec4 my_FragColor;\n"
1048                        << "void main()\n"
1049                        << "{\n"
1050                        << "    my_FragColor = vec4(";
1051         if (size)
1052         {
1053             fragmentSource << name << "[" << (size - 1) << "]";
1054         }
1055         else
1056         {
1057             fragmentSource << "1.0";
1058         }
1059         fragmentSource << ", 0.0, 0.0, 1.0);\n";
1060         fragmentSource << "}\n";
1061     };
1062 
1063     auto checkProgram = [=, &vertexSource, &fragmentSource](std::string name, bool declareVertex,
1064                                                             int sizeVertex, bool declareFragment,
1065                                                             int sizeFragment) {
1066         GLProgram program;
1067         vs(name, declareVertex, sizeVertex);
1068         fs(name, declareFragment, sizeFragment);
1069         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1070         return program.valid();
1071     };
1072 
1073     GLint maxClipDistances = 0;
1074     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1075     ASSERT_GT(maxClipDistances, 0);
1076 
1077     GLint maxCullDistances = 0;
1078     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1079     if (mCullDistanceSupportRequired)
1080     {
1081         ASSERT_GT(maxCullDistances, 0);
1082     }
1083     else
1084     {
1085         ASSERT_GE(maxCullDistances, 0);
1086     }
1087 
1088     std::pair<std::string, int> entries[2] = {{"gl_ClipDistance", maxClipDistances},
1089                                               {"gl_CullDistance", maxCullDistances}};
1090     for (auto entry : entries)
1091     {
1092         const std::string name = entry.first;
1093         const int maxSize      = entry.second;
1094 
1095         // Any VS array size is valid when the value is not accessed in the fragment shader
1096         for (int i = 1; i <= maxSize; i++)
1097         {
1098             EXPECT_TRUE(checkProgram(name, false, i, false, 0));
1099             EXPECT_TRUE(checkProgram(name, true, i, false, 0));
1100         }
1101 
1102         // Any FS array size is invalid when the value is not written in the vertex shader
1103         for (int i = 1; i <= maxSize; i++)
1104         {
1105             EXPECT_FALSE(checkProgram(name, false, 0, false, i));
1106             EXPECT_FALSE(checkProgram(name, false, 0, true, i));
1107         }
1108 
1109         // Matching sizes are valid both for redeclared and implicitly sized arrays
1110         for (int i = 1; i <= maxSize; i++)
1111         {
1112             EXPECT_TRUE(checkProgram(name, false, i, false, i));
1113             EXPECT_TRUE(checkProgram(name, false, i, true, i));
1114             EXPECT_TRUE(checkProgram(name, true, i, false, i));
1115             EXPECT_TRUE(checkProgram(name, true, i, true, i));
1116         }
1117 
1118         // Non-matching sizes are invalid both for redeclared and implicitly sized arrays
1119         for (int i = 2; i <= maxSize; i++)
1120         {
1121             EXPECT_FALSE(checkProgram(name, false, i - 1, false, i));
1122             EXPECT_FALSE(checkProgram(name, false, i - 1, true, i));
1123             EXPECT_FALSE(checkProgram(name, true, i - 1, false, i));
1124             EXPECT_FALSE(checkProgram(name, true, i - 1, true, i));
1125 
1126             EXPECT_FALSE(checkProgram(name, false, i, false, i - 1));
1127             EXPECT_FALSE(checkProgram(name, false, i, true, i - 1));
1128             EXPECT_FALSE(checkProgram(name, true, i, false, i - 1));
1129             EXPECT_FALSE(checkProgram(name, true, i, true, i - 1));
1130         }
1131 
1132         // Out-of-range sizes are invalid
1133         {
1134             EXPECT_FALSE(checkProgram(name, false, 0, false, maxSize + 1));
1135             EXPECT_FALSE(checkProgram(name, false, maxSize + 1, false, 0));
1136             EXPECT_FALSE(checkProgram(name, false, maxSize + 1, false, maxSize + 1));
1137             EXPECT_FALSE(checkProgram(name, false, 0, true, maxSize + 1));
1138             EXPECT_FALSE(checkProgram(name, false, maxSize + 1, true, maxSize + 1));
1139             EXPECT_FALSE(checkProgram(name, true, maxSize + 1, false, 0));
1140             EXPECT_FALSE(checkProgram(name, true, maxSize + 1, false, maxSize + 1));
1141             EXPECT_FALSE(checkProgram(name, true, maxSize + 1, true, maxSize + 1));
1142         }
1143     }
1144 }
1145 
1146 // Check that the sum of clip and cull distance array sizes is valid
TEST_P(ClipCullDistanceTest,SizeCheckCombined)1147 TEST_P(ClipCullDistanceTest, SizeCheckCombined)
1148 {
1149     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1150 
1151     std::stringstream vertexSource;
1152     auto vs = [this, &vertexSource](bool declareClip, int sizeClip, bool declareCull,
1153                                     int sizeCull) {
1154         vertexSource.str(std::string());
1155         vertexSource.clear();
1156         vertexSource << "#version 300 es\n";
1157         vertexSource << "#extension " << kExtensionName << " : require\n";
1158         if (declareClip)
1159         {
1160             ASSERT(sizeClip);
1161             vertexSource << "out highp float gl_ClipDistance[" << sizeClip << "];\n";
1162         }
1163         if (declareCull)
1164         {
1165             ASSERT(sizeCull);
1166             vertexSource << "out highp float gl_CullDistance[" << sizeCull << "];\n";
1167         }
1168         vertexSource << "void main()\n"
1169                      << "{\n"
1170                      << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1171                      << "    gl_ClipDistance[" << (sizeClip - 1) << "] = 1.0;\n"
1172                      << "    gl_CullDistance[" << (sizeCull - 1) << "] = 1.0;\n"
1173                      << "}";
1174     };
1175 
1176     std::stringstream fragmentSource;
1177     auto fs = [this, &fragmentSource](bool declareClip, int sizeClip, bool declareCull,
1178                                       int sizeCull) {
1179         fragmentSource.str(std::string());
1180         fragmentSource.clear();
1181         fragmentSource << "#version 300 es\n";
1182         fragmentSource << "#extension " << kExtensionName << " : require\n";
1183         if (declareClip)
1184         {
1185             ASSERT(sizeClip);
1186             fragmentSource << "in highp float gl_ClipDistance[" << sizeClip << "];\n";
1187         }
1188         if (declareCull)
1189         {
1190             ASSERT(sizeClip);
1191             fragmentSource << "in highp float gl_CullDistance[" << sizeCull << "];\n";
1192         }
1193         fragmentSource << "out highp vec4 my_FragColor;\n"
1194                        << "void main()\n"
1195                        << "{\n"
1196                        << "    my_FragColor = vec4(\n"
1197                        << "        gl_ClipDistance[" << (sizeClip - 1) << "],\n"
1198                        << "        gl_CullDistance[" << (sizeCull - 1) << "],\n"
1199                        << "        0.0, 1.0);\n"
1200                        << "}\n";
1201     };
1202 
1203     auto checkProgram = [=, &vertexSource, &fragmentSource](
1204                             bool declareVertexClip, bool declareFragmentClip, int sizeClip,
1205                             bool declareVertexCull, bool declareFragmentCull, int sizeCull) {
1206         GLProgram program;
1207         vs(declareVertexClip, sizeClip, declareVertexCull, sizeCull);
1208         fs(declareVertexClip, sizeClip, declareVertexCull, sizeCull);
1209         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1210         return program.valid();
1211     };
1212 
1213     GLint maxClipDistances = 0;
1214     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1215     ASSERT_GT(maxClipDistances, 0);
1216 
1217     GLint maxCullDistances = 0;
1218     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1219     if (mCullDistanceSupportRequired)
1220     {
1221         ASSERT_GT(maxCullDistances, 0);
1222     }
1223     else
1224     {
1225         ASSERT_GE(maxCullDistances, 0);
1226     }
1227 
1228     GLint maxCombinedClipAndCullDistances = 0;
1229     glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT, &maxCombinedClipAndCullDistances);
1230     if (mCullDistanceSupportRequired)
1231     {
1232         ASSERT_GT(maxCombinedClipAndCullDistances, 0);
1233     }
1234     else
1235     {
1236         ASSERT_GE(maxCombinedClipAndCullDistances, 0);
1237     }
1238 
1239     for (int sizeClip = 1; sizeClip <= maxClipDistances; sizeClip++)
1240     {
1241         for (int sizeCull = 1; sizeCull <= maxCullDistances; sizeCull++)
1242         {
1243             // clang-format off
1244             const bool valid = sizeClip + sizeCull <= maxCombinedClipAndCullDistances;
1245             EXPECT_EQ(checkProgram(false, false, sizeClip, false, false, sizeCull), valid);
1246             EXPECT_EQ(checkProgram(false, false, sizeClip, false, true,  sizeCull), valid);
1247             EXPECT_EQ(checkProgram(false, false, sizeClip, true,  false, sizeCull), valid);
1248             EXPECT_EQ(checkProgram(false, false, sizeClip, true,  true,  sizeCull), valid);
1249             EXPECT_EQ(checkProgram(false, true,  sizeClip, false, false, sizeCull), valid);
1250             EXPECT_EQ(checkProgram(false, true,  sizeClip, false, true,  sizeCull), valid);
1251             EXPECT_EQ(checkProgram(false, true,  sizeClip, true,  false, sizeCull), valid);
1252             EXPECT_EQ(checkProgram(false, true,  sizeClip, true,  true,  sizeCull), valid);
1253             EXPECT_EQ(checkProgram(true,  false, sizeClip, false, false, sizeCull), valid);
1254             EXPECT_EQ(checkProgram(true,  false, sizeClip, false, true,  sizeCull), valid);
1255             EXPECT_EQ(checkProgram(true,  false, sizeClip, true,  false, sizeCull), valid);
1256             EXPECT_EQ(checkProgram(true,  false, sizeClip, true,  true,  sizeCull), valid);
1257             EXPECT_EQ(checkProgram(true,  true,  sizeClip, false, false, sizeCull), valid);
1258             EXPECT_EQ(checkProgram(true,  true,  sizeClip, false, true,  sizeCull), valid);
1259             EXPECT_EQ(checkProgram(true,  true,  sizeClip, true,  false, sizeCull), valid);
1260             EXPECT_EQ(checkProgram(true,  true,  sizeClip, true,  true,  sizeCull), valid);
1261             // clang-format on
1262         }
1263     }
1264 }
1265 
1266 // Test that declared but unused built-ins do not cause frontend failures. The internal uniform,
1267 // which is used for passing GL state on some platforms, could be removed when built-ins are not
1268 // accessed.
TEST_P(ClipCullDistanceTest,Unused)1269 TEST_P(ClipCullDistanceTest, Unused)
1270 {
1271     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1272 
1273     std::stringstream vertexSource;
1274     auto vs = [this, &vertexSource](std::string name) {
1275         vertexSource.str(std::string());
1276         vertexSource.clear();
1277         vertexSource << "#version 300 es\n"
1278                      << "#extension " << kExtensionName << " : require\n"
1279                      << "out highp float " << name << "[8];\n"
1280                      << "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }";
1281     };
1282 
1283     std::stringstream fragmentSource;
1284     auto fs = [this, &fragmentSource](std::string name, bool declare) {
1285         fragmentSource.str(std::string());
1286         fragmentSource.clear();
1287         fragmentSource << "#version 300 es\n";
1288         fragmentSource << "#extension " << kExtensionName << " : require\n";
1289         if (declare)
1290         {
1291             fragmentSource << "in highp float " << name << "[8];\n";
1292         }
1293         fragmentSource << "out highp vec4 my_FragColor;\n"
1294                        << "void main() { my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }\n";
1295     };
1296 
1297     auto checkProgram = [=, &vertexSource, &fragmentSource](std::string name,
1298                                                             bool declareFragment) {
1299         GLProgram program;
1300         vs(name);
1301         fs(name, declareFragment);
1302         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1303         return program.valid();
1304     };
1305 
1306     GLint maxClipDistances = 0;
1307     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1308     ASSERT_GT(maxClipDistances, 0);
1309 
1310     GLint maxCullDistances = 0;
1311     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1312     if (mCullDistanceSupportRequired)
1313     {
1314         ASSERT_GT(maxCullDistances, 0);
1315     }
1316     else
1317     {
1318         ASSERT_GE(maxCullDistances, 0);
1319     }
1320 
1321     std::pair<std::string, int> entries[2] = {{"gl_ClipDistance", maxClipDistances},
1322                                               {"gl_CullDistance", maxCullDistances}};
1323     for (auto entry : entries)
1324     {
1325         if (entry.second == 0)
1326             continue;
1327 
1328         EXPECT_TRUE(checkProgram(entry.first, false));
1329         EXPECT_TRUE(checkProgram(entry.first, true));
1330     }
1331 }
1332 
1333 // Test that unused gl_ClipDistance does not cause a translator crash
TEST_P(ClipCullDistanceTest,UnusedVertexVaryingNoCrash)1334 TEST_P(ClipCullDistanceTest, UnusedVertexVaryingNoCrash)
1335 {
1336     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1337 
1338     std::string kVS = R"(#version 300 es
1339 #extension )" + kExtensionName +
1340                       R"( : require
1341 precision highp float;
1342 void main()
1343 {
1344   float r = gl_ClipDistance[1] + 0.5;
1345 })";
1346 
1347     GLProgram prg;
1348     prg.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
1349 
1350     EXPECT_TRUE(prg.valid());
1351 }
1352 
1353 // Test that unused gl_ClipDistance does not cause a translator crash
TEST_P(ClipCullDistanceTest,UnusedFragmentVaryingNoCrash)1354 TEST_P(ClipCullDistanceTest, UnusedFragmentVaryingNoCrash)
1355 {
1356     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1357 
1358     std::string kFS = R"(#version 300 es
1359 #extension )" + kExtensionName +
1360                       R"( : require
1361 precision highp float;
1362 out vec4 my_FragColor;
1363 void main()
1364 {
1365   float r = gl_ClipDistance[1] + 0.5;
1366 })";
1367 
1368     GLProgram prg;
1369     prg.makeRaster(essl3_shaders::vs::Simple(), kFS.c_str());
1370 
1371     EXPECT_FALSE(prg.valid());
1372 }
1373 
1374 // Test that length() does not compile for unsized arrays
TEST_P(ClipCullDistanceTest,UnsizedArrayLength)1375 TEST_P(ClipCullDistanceTest, UnsizedArrayLength)
1376 {
1377     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1378 
1379     for (std::string name : {"gl_ClipDistance", "gl_CullDistance"})
1380     {
1381         std::stringstream vertexSource;
1382         vertexSource << "#version 300 es\n"
1383                      << "#extension " << kExtensionName << " : require\n"
1384                      << "void main() { " << name << ".length(); }";
1385 
1386         GLProgram program;
1387         program.makeRaster(vertexSource.str().c_str(), essl3_shaders::fs::Red());
1388         EXPECT_FALSE(program.valid()) << name;
1389     }
1390 }
1391 
1392 // Test that length() returns correct values for sized arrays
TEST_P(ClipCullDistanceTest,SizedArrayLength)1393 TEST_P(ClipCullDistanceTest, SizedArrayLength)
1394 {
1395     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1396 
1397     std::stringstream vertexSource;
1398     auto vs = [this, &vertexSource](std::string name, bool declare, int size) {
1399         vertexSource.str(std::string());
1400         vertexSource.clear();
1401         vertexSource << "#version 300 es\n";
1402         vertexSource << "#extension " << kExtensionName << " : require\n";
1403         if (declare)
1404         {
1405             vertexSource << "out highp float " << name << "[" << size << "];\n";
1406         }
1407         vertexSource << "in vec4 a_position;\n"
1408                      << "out float v_length;\n"
1409                      << "void main()\n"
1410                      << "{\n"
1411                      << "    gl_Position = a_position;\n"
1412                      << "    v_length = float(" << name << ".length()) / 16.0;\n";
1413         // Assign all elements to avoid undefined behavior
1414         for (int i = 0; i < size; ++i)
1415         {
1416             vertexSource << "    " << name << "[" << i << "] = 1.0;\n";
1417         }
1418         vertexSource << "}";
1419     };
1420 
1421     std::string kFS = R"(#version 300 es
1422 #extension )" + kExtensionName +
1423                       R"( : require
1424 in mediump float v_length;
1425 out mediump vec4 my_FragColor;
1426 void main()
1427 {
1428     my_FragColor = vec4(v_length, 0.0, 0.0, 1.0);
1429 })";
1430 
1431     auto checkLength = [this, vs, kFS, &vertexSource](std::string name, bool declare, int size) {
1432         GLProgram program;
1433         vs(name, declare, size);
1434         program.makeRaster(vertexSource.str().c_str(), kFS.c_str());
1435         ASSERT_TRUE(program.valid()) << name;
1436 
1437         glClear(GL_COLOR_BUFFER_BIT);
1438         drawQuad(program, "a_position", 0);
1439         EXPECT_PIXEL_NEAR(0, 0, size * 16, 0, 0, 255, 1);
1440     };
1441 
1442     GLint maxClipDistances = 0;
1443     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1444     ASSERT_GT(maxClipDistances, 0);
1445 
1446     GLint maxCullDistances = 0;
1447     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1448     if (mCullDistanceSupportRequired)
1449     {
1450         ASSERT_GT(maxCullDistances, 0);
1451     }
1452     else
1453     {
1454         ASSERT_GE(maxCullDistances, 0);
1455     }
1456 
1457     std::pair<std::string, int> entries[2] = {{"gl_ClipDistance", maxClipDistances},
1458                                               {"gl_CullDistance", maxCullDistances}};
1459     for (auto entry : entries)
1460     {
1461         const std::string name = entry.first;
1462         const int maxSize      = entry.second;
1463         for (int i = 1; i <= maxSize; i++)
1464         {
1465             checkLength(name, false, i);
1466             checkLength(name, true, i);
1467         }
1468     }
1469 }
1470 
1471 // Test that pruning clip/cull distance variables does not cause a translator crash
TEST_P(ClipCullDistanceTest,Pruned)1472 TEST_P(ClipCullDistanceTest, Pruned)
1473 {
1474     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1475 
1476     std::stringstream vertexSource;
1477     auto vs = [this, &vertexSource](std::string name, bool doReturn) {
1478         vertexSource.str(std::string());
1479         vertexSource.clear();
1480         vertexSource << "#version 300 es\n";
1481         vertexSource << "#extension " << kExtensionName << " : require\n";
1482         vertexSource << "void main()\n"
1483                      << "{\n"
1484                      << "    " << (doReturn ? "return;\n" : "") << "    " << name << "[1];\n";
1485         vertexSource << "}";
1486     };
1487 
1488     std::stringstream fragmentSource;
1489     auto fs = [this, &fragmentSource](std::string name) {
1490         fragmentSource.str(std::string());
1491         fragmentSource.clear();
1492         fragmentSource << "#version 300 es\n";
1493         fragmentSource << "#extension " << kExtensionName << " : require\n";
1494         fragmentSource << "out mediump vec4 my_FragColor;\n"
1495                        << "void main()\n"
1496                        << "{\n"
1497                        << "    my_FragColor = vec4(" << name << "[1]);\n";
1498         fragmentSource << "}";
1499     };
1500 
1501     auto checkPruning = [vs, fs, &vertexSource, &fragmentSource](std::string name, bool doReturn) {
1502         GLProgram program;
1503         vs(name, doReturn);
1504         fs(name);
1505         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1506         ASSERT_TRUE(program.valid()) << name << (doReturn ? " after return" : "");
1507     };
1508 
1509     GLint maxClipDistances = 0;
1510     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1511     ASSERT_GT(maxClipDistances, 0);
1512     checkPruning("gl_ClipDistance", false);
1513     checkPruning("gl_ClipDistance", true);
1514 
1515     GLint maxCullDistances = 0;
1516     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1517     if (mCullDistanceSupportRequired)
1518     {
1519         ASSERT_GT(maxCullDistances, 0);
1520         checkPruning("gl_CullDistance", false);
1521         checkPruning("gl_CullDistance", true);
1522     }
1523 }
1524 
1525 // Write to one gl_ClipDistance element
TEST_P(ClipCullDistanceTest,OneClipDistance)1526 TEST_P(ClipCullDistanceTest, OneClipDistance)
1527 {
1528     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1529 
1530     std::string kVS = R"(#version 300 es
1531 #extension )" + kExtensionName +
1532                       R"( : require
1533 
1534 uniform vec4 u_plane;
1535 
1536 in vec2 a_position;
1537 
1538 void main()
1539 {
1540     gl_Position = vec4(a_position, 0.0, 1.0);
1541 
1542     gl_ClipDistance[0] = dot(gl_Position, u_plane);
1543 })";
1544 
1545     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1546     glUseProgram(programRed);
1547     ASSERT_GL_NO_ERROR();
1548 
1549     glEnable(GL_CLIP_DISTANCE0_EXT);
1550 
1551     // Clear to blue
1552     glClearColor(0, 0, 1, 1);
1553     glClear(GL_COLOR_BUFFER_BIT);
1554 
1555     // Draw full screen quad with color red
1556     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1557     EXPECT_GL_NO_ERROR();
1558     drawQuad(programRed, "a_position", 0);
1559     EXPECT_GL_NO_ERROR();
1560 
1561     // All pixels on the left of the plane x = -0.5 must be blue
1562     GLuint x      = 0;
1563     GLuint y      = 0;
1564     GLuint width  = getWindowWidth() / 4 - 1;
1565     GLuint height = getWindowHeight();
1566     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1567 
1568     // All pixels on the right of the plane x = -0.5 must be red
1569     x      = getWindowWidth() / 4 + 2;
1570     y      = 0;
1571     width  = getWindowWidth() - x;
1572     height = getWindowHeight();
1573     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1574 
1575     // Clear to green
1576     glClearColor(0, 1, 0, 1);
1577     glClear(GL_COLOR_BUFFER_BIT);
1578 
1579     // Draw full screen quad with color red
1580     glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
1581     EXPECT_GL_NO_ERROR();
1582     drawQuad(programRed, "a_position", 0);
1583     EXPECT_GL_NO_ERROR();
1584 
1585     // All pixels on the left of the plane x = -0.5 must be red
1586     x      = 0;
1587     y      = 0;
1588     width  = getWindowWidth() / 4 - 1;
1589     height = getWindowHeight();
1590     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1591 
1592     // All pixels on the right of the plane x = -0.5 must be green
1593     x      = getWindowWidth() / 4 + 2;
1594     y      = 0;
1595     width  = getWindowWidth() - x;
1596     height = getWindowHeight();
1597     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1598 
1599     // Disable GL_CLIP_DISTANCE
1600     glDisable(GL_CLIP_DISTANCE0_EXT);
1601     drawQuad(programRed, "a_position", 0);
1602 
1603     // All pixels must be red
1604     x      = 0;
1605     y      = 0;
1606     width  = getWindowWidth();
1607     height = getWindowHeight();
1608     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1609 }
1610 
1611 // Write to each gl_ClipDistance element
TEST_P(ClipCullDistanceTest,EachClipDistance)1612 TEST_P(ClipCullDistanceTest, EachClipDistance)
1613 {
1614     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1615 
1616     for (size_t i = 0; i < 8; i++)
1617     {
1618         std::stringstream vertexShaderStr;
1619         vertexShaderStr << "#version 300 es\n"
1620                         << "#extension " << kExtensionName << " : require\n"
1621                         << "uniform vec4 u_plane;\n"
1622                         << "in vec2 a_position;\n"
1623                         << "void main()\n"
1624                         << "{\n"
1625                         << "    gl_Position = vec4(a_position, 0.0, 1.0);\n"
1626                         << "    gl_ClipDistance[" << i << "] = dot(gl_Position, u_plane);\n"
1627                         << "}";
1628 
1629         ANGLE_GL_PROGRAM(programRed, vertexShaderStr.str().c_str(), essl3_shaders::fs::Red());
1630         glUseProgram(programRed);
1631         ASSERT_GL_NO_ERROR();
1632 
1633         // Enable the current clip distance, disable all others.
1634         for (size_t j = 0; j < 8; j++)
1635         {
1636             if (j == i)
1637                 glEnable(GL_CLIP_DISTANCE0_EXT + j);
1638             else
1639                 glDisable(GL_CLIP_DISTANCE0_EXT + j);
1640         }
1641 
1642         // Clear to blue
1643         glClearColor(0, 0, 1, 1);
1644         glClear(GL_COLOR_BUFFER_BIT);
1645 
1646         // Draw full screen quad with color red
1647         glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1648         EXPECT_GL_NO_ERROR();
1649         drawQuad(programRed, "a_position", 0);
1650         EXPECT_GL_NO_ERROR();
1651 
1652         // All pixels on the left of the plane x = -0.5 must be blue
1653         GLuint x      = 0;
1654         GLuint y      = 0;
1655         GLuint width  = getWindowWidth() / 4 - 1;
1656         GLuint height = getWindowHeight();
1657         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1658 
1659         // All pixels on the right of the plane x = -0.5 must be red
1660         x      = getWindowWidth() / 4 + 2;
1661         y      = 0;
1662         width  = getWindowWidth() - x;
1663         height = getWindowHeight();
1664         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1665 
1666         // Clear to green
1667         glClearColor(0, 1, 0, 1);
1668         glClear(GL_COLOR_BUFFER_BIT);
1669 
1670         // Draw full screen quad with color red
1671         glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
1672         EXPECT_GL_NO_ERROR();
1673         drawQuad(programRed, "a_position", 0);
1674         EXPECT_GL_NO_ERROR();
1675 
1676         // All pixels on the left of the plane x = -0.5 must be red
1677         x      = 0;
1678         y      = 0;
1679         width  = getWindowWidth() / 4 - 1;
1680         height = getWindowHeight();
1681         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1682 
1683         // All pixels on the right of the plane x = -0.5 must be green
1684         x      = getWindowWidth() / 4 + 2;
1685         y      = 0;
1686         width  = getWindowWidth() - x;
1687         height = getWindowHeight();
1688         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1689 
1690         // Disable GL_CLIP_DISTANCE
1691         glDisable(GL_CLIP_DISTANCE0_EXT + i);
1692         drawQuad(programRed, "a_position", 0);
1693 
1694         // All pixels must be red
1695         x      = 0;
1696         y      = 0;
1697         width  = getWindowWidth();
1698         height = getWindowHeight();
1699         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1700     }
1701 }
1702 
1703 // Use 8 clip distances to draw an octagon
TEST_P(ClipCullDistanceTest,Octagon)1704 TEST_P(ClipCullDistanceTest, Octagon)
1705 {
1706     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1707 
1708     std::string kVS = R"(#version 300 es
1709 #extension )" + kExtensionName +
1710                       R"( : require
1711 
1712 in vec2 a_position;
1713 
1714 void main()
1715 {
1716     gl_Position = vec4(a_position, 0.0, 1.0);
1717 
1718     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
1719     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
1720     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
1721     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
1722     gl_ClipDistance[4] = dot(gl_Position, vec4( 1,  1, 0, 0.70710678));
1723     gl_ClipDistance[5] = dot(gl_Position, vec4( 1, -1, 0, 0.70710678));
1724     gl_ClipDistance[6] = dot(gl_Position, vec4(-1,  1, 0, 0.70710678));
1725     gl_ClipDistance[7] = dot(gl_Position, vec4(-1, -1, 0, 0.70710678));
1726 })";
1727 
1728     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1729     glUseProgram(programRed);
1730     ASSERT_GL_NO_ERROR();
1731 
1732     glEnable(GL_CLIP_DISTANCE0_EXT);
1733     glEnable(GL_CLIP_DISTANCE1_EXT);
1734     glEnable(GL_CLIP_DISTANCE2_EXT);
1735     glEnable(GL_CLIP_DISTANCE3_EXT);
1736     glEnable(GL_CLIP_DISTANCE4_EXT);
1737     glEnable(GL_CLIP_DISTANCE5_EXT);
1738     glEnable(GL_CLIP_DISTANCE6_EXT);
1739     glEnable(GL_CLIP_DISTANCE7_EXT);
1740 
1741     // Clear to blue
1742     glClearColor(0, 0, 1, 1);
1743     glClear(GL_COLOR_BUFFER_BIT);
1744 
1745     // Draw full screen quad with color red
1746     drawQuad(programRed, "a_position", 0);
1747     EXPECT_GL_NO_ERROR();
1748 
1749     // Top edge
1750     EXPECT_PIXEL_COLOR_EQ(32, 56, GLColor::blue);
1751     EXPECT_PIXEL_COLOR_EQ(32, 40, GLColor::red);
1752 
1753     // Top-right edge
1754     EXPECT_PIXEL_COLOR_EQ(48, 48, GLColor::blue);
1755     EXPECT_PIXEL_COLOR_EQ(40, 40, GLColor::red);
1756 
1757     // Right edge
1758     EXPECT_PIXEL_COLOR_EQ(56, 32, GLColor::blue);
1759     EXPECT_PIXEL_COLOR_EQ(40, 32, GLColor::red);
1760 
1761     // Bottom-right edge
1762     EXPECT_PIXEL_COLOR_EQ(48, 16, GLColor::blue);
1763     EXPECT_PIXEL_COLOR_EQ(40, 24, GLColor::red);
1764 
1765     // Bottom edge
1766     EXPECT_PIXEL_COLOR_EQ(32, 8, GLColor::blue);
1767     EXPECT_PIXEL_COLOR_EQ(32, 24, GLColor::red);
1768 
1769     // Bottom-left edge
1770     EXPECT_PIXEL_COLOR_EQ(16, 16, GLColor::blue);
1771     EXPECT_PIXEL_COLOR_EQ(24, 24, GLColor::red);
1772 
1773     // Left edge
1774     EXPECT_PIXEL_COLOR_EQ(8, 32, GLColor::blue);
1775     EXPECT_PIXEL_COLOR_EQ(24, 32, GLColor::red);
1776 
1777     // Top-left edge
1778     EXPECT_PIXEL_COLOR_EQ(16, 48, GLColor::blue);
1779     EXPECT_PIXEL_COLOR_EQ(24, 40, GLColor::red);
1780 }
1781 
1782 // Write to 3 clip distances
TEST_P(ClipCullDistanceTest,ThreeClipDistances)1783 TEST_P(ClipCullDistanceTest, ThreeClipDistances)
1784 {
1785     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1786 
1787     std::string kVS = R"(#version 300 es
1788 #extension )" + kExtensionName +
1789                       R"( : require
1790 
1791 uniform vec4 u_plane[3];
1792 
1793 in vec2 a_position;
1794 
1795 void main()
1796 {
1797     gl_Position = vec4(a_position, 0.0, 1.0);
1798 
1799     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
1800     gl_ClipDistance[3] = dot(gl_Position, u_plane[1]);
1801     gl_ClipDistance[7] = dot(gl_Position, u_plane[2]);
1802 })";
1803 
1804     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1805     glUseProgram(programRed);
1806     ASSERT_GL_NO_ERROR();
1807 
1808     // Enable 3 clip distances
1809     glEnable(GL_CLIP_DISTANCE0_EXT);
1810     glEnable(GL_CLIP_DISTANCE3_EXT);
1811     glEnable(GL_CLIP_DISTANCE7_EXT);
1812     ASSERT_GL_NO_ERROR();
1813 
1814     // Clear to blue
1815     glClearColor(0, 0, 1, 1);
1816     glClear(GL_COLOR_BUFFER_BIT);
1817 
1818     // Draw full screen quad with color red
1819     // x = -0.5
1820     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
1821     // x = 0.5
1822     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
1823     // x + y = 1
1824     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
1825     EXPECT_GL_NO_ERROR();
1826     drawQuad(programRed, "a_position", 0);
1827     EXPECT_GL_NO_ERROR();
1828 
1829     {
1830         // All pixels on the left of the plane x = -0.5 must be blue
1831         GLuint x      = 0;
1832         GLuint y      = 0;
1833         GLuint width  = getWindowWidth() / 4 - 1;
1834         GLuint height = getWindowHeight();
1835         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1836 
1837         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1838         x      = getWindowWidth() / 4 + 2;
1839         y      = 0;
1840         width  = getWindowWidth() / 2 - x;
1841         height = getWindowHeight();
1842         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1843     }
1844 
1845     {
1846         // Check pixels to the right of the plane x = 0
1847         std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1848         glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1849                      actualColors.data());
1850         for (int y = 0; y < getWindowHeight(); ++y)
1851         {
1852             for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1853             {
1854                 const int currentPosition = y * getWindowHeight() + x;
1855 
1856                 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
1857                 {
1858                     // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
1859                     EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1860                 }
1861                 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
1862                 {
1863                     // Top of the plane x + y = 1 plus right of x = 0.5 plane
1864                     EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1865                 }
1866             }
1867         }
1868     }
1869 
1870     // Clear to green
1871     glClearColor(0, 1, 0, 1);
1872     glClear(GL_COLOR_BUFFER_BIT);
1873 
1874     // Disable gl_ClipDistance[3]
1875     glDisable(GL_CLIP_DISTANCE3_EXT);
1876 
1877     // Draw full screen quad with color red
1878     EXPECT_GL_NO_ERROR();
1879     drawQuad(programRed, "a_position", 0);
1880     EXPECT_GL_NO_ERROR();
1881 
1882     {
1883         // All pixels on the left of the plane x = -0.5 must be green
1884         GLuint x      = 0;
1885         GLuint y      = 0;
1886         GLuint width  = getWindowWidth() / 4 - 1;
1887         GLuint height = getWindowHeight();
1888         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1889 
1890         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1891         x      = getWindowWidth() / 4 + 2;
1892         y      = 0;
1893         width  = getWindowWidth() / 2 - x;
1894         height = getWindowHeight();
1895         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1896     }
1897 
1898     // Check pixels to the right of the plane x = 0
1899     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1900     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1901                  actualColors.data());
1902     for (int y = 0; y < getWindowHeight(); ++y)
1903     {
1904         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1905         {
1906             const int currentPosition = y * getWindowHeight() + x;
1907 
1908             if (x < getWindowWidth() * 3 / 2 - y - 1)
1909             {
1910                 // Bottom of the plane x + y = 1
1911                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1912             }
1913             else if (x > getWindowWidth() * 3 / 2 - y + 1)
1914             {
1915                 // Top of the plane x + y = 1
1916                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
1917             }
1918         }
1919     }
1920 }
1921 
1922 // Redeclare gl_ClipDistance in shader with explicit size, also use it in a global function
1923 // outside main()
TEST_P(ClipCullDistanceTest,ThreeClipDistancesRedeclared)1924 TEST_P(ClipCullDistanceTest, ThreeClipDistancesRedeclared)
1925 {
1926     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1927 
1928     std::string kVS = R"(#version 300 es
1929 #extension )" + kExtensionName +
1930                       R"( : require
1931 
1932 out highp float gl_ClipDistance[3];
1933 
1934 void computeClipDistances(in vec4 position, in vec4 plane[3])
1935 {
1936     gl_ClipDistance[0] = dot(position, plane[0]);
1937     gl_ClipDistance[1] = dot(position, plane[1]);
1938     gl_ClipDistance[2] = dot(position, plane[2]);
1939 }
1940 
1941 uniform vec4 u_plane[3];
1942 
1943 in vec2 a_position;
1944 
1945 void main()
1946 {
1947     gl_Position = vec4(a_position, 0.0, 1.0);
1948 
1949     computeClipDistances(gl_Position, u_plane);
1950 })";
1951 
1952     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1953     glUseProgram(programRed);
1954     ASSERT_GL_NO_ERROR();
1955 
1956     // Enable 3 clip distances
1957     glEnable(GL_CLIP_DISTANCE0_EXT);
1958     glEnable(GL_CLIP_DISTANCE1_EXT);
1959     glEnable(GL_CLIP_DISTANCE2_EXT);
1960     ASSERT_GL_NO_ERROR();
1961 
1962     // Clear to blue
1963     glClearColor(0, 0, 1, 1);
1964     glClear(GL_COLOR_BUFFER_BIT);
1965 
1966     // Draw full screen quad with color red
1967     // x = -0.5
1968     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
1969     // x = 0.5
1970     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
1971     // x + y = 1
1972     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
1973     EXPECT_GL_NO_ERROR();
1974     drawQuad(programRed, "a_position", 0);
1975     EXPECT_GL_NO_ERROR();
1976 
1977     {
1978         // All pixels on the left of the plane x = -0.5 must be blue
1979         GLuint x      = 0;
1980         GLuint y      = 0;
1981         GLuint width  = getWindowWidth() / 4 - 1;
1982         GLuint height = getWindowHeight();
1983         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1984 
1985         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1986         x      = getWindowWidth() / 4 + 2;
1987         y      = 0;
1988         width  = getWindowWidth() / 2 - x;
1989         height = getWindowHeight();
1990         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1991     }
1992 
1993     // Check pixels to the right of the plane x = 0
1994     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1995     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1996                  actualColors.data());
1997     for (int y = 0; y < getWindowHeight(); ++y)
1998     {
1999         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
2000         {
2001             const int currentPosition = y * getWindowHeight() + x;
2002 
2003             if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
2004             {
2005                 // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
2006                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2007             }
2008             else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
2009             {
2010                 // Top of the plane x + y = 1 plus right of x = 0.5 plane
2011                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2012             }
2013         }
2014     }
2015 }
2016 
2017 // Read clip distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,ClipInterpolation)2018 TEST_P(ClipCullDistanceTest, ClipInterpolation)
2019 {
2020     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2021 
2022     std::string kVS = R"(#version 300 es
2023 #extension )" + kExtensionName +
2024                       R"( : require
2025 in vec2 a_position;
2026 void main()
2027 {
2028     gl_Position = vec4(a_position, 0.0, 1.0);
2029     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
2030     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
2031     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
2032     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
2033     gl_ClipDistance[4] = gl_ClipDistance[0];
2034     gl_ClipDistance[5] = gl_ClipDistance[1];
2035     gl_ClipDistance[6] = gl_ClipDistance[2];
2036     gl_ClipDistance[7] = gl_ClipDistance[3];
2037 })";
2038 
2039     std::string kFS = R"(#version 300 es
2040 #extension )" + kExtensionName +
2041                       R"( : require
2042 precision highp float;
2043 out vec4 my_FragColor;
2044 void main()
2045 {
2046     float r = gl_ClipDistance[0] + gl_ClipDistance[1];
2047     float g = gl_ClipDistance[2] + gl_ClipDistance[3];
2048     float b = gl_ClipDistance[4] + gl_ClipDistance[5];
2049     float a = gl_ClipDistance[6] + gl_ClipDistance[7];
2050     my_FragColor = vec4(r, g, b, a) * 0.5;
2051 })";
2052 
2053     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), kFS.c_str());
2054     glUseProgram(programRed);
2055     ASSERT_GL_NO_ERROR();
2056 
2057     glEnable(GL_CLIP_DISTANCE0_EXT);
2058     glEnable(GL_CLIP_DISTANCE1_EXT);
2059     glEnable(GL_CLIP_DISTANCE2_EXT);
2060     glEnable(GL_CLIP_DISTANCE3_EXT);
2061     glEnable(GL_CLIP_DISTANCE4_EXT);
2062     glEnable(GL_CLIP_DISTANCE5_EXT);
2063     glEnable(GL_CLIP_DISTANCE6_EXT);
2064     glEnable(GL_CLIP_DISTANCE7_EXT);
2065 
2066     // Clear to blue
2067     glClearColor(0, 0, 1, 1);
2068     glClear(GL_COLOR_BUFFER_BIT);
2069 
2070     // Draw full screen quad with color red
2071     drawQuad(programRed, "a_position", 0);
2072     EXPECT_GL_NO_ERROR();
2073 
2074     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2075     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2076                  actualColors.data());
2077     for (int x = 0; x < getWindowWidth(); x++)
2078     {
2079         for (int y = 0; y < getWindowHeight(); y++)
2080         {
2081             const int currentPosition = y * getWindowHeight() + x;
2082 
2083             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2084                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2085             {
2086                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2087             }
2088             else
2089             {
2090                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2091             }
2092         }
2093     }
2094 }
2095 
2096 // Write to one gl_CullDistance element
TEST_P(ClipCullDistanceTest,OneCullDistance)2097 TEST_P(ClipCullDistanceTest, OneCullDistance)
2098 {
2099     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2100 
2101     std::string kVS = R"(#version 300 es
2102 #extension )" + kExtensionName +
2103                       R"( : require
2104 
2105 uniform vec4 u_plane;
2106 
2107 in vec2 a_position;
2108 
2109 void main()
2110 {
2111     gl_Position = vec4(a_position, 0.0, 1.0);
2112 
2113     gl_CullDistance[0] = dot(gl_Position, u_plane);
2114 })";
2115 
2116     GLProgram programRed;
2117     programRed.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
2118     if (!mCullDistanceSupportRequired)
2119     {
2120         GLint maxCullDistances;
2121         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2122         if (maxCullDistances == 0)
2123         {
2124             ASSERT_FALSE(programRed.valid());
2125             return;
2126         }
2127     }
2128     glUseProgram(programRed);
2129     ASSERT_GL_NO_ERROR();
2130 
2131     // Clear to blue
2132     glClearColor(0, 0, 1, 1);
2133     glClear(GL_COLOR_BUFFER_BIT);
2134 
2135     // Draw full screen quad with color red
2136     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
2137     EXPECT_GL_NO_ERROR();
2138     drawQuad(programRed, "a_position", 0);
2139     EXPECT_GL_NO_ERROR();
2140 
2141     {
2142         // All pixels must be red
2143         GLuint x      = 0;
2144         GLuint y      = 0;
2145         GLuint width  = getWindowWidth();
2146         GLuint height = getWindowHeight();
2147         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
2148     }
2149 
2150     // Clear to green
2151     glClearColor(0, 1, 0, 1);
2152     glClear(GL_COLOR_BUFFER_BIT);
2153 
2154     // Draw full screen quad with color red
2155     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 1, 0, 0);
2156     EXPECT_GL_NO_ERROR();
2157     drawQuad(programRed, "a_position", 0);
2158     EXPECT_GL_NO_ERROR();
2159 
2160     // All pixels on the plane y >= -x must be red
2161     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2162     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2163                  actualColors.data());
2164     for (int x = 0; x < getWindowWidth(); ++x)
2165     {
2166         for (int y = 0; y < getWindowHeight(); ++y)
2167         {
2168             const int currentPosition = y * getWindowHeight() + x;
2169 
2170             if ((x + y) >= 0)
2171             {
2172                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2173             }
2174             else
2175             {
2176                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
2177             }
2178         }
2179     }
2180 }
2181 
2182 // Read cull distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,CullInterpolation)2183 TEST_P(ClipCullDistanceTest, CullInterpolation)
2184 {
2185     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2186 
2187     std::string kVS = R"(#version 300 es
2188 #extension )" + kExtensionName +
2189                       R"( : require
2190 in vec2 a_position;
2191 void main()
2192 {
2193     gl_Position = vec4(a_position, 0.0, 1.0);
2194     gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
2195     gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
2196     gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
2197     gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
2198     gl_CullDistance[4] = gl_CullDistance[0];
2199     gl_CullDistance[5] = gl_CullDistance[1];
2200     gl_CullDistance[6] = gl_CullDistance[2];
2201     gl_CullDistance[7] = gl_CullDistance[3];
2202 })";
2203 
2204     std::string kFS = R"(#version 300 es
2205 #extension )" + kExtensionName +
2206                       R"( : require
2207 precision highp float;
2208 out vec4 my_FragColor;
2209 void main()
2210 {
2211     float r = gl_CullDistance[0] + gl_CullDistance[1];
2212     float g = gl_CullDistance[2] + gl_CullDistance[3];
2213     float b = gl_CullDistance[4] + gl_CullDistance[5];
2214     float a = gl_CullDistance[6] + gl_CullDistance[7];
2215     my_FragColor = vec4(r, g, b, a) * 0.25;
2216 })";
2217 
2218     GLProgram programRed;
2219     programRed.makeRaster(kVS.c_str(), kFS.c_str());
2220     if (!mCullDistanceSupportRequired)
2221     {
2222         GLint maxCullDistances;
2223         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2224         if (maxCullDistances == 0)
2225         {
2226             ASSERT_FALSE(programRed.valid());
2227             return;
2228         }
2229     }
2230     glUseProgram(programRed);
2231     ASSERT_GL_NO_ERROR();
2232 
2233     // Clear to blue
2234     glClearColor(0, 0, 1, 1);
2235     glClear(GL_COLOR_BUFFER_BIT);
2236 
2237     // Draw full screen quad with color red
2238     drawQuad(programRed, "a_position", 0, 0.5);
2239     EXPECT_GL_NO_ERROR();
2240 
2241     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2242     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2243                  actualColors.data());
2244     for (int x = 0; x < getWindowWidth(); x++)
2245     {
2246         for (int y = 0; y < getWindowHeight(); y++)
2247         {
2248             const int currentPosition = y * getWindowHeight() + x;
2249 
2250             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2251                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2252             {
2253                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2254             }
2255             else
2256             {
2257                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2258             }
2259         }
2260     }
2261 }
2262 
2263 // Read both clip and cull distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,ClipCullInterpolation)2264 TEST_P(ClipCullDistanceTest, ClipCullInterpolation)
2265 {
2266     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2267 
2268     std::string kVS = R"(#version 300 es
2269 #extension )" + kExtensionName +
2270                       R"( : require
2271 in vec2 a_position;
2272 void main()
2273 {
2274     gl_Position = vec4(a_position, 0.0, 1.0);
2275     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
2276     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
2277     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
2278     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
2279     gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
2280     gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
2281     gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
2282     gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
2283 })";
2284 
2285     std::string kFS = R"(#version 300 es
2286 #extension )" + kExtensionName +
2287                       R"( : require
2288 precision highp float;
2289 out vec4 my_FragColor;
2290 void main()
2291 {
2292     my_FragColor =
2293         vec4(gl_ClipDistance[0] + gl_ClipDistance[1],
2294              gl_ClipDistance[2] + gl_ClipDistance[3],
2295              gl_CullDistance[0] + gl_CullDistance[1],
2296              gl_CullDistance[2] + gl_CullDistance[3]) *
2297         vec4(0.5, 0.5, 0.25, 0.25);
2298 })";
2299 
2300     GLProgram programRed;
2301     programRed.makeRaster(kVS.c_str(), kFS.c_str());
2302     if (!mCullDistanceSupportRequired)
2303     {
2304         GLint maxCullDistances;
2305         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2306         if (maxCullDistances == 0)
2307         {
2308             ASSERT_FALSE(programRed.valid());
2309             return;
2310         }
2311     }
2312     glUseProgram(programRed);
2313     ASSERT_GL_NO_ERROR();
2314 
2315     glEnable(GL_CLIP_DISTANCE0_EXT);
2316     glEnable(GL_CLIP_DISTANCE1_EXT);
2317     glEnable(GL_CLIP_DISTANCE2_EXT);
2318     glEnable(GL_CLIP_DISTANCE3_EXT);
2319 
2320     // Clear to blue
2321     glClearColor(0, 0, 1, 1);
2322     glClear(GL_COLOR_BUFFER_BIT);
2323 
2324     // Draw full screen quad with color red
2325     drawQuad(programRed, "a_position", 0);
2326     EXPECT_GL_NO_ERROR();
2327 
2328     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2329     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2330                  actualColors.data());
2331     for (int x = 0; x < getWindowWidth(); x++)
2332     {
2333         for (int y = 0; y < getWindowHeight(); y++)
2334         {
2335             const int currentPosition = y * getWindowHeight() + x;
2336 
2337             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2338                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2339             {
2340                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2341             }
2342             else
2343             {
2344                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2345             }
2346         }
2347     }
2348 }
2349 
2350 // Write to 4 clip distances
TEST_P(ClipCullDistanceTest,FourClipDistances)2351 TEST_P(ClipCullDistanceTest, FourClipDistances)
2352 {
2353     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2354 
2355     std::string kVS = R"(#version 300 es
2356 #extension )" + kExtensionName +
2357                       R"( : require
2358 
2359 in vec2 a_position;
2360 uniform vec4 u_plane[4];
2361 
2362 void main()
2363 {
2364     gl_Position = vec4(a_position, 0.0, 1.0);
2365 
2366     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
2367     gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
2368     gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
2369     gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
2370 })";
2371 
2372     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
2373     glUseProgram(programRed);
2374     ASSERT_GL_NO_ERROR();
2375 
2376     // Enable 3 clip distances
2377     glEnable(GL_CLIP_DISTANCE0_EXT);
2378     glEnable(GL_CLIP_DISTANCE2_EXT);
2379     glEnable(GL_CLIP_DISTANCE3_EXT);
2380     ASSERT_GL_NO_ERROR();
2381 
2382     // Disable 1 clip distances
2383     glDisable(GL_CLIP_DISTANCE1_EXT);
2384     ASSERT_GL_NO_ERROR();
2385 
2386     // Clear to blue
2387     glClearColor(0, 0, 1, 1);
2388     glClear(GL_COLOR_BUFFER_BIT);
2389 
2390     constexpr unsigned int kNumVertices                  = 12;
2391     const std::array<Vector3, kNumVertices> quadVertices = {
2392         {Vector3(-1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f),
2393          Vector3(1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, -1.0f, 0.0f),
2394          Vector3(1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, -1.0f, 0.0f),
2395          Vector3(-1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, 1.0f, 0.0f)}};
2396 
2397     GLBuffer vertexBuffer;
2398     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2399     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2400                  GL_STATIC_DRAW);
2401     ASSERT_GL_NO_ERROR();
2402 
2403     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2404     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2405     ASSERT_GL_NO_ERROR();
2406 
2407     glEnableVertexAttribArray(positionLocation);
2408     ASSERT_GL_NO_ERROR();
2409 
2410     // Draw full screen quad and small size triangle with color red
2411     // y <= 1.0f
2412     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2413     // y >= 0.5f
2414     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2415     // y >= 3x-0.5f
2416     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2417     // y >= -3x-0.5f
2418     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2419     EXPECT_GL_NO_ERROR();
2420 
2421     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2422     EXPECT_GL_NO_ERROR();
2423 
2424     const int windowWidth   = getWindowWidth();
2425     const int windowHeight  = getWindowHeight();
2426     auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2427         return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
2428     };
2429     auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2430         return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
2431     };
2432 
2433     // Only pixels in the triangle must be red
2434     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2435     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2436                  actualColors.data());
2437     for (int x = 0; x < getWindowWidth(); ++x)
2438     {
2439         for (int y = 0; y < getWindowHeight(); ++y)
2440         {
2441             // The drawing method of Swiftshader and Native graphic card is different. So the
2442             // compare function doesn't check the value on the line.
2443             const int currentPosition = y * getWindowHeight() + x;
2444 
2445             if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
2446             {
2447                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2448             }
2449             else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
2450             {
2451                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2452             }
2453         }
2454     }
2455 }
2456 
2457 // Write to 4 cull distances
TEST_P(ClipCullDistanceTest,FourCullDistances)2458 TEST_P(ClipCullDistanceTest, FourCullDistances)
2459 {
2460     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2461 
2462     // SwiftShader bug: http://anglebug.com/42263990
2463     ANGLE_SKIP_TEST_IF(isSwiftshader());
2464 
2465     std::string kVS = R"(#version 300 es
2466 #extension )" + kExtensionName +
2467                       R"( : require
2468 
2469 uniform vec4 u_plane[4];
2470 
2471 in vec2 a_position;
2472 
2473 void main()
2474 {
2475     gl_Position = vec4(a_position, 0.0, 1.0);
2476 
2477     gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
2478     gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
2479     gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
2480     gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
2481 })";
2482 
2483     GLProgram programRed;
2484     programRed.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
2485     if (!mCullDistanceSupportRequired)
2486     {
2487         GLint maxCullDistances;
2488         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2489         if (maxCullDistances == 0)
2490         {
2491             ASSERT_FALSE(programRed.valid());
2492             return;
2493         }
2494     }
2495     glUseProgram(programRed);
2496     ASSERT_GL_NO_ERROR();
2497 
2498     // Clear to blue
2499     glClearColor(0, 0, 1, 1);
2500     glClear(GL_COLOR_BUFFER_BIT);
2501 
2502     constexpr unsigned int kNumVertices                  = 12;
2503     const std::array<Vector2, kNumVertices> quadVertices = {
2504         {Vector2(-1.0f, 1.0f), Vector2(0.0f, 0.0f), Vector2(1.0f, 1.0f), Vector2(1.0f, 1.0f),
2505          Vector2(0.0f, 0.0f), Vector2(1.0f, -1.0f), Vector2(1.0f, -1.0f), Vector2(0.0f, 0.0f),
2506          Vector2(-1.0f, -1.0f), Vector2(-1.0f, -1.0f), Vector2(0.0f, 0.0f), Vector2(-1.0f, 1.0f)}};
2507 
2508     GLBuffer vertexBuffer;
2509     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2510     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * kNumVertices, quadVertices.data(),
2511                  GL_STATIC_DRAW);
2512     ASSERT_GL_NO_ERROR();
2513 
2514     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2515     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
2516     ASSERT_GL_NO_ERROR();
2517 
2518     glEnableVertexAttribArray(positionLocation);
2519     ASSERT_GL_NO_ERROR();
2520 
2521     // Draw full screen quad and small size triangle with color red
2522     // y <= 1.0f
2523     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2524     // y >= 0.5f
2525     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2526     // y >= 3x-0.5f
2527     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2528     // y >= -3x-0.5f
2529     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2530     EXPECT_GL_NO_ERROR();
2531 
2532     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2533     EXPECT_GL_NO_ERROR();
2534 
2535     // Only the bottom triangle must be culled
2536     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2537     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2538                  actualColors.data());
2539     for (int x = 0; x < getWindowWidth(); ++x)
2540     {
2541         for (int y = 0; y < getWindowHeight(); ++y)
2542         {
2543             const int currentPosition = y * getWindowHeight() + x;
2544 
2545             if (y > x || y >= -x + getWindowHeight() - 1)
2546             {
2547                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2548             }
2549             else
2550             {
2551                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2552             }
2553         }
2554     }
2555 }
2556 
2557 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,ClipDistanceInteractWithGeometryShader)2558 TEST_P(ClipCullDistanceTest, ClipDistanceInteractWithGeometryShader)
2559 {
2560     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName) ||
2561                        !EnsureGLExtensionEnabled("GL_EXT_geometry_shader"));
2562 
2563     std::string kVS = R"(#version 310 es
2564 #extension )" + kExtensionName +
2565                       R"( : require
2566 #extension GL_EXT_geometry_shader : require
2567 
2568 in vec2 a_position;
2569 uniform vec4 u_plane[4];
2570 
2571 void main()
2572 {
2573     gl_Position = vec4(a_position, 0.0, 1.0);
2574 
2575     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
2576     gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
2577     gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
2578     gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
2579 })";
2580 
2581     std::string kGS = R"(#version 310 es
2582 #extension )" + kExtensionName +
2583                       R"( : require
2584 #extension GL_EXT_geometry_shader : require
2585 
2586 layout (triangles) in;
2587 layout (triangle_strip, max_vertices = 3) out;
2588 
2589 in gl_PerVertex {
2590     highp vec4 gl_Position;
2591     highp float gl_ClipDistance[];
2592 } gl_in[];
2593 
2594 out gl_PerVertex {
2595     highp vec4 gl_Position;
2596     highp float gl_ClipDistance[];
2597 };
2598 
2599 uniform vec4 u_plane[4];
2600 
2601 void GetNewPosition(int i)
2602 {
2603     gl_Position = 2.0f * gl_in[i].gl_Position;
2604 
2605     for (int index = 0 ; index < 4 ; index++)
2606     {
2607         if (gl_in[i].gl_ClipDistance[index] < 0.0f)
2608         {
2609             gl_ClipDistance[index] = dot(gl_Position, u_plane[index]);
2610         }
2611     }
2612     EmitVertex();
2613 }
2614 
2615 void main()
2616 {
2617     for (int i = 0 ; i < 3 ; i++)
2618     {
2619         GetNewPosition(i);
2620     }
2621     EndPrimitive();
2622 })";
2623 
2624     ANGLE_GL_PROGRAM_WITH_GS(programRed, kVS.c_str(), kGS.c_str(), essl31_shaders::fs::Red());
2625     glUseProgram(programRed);
2626     ASSERT_GL_NO_ERROR();
2627 
2628     // Enable 3 clip distances
2629     glEnable(GL_CLIP_DISTANCE0_EXT);
2630     glEnable(GL_CLIP_DISTANCE2_EXT);
2631     glEnable(GL_CLIP_DISTANCE3_EXT);
2632     ASSERT_GL_NO_ERROR();
2633 
2634     // Disable 1 clip distances
2635     glDisable(GL_CLIP_DISTANCE1_EXT);
2636     ASSERT_GL_NO_ERROR();
2637 
2638     // Clear to blue
2639     glClearColor(0, 0, 1, 1);
2640     glClear(GL_COLOR_BUFFER_BIT);
2641 
2642     constexpr unsigned int kNumVertices                  = 12;
2643     const std::array<Vector3, kNumVertices> quadVertices = {
2644         {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
2645          Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
2646          Vector3(0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f),
2647          Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, 0.5f, 0.0f)}};
2648 
2649     GLBuffer vertexBuffer;
2650     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2651     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2652                  GL_STATIC_DRAW);
2653     ASSERT_GL_NO_ERROR();
2654 
2655     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2656     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2657     ASSERT_GL_NO_ERROR();
2658 
2659     glEnableVertexAttribArray(positionLocation);
2660     ASSERT_GL_NO_ERROR();
2661 
2662     // Draw full screen quad and small size triangle with color red
2663     // y <= 1.0f
2664     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2665     // y >= 0.5f
2666     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2667     // y >= 3x-0.5f
2668     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2669     // y >= -3x-0.5f
2670     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2671     EXPECT_GL_NO_ERROR();
2672 
2673     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2674     EXPECT_GL_NO_ERROR();
2675 
2676     const int windowWidth   = getWindowWidth();
2677     const int windowHeight  = getWindowHeight();
2678     auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2679         return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
2680     };
2681     auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2682         return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
2683     };
2684 
2685     // Only pixels in the triangle must be red
2686     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2687     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2688                  actualColors.data());
2689     for (int x = 0; x < getWindowWidth(); ++x)
2690     {
2691         for (int y = 0; y < getWindowHeight(); ++y)
2692         {
2693             // The drawing method of Swiftshader and Native graphic card is different. So the
2694             // compare function doesn't check the value on the line.
2695             const int currentPosition = y * getWindowHeight() + x;
2696 
2697             if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
2698             {
2699                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2700             }
2701             else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
2702             {
2703                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2704             }
2705         }
2706     }
2707 }
2708 
2709 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,CullDistanceInteractWithGeometryShader)2710 TEST_P(ClipCullDistanceTest, CullDistanceInteractWithGeometryShader)
2711 {
2712     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName) ||
2713                        !EnsureGLExtensionEnabled("GL_EXT_geometry_shader"));
2714 
2715     std::string kVS = R"(#version 310 es
2716 #extension )" + kExtensionName +
2717                       R"( : require
2718 #extension GL_EXT_geometry_shader : require
2719 
2720 in vec2 a_position;
2721 uniform vec4 u_plane[4];
2722 
2723 void main()
2724 {
2725     gl_Position = vec4(a_position, 0.0, 1.0);
2726 
2727     gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
2728     gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
2729     gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
2730     gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
2731 })";
2732 
2733     std::string kGS = R"(#version 310 es
2734 #extension )" + kExtensionName +
2735                       R"( : require
2736 #extension GL_EXT_geometry_shader : require
2737 
2738 layout (triangles) in;
2739 layout (triangle_strip, max_vertices = 3) out;
2740 
2741 in gl_PerVertex {
2742     highp vec4 gl_Position;
2743     highp float gl_CullDistance[];
2744 } gl_in[];
2745 
2746 out gl_PerVertex {
2747     highp vec4 gl_Position;
2748     highp float gl_CullDistance[];
2749 };
2750 
2751 uniform vec4 u_plane[4];
2752 
2753 void GetNewPosition(int i)
2754 {
2755     gl_Position = 2.0f * gl_in[i].gl_Position;
2756 
2757     for (int index = 0 ; index < 4 ; index++)
2758     {
2759         if (gl_in[i].gl_CullDistance[index] < 0.0f)
2760         {
2761             gl_CullDistance[index] = dot(gl_Position, u_plane[index]);
2762         }
2763     }
2764     EmitVertex();
2765 }
2766 
2767 void main()
2768 {
2769     for (int i = 0 ; i < 3 ; i++)
2770     {
2771         GetNewPosition(i);
2772     }
2773     EndPrimitive();
2774 })";
2775 
2776     GLProgram programRed;
2777     programRed.makeRaster(kVS.c_str(), kGS.c_str(), essl3_shaders::fs::Red());
2778     if (!mCullDistanceSupportRequired)
2779     {
2780         GLint maxCullDistances;
2781         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2782         if (maxCullDistances == 0)
2783         {
2784             ASSERT_FALSE(programRed.valid());
2785             return;
2786         }
2787     }
2788     glUseProgram(programRed);
2789     ASSERT_GL_NO_ERROR();
2790 
2791     // Clear to blue
2792     glClearColor(0, 0, 1, 1);
2793     glClear(GL_COLOR_BUFFER_BIT);
2794 
2795     constexpr unsigned int kNumVertices                  = 12;
2796     const std::array<Vector3, kNumVertices> quadVertices = {
2797         {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
2798          Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
2799          Vector3(0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f),
2800          Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, 0.5f, 0.0f)}};
2801 
2802     GLBuffer vertexBuffer;
2803     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2804     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2805                  GL_STATIC_DRAW);
2806     ASSERT_GL_NO_ERROR();
2807 
2808     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2809     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2810     ASSERT_GL_NO_ERROR();
2811 
2812     glEnableVertexAttribArray(positionLocation);
2813     ASSERT_GL_NO_ERROR();
2814 
2815     // Draw full screen quad and small size triangle with color red
2816     // y <= 1.0f
2817     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2818     // y >= 0.5f
2819     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2820     // y >= 3x-0.5f
2821     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2822     // y >= -3x-0.5f
2823     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2824     EXPECT_GL_NO_ERROR();
2825 
2826     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2827     EXPECT_GL_NO_ERROR();
2828 
2829     // Only pixels in the triangle must be red
2830     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2831     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2832                  actualColors.data());
2833     for (int x = 0; x < getWindowWidth(); ++x)
2834     {
2835         for (int y = 0; y < getWindowHeight(); ++y)
2836         {
2837             const int currentPosition = y * getWindowHeight() + x;
2838 
2839             if (y > x || y >= -x + getWindowHeight() - 1)
2840             {
2841                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2842             }
2843             else
2844             {
2845                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2846             }
2847         }
2848     }
2849 }
2850 
2851 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClipDistanceAPPLETest);
2852 
2853 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClipCullDistanceTest);
2854 ANGLE_INSTANTIATE_TEST_COMBINE_1(ClipCullDistanceTest,
2855                                  PrintToStringParamName,
2856                                  testing::Bool(),
2857                                  ANGLE_ALL_TEST_PLATFORMS_ES3,
2858                                  ANGLE_ALL_TEST_PLATFORMS_ES31);
2859