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