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