1 //
2 // Copyright 2016 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 // CHROMIUMPathRenderingTest
7 // Test CHROMIUM subset of NV_path_rendering
8 // This extension allows to render geometric paths as first class GL objects.
9
10 #include "test_utils/ANGLETest.h"
11 #include "shader_utils.h"
12
13 #include "common/angleutils.h"
14
15 #include <cmath>
16 #include <cstring>
17 #include <cstddef>
18 #include <fstream>
19
20 using namespace angle;
21
22 namespace
23 {
24
CheckPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLint tolerance,const angle::GLColor & color)25 bool CheckPixels(GLint x,
26 GLint y,
27 GLsizei width,
28 GLsizei height,
29 GLint tolerance,
30 const angle::GLColor &color)
31 {
32 for (GLint yy = 0; yy < height; ++yy)
33 {
34 for (GLint xx = 0; xx < width; ++xx)
35 {
36 const auto px = x + xx;
37 const auto py = y + yy;
38 EXPECT_PIXEL_NEAR(px, py, color.R, color.G, color.B, color.A, tolerance);
39 }
40 }
41
42 return true;
43 }
44
ExpectEqualMatrix(const GLfloat * expected,const GLfloat * actual)45 void ExpectEqualMatrix(const GLfloat *expected, const GLfloat *actual)
46 {
47 for (size_t i = 0; i < 16; ++i)
48 {
49 EXPECT_EQ(expected[i], actual[i]);
50 }
51 }
52
ExpectEqualMatrix(const GLfloat * expected,const GLint * actual)53 void ExpectEqualMatrix(const GLfloat *expected, const GLint *actual)
54 {
55 for (size_t i = 0; i < 16; ++i)
56 {
57 EXPECT_EQ(static_cast<GLint>(std::roundf(expected[i])), actual[i]);
58 }
59 }
60
61 const int kResolution = 300;
62
63 class CHROMIUMPathRenderingTest : public ANGLETest
64 {
65 protected:
CHROMIUMPathRenderingTest()66 CHROMIUMPathRenderingTest()
67 {
68 setWindowWidth(kResolution);
69 setWindowHeight(kResolution);
70 setConfigRedBits(8);
71 setConfigGreenBits(8);
72 setConfigBlueBits(8);
73 setConfigAlphaBits(8);
74 setConfigDepthBits(8);
75 setConfigStencilBits(8);
76 }
77
isApplicable() const78 bool isApplicable() const { return extensionEnabled("GL_CHROMIUM_path_rendering"); }
79
tryAllDrawFunctions(GLuint path,GLenum err)80 void tryAllDrawFunctions(GLuint path, GLenum err)
81 {
82 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F);
83 EXPECT_GL_ERROR(err);
84
85 glStencilFillPathCHROMIUM(path, GL_COUNT_DOWN_CHROMIUM, 0x7F);
86 EXPECT_GL_ERROR(err);
87
88 glStencilStrokePathCHROMIUM(path, 0x80, 0x80);
89 EXPECT_GL_ERROR(err);
90
91 glCoverFillPathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM);
92 EXPECT_GL_ERROR(err);
93
94 glCoverStrokePathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM);
95 EXPECT_GL_ERROR(err);
96
97 glStencilThenCoverStrokePathCHROMIUM(path, 0x80, 0x80, GL_BOUNDING_BOX_CHROMIUM);
98 EXPECT_GL_ERROR(err);
99
100 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F,
101 GL_BOUNDING_BOX_CHROMIUM);
102 EXPECT_GL_ERROR(err);
103 }
104 };
105
106 // Test setting and getting of path rendering matrices.
TEST_P(CHROMIUMPathRenderingTest,TestMatrix)107 TEST_P(CHROMIUMPathRenderingTest, TestMatrix)
108 {
109 if (!isApplicable())
110 return;
111
112 static const GLfloat kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
113 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
114
115 static const GLfloat kSeqMatrix[16] = {0.5f, -0.5f, -0.1f, -0.8f, 4.4f, 5.5f,
116 6.6f, 7.7f, 8.8f, 9.9f, 10.11f, 11.22f,
117 12.33f, 13.44f, 14.55f, 15.66f};
118
119 static const GLenum kMatrixModes[] = {GL_PATH_MODELVIEW_CHROMIUM, GL_PATH_PROJECTION_CHROMIUM};
120
121 static const GLenum kGetMatrixModes[] = {GL_PATH_MODELVIEW_MATRIX_CHROMIUM,
122 GL_PATH_PROJECTION_MATRIX_CHROMIUM};
123
124 for (size_t i = 0; i < 2; ++i)
125 {
126 GLfloat mf[16];
127 GLint mi[16];
128 std::memset(mf, 0, sizeof(mf));
129 std::memset(mi, 0, sizeof(mi));
130 glGetFloatv(kGetMatrixModes[i], mf);
131 glGetIntegerv(kGetMatrixModes[i], mi);
132 ExpectEqualMatrix(kIdentityMatrix, mf);
133 ExpectEqualMatrix(kIdentityMatrix, mi);
134
135 glMatrixLoadfCHROMIUM(kMatrixModes[i], kSeqMatrix);
136 std::memset(mf, 0, sizeof(mf));
137 std::memset(mi, 0, sizeof(mi));
138 glGetFloatv(kGetMatrixModes[i], mf);
139 glGetIntegerv(kGetMatrixModes[i], mi);
140 ExpectEqualMatrix(kSeqMatrix, mf);
141 ExpectEqualMatrix(kSeqMatrix, mi);
142
143 glMatrixLoadIdentityCHROMIUM(kMatrixModes[i]);
144 std::memset(mf, 0, sizeof(mf));
145 std::memset(mi, 0, sizeof(mi));
146 glGetFloatv(kGetMatrixModes[i], mf);
147 glGetIntegerv(kGetMatrixModes[i], mi);
148 ExpectEqualMatrix(kIdentityMatrix, mf);
149 ExpectEqualMatrix(kIdentityMatrix, mi);
150
151 ASSERT_GL_NO_ERROR();
152 }
153 }
154
155 // Test that trying to set incorrect matrix target results
156 // in a GL error.
TEST_P(CHROMIUMPathRenderingTest,TestMatrixErrors)157 TEST_P(CHROMIUMPathRenderingTest, TestMatrixErrors)
158 {
159 if (!isApplicable())
160 return;
161
162 GLfloat mf[16];
163 std::memset(mf, 0, sizeof(mf));
164
165 glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM, mf);
166 ASSERT_GL_NO_ERROR();
167
168 glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM);
169 ASSERT_GL_NO_ERROR();
170
171 // Test that invalid matrix targets fail.
172 glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM - 1, mf);
173 EXPECT_GL_ERROR(GL_INVALID_ENUM);
174
175 // Test that invalid matrix targets fail.
176 glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM + 1);
177 EXPECT_GL_ERROR(GL_INVALID_ENUM);
178 }
179
180 // Test basic path create and delete.
TEST_P(CHROMIUMPathRenderingTest,TestGenDelete)181 TEST_P(CHROMIUMPathRenderingTest, TestGenDelete)
182 {
183 if (!isApplicable())
184 return;
185
186 // This is unspecified in NV_path_rendering.
187 EXPECT_EQ(0u, glGenPathsCHROMIUM(0));
188 EXPECT_GL_ERROR(GL_INVALID_VALUE);
189
190 GLuint path = glGenPathsCHROMIUM(1);
191 EXPECT_NE(0u, path);
192 glDeletePathsCHROMIUM(path, 1);
193 ASSERT_GL_NO_ERROR();
194
195 GLuint first_path = glGenPathsCHROMIUM(5);
196 EXPECT_NE(0u, first_path);
197 glDeletePathsCHROMIUM(first_path, 5);
198 ASSERT_GL_NO_ERROR();
199
200 // Test deleting paths that are not actually allocated:
201 // "unused names in /paths/ are silently ignored".
202 first_path = glGenPathsCHROMIUM(5);
203 EXPECT_NE(0u, first_path);
204 glDeletePathsCHROMIUM(first_path, 6);
205 ASSERT_GL_NO_ERROR();
206
207 GLsizei big_range = 0xffff;
208 first_path = glGenPathsCHROMIUM(big_range);
209 EXPECT_NE(0u, first_path);
210 glDeletePathsCHROMIUM(first_path, big_range);
211 ASSERT_GL_NO_ERROR();
212
213 // Test glIsPathCHROMIUM(). A path object is not considered a path untill
214 // it has actually been specified with a path data.
215
216 path = glGenPathsCHROMIUM(1);
217 ASSERT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
218
219 // specify the data.
220 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
221 GLfloat coords[] = {50.0f, 50.0f};
222 glPathCommandsCHROMIUM(path, 2, commands, 2, GL_FLOAT, coords);
223 ASSERT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE);
224 glDeletePathsCHROMIUM(path, 1);
225 ASSERT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
226 }
227
228 // Test incorrect path creation and deletion and expect GL errors.
TEST_P(CHROMIUMPathRenderingTest,TestGenDeleteErrors)229 TEST_P(CHROMIUMPathRenderingTest, TestGenDeleteErrors)
230 {
231 if (!isApplicable())
232 return;
233
234 // GenPaths / DeletePaths tests.
235 // std::numeric_limits<GLuint>::max() is wrong for GLsizei.
236 GLuint first_path = glGenPathsCHROMIUM(std::numeric_limits<GLuint>::max());
237 EXPECT_EQ(first_path, 0u);
238 EXPECT_GL_ERROR(GL_INVALID_VALUE);
239
240 first_path = glGenPathsCHROMIUM(-1);
241 EXPECT_EQ(0u, first_path);
242 EXPECT_GL_ERROR(GL_INVALID_VALUE);
243
244 glDeletePathsCHROMIUM(1, -5);
245 EXPECT_GL_ERROR(GL_INVALID_VALUE);
246
247 first_path = glGenPathsCHROMIUM(-1);
248 EXPECT_EQ(0u, first_path);
249 EXPECT_GL_ERROR(GL_INVALID_VALUE);
250 }
251
252 // Test setting and getting path parameters.
TEST_P(CHROMIUMPathRenderingTest,TestPathParameter)253 TEST_P(CHROMIUMPathRenderingTest, TestPathParameter)
254 {
255 if (!isApplicable())
256 return;
257
258 GLuint path = glGenPathsCHROMIUM(1);
259
260 // specify the data.
261 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
262 GLfloat coords[] = {50.0f, 50.0f};
263 glPathCommandsCHROMIUM(path, 2, commands, 2, GL_FLOAT, coords);
264 ASSERT_GL_NO_ERROR();
265 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE);
266
267 static const GLenum kEndCaps[] = {GL_FLAT_CHROMIUM, GL_SQUARE_CHROMIUM, GL_ROUND_CHROMIUM};
268 for (std::size_t i = 0; i < 3; ++i)
269 {
270 GLint x;
271 glPathParameteriCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, static_cast<GLenum>(kEndCaps[i]));
272 ASSERT_GL_NO_ERROR();
273 glGetPathParameterivCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, &x);
274 ASSERT_GL_NO_ERROR();
275 EXPECT_EQ(kEndCaps[i], static_cast<GLenum>(x));
276
277 GLfloat f;
278 glPathParameterfCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM,
279 static_cast<GLfloat>(kEndCaps[(i + 1) % 3]));
280 glGetPathParameterfvCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, &f);
281 ASSERT_GL_NO_ERROR();
282 EXPECT_EQ(kEndCaps[(i + 1) % 3], static_cast<GLenum>(f));
283 }
284
285 static const GLenum kJoinStyles[] = {GL_MITER_REVERT_CHROMIUM, GL_BEVEL_CHROMIUM,
286 GL_ROUND_CHROMIUM};
287 for (std::size_t i = 0; i < 3; ++i)
288 {
289 GLint x;
290 glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM,
291 static_cast<GLenum>(kJoinStyles[i]));
292 ASSERT_GL_NO_ERROR();
293 glGetPathParameterivCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, &x);
294 ASSERT_GL_NO_ERROR();
295 EXPECT_EQ(kJoinStyles[i], static_cast<GLenum>(x));
296
297 GLfloat f;
298 glPathParameterfCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM,
299 static_cast<GLfloat>(kJoinStyles[(i + 1) % 3]));
300 ASSERT_GL_NO_ERROR();
301 glGetPathParameterfvCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, &f);
302 ASSERT_GL_NO_ERROR();
303 EXPECT_EQ(kJoinStyles[(i + 1) % 3], static_cast<GLenum>(f));
304 }
305
306 {
307 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f);
308 ASSERT_GL_NO_ERROR();
309
310 GLfloat f;
311 glGetPathParameterfvCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, &f);
312 EXPECT_EQ(5.0f, f);
313 }
314
315 glDeletePathsCHROMIUM(path, 1);
316 }
317
318 // Test that setting incorrect path parameter generates GL error.
TEST_P(CHROMIUMPathRenderingTest,TestPathParameterErrors)319 TEST_P(CHROMIUMPathRenderingTest, TestPathParameterErrors)
320 {
321 if (!isApplicable())
322 return;
323
324 GLuint path = glGenPathsCHROMIUM(1);
325
326 // PathParameter*: Wrong value for the pname should fail.
327 glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, GL_FLAT_CHROMIUM);
328 EXPECT_GL_ERROR(GL_INVALID_ENUM);
329
330 glPathParameterfCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, GL_MITER_REVERT_CHROMIUM);
331 EXPECT_GL_ERROR(GL_INVALID_ENUM);
332
333 // PathParameter*: Wrong floating-point value should fail.
334 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, -0.1f);
335 EXPECT_GL_ERROR(GL_INVALID_VALUE);
336
337 // PathParameter*: Wrong pname should fail.
338 glPathParameteriCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM - 1, 5);
339 EXPECT_GL_ERROR(GL_INVALID_ENUM);
340
341 glDeletePathsCHROMIUM(path, 1);
342 }
343
344 // Test expected path object state.
TEST_P(CHROMIUMPathRenderingTest,TestPathObjectState)345 TEST_P(CHROMIUMPathRenderingTest, TestPathObjectState)
346 {
347 if (!isApplicable())
348 return;
349
350 glViewport(0, 0, kResolution, kResolution);
351 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
352 glStencilMask(0xffffffff);
353 glClearStencil(0);
354 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
355 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
356 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
357 ASSERT_GL_NO_ERROR();
358
359 // Test that trying to draw non-existing paths does not produce errors or results.
360 GLuint non_existing_paths[] = {0, 55, 74744};
361 for (auto &p : non_existing_paths)
362 {
363 EXPECT_TRUE(glIsPathCHROMIUM(p) == GL_FALSE);
364 ASSERT_GL_NO_ERROR();
365 tryAllDrawFunctions(p, GL_NO_ERROR);
366 }
367
368 // Path name marked as used but without path object state causes
369 // a GL error upon any draw command.
370 GLuint path = glGenPathsCHROMIUM(1);
371 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
372 tryAllDrawFunctions(path, GL_INVALID_OPERATION);
373 glDeletePathsCHROMIUM(path, 1);
374
375 // Document a bit of an inconsistency: path name marked as used but without
376 // path object state causes a GL error upon any draw command (tested above).
377 // Path name that had path object state, but then was "cleared", still has a
378 // path object state, even though the state is empty.
379 path = glGenPathsCHROMIUM(1);
380 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
381
382 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
383 GLfloat coords[] = {50.0f, 50.0f};
384 glPathCommandsCHROMIUM(path, 2, commands, 2, GL_FLOAT, coords);
385 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE);
386
387 glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL);
388 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE); // The surprise.
389
390 tryAllDrawFunctions(path, GL_NO_ERROR);
391 glDeletePathsCHROMIUM(path, 1);
392
393 // Make sure nothing got drawn by the drawing commands that should not produce
394 // anything.
395 const angle::GLColor black = {0, 0, 0, 0};
396 EXPECT_TRUE(CheckPixels(0, 0, kResolution, kResolution, 0, black));
397 }
398
399 // Test that trying to use path object that doesn't exist generates
400 // a GL error.
TEST_P(CHROMIUMPathRenderingTest,TestUnnamedPathsErrors)401 TEST_P(CHROMIUMPathRenderingTest, TestUnnamedPathsErrors)
402 {
403 if (!isApplicable())
404 return;
405
406 // Unnamed paths: Trying to create a path object with non-existing path name
407 // produces error. (Not a error in real NV_path_rendering).
408 ASSERT_GL_NO_ERROR();
409 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
410 GLfloat coords[] = {50.0f, 50.0f};
411 glPathCommandsCHROMIUM(555, 2, commands, 2, GL_FLOAT, coords);
412 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
413
414 // PathParameter*: Using non-existing path object produces error.
415 ASSERT_GL_NO_ERROR();
416 glPathParameterfCHROMIUM(555, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f);
417 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
418
419 ASSERT_GL_NO_ERROR();
420 glPathParameteriCHROMIUM(555, GL_PATH_JOIN_STYLE_CHROMIUM, GL_ROUND_CHROMIUM);
421 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
422 }
423
424 // Test that setting incorrect path data generates a GL error.
TEST_P(CHROMIUMPathRenderingTest,TestPathCommandsErrors)425 TEST_P(CHROMIUMPathRenderingTest, TestPathCommandsErrors)
426 {
427 if (!isApplicable())
428 return;
429
430 static const GLenum kInvalidCoordType = GL_NONE;
431
432 GLuint path = glGenPathsCHROMIUM(1);
433 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
434 GLfloat coords[] = {50.0f, 50.0f};
435
436 glPathCommandsCHROMIUM(path, 2, commands, -4, GL_FLOAT, coords);
437 EXPECT_GL_ERROR(GL_INVALID_VALUE);
438
439 glPathCommandsCHROMIUM(path, -1, commands, 2, GL_FLOAT, coords);
440 EXPECT_GL_ERROR(GL_INVALID_VALUE);
441
442 glPathCommandsCHROMIUM(path, 2, commands, 2, kInvalidCoordType, coords);
443 EXPECT_GL_ERROR(GL_INVALID_ENUM);
444
445 // incorrect number of coordinates
446 glPathCommandsCHROMIUM(path, 2, commands, std::numeric_limits<GLsizei>::max(), GL_FLOAT,
447 coords);
448 EXPECT_GL_ERROR(GL_INVALID_VALUE);
449
450 // This should fail due to cmd count + coord count * short size.
451 glPathCommandsCHROMIUM(path, 2, commands, std::numeric_limits<GLsizei>::max(), GL_SHORT,
452 coords);
453 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
454
455 glDeletePathsCHROMIUM(path, 1);
456 }
457
458 // Test that trying to render a path with invalid arguments
459 // generates a GL error.
TEST_P(CHROMIUMPathRenderingTest,TestPathRenderingInvalidArgs)460 TEST_P(CHROMIUMPathRenderingTest, TestPathRenderingInvalidArgs)
461 {
462 if (!isApplicable())
463 return;
464
465 GLuint path = glGenPathsCHROMIUM(1);
466 glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL);
467
468 // Verify that normal calls work.
469 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F);
470 ASSERT_GL_NO_ERROR();
471 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, GL_BOUNDING_BOX_CHROMIUM);
472 ASSERT_GL_NO_ERROR();
473
474 // Using invalid fill mode causes INVALID_ENUM.
475 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM - 1, 0x7F);
476 EXPECT_GL_ERROR(GL_INVALID_ENUM);
477 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM - 1, 0x7F,
478 GL_BOUNDING_BOX_CHROMIUM);
479 EXPECT_GL_ERROR(GL_INVALID_ENUM);
480
481 // Using invalid cover mode causes INVALID_ENUM.
482 glCoverFillPathCHROMIUM(path, GL_CONVEX_HULL_CHROMIUM - 1);
483 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError());
484 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F,
485 GL_BOUNDING_BOX_CHROMIUM + 1);
486 EXPECT_GL_ERROR(GL_INVALID_ENUM);
487
488 // Using mask+1 not being power of two causes INVALID_VALUE with up/down fill mode
489 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x40);
490 EXPECT_GL_ERROR(GL_INVALID_VALUE);
491
492 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_DOWN_CHROMIUM, 12, GL_BOUNDING_BOX_CHROMIUM);
493 EXPECT_GL_ERROR(GL_INVALID_VALUE);
494
495 // check incorrect instance parameters.
496
497 // CoverFillPathInstanced
498 {
499 glCoverFillPathInstancedCHROMIUM(-1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
500 GL_NONE, NULL);
501 EXPECT_GL_ERROR(GL_INVALID_VALUE);
502
503 glCoverFillPathInstancedCHROMIUM(1, GL_FLOAT, &path, 0, GL_CONVEX_HULL_CHROMIUM, GL_NONE,
504 NULL);
505 EXPECT_GL_ERROR(GL_INVALID_ENUM);
506
507 glCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, NULL, 0, GL_CONVEX_HULL_CHROMIUM,
508 GL_NONE, NULL);
509 EXPECT_GL_ERROR(GL_INVALID_VALUE);
510
511 glCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_UNSIGNED_INT, GL_NONE,
512 NULL);
513 EXPECT_GL_ERROR(GL_INVALID_ENUM);
514
515 glCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
516 GL_UNSIGNED_INT, NULL);
517 EXPECT_GL_ERROR(GL_INVALID_ENUM);
518
519 glCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
520 GL_TRANSLATE_X_CHROMIUM, NULL);
521 EXPECT_GL_ERROR(GL_INVALID_VALUE);
522 }
523
524 // CoverStrokePathInstanced
525 {
526 glCoverStrokePathInstancedCHROMIUM(-1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
527 GL_NONE, NULL);
528 EXPECT_GL_ERROR(GL_INVALID_VALUE);
529
530 glCoverStrokePathInstancedCHROMIUM(1, GL_FLOAT, &path, 0, GL_CONVEX_HULL_CHROMIUM, GL_NONE,
531 NULL);
532 EXPECT_GL_ERROR(GL_INVALID_ENUM);
533
534 glCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, NULL, 0, GL_CONVEX_HULL_CHROMIUM,
535 GL_NONE, NULL);
536 EXPECT_GL_ERROR(GL_INVALID_VALUE);
537
538 glCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_UNSIGNED_INT, GL_NONE,
539 NULL);
540 EXPECT_GL_ERROR(GL_INVALID_ENUM);
541
542 glCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
543 GL_UNSIGNED_INT, NULL);
544 EXPECT_GL_ERROR(GL_INVALID_ENUM);
545
546 glCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
547 GL_TRANSLATE_X_CHROMIUM, NULL);
548 EXPECT_GL_ERROR(GL_INVALID_VALUE);
549 }
550
551 // StencilFillPathInstanced
552 {
553 glStencilFillPathInstancedCHROMIUM(-1, GL_UNSIGNED_INT, &path, 0, GL_COUNT_UP_CHROMIUM, 0x0,
554 GL_NONE, NULL);
555 EXPECT_GL_ERROR(GL_INVALID_VALUE);
556
557 glStencilFillPathInstancedCHROMIUM(1, GL_FLOAT, &path, 0, GL_COUNT_UP_CHROMIUM, 0x0,
558 GL_NONE, NULL);
559 EXPECT_GL_ERROR(GL_INVALID_ENUM);
560
561 glStencilFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, NULL, 0, GL_COUNT_UP_CHROMIUM, 0x0,
562 GL_NONE, NULL);
563 EXPECT_GL_ERROR(GL_INVALID_VALUE);
564
565 glStencilFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_UNSIGNED_INT, 0x0,
566 GL_NONE, NULL);
567 EXPECT_GL_ERROR(GL_INVALID_ENUM);
568
569 glStencilFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_COUNT_UP_CHROMIUM, 0x2,
570 GL_NONE, NULL);
571 EXPECT_GL_ERROR(GL_INVALID_VALUE);
572
573 glStencilFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_COUNT_UP_CHROMIUM, 0x0,
574 GL_UNSIGNED_INT, NULL);
575 EXPECT_GL_ERROR(GL_INVALID_ENUM);
576
577 glStencilFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_COUNT_UP_CHROMIUM, 0x0,
578 GL_TRANSLATE_X_CHROMIUM, NULL);
579 EXPECT_GL_ERROR(GL_INVALID_VALUE);
580 }
581
582 // StencilStrokePathInstanced
583 {
584 glStencilStrokePathInstancedCHROMIUM(-1, GL_UNSIGNED_INT, &path, 0, 0x00, 0x00, GL_NONE,
585 NULL);
586 EXPECT_GL_ERROR(GL_INVALID_VALUE);
587
588 glStencilStrokePathInstancedCHROMIUM(1, GL_FLOAT, &path, 0, 0x00, 0x00, GL_NONE, NULL);
589 EXPECT_GL_ERROR(GL_INVALID_ENUM);
590
591 glStencilStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, nullptr, 0, 0x00, 0x00, GL_NONE,
592 NULL);
593 EXPECT_GL_ERROR(GL_INVALID_VALUE);
594
595 glStencilStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, 0x00, 0x00,
596 GL_UNSIGNED_INT, NULL);
597 EXPECT_GL_ERROR(GL_INVALID_ENUM);
598
599 glStencilStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, 0x00, 0x00,
600 GL_TRANSLATE_X_CHROMIUM, NULL);
601 EXPECT_GL_ERROR(GL_INVALID_VALUE);
602 }
603
604 // StencilThenCoverFillPathInstanced
605 {
606 glStencilThenCoverFillPathInstancedCHROMIUM(-1, GL_UNSIGNED_INT, &path, 0,
607 GL_COUNT_UP_CHROMIUM, 0, GL_COUNT_UP_CHROMIUM,
608 GL_NONE, NULL);
609 EXPECT_GL_ERROR(GL_INVALID_VALUE);
610
611 glStencilThenCoverFillPathInstancedCHROMIUM(1, GL_FLOAT, &path, 0, GL_CONVEX_HULL_CHROMIUM,
612 0, GL_COUNT_UP_CHROMIUM, GL_NONE, NULL);
613 EXPECT_GL_ERROR(GL_INVALID_ENUM);
614
615 glStencilThenCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, NULL, 0,
616 GL_CONVEX_HULL_CHROMIUM, 0,
617 GL_COUNT_UP_CHROMIUM, GL_NONE, NULL);
618 EXPECT_GL_ERROR(GL_INVALID_VALUE);
619
620 glStencilThenCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, GL_UNSIGNED_INT,
621 0, GL_COUNT_UP_CHROMIUM, GL_NONE, NULL);
622 EXPECT_GL_ERROR(GL_INVALID_ENUM);
623
624 glStencilThenCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0,
625 GL_CONVEX_HULL_CHROMIUM, 0, GL_UNSIGNED_INT,
626 GL_NONE, NULL);
627 EXPECT_GL_ERROR(GL_INVALID_ENUM);
628
629 glStencilThenCoverFillPathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0,
630 GL_CONVEX_HULL_CHROMIUM, 0,
631 GL_COUNT_UP_CHROMIUM, GL_FLOAT, NULL);
632 EXPECT_GL_ERROR(GL_INVALID_ENUM);
633
634 glStencilThenCoverFillPathInstancedCHROMIUM(
635 1, GL_UNSIGNED_INT, &path, 0, GL_CONVEX_HULL_CHROMIUM, 0, GL_COUNT_UP_CHROMIUM,
636 GL_TRANSLATE_X_CHROMIUM, NULL);
637 EXPECT_GL_ERROR(GL_INVALID_VALUE);
638 }
639
640 // StencilThenCoverStrokePathInstanced
641 {
642 glStencilThenCoverStrokePathInstancedCHROMIUM(-1, GL_UNSIGNED_INT, &path, 0, 0x0, 0x0,
643 GL_CONVEX_HULL_CHROMIUM, GL_NONE, NULL);
644 EXPECT_GL_ERROR(GL_INVALID_VALUE);
645
646 glStencilThenCoverStrokePathInstancedCHROMIUM(1, GL_FLOAT, &path, 0, 0x0, 0x0,
647 GL_CONVEX_HULL_CHROMIUM, GL_NONE, NULL);
648 EXPECT_GL_ERROR(GL_INVALID_ENUM);
649
650 glStencilThenCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, NULL, 0, 0x0, 0x0,
651 GL_CONVEX_HULL_CHROMIUM, GL_NONE, NULL);
652 EXPECT_GL_ERROR(GL_INVALID_VALUE);
653
654 glStencilThenCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, 0x0, 0x0,
655 GL_FLOAT, GL_NONE, NULL);
656 EXPECT_GL_ERROR(GL_INVALID_ENUM);
657
658 glStencilThenCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, 0x0, 0x0,
659 GL_CONVEX_HULL_CHROMIUM, GL_FLOAT, NULL);
660 EXPECT_GL_ERROR(GL_INVALID_ENUM);
661
662 glStencilThenCoverStrokePathInstancedCHROMIUM(1, GL_UNSIGNED_INT, &path, 0, 0x0, 0x0,
663 GL_CONVEX_HULL_CHROMIUM,
664 GL_TRANSLATE_X_CHROMIUM, NULL);
665 EXPECT_GL_ERROR(GL_INVALID_VALUE);
666 }
667
668 glDeletePathsCHROMIUM(path, 1);
669 }
670
671 const GLfloat kProjectionMatrix[16] = {2.0f / kResolution,
672 0.0f,
673 0.0f,
674 0.0f,
675 0.0f,
676 2.0f / kResolution,
677 0.0f,
678 0.0f,
679 0.0f,
680 0.0f,
681 -1.0f,
682 0.0f,
683 -1.0f,
684 -1.0f,
685 0.0f,
686 1.0f};
687
688 class CHROMIUMPathRenderingDrawTest : public ANGLETest
689 {
690 protected:
CHROMIUMPathRenderingDrawTest()691 CHROMIUMPathRenderingDrawTest()
692 {
693 setWindowWidth(kResolution);
694 setWindowHeight(kResolution);
695 setConfigRedBits(8);
696 setConfigGreenBits(8);
697 setConfigBlueBits(8);
698 setConfigAlphaBits(8);
699 setConfigDepthBits(8);
700 setConfigStencilBits(8);
701 }
702
isApplicable() const703 bool isApplicable() const { return extensionEnabled("GL_CHROMIUM_path_rendering"); }
704
setupStateForTestPattern()705 void setupStateForTestPattern()
706 {
707 glViewport(0, 0, kResolution, kResolution);
708 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
709 glStencilMask(0xffffffff);
710 glClearStencil(0);
711 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
712 glEnable(GL_STENCIL_TEST);
713
714 static const char *kVertexShaderSource =
715 "void main() {\n"
716 " gl_Position = vec4(1.0); \n"
717 "}";
718
719 static const char *kFragmentShaderSource =
720 "precision mediump float;\n"
721 "uniform vec4 color;\n"
722 "void main() {\n"
723 " gl_FragColor = color;\n"
724 "}";
725
726 GLuint program = CompileProgram(kVertexShaderSource, kFragmentShaderSource);
727 glUseProgram(program);
728 mColorLoc = glGetUniformLocation(program, "color");
729 glDeleteProgram(program);
730
731 // Set up orthogonal projection with near/far plane distance of 2.
732 glMatrixLoadfCHROMIUM(GL_PATH_PROJECTION_CHROMIUM, kProjectionMatrix);
733 glMatrixLoadIdentityCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM);
734
735 ASSERT_GL_NO_ERROR();
736 }
737
setupPathStateForTestPattern(GLuint path)738 void setupPathStateForTestPattern(GLuint path)
739 {
740 static const GLubyte kCommands[] = {GL_MOVE_TO_CHROMIUM, GL_LINE_TO_CHROMIUM,
741 GL_QUADRATIC_CURVE_TO_CHROMIUM,
742 GL_CUBIC_CURVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
743
744 static const GLfloat kCoords[] = {50.0f, 50.0f, 75.0f, 75.0f, 100.0f, 62.5f, 50.0f,
745 25.5f, 0.0f, 62.5f, 50.0f, 50.0f, 25.0f, 75.0f};
746
747 glPathCommandsCHROMIUM(path, 5, kCommands, 14, GL_FLOAT, kCoords);
748 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f);
749 glPathParameterfCHROMIUM(path, GL_PATH_MITER_LIMIT_CHROMIUM, 1.0f);
750 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_BOUND_CHROMIUM, .02f);
751 glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, GL_ROUND_CHROMIUM);
752 glPathParameteriCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, GL_SQUARE_CHROMIUM);
753 ASSERT_GL_NO_ERROR();
754 }
755
verifyTestPatternFill(GLfloat flx,GLfloat fly)756 void verifyTestPatternFill(GLfloat flx, GLfloat fly)
757 {
758 static const GLint kFillCoords[] = {55, 54, 50, 28, 66, 63};
759 static const angle::GLColor kBlue = {0, 0, 255, 255};
760
761 GLint x = static_cast<GLint>(flx);
762 GLint y = static_cast<GLint>(fly);
763
764 for (size_t i = 0; i < 6; i += 2)
765 {
766 GLint fx = kFillCoords[i];
767 GLint fy = kFillCoords[i + 1];
768 EXPECT_TRUE(CheckPixels(x + fx, y + fy, 1, 1, 0, kBlue));
769 }
770 }
verifyTestPatternBg(GLfloat fx,GLfloat fy)771 void verifyTestPatternBg(GLfloat fx, GLfloat fy)
772 {
773 static const GLint kBackgroundCoords[] = {80, 80, 20, 20, 90, 1};
774 static const angle::GLColor kExpectedColor = {0, 0, 0, 0};
775
776 GLint x = static_cast<GLint>(fx);
777 GLint y = static_cast<GLint>(fy);
778
779 for (size_t i = 0; i < 6; i += 2)
780 {
781 GLint bx = kBackgroundCoords[i];
782 GLint by = kBackgroundCoords[i + 1];
783 EXPECT_TRUE(CheckPixels(x + bx, y + by, 1, 1, 0, kExpectedColor));
784 }
785 }
786
verifyTestPatternStroke(GLfloat fx,GLfloat fy)787 void verifyTestPatternStroke(GLfloat fx, GLfloat fy)
788 {
789 GLint x = static_cast<GLint>(fx);
790 GLint y = static_cast<GLint>(fy);
791
792 // Inside the stroke we should have green.
793 static const angle::GLColor kGreen = {0, 255, 0, 255};
794 EXPECT_TRUE(CheckPixels(x + 50, y + 53, 1, 1, 0, kGreen));
795 EXPECT_TRUE(CheckPixels(x + 26, y + 76, 1, 1, 0, kGreen));
796
797 // Outside the path we should have black.
798 static const angle::GLColor black = {0, 0, 0, 0};
799 EXPECT_TRUE(CheckPixels(x + 10, y + 10, 1, 1, 0, black));
800 EXPECT_TRUE(CheckPixels(x + 80, y + 80, 1, 1, 0, black));
801 }
802
803 GLuint mColorLoc;
804 };
805
806 // Tests that basic path rendering functions work.
TEST_P(CHROMIUMPathRenderingDrawTest,TestPathRendering)807 TEST_P(CHROMIUMPathRenderingDrawTest, TestPathRendering)
808 {
809 if (!isApplicable())
810 return;
811
812 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
813 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
814
815 setupStateForTestPattern();
816
817 GLuint path = glGenPathsCHROMIUM(1);
818 setupPathStateForTestPattern(path);
819
820 // Do the stencil fill, cover fill, stencil stroke, cover stroke
821 // in unconventional order:
822 // 1) stencil the stroke in stencil high bit
823 // 2) stencil the fill in low bits
824 // 3) cover the fill
825 // 4) cover the stroke
826 // This is done to check that glPathStencilFunc works, eg the mask
827 // goes through. Stencil func is not tested ATM, for simplicity.
828
829 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
830 glStencilStrokePathCHROMIUM(path, 0x80, 0x80);
831
832 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
833 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F);
834
835 glStencilFunc(GL_LESS, 0, 0x7F);
836 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
837 glUniform4fv(mColorLoc, 1, kBlue);
838 glCoverFillPathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM);
839
840 glStencilFunc(GL_EQUAL, 0x80, 0x80);
841 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
842 glUniform4fv(mColorLoc, 1, kGreen);
843 glCoverStrokePathCHROMIUM(path, GL_CONVEX_HULL_CHROMIUM);
844
845 glDeletePathsCHROMIUM(path, 1);
846
847 ASSERT_GL_NO_ERROR();
848
849 // Verify the image.
850 verifyTestPatternFill(0, 0);
851 verifyTestPatternBg(0, 0);
852 verifyTestPatternStroke(0, 0);
853 }
854
855 // Test that StencilThen{Stroke,Fill} path rendering functions work
TEST_P(CHROMIUMPathRenderingDrawTest,TestPathRenderingThenFunctions)856 TEST_P(CHROMIUMPathRenderingDrawTest, TestPathRenderingThenFunctions)
857 {
858 if (!isApplicable())
859 return;
860
861 static float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
862 static float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
863
864 setupStateForTestPattern();
865
866 GLuint path = glGenPathsCHROMIUM(1);
867 setupPathStateForTestPattern(path);
868
869 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
870 glStencilFunc(GL_EQUAL, 0x80, 0x80);
871 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
872 glUniform4fv(mColorLoc, 1, kGreen);
873 glStencilThenCoverStrokePathCHROMIUM(path, 0x80, 0x80, GL_BOUNDING_BOX_CHROMIUM);
874
875 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
876 glStencilFunc(GL_LESS, 0, 0x7F);
877 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
878 glUniform4fv(mColorLoc, 1, kBlue);
879 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, GL_CONVEX_HULL_CHROMIUM);
880
881 glDeletePathsCHROMIUM(path, 1);
882
883 // Verify the image.
884 verifyTestPatternFill(0, 0);
885 verifyTestPatternBg(0, 0);
886 verifyTestPatternStroke(0, 0);
887 }
888
889 // Tests that drawing with *Instanced functions work.
TEST_P(CHROMIUMPathRenderingDrawTest,TestPathRenderingInstanced)890 TEST_P(CHROMIUMPathRenderingDrawTest, TestPathRenderingInstanced)
891 {
892 if (!isApplicable())
893 return;
894
895 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
896 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
897
898 setupStateForTestPattern();
899
900 GLuint path = glGenPathsCHROMIUM(1);
901 setupPathStateForTestPattern(path);
902
903 const GLuint kPaths[] = {1, 1, 1, 1, 1};
904 const GLsizei kPathCount = 5;
905 const GLfloat kShapeSize = 80.0f;
906 static const GLfloat kTransforms[kPathCount * 12] = {
907 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
908 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, kShapeSize, 0.0f, 0.0f,
909 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, kShapeSize * 2, 0.0f, 0.0f,
910 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, kShapeSize, 0.0f,
911 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, kShapeSize, kShapeSize, 0.0f};
912
913 // The test pattern is the same as in the simple draw case above,
914 // except that the path is drawn kPathCount times with different offsets.
915 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
916 glStencilStrokePathInstancedCHROMIUM(kPathCount, GL_UNSIGNED_INT, kPaths, path - 1, 0x80, 0x80,
917 GL_AFFINE_3D_CHROMIUM, kTransforms);
918
919 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
920 glUniform4fv(mColorLoc, 1, kBlue);
921 glStencilFillPathInstancedCHROMIUM(kPathCount, GL_UNSIGNED_INT, kPaths, path - 1,
922 GL_COUNT_UP_CHROMIUM, 0x7F, GL_AFFINE_3D_CHROMIUM,
923 kTransforms);
924
925 ASSERT_GL_NO_ERROR();
926
927 glStencilFunc(GL_LESS, 0, 0x7F);
928 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
929 glCoverFillPathInstancedCHROMIUM(kPathCount, GL_UNSIGNED_INT, kPaths, path - 1,
930 GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM,
931 GL_AFFINE_3D_CHROMIUM, kTransforms);
932
933 ASSERT_GL_NO_ERROR();
934
935 glStencilFunc(GL_EQUAL, 0x80, 0x80);
936 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
937 glUniform4fv(mColorLoc, 1, kGreen);
938 glCoverStrokePathInstancedCHROMIUM(kPathCount, GL_UNSIGNED_INT, kPaths, path - 1,
939 GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM,
940 GL_AFFINE_3D_CHROMIUM, kTransforms);
941
942 ASSERT_GL_NO_ERROR();
943
944 glDeletePathsCHROMIUM(path, 1);
945
946 // Verify the image.
947 verifyTestPatternFill(0.0f, 0.0f);
948 verifyTestPatternBg(0.0f, 0.0f);
949 verifyTestPatternStroke(0.0f, 0.0f);
950
951 verifyTestPatternFill(kShapeSize, 0.0f);
952 verifyTestPatternBg(kShapeSize, 0.0f);
953 verifyTestPatternStroke(kShapeSize, 0.0f);
954
955 verifyTestPatternFill(kShapeSize * 2, 0.0f);
956 verifyTestPatternBg(kShapeSize * 2, 0.0f);
957 verifyTestPatternStroke(kShapeSize * 2, 0.0f);
958
959 verifyTestPatternFill(0.0f, kShapeSize);
960 verifyTestPatternBg(0.0f, kShapeSize);
961 verifyTestPatternStroke(0.0f, kShapeSize);
962
963 verifyTestPatternFill(kShapeSize, kShapeSize);
964 verifyTestPatternBg(kShapeSize, kShapeSize);
965 verifyTestPatternStroke(kShapeSize, kShapeSize);
966 }
967
968 // Test that instanced fill/stroke then cover functions work.
TEST_P(CHROMIUMPathRenderingDrawTest,TestPathRenderingThenFunctionsInstanced)969 TEST_P(CHROMIUMPathRenderingDrawTest, TestPathRenderingThenFunctionsInstanced)
970 {
971 if (!isApplicable())
972 return;
973
974 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
975 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
976
977 setupStateForTestPattern();
978
979 GLuint path = glGenPathsCHROMIUM(1);
980 setupPathStateForTestPattern(path);
981
982 const GLuint kPaths[] = {1, 1, 1, 1, 1};
983 const GLsizei kPathCount = 5;
984 const GLfloat kShapeSize = 80.0f;
985 static const GLfloat kTransforms[] = {
986 0.0f, 0.0f, kShapeSize, 0.0f, kShapeSize * 2,
987 0.0f, 0.0f, kShapeSize, kShapeSize, kShapeSize,
988 };
989
990 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
991 glStencilFunc(GL_EQUAL, 0x80, 0x80);
992 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
993 glUniform4fv(mColorLoc, 1, kGreen);
994 glStencilThenCoverStrokePathInstancedCHROMIUM(
995 kPathCount, GL_UNSIGNED_INT, kPaths, path - 1, 0x80, 0x80,
996 GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_TRANSLATE_2D_CHROMIUM, kTransforms);
997
998 ASSERT_GL_NO_ERROR();
999
1000 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
1001 glStencilFunc(GL_LESS, 0, 0x7F);
1002 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
1003 glUniform4fv(mColorLoc, 1, kBlue);
1004 glStencilThenCoverFillPathInstancedCHROMIUM(
1005 kPathCount, GL_UNSIGNED_INT, kPaths, path - 1, GL_COUNT_UP_CHROMIUM, 0x7F,
1006 GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_TRANSLATE_2D_CHROMIUM, kTransforms);
1007
1008 ASSERT_GL_NO_ERROR();
1009
1010 glDeletePathsCHROMIUM(path, 1);
1011
1012 // Verify the image.
1013 verifyTestPatternFill(0.0f, 0.0f);
1014 verifyTestPatternBg(0.0f, 0.0f);
1015 verifyTestPatternStroke(0.0f, 0.0f);
1016
1017 verifyTestPatternFill(kShapeSize, 0.0f);
1018 verifyTestPatternBg(kShapeSize, 0.0f);
1019 verifyTestPatternStroke(kShapeSize, 0.0f);
1020
1021 verifyTestPatternFill(kShapeSize * 2, 0.0f);
1022 verifyTestPatternBg(kShapeSize * 2, 0.0f);
1023 verifyTestPatternStroke(kShapeSize * 2, 0.0f);
1024
1025 verifyTestPatternFill(0.0f, kShapeSize);
1026 verifyTestPatternBg(0.0f, kShapeSize);
1027 verifyTestPatternStroke(0.0f, kShapeSize);
1028
1029 verifyTestPatternFill(kShapeSize, kShapeSize);
1030 verifyTestPatternBg(kShapeSize, kShapeSize);
1031 verifyTestPatternStroke(kShapeSize, kShapeSize);
1032 }
1033
1034
1035 // This class implements a test that draws a grid of v-shapes. The grid is
1036 // drawn so that even rows (from the bottom) are drawn with DrawArrays and odd
1037 // rows are drawn with path rendering. It can be used to test various texturing
1038 // modes, comparing how the fill would work in normal GL rendering and how to
1039 // setup same sort of fill with path rendering.
1040 // The texturing test is parametrized to run the test with and without
1041 // ANGLE name hashing.
1042 class CHROMIUMPathRenderingWithTexturingTest : public ANGLETest
1043 {
1044 protected:
CHROMIUMPathRenderingWithTexturingTest()1045 CHROMIUMPathRenderingWithTexturingTest() : mProgram(0)
1046 {
1047 setWindowWidth(kResolution);
1048 setWindowHeight(kResolution);
1049 setConfigRedBits(8);
1050 setConfigGreenBits(8);
1051 setConfigBlueBits(8);
1052 setConfigAlphaBits(8);
1053 setConfigDepthBits(8);
1054 setConfigStencilBits(8);
1055 }
1056
isApplicable() const1057 bool isApplicable() const { return extensionEnabled("GL_CHROMIUM_path_rendering"); }
1058
TearDown()1059 void TearDown() override
1060 {
1061 if (mProgram)
1062 {
1063 glDeleteProgram(mProgram);
1064 ASSERT_GL_NO_ERROR();
1065 }
1066
1067 ANGLETest::TearDown();
1068 }
1069
SetUp()1070 void SetUp() override
1071 {
1072 ANGLETest::SetUp();
1073 mBindUniformLocation = reinterpret_cast<PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC>(
1074 eglGetProcAddress("glBindUniformLocationCHROMIUM"));
1075 }
1076
1077 // Sets up the GL program state for the test.
1078 // Vertex shader needs at least following variables:
1079 // uniform mat4 view_matrix;
1080 // uniform mat? color_matrix; (accessible with kColorMatrixLocation)
1081 // uniform vec2 model_translate;
1082 // attribute vec2 position;
1083 // varying vec4 color;
1084 //
1085 // Fragment shader needs at least following variables:
1086 // varying vec4 color;
1087 //
1088 // (? can be anything)
compileProgram(const char * vertexShaderSource,const char * fragmentShaderSource)1089 void compileProgram(const char *vertexShaderSource, const char *fragmentShaderSource)
1090 {
1091 glViewport(0, 0, kResolution, kResolution);
1092 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1093 glStencilMask(0xffffffff);
1094 glClearStencil(0);
1095 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1096 glEnable(GL_BLEND);
1097 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1098
1099 ASSERT_GL_NO_ERROR();
1100
1101 GLuint vShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
1102 GLuint fShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
1103 ASSERT_NE(0u, vShader);
1104 ASSERT_NE(0u, fShader);
1105
1106 mProgram = glCreateProgram();
1107
1108 glAttachShader(mProgram, vShader);
1109 glAttachShader(mProgram, fShader);
1110 glDeleteShader(vShader);
1111 glDeleteShader(fShader);
1112
1113 ASSERT_GL_NO_ERROR();
1114 }
1115
bindProgram()1116 void bindProgram()
1117 {
1118 glBindAttribLocation(mProgram, kPositionLocation, "position");
1119 mBindUniformLocation(mProgram, kViewMatrixLocation, "view_matrix");
1120 mBindUniformLocation(mProgram, kColorMatrixLocation, "color_matrix");
1121 mBindUniformLocation(mProgram, kModelTranslateLocation, "model_translate");
1122 glBindFragmentInputLocationCHROMIUM(mProgram, kColorFragmentInputLocation, "color");
1123
1124 ASSERT_GL_NO_ERROR();
1125 }
1126
linkProgram()1127 bool linkProgram()
1128 {
1129 glLinkProgram(mProgram);
1130
1131 GLint linked = 0;
1132 glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
1133 if (linked)
1134 {
1135 glUseProgram(mProgram);
1136 }
1137
1138 return (linked == 1);
1139 }
1140
drawTestPattern()1141 void drawTestPattern()
1142 {
1143 // This v-shape is used both for DrawArrays and path rendering.
1144 static const GLfloat kVertices[] = {75.0f, 75.0f, 50.0f, 25.5f, 50.0f, 50.0f, 25.0f, 75.0f};
1145
1146 GLuint vbo = 0;
1147 glGenBuffers(1, &vbo);
1148 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1149 glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
1150 glEnableVertexAttribArray(kPositionLocation);
1151 glVertexAttribPointer(kPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
1152
1153 // Setup state for drawing the shape with path rendering.
1154 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
1155 glStencilFunc(GL_LESS, 0, 0x7F);
1156 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
1157 glMatrixLoadfCHROMIUM(GL_PATH_PROJECTION_CHROMIUM, kProjectionMatrix);
1158 glMatrixLoadIdentityCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM);
1159
1160 static const GLubyte kCommands[] = {GL_MOVE_TO_CHROMIUM, GL_LINE_TO_CHROMIUM,
1161 GL_LINE_TO_CHROMIUM, GL_LINE_TO_CHROMIUM,
1162 GL_CLOSE_PATH_CHROMIUM};
1163
1164 static const GLfloat kCoords[] = {
1165 kVertices[0], kVertices[1], kVertices[2], kVertices[3],
1166 kVertices[6], kVertices[7], kVertices[4], kVertices[5],
1167 };
1168
1169 GLuint path = glGenPathsCHROMIUM(1);
1170 glPathCommandsCHROMIUM(path, static_cast<GLsizei>(ArraySize(kCommands)), kCommands,
1171 static_cast<GLsizei>(ArraySize(kCoords)), GL_FLOAT, kCoords);
1172 ASSERT_GL_NO_ERROR();
1173
1174 GLfloat path_model_translate[16] = {
1175 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1176 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1177 };
1178
1179 // Draws the shapes. Every even row from the bottom is drawn with
1180 // DrawArrays, odd row with path rendering. The shader program is
1181 // the same for the both draws.
1182 for (int j = 0; j < kTestRows; ++j)
1183 {
1184 for (int i = 0; i < kTestColumns; ++i)
1185 {
1186 if (j % 2 == 0)
1187 {
1188 glDisable(GL_STENCIL_TEST);
1189 glUniform2f(kModelTranslateLocation, static_cast<GLfloat>(i * kShapeWidth),
1190 static_cast<GLfloat>(j * kShapeHeight));
1191 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1192 }
1193 else
1194 {
1195 glEnable(GL_STENCIL_TEST);
1196 path_model_translate[12] = static_cast<GLfloat>(i * kShapeWidth);
1197 path_model_translate[13] = static_cast<GLfloat>(j * kShapeHeight);
1198 glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM, path_model_translate);
1199 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F,
1200 GL_BOUNDING_BOX_CHROMIUM);
1201 }
1202 }
1203 }
1204 ASSERT_GL_NO_ERROR();
1205
1206 glDisableVertexAttribArray(kPositionLocation);
1207 glDeleteBuffers(1, &vbo);
1208 glDeletePathsCHROMIUM(path, 1);
1209 ASSERT_GL_NO_ERROR();
1210 }
1211
1212 enum
1213 {
1214 kShapeWidth = 75,
1215 kShapeHeight = 75,
1216 kTestRows = kResolution / kShapeHeight,
1217 kTestColumns = kResolution / kShapeWidth,
1218 };
1219
1220 typedef void(GL_APIENTRYP PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC)(GLuint mProgram,
1221 GLint location,
1222 const GLchar *name);
1223 PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC mBindUniformLocation = nullptr;
1224
1225 GLuint mProgram;
1226
1227 // This uniform be can set by the test. It should be used to set the color for
1228 // drawing with DrawArrays.
1229 static const GLint kColorMatrixLocation = 4;
1230
1231 // This fragment input can be set by the test. It should be used to set the
1232 // color for drawing with path rendering.
1233 static const GLint kColorFragmentInputLocation = 7;
1234
1235 static const GLint kModelTranslateLocation = 3;
1236 static const GLint kPositionLocation = 0;
1237 static const GLint kViewMatrixLocation = 7;
1238 };
1239
1240 // Test success and error cases for binding fragment input location.
TEST_P(CHROMIUMPathRenderingWithTexturingTest,TestBindFragmentInputLocation)1241 TEST_P(CHROMIUMPathRenderingWithTexturingTest, TestBindFragmentInputLocation)
1242 {
1243 if (!isApplicable())
1244 return;
1245
1246 // original NV_path_rendering specification doesn't define whether the
1247 // fragment shader input variables should be defined in the vertex shader or
1248 // not. In fact it doesn't even require a vertex shader.
1249 // However the GLES3.1 spec basically says that fragment inputs are
1250 // either built-ins or come from the previous shader stage.
1251 // (§ 14.1, Fragment Shader Variables).
1252 // Additionally there are many places that are based on the assumption of having
1253 // a vertex shader (command buffer, angle) so we're going to stick to the same
1254 // semantics and require a vertex shader and to have the vertex shader define the
1255 // varying fragment shader input.
1256
1257 // clang-format off
1258 const char* kVertexShaderSource =
1259 "varying vec4 color;\n"
1260 "void main() {}\n";
1261
1262 const char* kFragmentShaderSource =
1263 "precision mediump float;\n"
1264 "varying vec4 color;\n"
1265 "void main() {\n"
1266 " gl_FragColor = vec4(1.0);\n"
1267 "}\n";
1268
1269 // clang-format on
1270 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1271
1272 enum kBindLocations
1273 {
1274 kColorLocation = 5,
1275 kFragColorLocation = 6
1276 };
1277
1278 // successful bind.
1279 glBindFragmentInputLocationCHROMIUM(mProgram, kColorLocation, "color");
1280 ASSERT_GL_NO_ERROR();
1281
1282 // any name can be bound and names that do not actually exist in the program after
1283 // linking are ignored.
1284 glBindFragmentInputLocationCHROMIUM(mProgram, kColorLocation, "doesnt_exist");
1285 ASSERT_GL_NO_ERROR();
1286
1287 // illegal program
1288 glBindFragmentInputLocationCHROMIUM(mProgram + 1, kColorLocation, "color");
1289 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1290
1291 // illegal bind (built-in)
1292 glBindFragmentInputLocationCHROMIUM(mProgram, kFragColorLocation, "gl_FragColor");
1293 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1294
1295 glBindFragmentInputLocationCHROMIUM(mProgram, kFragColorLocation, NULL);
1296 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1297
1298 glBindFragmentInputLocationCHROMIUM(mProgram, 0xffffff, "color");
1299 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1300
1301 ASSERT_TRUE(linkProgram() == true);
1302
1303 const GLfloat kCoefficients16[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
1304 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f};
1305
1306 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorLocation, GL_EYE_LINEAR_CHROMIUM, 4,
1307 kCoefficients16);
1308 ASSERT_GL_NO_ERROR();
1309
1310 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, GL_EYE_LINEAR_CHROMIUM, 4, kCoefficients16);
1311 ASSERT_GL_NO_ERROR();
1312 }
1313
1314 // Test fragment input interpolation in CHROMIUM_EYE coordinates.
TEST_P(CHROMIUMPathRenderingWithTexturingTest,TestProgramPathFragmentInputGenCHROMIUM_EYE)1315 TEST_P(CHROMIUMPathRenderingWithTexturingTest, TestProgramPathFragmentInputGenCHROMIUM_EYE)
1316 {
1317 if (!isApplicable())
1318 return;
1319
1320 // clang-format off
1321 const char *kVertexShaderSource =
1322 "uniform mat4 view_matrix;\n"
1323 "uniform mat4 color_matrix;\n"
1324 "uniform vec2 model_translate;\n"
1325 "attribute vec2 position;\n"
1326 "varying vec3 color;\n"
1327 "void main() {\n"
1328 " vec4 p = vec4(model_translate + position, 1.0, 1.0);\n"
1329 " color = (color_matrix * p).rgb;\n"
1330 " gl_Position = view_matrix * p;\n"
1331 "}\n";
1332
1333 const char *kFragmentShaderSource =
1334 "precision mediump float;\n"
1335 "varying vec3 color;\n"
1336 "void main() {\n"
1337 " gl_FragColor = vec4(color, 1.0);\n"
1338 "}\n";
1339 // clang-format on
1340
1341 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1342 bindProgram();
1343 ASSERT_TRUE(linkProgram() == true);
1344
1345 glUniformMatrix4fv(kViewMatrixLocation, 1, GL_FALSE, kProjectionMatrix);
1346
1347 static const GLfloat kColorMatrix[16] = {
1348 1.0f / kResolution, 0.0f, 0.0f, 0.0f,
1349 0.0f, 1.0f / kResolution, 0.0f, 0.0f,
1350 0.0f, 0.0f, 0.0f, 0.0f,
1351 0.0f, 0.0f, 0.0f, 0.0f};
1352
1353 glUniformMatrix4fv(kColorMatrixLocation, 1, GL_FALSE, kColorMatrix);
1354
1355 // This is the functionality we are testing: ProgramPathFragmentInputGen
1356 // does the same work as the color transform in vertex shader.
1357 static const GLfloat kColorCoefficients[12] = {
1358 1.0f / kResolution, 0.0f, 0.0f,
1359 0.0f, 0.0f, 1.0f / kResolution,
1360 0.0f, 0.0f, 0.0f,
1361 0.0f, 0.0f, 0.0f};
1362 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorFragmentInputLocation,
1363 GL_EYE_LINEAR_CHROMIUM, 3, kColorCoefficients);
1364 ASSERT_GL_NO_ERROR();
1365
1366 drawTestPattern();
1367
1368 const GLfloat kFillCoords[6] = {59.0f, 50.0f, 50.0f, 28.0f, 66.0f, 63.0f};
1369
1370 for (int j = 0; j < kTestRows; ++j)
1371 {
1372 for (int i = 0; i < kTestColumns; ++i)
1373 {
1374 for (size_t k = 0; k < ArraySize(kFillCoords); k += 2)
1375 {
1376 const float fx = kFillCoords[k];
1377 const float fy = kFillCoords[k + 1];
1378 const float px = static_cast<float>(i * kShapeWidth);
1379 const float py = static_cast<float>(j * kShapeHeight);
1380
1381 angle::GLColor color;
1382 color.R = static_cast<GLubyte>(std::roundf((px + fx) / kResolution * 255.0f));
1383 color.G = static_cast<GLubyte>(std::roundf((py + fy) / kResolution * 255.0f));
1384 color.B = 0;
1385 color.A = 255;
1386 CheckPixels(static_cast<GLint>(px + fx), static_cast<GLint>(py + fy), 1, 1, 2,
1387 color);
1388 }
1389 }
1390 }
1391 }
1392
1393 // Test fragment input interpolation in CHROMIUM_OBJECT coordinates.
TEST_P(CHROMIUMPathRenderingWithTexturingTest,TestProgramPathFragmentInputGenCHROMIUM_OBJECT)1394 TEST_P(CHROMIUMPathRenderingWithTexturingTest, TestProgramPathFragmentInputGenCHROMIUM_OBJECT)
1395 {
1396 if (!isApplicable())
1397 return;
1398
1399 // clang-format off
1400 const char *kVertexShaderSource =
1401 "uniform mat4 view_matrix;\n"
1402 "uniform mat4 color_matrix;\n"
1403 "uniform vec2 model_translate;\n"
1404 "attribute vec2 position;\n"
1405 "varying vec3 color;\n"
1406 "void main() {\n"
1407 " color = (color_matrix * vec4(position, 1.0, 1.0)).rgb;\n"
1408 " vec4 p = vec4(model_translate + position, 1.0, 1.0);\n"
1409 " gl_Position = view_matrix * p;\n"
1410 "}";
1411
1412 const char *kFragmentShaderSource =
1413 "precision mediump float;\n"
1414 "varying vec3 color;\n"
1415 "void main() {\n"
1416 " gl_FragColor = vec4(color.rgb, 1.0);\n"
1417 "}";
1418 // clang-format on
1419
1420 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1421 bindProgram();
1422 ASSERT_TRUE(linkProgram() == true);
1423
1424 glUniformMatrix4fv(kViewMatrixLocation, 1, GL_FALSE, kProjectionMatrix);
1425
1426 static const GLfloat kColorMatrix[16] = {
1427 1.0f / kShapeWidth, 0.0f, 0.0f, 0.0f,
1428 0.0f, 1.0f / kShapeHeight, 0.0f, 0.0f,
1429 0.0f, 0.0f, 0.0f, 0.0f,
1430 0.0f, 0.0f, 0.0f, 0.0f };
1431 glUniformMatrix4fv(kColorMatrixLocation, 1, GL_FALSE, kColorMatrix);
1432
1433 // This is the functionality we are testing: ProgramPathFragmentInputGen
1434 // does the same work as the color transform in vertex shader.
1435 static const GLfloat kColorCoefficients[9] = {
1436 1.0f / kShapeWidth, 0.0f, 0.0f, 0.0f, 1.0f / kShapeHeight, 0.0f, 0.0f, 0.0f, 0.0f};
1437 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorFragmentInputLocation,
1438 GL_OBJECT_LINEAR_CHROMIUM, 3, kColorCoefficients);
1439
1440 ASSERT_GL_NO_ERROR();
1441
1442 drawTestPattern();
1443
1444 const GLfloat kFillCoords[6] = {59.0f, 50.0f, 50.0f, 28.0f, 66.0f, 63.0f};
1445
1446 for (int j = 0; j < kTestRows; ++j)
1447 {
1448 for (int i = 0; i < kTestColumns; ++i)
1449 {
1450 for (size_t k = 0; k < ArraySize(kFillCoords); k += 2)
1451 {
1452 const float fx = kFillCoords[k];
1453 const float fy = kFillCoords[k + 1];
1454 const float px = static_cast<float>(i * kShapeWidth);
1455 const float py = static_cast<float>(j * kShapeHeight);
1456
1457 angle::GLColor color;
1458 color.R = static_cast<GLubyte>(std::roundf(fx / kShapeWidth * 255.0f));
1459 color.G = static_cast<GLubyte>(std::roundf(fy / kShapeHeight * 255.0f));
1460 color.B = 0;
1461 color.A = 255;
1462 CheckPixels(static_cast<GLint>(px + fx), static_cast<GLint>(py + fy), 1, 1, 2,
1463 color);
1464 }
1465 }
1466 }
1467 }
1468
1469 // Test success and error cases for setting interpolation parameters.
TEST_P(CHROMIUMPathRenderingWithTexturingTest,TestProgramPathFragmentInputGenArgs)1470 TEST_P(CHROMIUMPathRenderingWithTexturingTest, TestProgramPathFragmentInputGenArgs)
1471 {
1472 if (!isApplicable())
1473 return;
1474
1475 // clang-format off
1476 const char *kVertexShaderSource =
1477 "varying vec2 vec2_var;\n"
1478 "varying vec3 vec3_var;\n"
1479 "varying vec4 vec4_var;\n"
1480 "varying float float_var;\n"
1481 "varying mat2 mat2_var;\n"
1482 "varying mat3 mat3_var;\n"
1483 "varying mat4 mat4_var;\n"
1484 "attribute float avoid_opt;\n"
1485 "void main() {\n"
1486 " vec2_var = vec2(1.0, 2.0 + avoid_opt);\n"
1487 " vec3_var = vec3(1.0, 2.0, 3.0 + avoid_opt);\n"
1488 " vec4_var = vec4(1.0, 2.0, 3.0, 4.0 + avoid_opt);\n"
1489 " float_var = 5.0 + avoid_opt;\n"
1490 " mat2_var = mat2(2.0 + avoid_opt);\n"
1491 " mat3_var = mat3(3.0 + avoid_opt);\n"
1492 " mat4_var = mat4(4.0 + avoid_opt);\n"
1493 " gl_Position = vec4(1.0);\n"
1494 "}";
1495
1496 const char* kFragmentShaderSource =
1497 "precision mediump float;\n"
1498 "varying vec2 vec2_var;\n"
1499 "varying vec3 vec3_var;\n"
1500 "varying vec4 vec4_var;\n"
1501 "varying float float_var;\n"
1502 "varying mat2 mat2_var;\n"
1503 "varying mat3 mat3_var;\n"
1504 "varying mat4 mat4_var;\n"
1505 "void main() {\n"
1506 " gl_FragColor = vec4(vec2_var, 0, 0) + vec4(vec3_var, 0) + vec4_var + "
1507 " vec4(float_var) + "
1508 " vec4(mat2_var[0][0], mat3_var[1][1], mat4_var[2][2], 1);\n"
1509 "}";
1510 // clang-format on
1511
1512 enum
1513 {
1514 kVec2Location = 0,
1515 kVec3Location,
1516 kVec4Location,
1517 kFloatLocation,
1518 kMat2Location,
1519 kMat3Location,
1520 kMat4Location,
1521 };
1522 struct
1523 {
1524 GLint location;
1525 const char *name;
1526 GLint components;
1527 } variables[] = {
1528 {kVec2Location, "vec2_var", 2},
1529 {kVec3Location, "vec3_var", 3},
1530 {kVec4Location, "vec4_var", 4},
1531 {kFloatLocation, "float_var", 1},
1532 // If a varying is not single-precision floating-point scalar or
1533 // vector, it always causes an invalid operation.
1534 {kMat2Location, "mat2_var", -1},
1535 {kMat3Location, "mat3_var", -1},
1536 {kMat4Location, "mat4_var", -1},
1537 };
1538
1539 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1540
1541 for (size_t i = 0; i < ArraySize(variables); ++i)
1542 {
1543 glBindFragmentInputLocationCHROMIUM(mProgram, variables[i].location, variables[i].name);
1544 }
1545
1546 // test that using invalid (not linked) program is an invalid operation.
1547 // See similar calls at the end of the test for discussion about the arguments.
1548 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, GL_NONE, 0, NULL);
1549 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1550
1551 ASSERT_TRUE(linkProgram() == true);
1552
1553 const GLfloat kCoefficients16[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
1554 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f};
1555 const GLenum kGenModes[] = {GL_NONE, GL_EYE_LINEAR_CHROMIUM, GL_OBJECT_LINEAR_CHROMIUM,
1556 GL_CONSTANT_CHROMIUM};
1557
1558 for (size_t variable = 0; variable < ArraySize(variables); ++variable)
1559 {
1560 for (GLint components = 0; components <= 4; ++components)
1561 {
1562 for (size_t genmode = 0; genmode < ArraySize(kGenModes); ++genmode)
1563 {
1564 glProgramPathFragmentInputGenCHROMIUM(mProgram, variables[variable].location,
1565 kGenModes[genmode], components,
1566 kCoefficients16);
1567
1568 if (components == 0 && kGenModes[genmode] == GL_NONE)
1569 {
1570 if (variables[variable].components == -1)
1571 {
1572 // Clearing a fragment input that is not single-precision floating
1573 // point scalar or vector is an invalid operation.
1574 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1575 }
1576 else
1577 {
1578 // Clearing a valid fragment input is ok.
1579 ASSERT_GL_NO_ERROR();
1580 }
1581 }
1582 else if (components == 0 || kGenModes[genmode] == GL_NONE)
1583 {
1584 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1585 }
1586 else
1587 {
1588 if (components == variables[variable].components)
1589 {
1590 // Setting a generator for a single-precision floating point
1591 // scalar or vector fragment input is ok.
1592 ASSERT_GL_NO_ERROR();
1593 }
1594 else
1595 {
1596 // Setting a generator when components do not match is an invalid operation.
1597 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1598 }
1599 }
1600 }
1601 }
1602 }
1603
1604 enum
1605 {
1606 kValidGenMode = GL_CONSTANT_CHROMIUM,
1607 kValidComponents = 3,
1608 kInvalidGenMode = 0xAB,
1609 kInvalidComponents = 5,
1610 };
1611
1612 // The location == -1 would mean fragment input was optimized away. At the
1613 // time of writing, -1 can not happen because the only way to obtain the
1614 // location numbers is through bind. Test just to be consistent.
1615 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kValidGenMode, kValidComponents,
1616 kCoefficients16);
1617 ASSERT_GL_NO_ERROR();
1618
1619 // Test that even though the spec says location == -1 causes the operation to
1620 // be skipped, the verification of other parameters is still done. This is a
1621 // GL policy.
1622 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kInvalidGenMode, kValidComponents,
1623 kCoefficients16);
1624 ASSERT_GL_ERROR(GL_INVALID_ENUM);
1625
1626 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kInvalidGenMode, kInvalidComponents,
1627 kCoefficients16);
1628 ASSERT_GL_ERROR(GL_INVALID_ENUM);
1629
1630 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kValidGenMode, kInvalidComponents,
1631 kCoefficients16);
1632 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1633
1634 glDeleteProgram(mProgram);
1635
1636 // Test that using invalid (deleted) program is an invalid operation.
1637 EXPECT_FALSE(glIsProgram(mProgram) == GL_FALSE);
1638
1639 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kValidGenMode, kValidComponents,
1640 kCoefficients16);
1641 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1642
1643 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kInvalidGenMode, kValidComponents,
1644 kCoefficients16);
1645 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1646
1647 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kInvalidGenMode, kInvalidComponents,
1648 kCoefficients16);
1649 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1650
1651 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, kValidGenMode, kInvalidComponents,
1652 kCoefficients16);
1653 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1654
1655 mProgram = 0u;
1656 }
1657
1658 // Test that having input statically aliased fragment inputs the linking fails
1659 // and then succeeds when the conflict is resolved.
TEST_P(CHROMIUMPathRenderingWithTexturingTest,TestConflictingBind)1660 TEST_P(CHROMIUMPathRenderingWithTexturingTest, TestConflictingBind)
1661 {
1662 if (!isApplicable())
1663 return;
1664
1665 // clang-format off
1666 const char* kVertexShaderSource =
1667 "attribute vec4 position;\n"
1668 "varying vec4 colorA;\n"
1669 "varying vec4 colorB;\n"
1670 "void main() {\n"
1671 " gl_Position = position;\n"
1672 " colorA = position + vec4(1);\n"
1673 " colorB = position + vec4(2);\n"
1674 "}";
1675
1676 const char* kFragmentShaderSource =
1677 "precision mediump float;\n"
1678 "varying vec4 colorA;\n"
1679 "varying vec4 colorB;\n"
1680 "void main() {\n"
1681 " gl_FragColor = colorA + colorB;\n"
1682 "}";
1683 // clang-format on
1684
1685 const GLint kColorALocation = 3;
1686 const GLint kColorBLocation = 4;
1687
1688 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1689
1690 glBindFragmentInputLocationCHROMIUM(mProgram, kColorALocation, "colorA");
1691 // Bind colorB to location a, causing conflicts. Linking should fail.
1692 glBindFragmentInputLocationCHROMIUM(mProgram, kColorALocation, "colorB");
1693
1694 // Should fail now.
1695 ASSERT_TRUE(linkProgram() == false);
1696 ASSERT_GL_NO_ERROR();
1697
1698 // Resolve the bind conflict.
1699 glBindFragmentInputLocationCHROMIUM(mProgram, kColorBLocation, "colorB");
1700
1701 ASSERT_TRUE(linkProgram() == true);
1702 ASSERT_GL_NO_ERROR();
1703 }
1704
1705 // Test binding with array variables, using zero indices. Tests that
1706 // binding colorA[0] with explicit "colorA[0]" as well as "colorA" produces
1707 // a correct location that can be used with PathProgramFragmentInputGen.
1708 // For path rendering, colorA[0] is bound to a location. The input generator for
1709 // the location is set to produce vec4(0, 0.1, 0, 0.1).
1710 // The default varying, color, is bound to a location and its generator
1711 // will produce vec4(10.0). The shader program produces green pixels.
1712 // For vertex-based rendering, the vertex shader produces the same effect as
1713 // the input generator for path rendering.
TEST_P(CHROMIUMPathRenderingWithTexturingTest,BindFragmentInputArray)1714 TEST_P(CHROMIUMPathRenderingWithTexturingTest, BindFragmentInputArray)
1715 {
1716 if (!isApplicable())
1717 return;
1718
1719 //clang-format off
1720 const char* kVertexShaderSource =
1721 "uniform mat4 view_matrix;\n"
1722 "uniform mat4 color_matrix;\n"
1723 "uniform vec2 model_translate;\n"
1724 "attribute vec2 position;\n"
1725 "varying vec4 color;\n"
1726 "varying vec4 colorA[4];\n"
1727 "void main() {\n"
1728 " vec4 p = vec4(model_translate + position, 1, 1);\n"
1729 " gl_Position = view_matrix * p;\n"
1730 " colorA[0] = vec4(0.0, 0.1, 0, 0.1);\n"
1731 " colorA[1] = vec4(0.2);\n"
1732 " colorA[2] = vec4(0.3);\n"
1733 " colorA[3] = vec4(0.4);\n"
1734 " color = vec4(10.0);\n"
1735 "}";
1736
1737 const char* kFragmentShaderSource =
1738 "precision mediump float;\n"
1739 "varying vec4 color;\n"
1740 "varying vec4 colorA[4];\n"
1741 "void main() {\n"
1742 " gl_FragColor = colorA[0] * color;\n"
1743 "}";
1744 // clang-format on
1745
1746 const GLint kColorA0Location = 4;
1747 const GLint kUnusedLocation = 5;
1748 const GLfloat kColorA0[] = {0.0f, 0.1f, 0.0f, 0.1f};
1749 const GLfloat kColor[] = {10.0f, 10.0f, 10.0f, 10.0f};
1750 const GLfloat kFillCoords[6] = {59.0f, 50.0f, 50.0f, 28.0f, 66.0f, 63.0f};
1751
1752 for (int pass = 0; pass < 2; ++pass)
1753 {
1754 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1755 if (pass == 0)
1756 {
1757 glBindFragmentInputLocationCHROMIUM(mProgram, kUnusedLocation, "colorA[0]");
1758 glBindFragmentInputLocationCHROMIUM(mProgram, kColorA0Location, "colorA");
1759 }
1760 else
1761 {
1762 glBindFragmentInputLocationCHROMIUM(mProgram, kUnusedLocation, "colorA");
1763 glBindFragmentInputLocationCHROMIUM(mProgram, kColorA0Location, "colorA[0]");
1764 }
1765
1766 bindProgram();
1767
1768 ASSERT_TRUE(linkProgram() == true);
1769
1770 glUniformMatrix4fv(kViewMatrixLocation, 1, GL_FALSE, kProjectionMatrix);
1771 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorA0Location, GL_CONSTANT_CHROMIUM, 4, kColorA0);
1772 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorFragmentInputLocation, GL_CONSTANT_CHROMIUM, 4, kColor);
1773 ASSERT_GL_NO_ERROR();
1774
1775 drawTestPattern();
1776
1777 for (int j = 0; j < kTestRows; ++j)
1778 {
1779 for (int i = 0; i < kTestColumns; ++i)
1780 {
1781 for (size_t k = 0; k < ArraySize(kFillCoords); k += 2)
1782 {
1783 const float fx = kFillCoords[k];
1784 const float fy = kFillCoords[k + 1];
1785 const float px = static_cast<float>(i * kShapeWidth);
1786 const float py = static_cast<float>(j * kShapeHeight);
1787
1788 angle::GLColor color;
1789 color.R = 0;
1790 color.G = 255;
1791 color.B = 0;
1792 color.A = 255;
1793 CheckPixels(static_cast<GLint>(px + fx), static_cast<GLint>(py + fy), 1, 1, 2,
1794 color);
1795 }
1796 }
1797 }
1798 }
1799 }
1800
1801 // Test binding array variables. This is like BindFragmentInputArray.
1802 // Currently disabled since it seems there's a driver bug with the
1803 // older drivers. This should work with driver >= 364.12
TEST_P(CHROMIUMPathRenderingWithTexturingTest,DISABLED_BindFragmentInputArrayNonZeroIndex)1804 TEST_P(CHROMIUMPathRenderingWithTexturingTest,
1805 DISABLED_BindFragmentInputArrayNonZeroIndex)
1806 {
1807 if (!isApplicable())
1808 return;
1809
1810 // clang-format off
1811 const char* kVertexShaderSource =
1812 "uniform mat4 view_matrix;\n"
1813 "uniform mat4 color_matrix;\n"
1814 "uniform vec2 model_translate;\n"
1815 "attribute vec2 position;\n"
1816 "varying vec4 color;\n"
1817 "varying vec4 colorA[4];\n"
1818 "void main() {\n"
1819 " vec4 p = vec4(model_translate + position, 1, 1);\n"
1820 " gl_Position = view_matrix * p;\n"
1821 " colorA[0] = vec4(0, 0.1, 0, 0.1);\n"
1822 " colorA[1] = vec4(0, 1, 0, 1);\n"
1823 " colorA[2] = vec4(0, 0.8, 0, 0.8);\n"
1824 " colorA[3] = vec4(0, 0.5, 0, 0.5);\n"
1825 " color = vec4(0.2);\n"
1826 "}\n";
1827
1828 const char* kFragmentShaderSource =
1829 "precision mediump float;\n"
1830 "varying vec4 colorA[4];\n"
1831 "varying vec4 color;\n"
1832 "void main() {\n"
1833 " gl_FragColor = (colorA[0] * colorA[1]) +\n"
1834 " colorA[2] + (colorA[3] * color);\n"
1835 "}\n";
1836 // clang-format on
1837
1838 const GLint kColorA0Location = 4;
1839 const GLint kColorA1Location = 1;
1840 const GLint kColorA2Location = 2;
1841 const GLint kColorA3Location = 3;
1842 const GLint kUnusedLocation = 5;
1843 const GLfloat kColorA0[] = {0.0f, 0.1f, 0.0f, 0.1f};
1844 const GLfloat kColorA1[] = {0.0f, 1.0f, 0.0f, 1.0f};
1845 const GLfloat kColorA2[] = {0.0f, 0.8f, 0.0f, 0.8f};
1846 const GLfloat kColorA3[] = {0.0f, 0.5f, 0.0f, 0.5f};
1847 const GLfloat kColor[] = {0.2f, 0.2f, 0.2f, 0.2f};
1848 const GLfloat kFillCoords[6] = {59.0f, 50.0f, 50.0f, 28.0f, 66.0f, 63.0f};
1849
1850 compileProgram(kVertexShaderSource, kFragmentShaderSource);
1851
1852 glBindFragmentInputLocationCHROMIUM(mProgram, kUnusedLocation, "colorA[0]");
1853 glBindFragmentInputLocationCHROMIUM(mProgram, kColorA1Location, "colorA[1]");
1854 glBindFragmentInputLocationCHROMIUM(mProgram, kColorA2Location, "colorA[2]");
1855 glBindFragmentInputLocationCHROMIUM(mProgram, kColorA3Location, "colorA[3]");
1856 glBindFragmentInputLocationCHROMIUM(mProgram, kColorA0Location, "colorA");
1857 ASSERT_GL_NO_ERROR();
1858
1859 bindProgram();
1860 ASSERT_TRUE(linkProgram() == true);
1861
1862 glUniformMatrix4fv(kViewMatrixLocation, 1, GL_FALSE, kProjectionMatrix);
1863
1864 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorA0Location, GL_CONSTANT_CHROMIUM, 4, kColorA0);
1865 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorA1Location, GL_CONSTANT_CHROMIUM, 4, kColorA1);
1866 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorA2Location, GL_CONSTANT_CHROMIUM, 4, kColorA2);
1867 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorA3Location, GL_CONSTANT_CHROMIUM, 4, kColorA3);
1868 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorFragmentInputLocation,
1869 GL_CONSTANT_CHROMIUM, 4, kColor);
1870 ASSERT_GL_NO_ERROR();
1871
1872 drawTestPattern();
1873
1874 for (int j = 0; j < kTestRows; ++j)
1875 {
1876 for (int i = 0; i < kTestColumns; ++i)
1877 {
1878 for (size_t k = 0; k < ArraySize(kFillCoords); k += 2)
1879 {
1880 const float fx = kFillCoords[k];
1881 const float fy = kFillCoords[k + 1];
1882 const float px = static_cast<float>(i * kShapeWidth);
1883 const float py = static_cast<float>(j * kShapeHeight);
1884
1885 angle::GLColor color;
1886 color.R = 0;
1887 color.G = 255;
1888 color.B = 0;
1889 color.A = 255;
1890 CheckPixels(static_cast<GLint>(px + fx), static_cast<GLint>(py + fy), 1, 1, 2,
1891 color);
1892 }
1893 }
1894 }
1895 }
1896
TEST_P(CHROMIUMPathRenderingWithTexturingTest,UnusedFragmentInputUpdate)1897 TEST_P(CHROMIUMPathRenderingWithTexturingTest, UnusedFragmentInputUpdate)
1898 {
1899 if (!isApplicable())
1900 return;
1901
1902 // clang-format off
1903 const char* kVertexShaderString =
1904 "attribute vec4 a_position;\n"
1905 "void main() {\n"
1906 " gl_Position = a_position;\n"
1907 "}";
1908
1909 const char* kFragmentShaderString =
1910 "precision mediump float;\n"
1911 "uniform vec4 u_colorA;\n"
1912 "uniform float u_colorU;\n"
1913 "uniform vec4 u_colorC;\n"
1914 "void main() {\n"
1915 " gl_FragColor = u_colorA + u_colorC;\n"
1916 "}";
1917 // clang-format on
1918
1919 const GLint kColorULocation = 1;
1920 const GLint kNonexistingLocation = 5;
1921 const GLint kUnboundLocation = 6;
1922
1923 compileProgram(kVertexShaderString, kFragmentShaderString);
1924
1925 glBindFragmentInputLocationCHROMIUM(mProgram, kColorULocation, "u_colorU");
1926
1927 // The non-existing input should behave like existing but optimized away input.
1928 glBindFragmentInputLocationCHROMIUM(mProgram, kNonexistingLocation, "nonexisting");
1929
1930 // Let A and C be assigned automatic locations.
1931 ASSERT_TRUE(linkProgram() == true);
1932
1933 const GLfloat kColor[16] = {};
1934
1935 // No errors on bound locations, since caller does not know
1936 // if the driver optimizes them away or not.
1937 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorULocation, GL_CONSTANT_CHROMIUM, 1, kColor);
1938 ASSERT_GL_NO_ERROR();
1939
1940 // No errors on bound locations of names that do not exist
1941 // in the shader. Otherwise it would be inconsistent wrt the
1942 // optimization case.
1943 glProgramPathFragmentInputGenCHROMIUM(mProgram, kNonexistingLocation, GL_CONSTANT_CHROMIUM, 1, kColor);
1944 ASSERT_GL_NO_ERROR();
1945
1946 // The above are equal to updating -1.
1947 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, GL_CONSTANT_CHROMIUM, 1, kColor);
1948 ASSERT_GL_NO_ERROR();
1949
1950 // No errors when updating with other type either.
1951 // The type can not be known with the non-existing case.
1952 glProgramPathFragmentInputGenCHROMIUM(mProgram, kColorULocation, GL_CONSTANT_CHROMIUM, 4, kColor);
1953 ASSERT_GL_NO_ERROR();
1954
1955 glProgramPathFragmentInputGenCHROMIUM(mProgram, kNonexistingLocation, GL_CONSTANT_CHROMIUM, 4, kColor);
1956 ASSERT_GL_NO_ERROR();
1957
1958 glProgramPathFragmentInputGenCHROMIUM(mProgram, -1, GL_CONSTANT_CHROMIUM, 4, kColor);
1959 ASSERT_GL_NO_ERROR();
1960
1961 // Updating an unbound, non-existing location still causes an error.
1962 glProgramPathFragmentInputGenCHROMIUM(mProgram, kUnboundLocation, GL_CONSTANT_CHROMIUM, 4, kColor);
1963 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1964 }
1965
1966
1967 } // namespace
1968
1969 ANGLE_INSTANTIATE_TEST(CHROMIUMPathRenderingTest,
1970 ES2_OPENGL(),
1971 ES2_OPENGLES(),
1972 ES3_OPENGL(),
1973 ES3_OPENGLES());
1974 ANGLE_INSTANTIATE_TEST(CHROMIUMPathRenderingDrawTest,
1975 ES2_OPENGL(),
1976 ES2_OPENGLES(),
1977 ES3_OPENGL(),
1978 ES3_OPENGLES());
1979
1980 ANGLE_INSTANTIATE_TEST(CHROMIUMPathRenderingWithTexturingTest,
1981 ES2_OPENGL(),
1982 ES2_OPENGLES(),
1983 ES3_OPENGL(),
1984 ES3_OPENGLES());