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