• 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;"
304                         << "attribute vec2 a_position;"
305                         << "void main()"
306                         << "{"
307                         << "    gl_Position = vec4(a_position, 0.0, 1.0);"
308                         << "    gl_ClipDistance[" << i << "] = dot(gl_Position, u_plane);"
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                      << "#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                      << "{\n"
1028                      << "    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                        << "#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                        << "}\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                      << "#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                        << "#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("
1195                        << "gl_ClipDistance[" << (sizeClip - 1) << "], "
1196                        << "gl_CullDistance[" << (sizeCull - 1) << "], "
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                        << "#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 // Write to one gl_ClipDistance element
TEST_P(ClipCullDistanceTest,OneClipDistance)1332 TEST_P(ClipCullDistanceTest, OneClipDistance)
1333 {
1334     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1335 
1336     std::string kVS = R"(#version 300 es
1337 #extension )" + kExtensionName +
1338                       R"( : require
1339 
1340 uniform vec4 u_plane;
1341 
1342 in vec2 a_position;
1343 
1344 void main()
1345 {
1346     gl_Position = vec4(a_position, 0.0, 1.0);
1347 
1348     gl_ClipDistance[0] = dot(gl_Position, u_plane);
1349 })";
1350 
1351     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1352     glUseProgram(programRed);
1353     ASSERT_GL_NO_ERROR();
1354 
1355     glEnable(GL_CLIP_DISTANCE0_EXT);
1356 
1357     // Clear to blue
1358     glClearColor(0, 0, 1, 1);
1359     glClear(GL_COLOR_BUFFER_BIT);
1360 
1361     // Draw full screen quad with color red
1362     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1363     EXPECT_GL_NO_ERROR();
1364     drawQuad(programRed, "a_position", 0);
1365     EXPECT_GL_NO_ERROR();
1366 
1367     // All pixels on the left of the plane x = -0.5 must be blue
1368     GLuint x      = 0;
1369     GLuint y      = 0;
1370     GLuint width  = getWindowWidth() / 4 - 1;
1371     GLuint height = getWindowHeight();
1372     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1373 
1374     // All pixels on the right of the plane x = -0.5 must be red
1375     x      = getWindowWidth() / 4 + 2;
1376     y      = 0;
1377     width  = getWindowWidth() - x;
1378     height = getWindowHeight();
1379     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1380 
1381     // Clear to green
1382     glClearColor(0, 1, 0, 1);
1383     glClear(GL_COLOR_BUFFER_BIT);
1384 
1385     // Draw full screen quad with color red
1386     glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
1387     EXPECT_GL_NO_ERROR();
1388     drawQuad(programRed, "a_position", 0);
1389     EXPECT_GL_NO_ERROR();
1390 
1391     // All pixels on the left of the plane x = -0.5 must be red
1392     x      = 0;
1393     y      = 0;
1394     width  = getWindowWidth() / 4 - 1;
1395     height = getWindowHeight();
1396     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1397 
1398     // All pixels on the right of the plane x = -0.5 must be green
1399     x      = getWindowWidth() / 4 + 2;
1400     y      = 0;
1401     width  = getWindowWidth() - x;
1402     height = getWindowHeight();
1403     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1404 
1405     // Disable GL_CLIP_DISTANCE
1406     glDisable(GL_CLIP_DISTANCE0_EXT);
1407     drawQuad(programRed, "a_position", 0);
1408 
1409     // All pixels must be red
1410     x      = 0;
1411     y      = 0;
1412     width  = getWindowWidth();
1413     height = getWindowHeight();
1414     EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1415 }
1416 
1417 // Write to each gl_ClipDistance element
TEST_P(ClipCullDistanceTest,EachClipDistance)1418 TEST_P(ClipCullDistanceTest, EachClipDistance)
1419 {
1420     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1421 
1422     for (size_t i = 0; i < 8; i++)
1423     {
1424         std::stringstream vertexShaderStr;
1425         vertexShaderStr << "#version 300 es\n"
1426                         << "#extension " << kExtensionName << " : require\n"
1427                         << "uniform vec4 u_plane;"
1428                         << "in vec2 a_position;"
1429                         << "void main()"
1430                         << "{"
1431                         << "    gl_Position = vec4(a_position, 0.0, 1.0);"
1432                         << "    gl_ClipDistance[" << i << "] = dot(gl_Position, u_plane);"
1433                         << "}";
1434 
1435         ANGLE_GL_PROGRAM(programRed, vertexShaderStr.str().c_str(), essl3_shaders::fs::Red());
1436         glUseProgram(programRed);
1437         ASSERT_GL_NO_ERROR();
1438 
1439         // Enable the current clip distance, disable all others.
1440         for (size_t j = 0; j < 8; j++)
1441         {
1442             if (j == i)
1443                 glEnable(GL_CLIP_DISTANCE0_EXT + j);
1444             else
1445                 glDisable(GL_CLIP_DISTANCE0_EXT + j);
1446         }
1447 
1448         // Clear to blue
1449         glClearColor(0, 0, 1, 1);
1450         glClear(GL_COLOR_BUFFER_BIT);
1451 
1452         // Draw full screen quad with color red
1453         glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1454         EXPECT_GL_NO_ERROR();
1455         drawQuad(programRed, "a_position", 0);
1456         EXPECT_GL_NO_ERROR();
1457 
1458         // All pixels on the left of the plane x = -0.5 must be blue
1459         GLuint x      = 0;
1460         GLuint y      = 0;
1461         GLuint width  = getWindowWidth() / 4 - 1;
1462         GLuint height = getWindowHeight();
1463         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1464 
1465         // All pixels on the right of the plane x = -0.5 must be red
1466         x      = getWindowWidth() / 4 + 2;
1467         y      = 0;
1468         width  = getWindowWidth() - x;
1469         height = getWindowHeight();
1470         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1471 
1472         // Clear to green
1473         glClearColor(0, 1, 0, 1);
1474         glClear(GL_COLOR_BUFFER_BIT);
1475 
1476         // Draw full screen quad with color red
1477         glUniform4f(glGetUniformLocation(programRed, "u_plane"), -1, 0, 0, -0.5);
1478         EXPECT_GL_NO_ERROR();
1479         drawQuad(programRed, "a_position", 0);
1480         EXPECT_GL_NO_ERROR();
1481 
1482         // All pixels on the left of the plane x = -0.5 must be red
1483         x      = 0;
1484         y      = 0;
1485         width  = getWindowWidth() / 4 - 1;
1486         height = getWindowHeight();
1487         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1488 
1489         // All pixels on the right of the plane x = -0.5 must be green
1490         x      = getWindowWidth() / 4 + 2;
1491         y      = 0;
1492         width  = getWindowWidth() - x;
1493         height = getWindowHeight();
1494         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1495 
1496         // Disable GL_CLIP_DISTANCE
1497         glDisable(GL_CLIP_DISTANCE0_EXT + i);
1498         drawQuad(programRed, "a_position", 0);
1499 
1500         // All pixels must be red
1501         x      = 0;
1502         y      = 0;
1503         width  = getWindowWidth();
1504         height = getWindowHeight();
1505         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1506     }
1507 }
1508 
1509 // Use 8 clip distances to draw an octagon
TEST_P(ClipCullDistanceTest,Octagon)1510 TEST_P(ClipCullDistanceTest, Octagon)
1511 {
1512     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1513 
1514     std::string kVS = R"(#version 300 es
1515 #extension )" + kExtensionName +
1516                       R"( : require
1517 
1518 in vec2 a_position;
1519 
1520 void main()
1521 {
1522     gl_Position = vec4(a_position, 0.0, 1.0);
1523 
1524     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
1525     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
1526     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
1527     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
1528     gl_ClipDistance[4] = dot(gl_Position, vec4( 1,  1, 0, 0.70710678));
1529     gl_ClipDistance[5] = dot(gl_Position, vec4( 1, -1, 0, 0.70710678));
1530     gl_ClipDistance[6] = dot(gl_Position, vec4(-1,  1, 0, 0.70710678));
1531     gl_ClipDistance[7] = dot(gl_Position, vec4(-1, -1, 0, 0.70710678));
1532 })";
1533 
1534     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1535     glUseProgram(programRed);
1536     ASSERT_GL_NO_ERROR();
1537 
1538     glEnable(GL_CLIP_DISTANCE0_EXT);
1539     glEnable(GL_CLIP_DISTANCE1_EXT);
1540     glEnable(GL_CLIP_DISTANCE2_EXT);
1541     glEnable(GL_CLIP_DISTANCE3_EXT);
1542     glEnable(GL_CLIP_DISTANCE4_EXT);
1543     glEnable(GL_CLIP_DISTANCE5_EXT);
1544     glEnable(GL_CLIP_DISTANCE6_EXT);
1545     glEnable(GL_CLIP_DISTANCE7_EXT);
1546 
1547     // Clear to blue
1548     glClearColor(0, 0, 1, 1);
1549     glClear(GL_COLOR_BUFFER_BIT);
1550 
1551     // Draw full screen quad with color red
1552     drawQuad(programRed, "a_position", 0);
1553     EXPECT_GL_NO_ERROR();
1554 
1555     // Top edge
1556     EXPECT_PIXEL_COLOR_EQ(32, 56, GLColor::blue);
1557     EXPECT_PIXEL_COLOR_EQ(32, 40, GLColor::red);
1558 
1559     // Top-right edge
1560     EXPECT_PIXEL_COLOR_EQ(48, 48, GLColor::blue);
1561     EXPECT_PIXEL_COLOR_EQ(40, 40, GLColor::red);
1562 
1563     // Right edge
1564     EXPECT_PIXEL_COLOR_EQ(56, 32, GLColor::blue);
1565     EXPECT_PIXEL_COLOR_EQ(40, 32, GLColor::red);
1566 
1567     // Bottom-right edge
1568     EXPECT_PIXEL_COLOR_EQ(48, 16, GLColor::blue);
1569     EXPECT_PIXEL_COLOR_EQ(40, 24, GLColor::red);
1570 
1571     // Bottom edge
1572     EXPECT_PIXEL_COLOR_EQ(32, 8, GLColor::blue);
1573     EXPECT_PIXEL_COLOR_EQ(32, 24, GLColor::red);
1574 
1575     // Bottom-left edge
1576     EXPECT_PIXEL_COLOR_EQ(16, 16, GLColor::blue);
1577     EXPECT_PIXEL_COLOR_EQ(24, 24, GLColor::red);
1578 
1579     // Left edge
1580     EXPECT_PIXEL_COLOR_EQ(8, 32, GLColor::blue);
1581     EXPECT_PIXEL_COLOR_EQ(24, 32, GLColor::red);
1582 
1583     // Top-left edge
1584     EXPECT_PIXEL_COLOR_EQ(16, 48, GLColor::blue);
1585     EXPECT_PIXEL_COLOR_EQ(24, 40, GLColor::red);
1586 }
1587 
1588 // Write to 3 clip distances
TEST_P(ClipCullDistanceTest,ThreeClipDistances)1589 TEST_P(ClipCullDistanceTest, ThreeClipDistances)
1590 {
1591     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1592 
1593     std::string kVS = R"(#version 300 es
1594 #extension )" + kExtensionName +
1595                       R"( : require
1596 
1597 uniform vec4 u_plane[3];
1598 
1599 in vec2 a_position;
1600 
1601 void main()
1602 {
1603     gl_Position = vec4(a_position, 0.0, 1.0);
1604 
1605     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
1606     gl_ClipDistance[3] = dot(gl_Position, u_plane[1]);
1607     gl_ClipDistance[7] = dot(gl_Position, u_plane[2]);
1608 })";
1609 
1610     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1611     glUseProgram(programRed);
1612     ASSERT_GL_NO_ERROR();
1613 
1614     // Enable 3 clip distances
1615     glEnable(GL_CLIP_DISTANCE0_EXT);
1616     glEnable(GL_CLIP_DISTANCE3_EXT);
1617     glEnable(GL_CLIP_DISTANCE7_EXT);
1618     ASSERT_GL_NO_ERROR();
1619 
1620     // Clear to blue
1621     glClearColor(0, 0, 1, 1);
1622     glClear(GL_COLOR_BUFFER_BIT);
1623 
1624     // Draw full screen quad with color red
1625     // x = -0.5
1626     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
1627     // x = 0.5
1628     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
1629     // x + y = 1
1630     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
1631     EXPECT_GL_NO_ERROR();
1632     drawQuad(programRed, "a_position", 0);
1633     EXPECT_GL_NO_ERROR();
1634 
1635     {
1636         // All pixels on the left of the plane x = -0.5 must be blue
1637         GLuint x      = 0;
1638         GLuint y      = 0;
1639         GLuint width  = getWindowWidth() / 4 - 1;
1640         GLuint height = getWindowHeight();
1641         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1642 
1643         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1644         x      = getWindowWidth() / 4 + 2;
1645         y      = 0;
1646         width  = getWindowWidth() / 2 - x;
1647         height = getWindowHeight();
1648         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1649     }
1650 
1651     {
1652         // Check pixels to the right of the plane x = 0
1653         std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1654         glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1655                      actualColors.data());
1656         for (int y = 0; y < getWindowHeight(); ++y)
1657         {
1658             for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1659             {
1660                 const int currentPosition = y * getWindowHeight() + x;
1661 
1662                 if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
1663                 {
1664                     // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
1665                     EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1666                 }
1667                 else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
1668                 {
1669                     // Top of the plane x + y = 1 plus right of x = 0.5 plane
1670                     EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1671                 }
1672             }
1673         }
1674     }
1675 
1676     // Clear to green
1677     glClearColor(0, 1, 0, 1);
1678     glClear(GL_COLOR_BUFFER_BIT);
1679 
1680     // Disable gl_ClipDistance[3]
1681     glDisable(GL_CLIP_DISTANCE3_EXT);
1682 
1683     // Draw full screen quad with color red
1684     EXPECT_GL_NO_ERROR();
1685     drawQuad(programRed, "a_position", 0);
1686     EXPECT_GL_NO_ERROR();
1687 
1688     {
1689         // All pixels on the left of the plane x = -0.5 must be green
1690         GLuint x      = 0;
1691         GLuint y      = 0;
1692         GLuint width  = getWindowWidth() / 4 - 1;
1693         GLuint height = getWindowHeight();
1694         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::green);
1695 
1696         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1697         x      = getWindowWidth() / 4 + 2;
1698         y      = 0;
1699         width  = getWindowWidth() / 2 - x;
1700         height = getWindowHeight();
1701         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1702     }
1703 
1704     // Check pixels to the right of the plane x = 0
1705     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1706     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1707                  actualColors.data());
1708     for (int y = 0; y < getWindowHeight(); ++y)
1709     {
1710         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1711         {
1712             const int currentPosition = y * getWindowHeight() + x;
1713 
1714             if (x < getWindowWidth() * 3 / 2 - y - 1)
1715             {
1716                 // Bottom of the plane x + y = 1
1717                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1718             }
1719             else if (x > getWindowWidth() * 3 / 2 - y + 1)
1720             {
1721                 // Top of the plane x + y = 1
1722                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
1723             }
1724         }
1725     }
1726 }
1727 
1728 // Redeclare gl_ClipDistance in shader with explicit size, also use it in a global function
1729 // outside main()
TEST_P(ClipCullDistanceTest,ThreeClipDistancesRedeclared)1730 TEST_P(ClipCullDistanceTest, ThreeClipDistancesRedeclared)
1731 {
1732     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1733 
1734     std::string kVS = R"(#version 300 es
1735 #extension )" + kExtensionName +
1736                       R"( : require
1737 
1738 out highp float gl_ClipDistance[3];
1739 
1740 void computeClipDistances(in vec4 position, in vec4 plane[3])
1741 {
1742     gl_ClipDistance[0] = dot(position, plane[0]);
1743     gl_ClipDistance[1] = dot(position, plane[1]);
1744     gl_ClipDistance[2] = dot(position, plane[2]);
1745 }
1746 
1747 uniform vec4 u_plane[3];
1748 
1749 in vec2 a_position;
1750 
1751 void main()
1752 {
1753     gl_Position = vec4(a_position, 0.0, 1.0);
1754 
1755     computeClipDistances(gl_Position, u_plane);
1756 })";
1757 
1758     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
1759     glUseProgram(programRed);
1760     ASSERT_GL_NO_ERROR();
1761 
1762     // Enable 3 clip distances
1763     glEnable(GL_CLIP_DISTANCE0_EXT);
1764     glEnable(GL_CLIP_DISTANCE1_EXT);
1765     glEnable(GL_CLIP_DISTANCE2_EXT);
1766     ASSERT_GL_NO_ERROR();
1767 
1768     // Clear to blue
1769     glClearColor(0, 0, 1, 1);
1770     glClear(GL_COLOR_BUFFER_BIT);
1771 
1772     // Draw full screen quad with color red
1773     // x = -0.5
1774     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 1, 0, 0, 0.5);
1775     // x = 0.5
1776     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), -1, 0, 0, 0.5);
1777     // x + y = 1
1778     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -1, -1, 0, 1);
1779     EXPECT_GL_NO_ERROR();
1780     drawQuad(programRed, "a_position", 0);
1781     EXPECT_GL_NO_ERROR();
1782 
1783     {
1784         // All pixels on the left of the plane x = -0.5 must be blue
1785         GLuint x      = 0;
1786         GLuint y      = 0;
1787         GLuint width  = getWindowWidth() / 4 - 1;
1788         GLuint height = getWindowHeight();
1789         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::blue);
1790 
1791         // All pixels from the plane x = -0.5 to the plane x = 0 must be red
1792         x      = getWindowWidth() / 4 + 2;
1793         y      = 0;
1794         width  = getWindowWidth() / 2 - x;
1795         height = getWindowHeight();
1796         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1797     }
1798 
1799     // Check pixels to the right of the plane x = 0
1800     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1801     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1802                  actualColors.data());
1803     for (int y = 0; y < getWindowHeight(); ++y)
1804     {
1805         for (int x = getWindowWidth() / 2; x < getWindowWidth(); ++x)
1806         {
1807             const int currentPosition = y * getWindowHeight() + x;
1808 
1809             if (x < getWindowWidth() * 3 / 2 - y - 1 && x < getWindowWidth() * 3 / 4 - 1)
1810             {
1811                 // Bottom of the plane x + y = 1 clipped by x = 0.5 plane
1812                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1813             }
1814             else if (x > getWindowWidth() * 3 / 2 - y + 1 || x > getWindowWidth() * 3 / 4 + 1)
1815             {
1816                 // Top of the plane x + y = 1 plus right of x = 0.5 plane
1817                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1818             }
1819         }
1820     }
1821 }
1822 
1823 // Read clip distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,ClipInterpolation)1824 TEST_P(ClipCullDistanceTest, ClipInterpolation)
1825 {
1826     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1827 
1828     std::string kVS = R"(#version 300 es
1829 #extension )" + kExtensionName +
1830                       R"( : require
1831 in vec2 a_position;
1832 void main()
1833 {
1834     gl_Position = vec4(a_position, 0.0, 1.0);
1835     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
1836     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
1837     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
1838     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
1839     gl_ClipDistance[4] = gl_ClipDistance[0];
1840     gl_ClipDistance[5] = gl_ClipDistance[1];
1841     gl_ClipDistance[6] = gl_ClipDistance[2];
1842     gl_ClipDistance[7] = gl_ClipDistance[3];
1843 })";
1844 
1845     std::string kFS = R"(#version 300 es
1846 #extension )" + kExtensionName +
1847                       R"( : require
1848 precision highp float;
1849 out vec4 my_FragColor;
1850 void main()
1851 {
1852     float r = gl_ClipDistance[0] + gl_ClipDistance[1];
1853     float g = gl_ClipDistance[2] + gl_ClipDistance[3];
1854     float b = gl_ClipDistance[4] + gl_ClipDistance[5];
1855     float a = gl_ClipDistance[6] + gl_ClipDistance[7];
1856     my_FragColor = vec4(r, g, b, a) * 0.5;
1857 })";
1858 
1859     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), kFS.c_str());
1860     glUseProgram(programRed);
1861     ASSERT_GL_NO_ERROR();
1862 
1863     glEnable(GL_CLIP_DISTANCE0_EXT);
1864     glEnable(GL_CLIP_DISTANCE1_EXT);
1865     glEnable(GL_CLIP_DISTANCE2_EXT);
1866     glEnable(GL_CLIP_DISTANCE3_EXT);
1867     glEnable(GL_CLIP_DISTANCE4_EXT);
1868     glEnable(GL_CLIP_DISTANCE5_EXT);
1869     glEnable(GL_CLIP_DISTANCE6_EXT);
1870     glEnable(GL_CLIP_DISTANCE7_EXT);
1871 
1872     // Clear to blue
1873     glClearColor(0, 0, 1, 1);
1874     glClear(GL_COLOR_BUFFER_BIT);
1875 
1876     // Draw full screen quad with color red
1877     drawQuad(programRed, "a_position", 0);
1878     EXPECT_GL_NO_ERROR();
1879 
1880     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1881     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1882                  actualColors.data());
1883     for (int x = 0; x < getWindowWidth(); x++)
1884     {
1885         for (int y = 0; y < getWindowHeight(); y++)
1886         {
1887             const int currentPosition = y * getWindowHeight() + x;
1888 
1889             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
1890                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
1891             {
1892                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
1893             }
1894             else
1895             {
1896                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
1897             }
1898         }
1899     }
1900 }
1901 
1902 // Write to one gl_CullDistance element
TEST_P(ClipCullDistanceTest,OneCullDistance)1903 TEST_P(ClipCullDistanceTest, OneCullDistance)
1904 {
1905     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1906 
1907     std::string kVS = R"(#version 300 es
1908 #extension )" + kExtensionName +
1909                       R"( : require
1910 
1911 uniform vec4 u_plane;
1912 
1913 in vec2 a_position;
1914 
1915 void main()
1916 {
1917     gl_Position = vec4(a_position, 0.0, 1.0);
1918 
1919     gl_CullDistance[0] = dot(gl_Position, u_plane);
1920 })";
1921 
1922     GLProgram programRed;
1923     programRed.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
1924     if (!mCullDistanceSupportRequired)
1925     {
1926         GLint maxCullDistances;
1927         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
1928         if (maxCullDistances == 0)
1929         {
1930             ASSERT_FALSE(programRed.valid());
1931             return;
1932         }
1933     }
1934     glUseProgram(programRed);
1935     ASSERT_GL_NO_ERROR();
1936 
1937     // Clear to blue
1938     glClearColor(0, 0, 1, 1);
1939     glClear(GL_COLOR_BUFFER_BIT);
1940 
1941     // Draw full screen quad with color red
1942     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 0, 0, 0.5);
1943     EXPECT_GL_NO_ERROR();
1944     drawQuad(programRed, "a_position", 0);
1945     EXPECT_GL_NO_ERROR();
1946 
1947     {
1948         // All pixels must be red
1949         GLuint x      = 0;
1950         GLuint y      = 0;
1951         GLuint width  = getWindowWidth();
1952         GLuint height = getWindowHeight();
1953         EXPECT_PIXEL_RECT_EQ(x, y, width, height, GLColor::red);
1954     }
1955 
1956     // Clear to green
1957     glClearColor(0, 1, 0, 1);
1958     glClear(GL_COLOR_BUFFER_BIT);
1959 
1960     // Draw full screen quad with color red
1961     glUniform4f(glGetUniformLocation(programRed, "u_plane"), 1, 1, 0, 0);
1962     EXPECT_GL_NO_ERROR();
1963     drawQuad(programRed, "a_position", 0);
1964     EXPECT_GL_NO_ERROR();
1965 
1966     // All pixels on the plane y >= -x must be red
1967     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
1968     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
1969                  actualColors.data());
1970     for (int x = 0; x < getWindowWidth(); ++x)
1971     {
1972         for (int y = 0; y < getWindowHeight(); ++y)
1973         {
1974             const int currentPosition = y * getWindowHeight() + x;
1975 
1976             if ((x + y) >= 0)
1977             {
1978                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
1979             }
1980             else
1981             {
1982                 EXPECT_EQ(GLColor::green, actualColors[currentPosition]);
1983             }
1984         }
1985     }
1986 }
1987 
1988 // Read cull distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,CullInterpolation)1989 TEST_P(ClipCullDistanceTest, CullInterpolation)
1990 {
1991     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
1992 
1993     std::string kVS = R"(#version 300 es
1994 #extension )" + kExtensionName +
1995                       R"( : require
1996 in vec2 a_position;
1997 void main()
1998 {
1999     gl_Position = vec4(a_position, 0.0, 1.0);
2000     gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
2001     gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
2002     gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
2003     gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
2004     gl_CullDistance[4] = gl_CullDistance[0];
2005     gl_CullDistance[5] = gl_CullDistance[1];
2006     gl_CullDistance[6] = gl_CullDistance[2];
2007     gl_CullDistance[7] = gl_CullDistance[3];
2008 })";
2009 
2010     std::string kFS = R"(#version 300 es
2011 #extension )" + kExtensionName +
2012                       R"( : require
2013 precision highp float;
2014 out vec4 my_FragColor;
2015 void main()
2016 {
2017     float r = gl_CullDistance[0] + gl_CullDistance[1];
2018     float g = gl_CullDistance[2] + gl_CullDistance[3];
2019     float b = gl_CullDistance[4] + gl_CullDistance[5];
2020     float a = gl_CullDistance[6] + gl_CullDistance[7];
2021     my_FragColor = vec4(r, g, b, a) * 0.25;
2022 })";
2023 
2024     GLProgram programRed;
2025     programRed.makeRaster(kVS.c_str(), kFS.c_str());
2026     if (!mCullDistanceSupportRequired)
2027     {
2028         GLint maxCullDistances;
2029         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2030         if (maxCullDistances == 0)
2031         {
2032             ASSERT_FALSE(programRed.valid());
2033             return;
2034         }
2035     }
2036     glUseProgram(programRed);
2037     ASSERT_GL_NO_ERROR();
2038 
2039     // Clear to blue
2040     glClearColor(0, 0, 1, 1);
2041     glClear(GL_COLOR_BUFFER_BIT);
2042 
2043     // Draw full screen quad with color red
2044     drawQuad(programRed, "a_position", 0, 0.5);
2045     EXPECT_GL_NO_ERROR();
2046 
2047     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2048     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2049                  actualColors.data());
2050     for (int x = 0; x < getWindowWidth(); x++)
2051     {
2052         for (int y = 0; y < getWindowHeight(); y++)
2053         {
2054             const int currentPosition = y * getWindowHeight() + x;
2055 
2056             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2057                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2058             {
2059                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2060             }
2061             else
2062             {
2063                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2064             }
2065         }
2066     }
2067 }
2068 
2069 // Read both clip and cull distance varyings in fragment shaders
TEST_P(ClipCullDistanceTest,ClipCullInterpolation)2070 TEST_P(ClipCullDistanceTest, ClipCullInterpolation)
2071 {
2072     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2073 
2074     std::string kVS = R"(#version 300 es
2075 #extension )" + kExtensionName +
2076                       R"( : require
2077 in vec2 a_position;
2078 void main()
2079 {
2080     gl_Position = vec4(a_position, 0.0, 1.0);
2081     gl_ClipDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 0.5));
2082     gl_ClipDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 0.5));
2083     gl_ClipDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 0.5));
2084     gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5));
2085     gl_CullDistance[0] = dot(gl_Position, vec4( 1,  0, 0, 1));
2086     gl_CullDistance[1] = dot(gl_Position, vec4(-1,  0, 0, 1));
2087     gl_CullDistance[2] = dot(gl_Position, vec4( 0,  1, 0, 1));
2088     gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1));
2089 })";
2090 
2091     std::string kFS = R"(#version 300 es
2092 #extension )" + kExtensionName +
2093                       R"( : require
2094 precision highp float;
2095 out vec4 my_FragColor;
2096 void main()
2097 {
2098     my_FragColor =
2099         vec4(gl_ClipDistance[0] + gl_ClipDistance[1],
2100              gl_ClipDistance[2] + gl_ClipDistance[3],
2101              gl_CullDistance[0] + gl_CullDistance[1],
2102              gl_CullDistance[2] + gl_CullDistance[3]) *
2103         vec4(0.5, 0.5, 0.25, 0.25);
2104 })";
2105 
2106     GLProgram programRed;
2107     programRed.makeRaster(kVS.c_str(), kFS.c_str());
2108     if (!mCullDistanceSupportRequired)
2109     {
2110         GLint maxCullDistances;
2111         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2112         if (maxCullDistances == 0)
2113         {
2114             ASSERT_FALSE(programRed.valid());
2115             return;
2116         }
2117     }
2118     glUseProgram(programRed);
2119     ASSERT_GL_NO_ERROR();
2120 
2121     glEnable(GL_CLIP_DISTANCE0_EXT);
2122     glEnable(GL_CLIP_DISTANCE1_EXT);
2123     glEnable(GL_CLIP_DISTANCE2_EXT);
2124     glEnable(GL_CLIP_DISTANCE3_EXT);
2125 
2126     // Clear to blue
2127     glClearColor(0, 0, 1, 1);
2128     glClear(GL_COLOR_BUFFER_BIT);
2129 
2130     // Draw full screen quad with color red
2131     drawQuad(programRed, "a_position", 0);
2132     EXPECT_GL_NO_ERROR();
2133 
2134     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2135     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2136                  actualColors.data());
2137     for (int x = 0; x < getWindowWidth(); x++)
2138     {
2139         for (int y = 0; y < getWindowHeight(); y++)
2140         {
2141             const int currentPosition = y * getWindowHeight() + x;
2142 
2143             if (x >= getWindowWidth() / 4 && x < getWindowWidth() * 3 / 4 &&
2144                 y >= getWindowHeight() / 4 && y < getWindowHeight() * 3 / 4)
2145             {
2146                 EXPECT_COLOR_NEAR(GLColor(127, 127, 127, 127), actualColors[currentPosition], 1);
2147             }
2148             else
2149             {
2150                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2151             }
2152         }
2153     }
2154 }
2155 
2156 // Write to 4 clip distances
TEST_P(ClipCullDistanceTest,FourClipDistances)2157 TEST_P(ClipCullDistanceTest, FourClipDistances)
2158 {
2159     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2160 
2161     std::string kVS = R"(#version 300 es
2162 #extension )" + kExtensionName +
2163                       R"( : require
2164 
2165 in vec2 a_position;
2166 uniform vec4 u_plane[4];
2167 
2168 void main()
2169 {
2170     gl_Position = vec4(a_position, 0.0, 1.0);
2171 
2172     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
2173     gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
2174     gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
2175     gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
2176 })";
2177 
2178     ANGLE_GL_PROGRAM(programRed, kVS.c_str(), essl3_shaders::fs::Red());
2179     glUseProgram(programRed);
2180     ASSERT_GL_NO_ERROR();
2181 
2182     // Enable 3 clip distances
2183     glEnable(GL_CLIP_DISTANCE0_EXT);
2184     glEnable(GL_CLIP_DISTANCE2_EXT);
2185     glEnable(GL_CLIP_DISTANCE3_EXT);
2186     ASSERT_GL_NO_ERROR();
2187 
2188     // Disable 1 clip distances
2189     glDisable(GL_CLIP_DISTANCE1_EXT);
2190     ASSERT_GL_NO_ERROR();
2191 
2192     // Clear to blue
2193     glClearColor(0, 0, 1, 1);
2194     glClear(GL_COLOR_BUFFER_BIT);
2195 
2196     constexpr unsigned int kNumVertices                  = 12;
2197     const std::array<Vector3, kNumVertices> quadVertices = {
2198         {Vector3(-1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f),
2199          Vector3(1.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(1.0f, -1.0f, 0.0f),
2200          Vector3(1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, -1.0f, 0.0f),
2201          Vector3(-1.0f, -1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-1.0f, 1.0f, 0.0f)}};
2202 
2203     GLBuffer vertexBuffer;
2204     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2205     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2206                  GL_STATIC_DRAW);
2207     ASSERT_GL_NO_ERROR();
2208 
2209     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2210     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2211     ASSERT_GL_NO_ERROR();
2212 
2213     glEnableVertexAttribArray(positionLocation);
2214     ASSERT_GL_NO_ERROR();
2215 
2216     // Draw full screen quad and small size triangle with color red
2217     // y <= 1.0f
2218     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2219     // y >= 0.5f
2220     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2221     // y >= 3x-0.5f
2222     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2223     // y >= -3x-0.5f
2224     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2225     EXPECT_GL_NO_ERROR();
2226 
2227     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2228     EXPECT_GL_NO_ERROR();
2229 
2230     const int windowWidth   = getWindowWidth();
2231     const int windowHeight  = getWindowHeight();
2232     auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2233         return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
2234     };
2235     auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2236         return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
2237     };
2238 
2239     // Only pixels in the triangle must be red
2240     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2241     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2242                  actualColors.data());
2243     for (int x = 0; x < getWindowWidth(); ++x)
2244     {
2245         for (int y = 0; y < getWindowHeight(); ++y)
2246         {
2247             // The drawing method of Swiftshader and Native graphic card is different. So the
2248             // compare function doesn't check the value on the line.
2249             const int currentPosition = y * getWindowHeight() + x;
2250 
2251             if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
2252             {
2253                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2254             }
2255             else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
2256             {
2257                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2258             }
2259         }
2260     }
2261 }
2262 
2263 // Write to 4 cull distances
TEST_P(ClipCullDistanceTest,FourCullDistances)2264 TEST_P(ClipCullDistanceTest, FourCullDistances)
2265 {
2266     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName));
2267 
2268     // SwiftShader bug: http://anglebug.com/5451
2269     ANGLE_SKIP_TEST_IF(isSwiftshader());
2270 
2271     std::string kVS = R"(#version 300 es
2272 #extension )" + kExtensionName +
2273                       R"( : require
2274 
2275 uniform vec4 u_plane[4];
2276 
2277 in vec2 a_position;
2278 
2279 void main()
2280 {
2281     gl_Position = vec4(a_position, 0.0, 1.0);
2282 
2283     gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
2284     gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
2285     gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
2286     gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
2287 })";
2288 
2289     GLProgram programRed;
2290     programRed.makeRaster(kVS.c_str(), essl3_shaders::fs::Red());
2291     if (!mCullDistanceSupportRequired)
2292     {
2293         GLint maxCullDistances;
2294         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2295         if (maxCullDistances == 0)
2296         {
2297             ASSERT_FALSE(programRed.valid());
2298             return;
2299         }
2300     }
2301     glUseProgram(programRed);
2302     ASSERT_GL_NO_ERROR();
2303 
2304     // Clear to blue
2305     glClearColor(0, 0, 1, 1);
2306     glClear(GL_COLOR_BUFFER_BIT);
2307 
2308     constexpr unsigned int kNumVertices                  = 12;
2309     const std::array<Vector2, kNumVertices> quadVertices = {
2310         {Vector2(-1.0f, 1.0f), Vector2(0.0f, 0.0f), Vector2(1.0f, 1.0f), Vector2(1.0f, 1.0f),
2311          Vector2(0.0f, 0.0f), Vector2(1.0f, -1.0f), Vector2(1.0f, -1.0f), Vector2(0.0f, 0.0f),
2312          Vector2(-1.0f, -1.0f), Vector2(-1.0f, -1.0f), Vector2(0.0f, 0.0f), Vector2(-1.0f, 1.0f)}};
2313 
2314     GLBuffer vertexBuffer;
2315     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2316     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * kNumVertices, quadVertices.data(),
2317                  GL_STATIC_DRAW);
2318     ASSERT_GL_NO_ERROR();
2319 
2320     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2321     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
2322     ASSERT_GL_NO_ERROR();
2323 
2324     glEnableVertexAttribArray(positionLocation);
2325     ASSERT_GL_NO_ERROR();
2326 
2327     // Draw full screen quad and small size triangle with color red
2328     // y <= 1.0f
2329     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2330     // y >= 0.5f
2331     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2332     // y >= 3x-0.5f
2333     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2334     // y >= -3x-0.5f
2335     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2336     EXPECT_GL_NO_ERROR();
2337 
2338     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2339     EXPECT_GL_NO_ERROR();
2340 
2341     // Only the bottom triangle must be culled
2342     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2343     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2344                  actualColors.data());
2345     for (int x = 0; x < getWindowWidth(); ++x)
2346     {
2347         for (int y = 0; y < getWindowHeight(); ++y)
2348         {
2349             const int currentPosition = y * getWindowHeight() + x;
2350 
2351             if (y > x || y >= -x + getWindowHeight() - 1)
2352             {
2353                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2354             }
2355             else
2356             {
2357                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2358             }
2359         }
2360     }
2361 }
2362 
2363 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,ClipDistanceInteractWithGeometryShader)2364 TEST_P(ClipCullDistanceTest, ClipDistanceInteractWithGeometryShader)
2365 {
2366     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName) ||
2367                        !EnsureGLExtensionEnabled("GL_EXT_geometry_shader"));
2368 
2369     std::string kVS = R"(#version 310 es
2370 #extension )" + kExtensionName +
2371                       R"( : require
2372 #extension GL_EXT_geometry_shader : require
2373 
2374 in vec2 a_position;
2375 uniform vec4 u_plane[4];
2376 
2377 void main()
2378 {
2379     gl_Position = vec4(a_position, 0.0, 1.0);
2380 
2381     gl_ClipDistance[0] = dot(gl_Position, u_plane[0]);
2382     gl_ClipDistance[1] = dot(gl_Position, u_plane[1]);
2383     gl_ClipDistance[2] = dot(gl_Position, u_plane[2]);
2384     gl_ClipDistance[3] = dot(gl_Position, u_plane[3]);
2385 })";
2386 
2387     std::string kGS = R"(#version 310 es
2388 #extension )" + kExtensionName +
2389                       R"( : require
2390 #extension GL_EXT_geometry_shader : require
2391 
2392 layout (triangles) in;
2393 layout (triangle_strip, max_vertices = 3) out;
2394 
2395 in gl_PerVertex {
2396     highp vec4 gl_Position;
2397     highp float gl_ClipDistance[];
2398 } gl_in[];
2399 
2400 out gl_PerVertex {
2401     highp vec4 gl_Position;
2402     highp float gl_ClipDistance[];
2403 };
2404 
2405 uniform vec4 u_plane[4];
2406 
2407 void GetNewPosition(int i)
2408 {
2409     gl_Position = 2.0f * gl_in[i].gl_Position;
2410 
2411     for (int index = 0 ; index < 4 ; index++)
2412     {
2413         if (gl_in[i].gl_ClipDistance[index] < 0.0f)
2414         {
2415             gl_ClipDistance[index] = dot(gl_Position, u_plane[index]);
2416         }
2417     }
2418     EmitVertex();
2419 }
2420 
2421 void main()
2422 {
2423     for (int i = 0 ; i < 3 ; i++)
2424     {
2425         GetNewPosition(i);
2426     }
2427     EndPrimitive();
2428 })";
2429 
2430     ANGLE_GL_PROGRAM_WITH_GS(programRed, kVS.c_str(), kGS.c_str(), essl31_shaders::fs::Red());
2431     glUseProgram(programRed);
2432     ASSERT_GL_NO_ERROR();
2433 
2434     // Enable 3 clip distances
2435     glEnable(GL_CLIP_DISTANCE0_EXT);
2436     glEnable(GL_CLIP_DISTANCE2_EXT);
2437     glEnable(GL_CLIP_DISTANCE3_EXT);
2438     ASSERT_GL_NO_ERROR();
2439 
2440     // Disable 1 clip distances
2441     glDisable(GL_CLIP_DISTANCE1_EXT);
2442     ASSERT_GL_NO_ERROR();
2443 
2444     // Clear to blue
2445     glClearColor(0, 0, 1, 1);
2446     glClear(GL_COLOR_BUFFER_BIT);
2447 
2448     constexpr unsigned int kNumVertices                  = 12;
2449     const std::array<Vector3, kNumVertices> quadVertices = {
2450         {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
2451          Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
2452          Vector3(0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f),
2453          Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, 0.5f, 0.0f)}};
2454 
2455     GLBuffer vertexBuffer;
2456     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2457     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2458                  GL_STATIC_DRAW);
2459     ASSERT_GL_NO_ERROR();
2460 
2461     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2462     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2463     ASSERT_GL_NO_ERROR();
2464 
2465     glEnableVertexAttribArray(positionLocation);
2466     ASSERT_GL_NO_ERROR();
2467 
2468     // Draw full screen quad and small size triangle with color red
2469     // y <= 1.0f
2470     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2471     // y >= 0.5f
2472     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2473     // y >= 3x-0.5f
2474     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2475     // y >= -3x-0.5f
2476     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2477     EXPECT_GL_NO_ERROR();
2478 
2479     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2480     EXPECT_GL_NO_ERROR();
2481 
2482     const int windowWidth   = getWindowWidth();
2483     const int windowHeight  = getWindowHeight();
2484     auto checkLeftPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2485         return (3 * (x - (windowWidth / 2 - 1)) - (windowHeight / 4 + 1) + y);
2486     };
2487     auto checkRightPlaneFunc = [windowWidth, windowHeight](int x, int y) -> float {
2488         return (-3 * (x - (windowWidth / 2)) - (windowHeight / 4 + 1) + y);
2489     };
2490 
2491     // Only pixels in the triangle must be red
2492     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2493     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2494                  actualColors.data());
2495     for (int x = 0; x < getWindowWidth(); ++x)
2496     {
2497         for (int y = 0; y < getWindowHeight(); ++y)
2498         {
2499             // The drawing method of Swiftshader and Native graphic card is different. So the
2500             // compare function doesn't check the value on the line.
2501             const int currentPosition = y * getWindowHeight() + x;
2502 
2503             if (checkLeftPlaneFunc(x, y) > 0 && checkRightPlaneFunc(x, y) > 0)
2504             {
2505                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2506             }
2507             else if (checkLeftPlaneFunc(x, y) < 0 || checkRightPlaneFunc(x, y) < 0)
2508             {
2509                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2510             }
2511         }
2512     }
2513 }
2514 
2515 // Verify that EXT_clip_cull_distance works with EXT_geometry_shader
TEST_P(ClipCullDistanceTest,CullDistanceInteractWithGeometryShader)2516 TEST_P(ClipCullDistanceTest, CullDistanceInteractWithGeometryShader)
2517 {
2518     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled(kExtensionName) ||
2519                        !EnsureGLExtensionEnabled("GL_EXT_geometry_shader"));
2520 
2521     std::string kVS = R"(#version 310 es
2522 #extension )" + kExtensionName +
2523                       R"( : require
2524 #extension GL_EXT_geometry_shader : require
2525 
2526 in vec2 a_position;
2527 uniform vec4 u_plane[4];
2528 
2529 void main()
2530 {
2531     gl_Position = vec4(a_position, 0.0, 1.0);
2532 
2533     gl_CullDistance[0] = dot(gl_Position, u_plane[0]);
2534     gl_CullDistance[1] = dot(gl_Position, u_plane[1]);
2535     gl_CullDistance[2] = dot(gl_Position, u_plane[2]);
2536     gl_CullDistance[3] = dot(gl_Position, u_plane[3]);
2537 })";
2538 
2539     std::string kGS = R"(#version 310 es
2540 #extension )" + kExtensionName +
2541                       R"( : require
2542 #extension GL_EXT_geometry_shader : require
2543 
2544 layout (triangles) in;
2545 layout (triangle_strip, max_vertices = 3) out;
2546 
2547 in gl_PerVertex {
2548     highp vec4 gl_Position;
2549     highp float gl_CullDistance[];
2550 } gl_in[];
2551 
2552 out gl_PerVertex {
2553     highp vec4 gl_Position;
2554     highp float gl_CullDistance[];
2555 };
2556 
2557 uniform vec4 u_plane[4];
2558 
2559 void GetNewPosition(int i)
2560 {
2561     gl_Position = 2.0f * gl_in[i].gl_Position;
2562 
2563     for (int index = 0 ; index < 4 ; index++)
2564     {
2565         if (gl_in[i].gl_CullDistance[index] < 0.0f)
2566         {
2567             gl_CullDistance[index] = dot(gl_Position, u_plane[index]);
2568         }
2569     }
2570     EmitVertex();
2571 }
2572 
2573 void main()
2574 {
2575     for (int i = 0 ; i < 3 ; i++)
2576     {
2577         GetNewPosition(i);
2578     }
2579     EndPrimitive();
2580 })";
2581 
2582     GLProgram programRed;
2583     programRed.makeRaster(kVS.c_str(), kGS.c_str(), essl3_shaders::fs::Red());
2584     if (!mCullDistanceSupportRequired)
2585     {
2586         GLint maxCullDistances;
2587         glGetIntegerv(GL_MAX_CULL_DISTANCES_EXT, &maxCullDistances);
2588         if (maxCullDistances == 0)
2589         {
2590             ASSERT_FALSE(programRed.valid());
2591             return;
2592         }
2593     }
2594     glUseProgram(programRed);
2595     ASSERT_GL_NO_ERROR();
2596 
2597     // Clear to blue
2598     glClearColor(0, 0, 1, 1);
2599     glClear(GL_COLOR_BUFFER_BIT);
2600 
2601     constexpr unsigned int kNumVertices                  = 12;
2602     const std::array<Vector3, kNumVertices> quadVertices = {
2603         {Vector3(-0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f),
2604          Vector3(0.5f, 0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, -0.5f, 0.0f),
2605          Vector3(0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f),
2606          Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(-0.5f, 0.5f, 0.0f)}};
2607 
2608     GLBuffer vertexBuffer;
2609     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2610     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * kNumVertices, quadVertices.data(),
2611                  GL_STATIC_DRAW);
2612     ASSERT_GL_NO_ERROR();
2613 
2614     GLint positionLocation = glGetAttribLocation(programRed, "a_position");
2615     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2616     ASSERT_GL_NO_ERROR();
2617 
2618     glEnableVertexAttribArray(positionLocation);
2619     ASSERT_GL_NO_ERROR();
2620 
2621     // Draw full screen quad and small size triangle with color red
2622     // y <= 1.0f
2623     glUniform4f(glGetUniformLocation(programRed, "u_plane[0]"), 0, -1, 0, 1);
2624     // y >= 0.5f
2625     glUniform4f(glGetUniformLocation(programRed, "u_plane[1]"), 0, 1, 0, -0.5);
2626     // y >= 3x-0.5f
2627     glUniform4f(glGetUniformLocation(programRed, "u_plane[2]"), -3, 1, 0, 0.5);
2628     // y >= -3x-0.5f
2629     glUniform4f(glGetUniformLocation(programRed, "u_plane[3]"), 3, 1, 0, 0.5);
2630     EXPECT_GL_NO_ERROR();
2631 
2632     glDrawArrays(GL_TRIANGLES, 0, kNumVertices);
2633     EXPECT_GL_NO_ERROR();
2634 
2635     // Only pixels in the triangle must be red
2636     std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2637     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2638                  actualColors.data());
2639     for (int x = 0; x < getWindowWidth(); ++x)
2640     {
2641         for (int y = 0; y < getWindowHeight(); ++y)
2642         {
2643             const int currentPosition = y * getWindowHeight() + x;
2644 
2645             if (y > x || y >= -x + getWindowHeight() - 1)
2646             {
2647                 EXPECT_EQ(GLColor::red, actualColors[currentPosition]);
2648             }
2649             else
2650             {
2651                 EXPECT_EQ(GLColor::blue, actualColors[currentPosition]);
2652             }
2653         }
2654     }
2655 }
2656 
2657 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClipDistanceAPPLETest);
2658 
2659 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClipCullDistanceTest);
2660 ANGLE_INSTANTIATE_TEST_COMBINE_1(ClipCullDistanceTest,
2661                                  PrintToStringParamName,
2662                                  testing::Bool(),
2663                                  ANGLE_ALL_TEST_PLATFORMS_ES3,
2664                                  ANGLE_ALL_TEST_PLATFORMS_ES31);
2665