• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ClipDistanceTest.cpp: Test cases for
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 = [=, &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 = [=, &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 = [=](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 = [=, &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 = [=, &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 = [=, &vertexSource](bool declareClip, int sizeClip, bool declareCull, int sizeCull) {
1153         vertexSource.str(std::string());
1154         vertexSource.clear();
1155         vertexSource << "#version 300 es\n";
1156         vertexSource << "#extension " << kExtensionName << " : require\n";
1157         if (declareClip)
1158         {
1159             ASSERT(sizeClip);
1160             vertexSource << "out highp float gl_ClipDistance[" << sizeClip << "];\n";
1161         }
1162         if (declareCull)
1163         {
1164             ASSERT(sizeCull);
1165             vertexSource << "out highp float gl_CullDistance[" << sizeCull << "];\n";
1166         }
1167         vertexSource << "void main()\n"
1168                      << "{\n"
1169                      << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1170                      << "    gl_ClipDistance[" << (sizeClip - 1) << "] = 1.0;\n"
1171                      << "    gl_CullDistance[" << (sizeCull - 1) << "] = 1.0;\n"
1172                      << "}";
1173     };
1174 
1175     std::stringstream fragmentSource;
1176     auto fs = [=, &fragmentSource](bool declareClip, int sizeClip, bool declareCull, int sizeCull) {
1177         fragmentSource.str(std::string());
1178         fragmentSource.clear();
1179         fragmentSource << "#version 300 es\n";
1180         fragmentSource << "#extension " << kExtensionName << " : require\n";
1181         if (declareClip)
1182         {
1183             ASSERT(sizeClip);
1184             fragmentSource << "in highp float gl_ClipDistance[" << sizeClip << "];\n";
1185         }
1186         if (declareCull)
1187         {
1188             ASSERT(sizeClip);
1189             fragmentSource << "in highp float gl_CullDistance[" << sizeCull << "];\n";
1190         }
1191         fragmentSource << "out highp vec4 my_FragColor;\n"
1192                        << "void main()\n"
1193                        << "{\n"
1194                        << "    my_FragColor = vec4(\n"
1195                        << "        gl_ClipDistance[" << (sizeClip - 1) << "],\n"
1196                        << "        gl_CullDistance[" << (sizeCull - 1) << "],\n"
1197                        << "        0.0, 1.0);\n"
1198                        << "}\n";
1199     };
1200 
1201     auto checkProgram = [=, &vertexSource, &fragmentSource](
1202                             bool declareVertexClip, bool declareFragmentClip, int sizeClip,
1203                             bool declareVertexCull, bool declareFragmentCull, int sizeCull) {
1204         GLProgram program;
1205         vs(declareVertexClip, sizeClip, declareVertexCull, sizeCull);
1206         fs(declareVertexClip, sizeClip, declareVertexCull, sizeCull);
1207         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1208         return program.valid();
1209     };
1210 
1211     GLint maxClipDistances = 0;
1212     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1213     ASSERT_GT(maxClipDistances, 0);
1214 
1215     GLint maxCullDistances = 0;
1216     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1217     if (mCullDistanceSupportRequired)
1218     {
1219         ASSERT_GT(maxCullDistances, 0);
1220     }
1221     else
1222     {
1223         ASSERT_GE(maxCullDistances, 0);
1224     }
1225 
1226     GLint maxCombinedClipAndCullDistances = 0;
1227     glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT, &maxCombinedClipAndCullDistances);
1228     if (mCullDistanceSupportRequired)
1229     {
1230         ASSERT_GT(maxCombinedClipAndCullDistances, 0);
1231     }
1232     else
1233     {
1234         ASSERT_GE(maxCombinedClipAndCullDistances, 0);
1235     }
1236 
1237     for (int sizeClip = 1; sizeClip <= maxClipDistances; sizeClip++)
1238     {
1239         for (int sizeCull = 1; sizeCull <= maxCullDistances; sizeCull++)
1240         {
1241             // clang-format off
1242             const bool valid = sizeClip + sizeCull <= maxCombinedClipAndCullDistances;
1243             EXPECT_EQ(checkProgram(false, false, sizeClip, false, false, sizeCull), valid);
1244             EXPECT_EQ(checkProgram(false, false, sizeClip, false, true,  sizeCull), valid);
1245             EXPECT_EQ(checkProgram(false, false, sizeClip, true,  false, sizeCull), valid);
1246             EXPECT_EQ(checkProgram(false, false, sizeClip, true,  true,  sizeCull), valid);
1247             EXPECT_EQ(checkProgram(false, true,  sizeClip, false, false, sizeCull), valid);
1248             EXPECT_EQ(checkProgram(false, true,  sizeClip, false, true,  sizeCull), valid);
1249             EXPECT_EQ(checkProgram(false, true,  sizeClip, true,  false, sizeCull), valid);
1250             EXPECT_EQ(checkProgram(false, true,  sizeClip, true,  true,  sizeCull), valid);
1251             EXPECT_EQ(checkProgram(true,  false, sizeClip, false, false, sizeCull), valid);
1252             EXPECT_EQ(checkProgram(true,  false, sizeClip, false, true,  sizeCull), valid);
1253             EXPECT_EQ(checkProgram(true,  false, sizeClip, true,  false, sizeCull), valid);
1254             EXPECT_EQ(checkProgram(true,  false, sizeClip, true,  true,  sizeCull), valid);
1255             EXPECT_EQ(checkProgram(true,  true,  sizeClip, false, false, sizeCull), valid);
1256             EXPECT_EQ(checkProgram(true,  true,  sizeClip, false, true,  sizeCull), valid);
1257             EXPECT_EQ(checkProgram(true,  true,  sizeClip, true,  false, sizeCull), valid);
1258             EXPECT_EQ(checkProgram(true,  true,  sizeClip, true,  true,  sizeCull), valid);
1259             // clang-format on
1260         }
1261     }
1262 }
1263 
1264 // Test that declared but unused built-ins do not cause frontend failures. The internal uniform,
1265 // which is used for passing GL state on some platforms, could be removed when built-ins are not
1266 // accessed.
TEST_P(ClipCullDistanceTest,Unused)1267 TEST_P(ClipCullDistanceTest, Unused)
1268 {
1269     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1270 
1271     std::stringstream vertexSource;
1272     auto vs = [=, &vertexSource](std::string name) {
1273         vertexSource.str(std::string());
1274         vertexSource.clear();
1275         vertexSource << "#version 300 es\n"
1276                      << "#extension " << kExtensionName << " : require\n"
1277                      << "out highp float " << name << "[8];\n"
1278                      << "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }";
1279     };
1280 
1281     std::stringstream fragmentSource;
1282     auto fs = [=, &fragmentSource](std::string name, bool declare) {
1283         fragmentSource.str(std::string());
1284         fragmentSource.clear();
1285         fragmentSource << "#version 300 es\n";
1286         fragmentSource << "#extension " << kExtensionName << " : require\n";
1287         if (declare)
1288         {
1289             fragmentSource << "in highp float " << name << "[8];\n";
1290         }
1291         fragmentSource << "out highp vec4 my_FragColor;\n"
1292                        << "void main() { my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }\n";
1293     };
1294 
1295     auto checkProgram = [=, &vertexSource, &fragmentSource](std::string name,
1296                                                             bool declareFragment) {
1297         GLProgram program;
1298         vs(name);
1299         fs(name, declareFragment);
1300         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1301         return program.valid();
1302     };
1303 
1304     GLint maxClipDistances = 0;
1305     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1306     ASSERT_GT(maxClipDistances, 0);
1307 
1308     GLint maxCullDistances = 0;
1309     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1310     if (mCullDistanceSupportRequired)
1311     {
1312         ASSERT_GT(maxCullDistances, 0);
1313     }
1314     else
1315     {
1316         ASSERT_GE(maxCullDistances, 0);
1317     }
1318 
1319     std::pair<std::string, int> entries[2] = {{"gl_ClipDistance", maxClipDistances},
1320                                               {"gl_CullDistance", maxCullDistances}};
1321     for (auto entry : entries)
1322     {
1323         if (entry.second == 0)
1324             continue;
1325 
1326         EXPECT_TRUE(checkProgram(entry.first, false));
1327         EXPECT_TRUE(checkProgram(entry.first, true));
1328     }
1329 }
1330 
1331 // Test that unused gl_ClipDistance does not cause a translator crash
TEST_P(ClipCullDistanceTest,UnusedVertexVaryingNoCrash)1332 TEST_P(ClipCullDistanceTest, UnusedVertexVaryingNoCrash)
1333 {
1334     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1335 
1336     std::string kVS = R"(#version 300 es
1337 #extension )" + kExtensionName +
1338                       R"( : require
1339 precision highp float;
1340 void main()
1341 {
1342   float r = gl_ClipDistance[1] + 0.5;
1343 })";
1344 
1345     GLProgram prg;
1346     prg.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
1347 
1348     EXPECT_TRUE(prg.valid());
1349 }
1350 
1351 // Test that unused gl_ClipDistance does not cause a translator crash
TEST_P(ClipCullDistanceTest,UnusedFragmentVaryingNoCrash)1352 TEST_P(ClipCullDistanceTest, UnusedFragmentVaryingNoCrash)
1353 {
1354     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1355 
1356     std::string kFS = R"(#version 300 es
1357 #extension )" + kExtensionName +
1358                       R"( : require
1359 precision highp float;
1360 out vec4 my_FragColor;
1361 void main()
1362 {
1363   float r = gl_ClipDistance[1] + 0.5;
1364 })";
1365 
1366     GLProgram prg;
1367     prg.makeRaster(essl3_shaders::vs::Simple(), kFS.c_str());
1368 
1369     EXPECT_FALSE(prg.valid());
1370 }
1371 
1372 // Test that length() does not compile for unsized arrays
TEST_P(ClipCullDistanceTest,UnsizedArrayLength)1373 TEST_P(ClipCullDistanceTest, UnsizedArrayLength)
1374 {
1375     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1376 
1377     for (std::string name : {"gl_ClipDistance", "gl_CullDistance"})
1378     {
1379         std::stringstream vertexSource;
1380         vertexSource << "#version 300 es\n"
1381                      << "#extension " << kExtensionName << " : require\n"
1382                      << "void main() { " << name << ".length(); }";
1383 
1384         GLProgram program;
1385         program.makeRaster(vertexSource.str().c_str(), essl3_shaders::fs::Red());
1386         EXPECT_FALSE(program.valid()) << name;
1387     }
1388 }
1389 
1390 // Test that length() returns correct values for sized arrays
TEST_P(ClipCullDistanceTest,SizedArrayLength)1391 TEST_P(ClipCullDistanceTest, SizedArrayLength)
1392 {
1393     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1394 
1395     std::stringstream vertexSource;
1396     auto vs = [=, &vertexSource](std::string name, bool declare, int size) {
1397         vertexSource.str(std::string());
1398         vertexSource.clear();
1399         vertexSource << "#version 300 es\n";
1400         vertexSource << "#extension " << kExtensionName << " : require\n";
1401         if (declare)
1402         {
1403             vertexSource << "out highp float " << name << "[" << size << "];\n";
1404         }
1405         vertexSource << "in vec4 a_position;\n"
1406                      << "out float v_length;\n"
1407                      << "void main()\n"
1408                      << "{\n"
1409                      << "    gl_Position = a_position;\n"
1410                      << "    v_length = float(" << name << ".length()) / 16.0;\n";
1411         // Assign all elements to avoid undefined behavior
1412         for (int i = 0; i < size; ++i)
1413         {
1414             vertexSource << "    " << name << "[" << i << "] = 1.0;\n";
1415         }
1416         vertexSource << "}";
1417     };
1418 
1419     std::string kFS = R"(#version 300 es
1420 #extension )" + kExtensionName +
1421                       R"( : require
1422 in mediump float v_length;
1423 out mediump vec4 my_FragColor;
1424 void main()
1425 {
1426     my_FragColor = vec4(v_length, 0.0, 0.0, 1.0);
1427 })";
1428 
1429     auto checkLength = [=, &vertexSource](std::string name, bool declare, int size) {
1430         GLProgram program;
1431         vs(name, declare, size);
1432         program.makeRaster(vertexSource.str().c_str(), kFS.c_str());
1433         ASSERT_TRUE(program.valid()) << name;
1434 
1435         glClear(GL_COLOR_BUFFER_BIT);
1436         drawQuad(program, "a_position", 0);
1437         EXPECT_PIXEL_NEAR(0, 0, size * 16, 0, 0, 255, 1);
1438     };
1439 
1440     GLint maxClipDistances = 0;
1441     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1442     ASSERT_GT(maxClipDistances, 0);
1443 
1444     GLint maxCullDistances = 0;
1445     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1446     if (mCullDistanceSupportRequired)
1447     {
1448         ASSERT_GT(maxCullDistances, 0);
1449     }
1450     else
1451     {
1452         ASSERT_GE(maxCullDistances, 0);
1453     }
1454 
1455     std::pair<std::string, int> entries[2] = {{"gl_ClipDistance", maxClipDistances},
1456                                               {"gl_CullDistance", maxCullDistances}};
1457     for (auto entry : entries)
1458     {
1459         const std::string name = entry.first;
1460         const int maxSize      = entry.second;
1461         for (int i = 1; i <= maxSize; i++)
1462         {
1463             checkLength(name, false, i);
1464             checkLength(name, true, i);
1465         }
1466     }
1467 }
1468 
1469 // Test that pruning clip/cull distance variables does not cause a translator crash
TEST_P(ClipCullDistanceTest,Pruned)1470 TEST_P(ClipCullDistanceTest, Pruned)
1471 {
1472     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1473 
1474     std::stringstream vertexSource;
1475     auto vs = [=, &vertexSource](std::string name, bool doReturn) {
1476         vertexSource.str(std::string());
1477         vertexSource.clear();
1478         vertexSource << "#version 300 es\n";
1479         vertexSource << "#extension " << kExtensionName << " : require\n";
1480         vertexSource << "void main()\n"
1481                      << "{\n"
1482                      << "    " << (doReturn ? "return;\n" : "") << "    " << name << "[1];\n";
1483         vertexSource << "}";
1484     };
1485 
1486     std::stringstream fragmentSource;
1487     auto fs = [=, &fragmentSource](std::string name) {
1488         fragmentSource.str(std::string());
1489         fragmentSource.clear();
1490         fragmentSource << "#version 300 es\n";
1491         fragmentSource << "#extension " << kExtensionName << " : require\n";
1492         fragmentSource << "out mediump vec4 my_FragColor;\n"
1493                        << "void main()\n"
1494                        << "{\n"
1495                        << "    my_FragColor = vec4(" << name << "[1]);\n";
1496         fragmentSource << "}";
1497     };
1498 
1499     auto checkPruning = [=, &vertexSource, &fragmentSource](std::string name, bool doReturn) {
1500         GLProgram program;
1501         vs(name, doReturn);
1502         fs(name);
1503         program.makeRaster(vertexSource.str().c_str(), fragmentSource.str().c_str());
1504         ASSERT_TRUE(program.valid()) << name << (doReturn ? " after return" : "");
1505     };
1506 
1507     GLint maxClipDistances = 0;
1508     glGetIntegerv(GL_MAX_CLIP_DISTANCES_EXT, &maxClipDistances);
1509     ASSERT_GT(maxClipDistances, 0);
1510     checkPruning("gl_ClipDistance", false);
1511     checkPruning("gl_ClipDistance", true);
1512 
1513     GLint maxCullDistances = 0;
1514     glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1515     if (mCullDistanceSupportRequired)
1516     {
1517         ASSERT_GT(maxCullDistances, 0);
1518         checkPruning("gl_CullDistance", false);
1519         checkPruning("gl_CullDistance", true);
1520     }
1521 }
1522 
1523 // Write to one gl_ClipDistance element
TEST_P(ClipCullDistanceTest,OneClipDistance)1524 TEST_P(ClipCullDistanceTest, OneClipDistance)
1525 {
1526     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1527 
1528     std::string kVS = R"(#version 300 es
1529 #extension )" + kExtensionName +
1530                       R"( : require
1531 
1532 uniform vec4 u_plane;
1533 
1534 in vec2 a_position;
1535 
1536 void main()
1537 {
1538     gl_Position = vec4(a_position, 0.0, 1.0);
1539 
1540     gl_ClipDistance[0] = dot(gl_Position, u_plane);
1541 })";
1542 
1543     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1544     glUseProgram(programRed);
1545     ASSERT_GL_NO_ERROR();
1546 
1547     glEnable(GL_CLIP_DISTANCE0_EXT);
1548 
1549     // Clear to blue
1550     glClearColor(0, 0, 1, 1);
1551     glClear(GL_COLOR_BUFFER_BIT);
1552 
1553     // Draw full screen quad with color red
1554     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1555     EXPECT_GL_NO_ERROR();
1556     drawQuad(programRed, "a_position", 0);
1557     EXPECT_GL_NO_ERROR();
1558 
1559     // All pixels on the left of the plane x = -0.5 must be blue
1560     GLuint x      = 0;
1561     GLuint y      = 0;
1562     GLuint width  = getWindowWidth() / 4 - 1;
1563     GLuint height = getWindowHeight();
1564     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1565 
1566     // All pixels on the right of the plane x = -0.5 must be red
1567     x      = getWindowWidth() / 4 + 2;
1568     y      = 0;
1569     width  = getWindowWidth() - x;
1570     height = getWindowHeight();
1571     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1572 
1573     // Clear to green
1574     glClearColor(0, 1, 0, 1);
1575     glClear(GL_COLOR_BUFFER_BIT);
1576 
1577     // Draw full screen quad with color red
1578     glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
1579     EXPECT_GL_NO_ERROR();
1580     drawQuad(programRed, "a_position", 0);
1581     EXPECT_GL_NO_ERROR();
1582 
1583     // All pixels on the left of the plane x = -0.5 must be red
1584     x      = 0;
1585     y      = 0;
1586     width  = getWindowWidth() / 4 - 1;
1587     height = getWindowHeight();
1588     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1589 
1590     // All pixels on the right of the plane x = -0.5 must be green
1591     x      = getWindowWidth() / 4 + 2;
1592     y      = 0;
1593     width  = getWindowWidth() - x;
1594     height = getWindowHeight();
1595     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1596 
1597     // Disable GL_CLIP_DISTANCE
1598     glDisable(GL_CLIP_DISTANCE0_EXT);
1599     drawQuad(programRed, "a_position", 0);
1600 
1601     // All pixels must be red
1602     x      = 0;
1603     y      = 0;
1604     width  = getWindowWidth();
1605     height = getWindowHeight();
1606     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1607 }
1608 
1609 // Write to each gl_ClipDistance element
TEST_P(ClipCullDistanceTest,EachClipDistance)1610 TEST_P(ClipCullDistanceTest, EachClipDistance)
1611 {
1612     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1613 
1614     for (size_t i = 0; i < 8; i++)
1615     {
1616         std::stringstream vertexShaderStr;
1617         vertexShaderStr << "#version 300 es\n"
1618                         << "#extension " << kExtensionName << " : require\n"
1619                         << "uniform vec4 u_plane;\n"
1620                         << "in vec2 a_position;\n"
1621                         << "void main()\n"
1622                         << "{\n"
1623                         << "    gl_Position = vec4(a_position, 0.0, 1.0);\n"
1624                         << "    gl_ClipDistance[" << i << "] = dot(gl_Position, u_plane);\n"
1625                         << "}";
1626 
1627         ANGLE_GL_PROGRAM(programRed, vertexShaderStr.str().c_str(), essl3_shaders::fs::Red());
1628         glUseProgram(programRed);
1629         ASSERT_GL_NO_ERROR();
1630 
1631         // Enable the current clip distance, disable all others.
1632         for (size_t j = 0; j < 8; j++)
1633         {
1634             if (j == i)
1635                 glEnable(GL_CLIP_DISTANCE0_EXT + j);
1636             else
1637                 glDisable(GL_CLIP_DISTANCE0_EXT + j);
1638         }
1639 
1640         // Clear to blue
1641         glClearColor(0, 0, 1, 1);
1642         glClear(GL_COLOR_BUFFER_BIT);
1643 
1644         // Draw full screen quad with color red
1645         glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1646         EXPECT_GL_NO_ERROR();
1647         drawQuad(programRed, "a_position", 0);
1648         EXPECT_GL_NO_ERROR();
1649 
1650         // All pixels on the left of the plane x = -0.5 must be blue
1651         GLuint x      = 0;
1652         GLuint y      = 0;
1653         GLuint width  = getWindowWidth() / 4 - 1;
1654         GLuint height = getWindowHeight();
1655         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1656 
1657         // All pixels on the right of the plane x = -0.5 must be red
1658         x      = getWindowWidth() / 4 + 2;
1659         y      = 0;
1660         width  = getWindowWidth() - x;
1661         height = getWindowHeight();
1662         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1663 
1664         // Clear to green
1665         glClearColor(0, 1, 0, 1);
1666         glClear(GL_COLOR_BUFFER_BIT);
1667 
1668         // Draw full screen quad with color red
1669         glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
1670         EXPECT_GL_NO_ERROR();
1671         drawQuad(programRed, "a_position", 0);
1672         EXPECT_GL_NO_ERROR();
1673 
1674         // All pixels on the left of the plane x = -0.5 must be red
1675         x      = 0;
1676         y      = 0;
1677         width  = getWindowWidth() / 4 - 1;
1678         height = getWindowHeight();
1679         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1680 
1681         // All pixels on the right of the plane x = -0.5 must be green
1682         x      = getWindowWidth() / 4 + 2;
1683         y      = 0;
1684         width  = getWindowWidth() - x;
1685         height = getWindowHeight();
1686         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1687 
1688         // Disable GL_CLIP_DISTANCE
1689         glDisable(GL_CLIP_DISTANCE0_EXT + i);
1690         drawQuad(programRed, "a_position", 0);
1691 
1692         // All pixels must be red
1693         x      = 0;
1694         y      = 0;
1695         width  = getWindowWidth();
1696         height = getWindowHeight();
1697         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1698     }
1699 }
1700 
1701 // Use 8 clip distances to draw an octagon
TEST_P(ClipCullDistanceTest,Octagon)1702 TEST_P(ClipCullDistanceTest, Octagon)
1703 {
1704     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1705 
1706     std::string kVS = R"(#version 300 es
1707 #extension )" + kExtensionName +
1708                       R"( : require
1709 
1710 in vec2 a_position;
1711 
1712 void main()
1713 {
1714     gl_Position = vec4(a_position, 0.0, 1.0);
1715 
1716     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
1717     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
1718     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
1719     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
1720     gl_ClipDistance[4] = dot(gl_Position, vec4( 1,  1, 0, 0.70710678));
1721     gl_ClipDistance[5] = dot(gl_Position, vec4( 1, -1, 0, 0.70710678));
1722     gl_ClipDistance[6] = dot(gl_Position, vec4(-1,  1, 0, 0.70710678));
1723     gl_ClipDistance[7] = dot(gl_Position, vec4(-1, -1, 0, 0.70710678));
1724 })";
1725 
1726     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1727     glUseProgram(programRed);
1728     ASSERT_GL_NO_ERROR();
1729 
1730     glEnable(GL_CLIP_DISTANCE0_EXT);
1731     glEnable(GL_CLIP_DISTANCE1_EXT);
1732     glEnable(GL_CLIP_DISTANCE2_EXT);
1733     glEnable(GL_CLIP_DISTANCE3_EXT);
1734     glEnable(GL_CLIP_DISTANCE4_EXT);
1735     glEnable(GL_CLIP_DISTANCE5_EXT);
1736     glEnable(GL_CLIP_DISTANCE6_EXT);
1737     glEnable(GL_CLIP_DISTANCE7_EXT);
1738 
1739     // Clear to blue
1740     glClearColor(0, 0, 1, 1);
1741     glClear(GL_COLOR_BUFFER_BIT);
1742 
1743     // Draw full screen quad with color red
1744     drawQuad(programRed, "a_position", 0);
1745     EXPECT_GL_NO_ERROR();
1746 
1747     // Top edge
1748     EXPECT_PIXEL_COLOR_EQ(32, 56, GLColor::blue);
1749     EXPECT_PIXEL_COLOR_EQ(32, 40, GLColor::red);
1750 
1751     // Top-right edge
1752     EXPECT_PIXEL_COLOR_EQ(48, 48, GLColor::blue);
1753     EXPECT_PIXEL_COLOR_EQ(40, 40, GLColor::red);
1754 
1755     // Right edge
1756     EXPECT_PIXEL_COLOR_EQ(56, 32, GLColor::blue);
1757     EXPECT_PIXEL_COLOR_EQ(40, 32, GLColor::red);
1758 
1759     // Bottom-right edge
1760     EXPECT_PIXEL_COLOR_EQ(48, 16, GLColor::blue);
1761     EXPECT_PIXEL_COLOR_EQ(40, 24, GLColor::red);
1762 
1763     // Bottom edge
1764     EXPECT_PIXEL_COLOR_EQ(32, 8, GLColor::blue);
1765     EXPECT_PIXEL_COLOR_EQ(32, 24, GLColor::red);
1766 
1767     // Bottom-left edge
1768     EXPECT_PIXEL_COLOR_EQ(16, 16, GLColor::blue);
1769     EXPECT_PIXEL_COLOR_EQ(24, 24, GLColor::red);
1770 
1771     // Left edge
1772     EXPECT_PIXEL_COLOR_EQ(8, 32, GLColor::blue);
1773     EXPECT_PIXEL_COLOR_EQ(24, 32, GLColor::red);
1774 
1775     // Top-left edge
1776     EXPECT_PIXEL_COLOR_EQ(16, 48, GLColor::blue);
1777     EXPECT_PIXEL_COLOR_EQ(24, 40, GLColor::red);
1778 }
1779 
1780 // Write to 3 clip distances
TEST_P(ClipCullDistanceTest,ThreeClipDistances)1781 TEST_P(ClipCullDistanceTest, ThreeClipDistances)
1782 {
1783     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1784 
1785     std::string kVS = R"(#version 300 es
1786 #extension )" + kExtensionName +
1787                       R"( : require
1788 
1789 uniform vec4 u_plane[3];
1790 
1791 in vec2 a_position;
1792 
1793 void main()
1794 {
1795     gl_Position = vec4(a_position, 0.0, 1.0);
1796 
1797     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
1798     gl_ClipDistance[3] = dot(gl_Position, u_plane[1]);
1799     gl_ClipDistance[7] = dot(gl_Position, u_plane[2]);
1800 })";
1801 
1802     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1803     glUseProgram(programRed);
1804     ASSERT_GL_NO_ERROR();
1805 
1806     // Enable 3 clip distances
1807     glEnable(GL_CLIP_DISTANCE0_EXT);
1808     glEnable(GL_CLIP_DISTANCE3_EXT);
1809     glEnable(GL_CLIP_DISTANCE7_EXT);
1810     ASSERT_GL_NO_ERROR();
1811 
1812     // Clear to blue
1813     glClearColor(0, 0, 1, 1);
1814     glClear(GL_COLOR_BUFFER_BIT);
1815 
1816     // Draw full screen quad with color red
1817     // x = -0.5
1818     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
1819     // x = 0.5
1820     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
1821     // x + y = 1
1822     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
1823     EXPECT_GL_NO_ERROR();
1824     drawQuad(programRed, "a_position", 0);
1825     EXPECT_GL_NO_ERROR();
1826 
1827     {
1828         // All pixels on the left of the plane x = -0.5 must be blue
1829         GLuint x      = 0;
1830         GLuint y      = 0;
1831         GLuint width  = getWindowWidth() / 4 - 1;
1832         GLuint height = getWindowHeight();
1833         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1834 
1835         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1836         x      = getWindowWidth() / 4 + 2;
1837         y      = 0;
1838         width  = getWindowWidth() / 2 - x;
1839         height = getWindowHeight();
1840         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1841     }
1842 
1843     {
1844         // Check pixels to the right of the plane x = 0
1845         std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1846         glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1847                      actualColors.data());
1848         for (int y = 0; y < getWindowHeight(); ++y)
1849         {
1850             for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1851             {
1852                 const int currentPosition = y * getWindowHeight() + x;
1853 
1854                 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
1855                 {
1856                     // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
1857                     EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1858                 }
1859                 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
1860                 {
1861                     // Top of the plane x + y = 1 plus right of x = 0.5 plane
1862                     EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1863                 }
1864             }
1865         }
1866     }
1867 
1868     // Clear to green
1869     glClearColor(0, 1, 0, 1);
1870     glClear(GL_COLOR_BUFFER_BIT);
1871 
1872     // Disable gl_ClipDistance[3]
1873     glDisable(GL_CLIP_DISTANCE3_EXT);
1874 
1875     // Draw full screen quad with color red
1876     EXPECT_GL_NO_ERROR();
1877     drawQuad(programRed, "a_position", 0);
1878     EXPECT_GL_NO_ERROR();
1879 
1880     {
1881         // All pixels on the left of the plane x = -0.5 must be green
1882         GLuint x      = 0;
1883         GLuint y      = 0;
1884         GLuint width  = getWindowWidth() / 4 - 1;
1885         GLuint height = getWindowHeight();
1886         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1887 
1888         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1889         x      = getWindowWidth() / 4 + 2;
1890         y      = 0;
1891         width  = getWindowWidth() / 2 - x;
1892         height = getWindowHeight();
1893         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1894     }
1895 
1896     // Check pixels to the right of the plane x = 0
1897     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1898     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1899                  actualColors.data());
1900     for (int y = 0; y < getWindowHeight(); ++y)
1901     {
1902         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1903         {
1904             const int currentPosition = y * getWindowHeight() + x;
1905 
1906             if (x < getWindowWidth() * 3 / 2 - y - 1)
1907             {
1908                 // Bottom of the plane x + y = 1
1909                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1910             }
1911             else if (x > getWindowWidth() * 3 / 2 - y + 1)
1912             {
1913                 // Top of the plane x + y = 1
1914                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
1915             }
1916         }
1917     }
1918 }
1919 
1920 // Redeclare gl_ClipDistance in shader with explicit size, also use it in a global function
1921 // outside main()
TEST_P(ClipCullDistanceTest,ThreeClipDistancesRedeclared)1922 TEST_P(ClipCullDistanceTest, ThreeClipDistancesRedeclared)
1923 {
1924     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1925 
1926     std::string kVS = R"(#version 300 es
1927 #extension )" + kExtensionName +
1928                       R"( : require
1929 
1930 out highp float gl_ClipDistance[3];
1931 
1932 void computeClipDistances(in vec4 position, in vec4 plane[3])
1933 {
1934     gl_ClipDistance[0] = dot(position, plane[0]);
1935     gl_ClipDistance[1] = dot(position, plane[1]);
1936     gl_ClipDistance[2] = dot(position, plane[2]);
1937 }
1938 
1939 uniform vec4 u_plane[3];
1940 
1941 in vec2 a_position;
1942 
1943 void main()
1944 {
1945     gl_Position = vec4(a_position, 0.0, 1.0);
1946 
1947     computeClipDistances(gl_Position, u_plane);
1948 })";
1949 
1950     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1951     glUseProgram(programRed);
1952     ASSERT_GL_NO_ERROR();
1953 
1954     // Enable 3 clip distances
1955     glEnable(GL_CLIP_DISTANCE0_EXT);
1956     glEnable(GL_CLIP_DISTANCE1_EXT);
1957     glEnable(GL_CLIP_DISTANCE2_EXT);
1958     ASSERT_GL_NO_ERROR();
1959 
1960     // Clear to blue
1961     glClearColor(0, 0, 1, 1);
1962     glClear(GL_COLOR_BUFFER_BIT);
1963 
1964     // Draw full screen quad with color red
1965     // x = -0.5
1966     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
1967     // x = 0.5
1968     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
1969     // x + y = 1
1970     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
1971     EXPECT_GL_NO_ERROR();
1972     drawQuad(programRed, "a_position", 0);
1973     EXPECT_GL_NO_ERROR();
1974 
1975     {
1976         // All pixels on the left of the plane x = -0.5 must be blue
1977         GLuint x      = 0;
1978         GLuint y      = 0;
1979         GLuint width  = getWindowWidth() / 4 - 1;
1980         GLuint height = getWindowHeight();
1981         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1982 
1983         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1984         x      = getWindowWidth() / 4 + 2;
1985         y      = 0;
1986         width  = getWindowWidth() / 2 - x;
1987         height = getWindowHeight();
1988         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1989     }
1990 
1991     // Check pixels to the right of the plane x = 0
1992     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1993     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1994                  actualColors.data());
1995     for (int y = 0; y < getWindowHeight(); ++y)
1996     {
1997         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1998         {
1999             const int currentPosition = y * getWindowHeight() + x;
2000 
2001             if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
2002             {
2003                 // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
2004                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2005             }
2006             else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
2007             {
2008                 // Top of the plane x + y = 1 plus right of x = 0.5 plane
2009                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2010             }
2011         }
2012     }
2013 }
2014 
2015 // Read clip distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,ClipInterpolation)2016 TEST_P(ClipCullDistanceTest, ClipInterpolation)
2017 {
2018     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2019 
2020     std::string kVS = R"(#version 300 es
2021 #extension )" + kExtensionName +
2022                       R"( : require
2023 in vec2 a_position;
2024 void main()
2025 {
2026     gl_Position = vec4(a_position, 0.0, 1.0);
2027     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
2028     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
2029     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
2030     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
2031     gl_ClipDistance[4] = gl_ClipDistance[0];
2032     gl_ClipDistance[5] = gl_ClipDistance[1];
2033     gl_ClipDistance[6] = gl_ClipDistance[2];
2034     gl_ClipDistance[7] = gl_ClipDistance[3];
2035 })";
2036 
2037     std::string kFS = R"(#version 300 es
2038 #extension )" + kExtensionName +
2039                       R"( : require
2040 precision highp float;
2041 out vec4 my_FragColor;
2042 void main()
2043 {
2044     float r = gl_ClipDistance[0] + gl_ClipDistance[1];
2045     float g = gl_ClipDistance[2] + gl_ClipDistance[3];
2046     float b = gl_ClipDistance[4] + gl_ClipDistance[5];
2047     float a = gl_ClipDistance[6] + gl_ClipDistance[7];
2048     my_FragColor = vec4(r, g, b, a) * 0.5;
2049 })";
2050 
2051     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), kFS.c_str());
2052     glUseProgram(programRed);
2053     ASSERT_GL_NO_ERROR();
2054 
2055     glEnable(GL_CLIP_DISTANCE0_EXT);
2056     glEnable(GL_CLIP_DISTANCE1_EXT);
2057     glEnable(GL_CLIP_DISTANCE2_EXT);
2058     glEnable(GL_CLIP_DISTANCE3_EXT);
2059     glEnable(GL_CLIP_DISTANCE4_EXT);
2060     glEnable(GL_CLIP_DISTANCE5_EXT);
2061     glEnable(GL_CLIP_DISTANCE6_EXT);
2062     glEnable(GL_CLIP_DISTANCE7_EXT);
2063 
2064     // Clear to blue
2065     glClearColor(0, 0, 1, 1);
2066     glClear(GL_COLOR_BUFFER_BIT);
2067 
2068     // Draw full screen quad with color red
2069     drawQuad(programRed, "a_position", 0);
2070     EXPECT_GL_NO_ERROR();
2071 
2072     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2073     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2074                  actualColors.data());
2075     for (int x = 0; x < getWindowWidth(); x++)
2076     {
2077         for (int y = 0; y < getWindowHeight(); y++)
2078         {
2079             const int currentPosition = y * getWindowHeight() + x;
2080 
2081             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2082                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2083             {
2084                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2085             }
2086             else
2087             {
2088                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2089             }
2090         }
2091     }
2092 }
2093 
2094 // Write to one gl_CullDistance element
TEST_P(ClipCullDistanceTest,OneCullDistance)2095 TEST_P(ClipCullDistanceTest, OneCullDistance)
2096 {
2097     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2098 
2099     std::string kVS = R"(#version 300 es
2100 #extension )" + kExtensionName +
2101                       R"( : require
2102 
2103 uniform vec4 u_plane;
2104 
2105 in vec2 a_position;
2106 
2107 void main()
2108 {
2109     gl_Position = vec4(a_position, 0.0, 1.0);
2110 
2111     gl_CullDistance[0] = dot(gl_Position, u_plane);
2112 })";
2113 
2114     GLProgram programRed;
2115     programRed.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
2116     if (!mCullDistanceSupportRequired)
2117     {
2118         GLint maxCullDistances;
2119         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2120         if (maxCullDistances == 0)
2121         {
2122             ASSERT_FALSE(programRed.valid());
2123             return;
2124         }
2125     }
2126     glUseProgram(programRed);
2127     ASSERT_GL_NO_ERROR();
2128 
2129     // Clear to blue
2130     glClearColor(0, 0, 1, 1);
2131     glClear(GL_COLOR_BUFFER_BIT);
2132 
2133     // Draw full screen quad with color red
2134     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
2135     EXPECT_GL_NO_ERROR();
2136     drawQuad(programRed, "a_position", 0);
2137     EXPECT_GL_NO_ERROR();
2138 
2139     {
2140         // All pixels must be red
2141         GLuint x      = 0;
2142         GLuint y      = 0;
2143         GLuint width  = getWindowWidth();
2144         GLuint height = getWindowHeight();
2145         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
2146     }
2147 
2148     // Clear to green
2149     glClearColor(0, 1, 0, 1);
2150     glClear(GL_COLOR_BUFFER_BIT);
2151 
2152     // Draw full screen quad with color red
2153     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 1, 0, 0);
2154     EXPECT_GL_NO_ERROR();
2155     drawQuad(programRed, "a_position", 0);
2156     EXPECT_GL_NO_ERROR();
2157 
2158     // All pixels on the plane y >= -x must be red
2159     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2160     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2161                  actualColors.data());
2162     for (int x = 0; x < getWindowWidth(); ++x)
2163     {
2164         for (int y = 0; y < getWindowHeight(); ++y)
2165         {
2166             const int currentPosition = y * getWindowHeight() + x;
2167 
2168             if ((x + y) >= 0)
2169             {
2170                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2171             }
2172             else
2173             {
2174                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
2175             }
2176         }
2177     }
2178 }
2179 
2180 // Read cull distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,CullInterpolation)2181 TEST_P(ClipCullDistanceTest, CullInterpolation)
2182 {
2183     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2184 
2185     std::string kVS = R"(#version 300 es
2186 #extension )" + kExtensionName +
2187                       R"( : require
2188 in vec2 a_position;
2189 void main()
2190 {
2191     gl_Position = vec4(a_position, 0.0, 1.0);
2192     gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
2193     gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
2194     gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
2195     gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
2196     gl_CullDistance[4] = gl_CullDistance[0];
2197     gl_CullDistance[5] = gl_CullDistance[1];
2198     gl_CullDistance[6] = gl_CullDistance[2];
2199     gl_CullDistance[7] = gl_CullDistance[3];
2200 })";
2201 
2202     std::string kFS = R"(#version 300 es
2203 #extension )" + kExtensionName +
2204                       R"( : require
2205 precision highp float;
2206 out vec4 my_FragColor;
2207 void main()
2208 {
2209     float r = gl_CullDistance[0] + gl_CullDistance[1];
2210     float g = gl_CullDistance[2] + gl_CullDistance[3];
2211     float b = gl_CullDistance[4] + gl_CullDistance[5];
2212     float a = gl_CullDistance[6] + gl_CullDistance[7];
2213     my_FragColor = vec4(r, g, b, a) * 0.25;
2214 })";
2215 
2216     GLProgram programRed;
2217     programRed.makeRaster(kVS.c_str(), kFS.c_str());
2218     if (!mCullDistanceSupportRequired)
2219     {
2220         GLint maxCullDistances;
2221         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2222         if (maxCullDistances == 0)
2223         {
2224             ASSERT_FALSE(programRed.valid());
2225             return;
2226         }
2227     }
2228     glUseProgram(programRed);
2229     ASSERT_GL_NO_ERROR();
2230 
2231     // Clear to blue
2232     glClearColor(0, 0, 1, 1);
2233     glClear(GL_COLOR_BUFFER_BIT);
2234 
2235     // Draw full screen quad with color red
2236     drawQuad(programRed, "a_position", 0, 0.5);
2237     EXPECT_GL_NO_ERROR();
2238 
2239     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2240     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2241                  actualColors.data());
2242     for (int x = 0; x < getWindowWidth(); x++)
2243     {
2244         for (int y = 0; y < getWindowHeight(); y++)
2245         {
2246             const int currentPosition = y * getWindowHeight() + x;
2247 
2248             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2249                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2250             {
2251                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2252             }
2253             else
2254             {
2255                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2256             }
2257         }
2258     }
2259 }
2260 
2261 // Read both clip and cull distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,ClipCullInterpolation)2262 TEST_P(ClipCullDistanceTest, ClipCullInterpolation)
2263 {
2264     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2265 
2266     std::string kVS = R"(#version 300 es
2267 #extension )" + kExtensionName +
2268                       R"( : require
2269 in vec2 a_position;
2270 void main()
2271 {
2272     gl_Position = vec4(a_position, 0.0, 1.0);
2273     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
2274     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
2275     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
2276     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
2277     gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
2278     gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
2279     gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
2280     gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
2281 })";
2282 
2283     std::string kFS = R"(#version 300 es
2284 #extension )" + kExtensionName +
2285                       R"( : require
2286 precision highp float;
2287 out vec4 my_FragColor;
2288 void main()
2289 {
2290     my_FragColor =
2291         vec4(gl_ClipDistance[0] + gl_ClipDistance[1],
2292              gl_ClipDistance[2] + gl_ClipDistance[3],
2293              gl_CullDistance[0] + gl_CullDistance[1],
2294              gl_CullDistance[2] + gl_CullDistance[3]) *
2295         vec4(0.5, 0.5, 0.25, 0.25);
2296 })";
2297 
2298     GLProgram programRed;
2299     programRed.makeRaster(kVS.c_str(), kFS.c_str());
2300     if (!mCullDistanceSupportRequired)
2301     {
2302         GLint maxCullDistances;
2303         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2304         if (maxCullDistances == 0)
2305         {
2306             ASSERT_FALSE(programRed.valid());
2307             return;
2308         }
2309     }
2310     glUseProgram(programRed);
2311     ASSERT_GL_NO_ERROR();
2312 
2313     glEnable(GL_CLIP_DISTANCE0_EXT);
2314     glEnable(GL_CLIP_DISTANCE1_EXT);
2315     glEnable(GL_CLIP_DISTANCE2_EXT);
2316     glEnable(GL_CLIP_DISTANCE3_EXT);
2317 
2318     // Clear to blue
2319     glClearColor(0, 0, 1, 1);
2320     glClear(GL_COLOR_BUFFER_BIT);
2321 
2322     // Draw full screen quad with color red
2323     drawQuad(programRed, "a_position", 0);
2324     EXPECT_GL_NO_ERROR();
2325 
2326     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2327     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2328                  actualColors.data());
2329     for (int x = 0; x < getWindowWidth(); x++)
2330     {
2331         for (int y = 0; y < getWindowHeight(); y++)
2332         {
2333             const int currentPosition = y * getWindowHeight() + x;
2334 
2335             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2336                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2337             {
2338                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2339             }
2340             else
2341             {
2342                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2343             }
2344         }
2345     }
2346 }
2347 
2348 // Write to 4 clip distances
TEST_P(ClipCullDistanceTest,FourClipDistances)2349 TEST_P(ClipCullDistanceTest, FourClipDistances)
2350 {
2351     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2352 
2353     std::string kVS = R"(#version 300 es
2354 #extension )" + kExtensionName +
2355                       R"( : require
2356 
2357 in vec2 a_position;
2358 uniform vec4 u_plane[4];
2359 
2360 void main()
2361 {
2362     gl_Position = vec4(a_position, 0.0, 1.0);
2363 
2364     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
2365     gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
2366     gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
2367     gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
2368 })";
2369 
2370     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
2371     glUseProgram(programRed);
2372     ASSERT_GL_NO_ERROR();
2373 
2374     // Enable 3 clip distances
2375     glEnable(GL_CLIP_DISTANCE0_EXT);
2376     glEnable(GL_CLIP_DISTANCE2_EXT);
2377     glEnable(GL_CLIP_DISTANCE3_EXT);
2378     ASSERT_GL_NO_ERROR();
2379 
2380     // Disable 1 clip distances
2381     glDisable(GL_CLIP_DISTANCE1_EXT);
2382     ASSERT_GL_NO_ERROR();
2383 
2384     // Clear to blue
2385     glClearColor(0, 0, 1, 1);
2386     glClear(GL_COLOR_BUFFER_BIT);
2387 
2388     constexpr unsigned int kNumVertices                  = 12;
2389     const std::array<Vector3, kNumVertices> quadVertices = {
2390         {Vector3(-1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f),
2391          Vector3(1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, -1.0f, 0.0f),
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 
2395     GLBuffer vertexBuffer;
2396     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2397     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2398                  GL_STATIC_DRAW);
2399     ASSERT_GL_NO_ERROR();
2400 
2401     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2402     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2403     ASSERT_GL_NO_ERROR();
2404 
2405     glEnableVertexAttribArray(positionLocation);
2406     ASSERT_GL_NO_ERROR();
2407 
2408     // Draw full screen quad and small size triangle with color red
2409     // y <= 1.0f
2410     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2411     // y >= 0.5f
2412     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2413     // y >= 3x-0.5f
2414     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2415     // y >= -3x-0.5f
2416     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2417     EXPECT_GL_NO_ERROR();
2418 
2419     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2420     EXPECT_GL_NO_ERROR();
2421 
2422     const int windowWidth   = getWindowWidth();
2423     const int windowHeight  = getWindowHeight();
2424     auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2425         return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
2426     };
2427     auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2428         return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
2429     };
2430 
2431     // Only pixels in the triangle must be red
2432     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2433     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2434                  actualColors.data());
2435     for (int x = 0; x < getWindowWidth(); ++x)
2436     {
2437         for (int y = 0; y < getWindowHeight(); ++y)
2438         {
2439             // The drawing method of Swiftshader and Native graphic card is different. So the
2440             // compare function doesn't check the value on the line.
2441             const int currentPosition = y * getWindowHeight() + x;
2442 
2443             if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
2444             {
2445                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2446             }
2447             else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
2448             {
2449                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2450             }
2451         }
2452     }
2453 }
2454 
2455 // Write to 4 cull distances
TEST_P(ClipCullDistanceTest,FourCullDistances)2456 TEST_P(ClipCullDistanceTest, FourCullDistances)
2457 {
2458     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2459 
2460     // SwiftShader bug: http://anglebug.com/5451
2461     ANGLE_SKIP_TEST_IF(isSwiftshader());
2462 
2463     std::string kVS = R"(#version 300 es
2464 #extension )" + kExtensionName +
2465                       R"( : require
2466 
2467 uniform vec4 u_plane[4];
2468 
2469 in vec2 a_position;
2470 
2471 void main()
2472 {
2473     gl_Position = vec4(a_position, 0.0, 1.0);
2474 
2475     gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
2476     gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
2477     gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
2478     gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
2479 })";
2480 
2481     GLProgram programRed;
2482     programRed.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
2483     if (!mCullDistanceSupportRequired)
2484     {
2485         GLint maxCullDistances;
2486         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2487         if (maxCullDistances == 0)
2488         {
2489             ASSERT_FALSE(programRed.valid());
2490             return;
2491         }
2492     }
2493     glUseProgram(programRed);
2494     ASSERT_GL_NO_ERROR();
2495 
2496     // Clear to blue
2497     glClearColor(0, 0, 1, 1);
2498     glClear(GL_COLOR_BUFFER_BIT);
2499 
2500     constexpr unsigned int kNumVertices                  = 12;
2501     const std::array<Vector2, kNumVertices> quadVertices = {
2502         {Vector2(-1.0f, 1.0f), Vector2(0.0f, 0.0f), Vector2(1.0f, 1.0f), Vector2(1.0f, 1.0f),
2503          Vector2(0.0f, 0.0f), Vector2(1.0f, -1.0f), Vector2(1.0f, -1.0f), Vector2(0.0f, 0.0f),
2504          Vector2(-1.0f, -1.0f), Vector2(-1.0f, -1.0f), Vector2(0.0f, 0.0f), Vector2(-1.0f, 1.0f)}};
2505 
2506     GLBuffer vertexBuffer;
2507     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2508     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * kNumVertices, quadVertices.data(),
2509                  GL_STATIC_DRAW);
2510     ASSERT_GL_NO_ERROR();
2511 
2512     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2513     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
2514     ASSERT_GL_NO_ERROR();
2515 
2516     glEnableVertexAttribArray(positionLocation);
2517     ASSERT_GL_NO_ERROR();
2518 
2519     // Draw full screen quad and small size triangle with color red
2520     // y <= 1.0f
2521     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2522     // y >= 0.5f
2523     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2524     // y >= 3x-0.5f
2525     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2526     // y >= -3x-0.5f
2527     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2528     EXPECT_GL_NO_ERROR();
2529 
2530     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2531     EXPECT_GL_NO_ERROR();
2532 
2533     // Only the bottom triangle must be culled
2534     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2535     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2536                  actualColors.data());
2537     for (int x = 0; x < getWindowWidth(); ++x)
2538     {
2539         for (int y = 0; y < getWindowHeight(); ++y)
2540         {
2541             const int currentPosition = y * getWindowHeight() + x;
2542 
2543             if (y > x || y >= -x + getWindowHeight() - 1)
2544             {
2545                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2546             }
2547             else
2548             {
2549                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2550             }
2551         }
2552     }
2553 }
2554 
2555 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,ClipDistanceInteractWithGeometryShader)2556 TEST_P(ClipCullDistanceTest, ClipDistanceInteractWithGeometryShader)
2557 {
2558     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName) ||
2559                        !EnsureGLExtensionEnabled("GL_EXT_geometry_shader"));
2560 
2561     std::string kVS = R"(#version 310 es
2562 #extension )" + kExtensionName +
2563                       R"( : require
2564 #extension GL_EXT_geometry_shader : require
2565 
2566 in vec2 a_position;
2567 uniform vec4 u_plane[4];
2568 
2569 void main()
2570 {
2571     gl_Position = vec4(a_position, 0.0, 1.0);
2572 
2573     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
2574     gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
2575     gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
2576     gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
2577 })";
2578 
2579     std::string kGS = R"(#version 310 es
2580 #extension )" + kExtensionName +
2581                       R"( : require
2582 #extension GL_EXT_geometry_shader : require
2583 
2584 layout (triangles) in;
2585 layout (triangle_strip, max_vertices = 3) out;
2586 
2587 in gl_PerVertex {
2588     highp vec4 gl_Position;
2589     highp float gl_ClipDistance[];
2590 } gl_in[];
2591 
2592 out gl_PerVertex {
2593     highp vec4 gl_Position;
2594     highp float gl_ClipDistance[];
2595 };
2596 
2597 uniform vec4 u_plane[4];
2598 
2599 void GetNewPosition(int i)
2600 {
2601     gl_Position = 2.0f * gl_in[i].gl_Position;
2602 
2603     for (int index = 0 ; index < 4 ; index++)
2604     {
2605         if (gl_in[i].gl_ClipDistance[index] < 0.0f)
2606         {
2607             gl_ClipDistance[index] = dot(gl_Position, u_plane[index]);
2608         }
2609     }
2610     EmitVertex();
2611 }
2612 
2613 void main()
2614 {
2615     for (int i = 0 ; i < 3 ; i++)
2616     {
2617         GetNewPosition(i);
2618     }
2619     EndPrimitive();
2620 })";
2621 
2622     ANGLE_GL_PROGRAM_WITH_GS(programRed, kVS.c_str(), kGS.c_str(), essl31_shaders::fs::Red());
2623     glUseProgram(programRed);
2624     ASSERT_GL_NO_ERROR();
2625 
2626     // Enable 3 clip distances
2627     glEnable(GL_CLIP_DISTANCE0_EXT);
2628     glEnable(GL_CLIP_DISTANCE2_EXT);
2629     glEnable(GL_CLIP_DISTANCE3_EXT);
2630     ASSERT_GL_NO_ERROR();
2631 
2632     // Disable 1 clip distances
2633     glDisable(GL_CLIP_DISTANCE1_EXT);
2634     ASSERT_GL_NO_ERROR();
2635 
2636     // Clear to blue
2637     glClearColor(0, 0, 1, 1);
2638     glClear(GL_COLOR_BUFFER_BIT);
2639 
2640     constexpr unsigned int kNumVertices                  = 12;
2641     const std::array<Vector3, kNumVertices> quadVertices = {
2642         {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
2643          Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
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 
2647     GLBuffer vertexBuffer;
2648     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2649     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2650                  GL_STATIC_DRAW);
2651     ASSERT_GL_NO_ERROR();
2652 
2653     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2654     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2655     ASSERT_GL_NO_ERROR();
2656 
2657     glEnableVertexAttribArray(positionLocation);
2658     ASSERT_GL_NO_ERROR();
2659 
2660     // Draw full screen quad and small size triangle with color red
2661     // y <= 1.0f
2662     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2663     // y >= 0.5f
2664     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2665     // y >= 3x-0.5f
2666     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2667     // y >= -3x-0.5f
2668     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2669     EXPECT_GL_NO_ERROR();
2670 
2671     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2672     EXPECT_GL_NO_ERROR();
2673 
2674     const int windowWidth   = getWindowWidth();
2675     const int windowHeight  = getWindowHeight();
2676     auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2677         return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
2678     };
2679     auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2680         return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
2681     };
2682 
2683     // Only pixels in the triangle must be red
2684     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2685     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2686                  actualColors.data());
2687     for (int x = 0; x < getWindowWidth(); ++x)
2688     {
2689         for (int y = 0; y < getWindowHeight(); ++y)
2690         {
2691             // The drawing method of Swiftshader and Native graphic card is different. So the
2692             // compare function doesn't check the value on the line.
2693             const int currentPosition = y * getWindowHeight() + x;
2694 
2695             if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
2696             {
2697                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2698             }
2699             else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
2700             {
2701                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2702             }
2703         }
2704     }
2705 }
2706 
2707 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,CullDistanceInteractWithGeometryShader)2708 TEST_P(ClipCullDistanceTest, CullDistanceInteractWithGeometryShader)
2709 {
2710     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName) ||
2711                        !EnsureGLExtensionEnabled("GL_EXT_geometry_shader"));
2712 
2713     std::string kVS = R"(#version 310 es
2714 #extension )" + kExtensionName +
2715                       R"( : require
2716 #extension GL_EXT_geometry_shader : require
2717 
2718 in vec2 a_position;
2719 uniform vec4 u_plane[4];
2720 
2721 void main()
2722 {
2723     gl_Position = vec4(a_position, 0.0, 1.0);
2724 
2725     gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
2726     gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
2727     gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
2728     gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
2729 })";
2730 
2731     std::string kGS = R"(#version 310 es
2732 #extension )" + kExtensionName +
2733                       R"( : require
2734 #extension GL_EXT_geometry_shader : require
2735 
2736 layout (triangles) in;
2737 layout (triangle_strip, max_vertices = 3) out;
2738 
2739 in gl_PerVertex {
2740     highp vec4 gl_Position;
2741     highp float gl_CullDistance[];
2742 } gl_in[];
2743 
2744 out gl_PerVertex {
2745     highp vec4 gl_Position;
2746     highp float gl_CullDistance[];
2747 };
2748 
2749 uniform vec4 u_plane[4];
2750 
2751 void GetNewPosition(int i)
2752 {
2753     gl_Position = 2.0f * gl_in[i].gl_Position;
2754 
2755     for (int index = 0 ; index < 4 ; index++)
2756     {
2757         if (gl_in[i].gl_CullDistance[index] < 0.0f)
2758         {
2759             gl_CullDistance[index] = dot(gl_Position, u_plane[index]);
2760         }
2761     }
2762     EmitVertex();
2763 }
2764 
2765 void main()
2766 {
2767     for (int i = 0 ; i < 3 ; i++)
2768     {
2769         GetNewPosition(i);
2770     }
2771     EndPrimitive();
2772 })";
2773 
2774     GLProgram programRed;
2775     programRed.makeRaster(kVS.c_str(), kGS.c_str(), essl3_shaders::fs::Red());
2776     if (!mCullDistanceSupportRequired)
2777     {
2778         GLint maxCullDistances;
2779         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2780         if (maxCullDistances == 0)
2781         {
2782             ASSERT_FALSE(programRed.valid());
2783             return;
2784         }
2785     }
2786     glUseProgram(programRed);
2787     ASSERT_GL_NO_ERROR();
2788 
2789     // Clear to blue
2790     glClearColor(0, 0, 1, 1);
2791     glClear(GL_COLOR_BUFFER_BIT);
2792 
2793     constexpr unsigned int kNumVertices                  = 12;
2794     const std::array<Vector3, kNumVertices> quadVertices = {
2795         {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
2796          Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
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 
2800     GLBuffer vertexBuffer;
2801     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2802     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2803                  GL_STATIC_DRAW);
2804     ASSERT_GL_NO_ERROR();
2805 
2806     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2807     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2808     ASSERT_GL_NO_ERROR();
2809 
2810     glEnableVertexAttribArray(positionLocation);
2811     ASSERT_GL_NO_ERROR();
2812 
2813     // Draw full screen quad and small size triangle with color red
2814     // y <= 1.0f
2815     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2816     // y >= 0.5f
2817     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2818     // y >= 3x-0.5f
2819     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2820     // y >= -3x-0.5f
2821     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2822     EXPECT_GL_NO_ERROR();
2823 
2824     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2825     EXPECT_GL_NO_ERROR();
2826 
2827     // Only pixels in the triangle must be red
2828     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2829     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2830                  actualColors.data());
2831     for (int x = 0; x < getWindowWidth(); ++x)
2832     {
2833         for (int y = 0; y < getWindowHeight(); ++y)
2834         {
2835             const int currentPosition = y * getWindowHeight() + x;
2836 
2837             if (y > x || y >= -x + getWindowHeight() - 1)
2838             {
2839                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2840             }
2841             else
2842             {
2843                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2844             }
2845         }
2846     }
2847 }
2848 
2849 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClipDistanceAPPLETest);
2850 
2851 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClipCullDistanceTest);
2852 ANGLE_INSTANTIATE_TEST_COMBINE_1(ClipCullDistanceTest,
2853                                  PrintToStringParamName,
2854                                  testing::Bool(),
2855                                  ANGLE_ALL_TEST_PLATFORMS_ES3,
2856                                  ANGLE_ALL_TEST_PLATFORMS_ES31);
2857