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());