blob: e1032c7c2d570def2abb67e2e64f707d557cc580 [file] [log] [blame]
Sami Väisänene45e53b2016-05-25 10:36:04 +03001//
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 <cmath>
14#include <cstring>
15#include <cstddef>
16#include <fstream>
17
18using namespace angle;
19
20namespace
21{
22
23bool CheckPixels(GLint x,
24 GLint y,
25 GLsizei width,
26 GLsizei height,
27 GLint tolerance,
28 const angle::GLColor &color)
29{
30 for (GLint yy = 0; yy < height; ++yy)
31 {
32 for (GLint xx = 0; xx < width; ++xx)
33 {
34 const auto px = x + xx;
35 const auto py = y + yy;
36 EXPECT_PIXEL_COLOR_EQ(px, py, color);
37 }
38 }
39
40 return true;
41}
42
43void ExpectEqualMatrix(const GLfloat *expected, const GLfloat *actual)
44{
45 for (size_t i = 0; i < 16; ++i)
46 {
47 EXPECT_EQ(expected[i], actual[i]);
48 }
49}
50
51void ExpectEqualMatrix(const GLfloat *expected, const GLint *actual)
52{
53 for (size_t i = 0; i < 16; ++i)
54 {
55 EXPECT_EQ(static_cast<GLint>(std::roundf(expected[i])), actual[i]);
56 }
57}
58
59const int kResolution = 300;
60
61class CHROMIUMPathRenderingTest : public ANGLETest
62{
63 protected:
64 CHROMIUMPathRenderingTest()
65 {
66 setWindowWidth(kResolution);
67 setWindowHeight(kResolution);
68 setConfigRedBits(8);
69 setConfigGreenBits(8);
70 setConfigBlueBits(8);
71 setConfigAlphaBits(8);
72 setConfigDepthBits(8);
73 setConfigStencilBits(8);
74 }
75
76 bool isApplicable() const { return extensionEnabled("GL_CHROMIUM_path_rendering"); }
77
78 void tryAllDrawFunctions(GLuint path, GLenum err)
79 {
80 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F);
81 EXPECT_GL_ERROR(err);
82
83 glStencilFillPathCHROMIUM(path, GL_COUNT_DOWN_CHROMIUM, 0x7F);
84 EXPECT_GL_ERROR(err);
85
86 glStencilStrokePathCHROMIUM(path, 0x80, 0x80);
87 EXPECT_GL_ERROR(err);
88
89 glCoverFillPathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM);
90 EXPECT_GL_ERROR(err);
91
92 glCoverStrokePathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM);
93 EXPECT_GL_ERROR(err);
94
95 glStencilThenCoverStrokePathCHROMIUM(path, 0x80, 0x80, GL_BOUNDING_BOX_CHROMIUM);
96 EXPECT_GL_ERROR(err);
97
98 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F,
99 GL_BOUNDING_BOX_CHROMIUM);
100 EXPECT_GL_ERROR(err);
101 }
102};
103
104// Test setting and getting of path rendering matrices.
105TEST_P(CHROMIUMPathRenderingTest, TestMatrix)
106{
107 if (!isApplicable())
108 return;
109
110 static const GLfloat kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
111 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
112
113 static const GLfloat kSeqMatrix[16] = {0.5f, -0.5f, -0.1f, -0.8f, 4.4f, 5.5f,
114 6.6f, 7.7f, 8.8f, 9.9f, 10.11f, 11.22f,
115 12.33f, 13.44f, 14.55f, 15.66f};
116
117 static const GLenum kMatrixModes[] = {GL_PATH_MODELVIEW_CHROMIUM, GL_PATH_PROJECTION_CHROMIUM};
118
119 static const GLenum kGetMatrixModes[] = {GL_PATH_MODELVIEW_MATRIX_CHROMIUM,
120 GL_PATH_PROJECTION_MATRIX_CHROMIUM};
121
122 for (size_t i = 0; i < 2; ++i)
123 {
124 GLfloat mf[16];
125 GLint mi[16];
126 std::memset(mf, 0, sizeof(mf));
127 std::memset(mi, 0, sizeof(mi));
128 glGetFloatv(kGetMatrixModes[i], mf);
129 glGetIntegerv(kGetMatrixModes[i], mi);
130 ExpectEqualMatrix(kIdentityMatrix, mf);
131 ExpectEqualMatrix(kIdentityMatrix, mi);
132
133 glMatrixLoadfCHROMIUM(kMatrixModes[i], kSeqMatrix);
134 std::memset(mf, 0, sizeof(mf));
135 std::memset(mi, 0, sizeof(mi));
136 glGetFloatv(kGetMatrixModes[i], mf);
137 glGetIntegerv(kGetMatrixModes[i], mi);
138 ExpectEqualMatrix(kSeqMatrix, mf);
139 ExpectEqualMatrix(kSeqMatrix, mi);
140
141 glMatrixLoadIdentityCHROMIUM(kMatrixModes[i]);
142 std::memset(mf, 0, sizeof(mf));
143 std::memset(mi, 0, sizeof(mi));
144 glGetFloatv(kGetMatrixModes[i], mf);
145 glGetIntegerv(kGetMatrixModes[i], mi);
146 ExpectEqualMatrix(kIdentityMatrix, mf);
147 ExpectEqualMatrix(kIdentityMatrix, mi);
148
149 ASSERT_GL_NO_ERROR();
150 }
151}
152
153// Test that trying to set incorrect matrix target results
154// in a GL error.
155TEST_P(CHROMIUMPathRenderingTest, TestMatrixErrors)
156{
157 if (!isApplicable())
158 return;
159
160 GLfloat mf[16];
161 std::memset(mf, 0, sizeof(mf));
162
163 glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM, mf);
164 ASSERT_GL_NO_ERROR();
165
166 glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM);
167 ASSERT_GL_NO_ERROR();
168
169 // Test that invalid matrix targets fail.
170 glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM - 1, mf);
171 EXPECT_GL_ERROR(GL_INVALID_ENUM);
172
173 // Test that invalid matrix targets fail.
174 glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM + 1);
175 EXPECT_GL_ERROR(GL_INVALID_ENUM);
176}
177
178// Test basic path create and delete.
179TEST_P(CHROMIUMPathRenderingTest, TestGenDelete)
180{
181 if (!isApplicable())
182 return;
183
184 // This is unspecified in NV_path_rendering.
185 EXPECT_EQ(0u, glGenPathsCHROMIUM(0));
186 EXPECT_GL_ERROR(GL_INVALID_VALUE);
187
188 GLuint path = glGenPathsCHROMIUM(1);
189 EXPECT_NE(0u, path);
190 glDeletePathsCHROMIUM(path, 1);
191 ASSERT_GL_NO_ERROR();
192
193 GLuint first_path = glGenPathsCHROMIUM(5);
194 EXPECT_NE(0u, first_path);
195 glDeletePathsCHROMIUM(first_path, 5);
196 ASSERT_GL_NO_ERROR();
197
198 // Test deleting paths that are not actually allocated:
199 // "unused names in /paths/ are silently ignored".
200 first_path = glGenPathsCHROMIUM(5);
201 EXPECT_NE(0u, first_path);
202 glDeletePathsCHROMIUM(first_path, 6);
203 ASSERT_GL_NO_ERROR();
204
205 GLsizei big_range = 0xffff;
206 first_path = glGenPathsCHROMIUM(big_range);
207 EXPECT_NE(0u, first_path);
208 glDeletePathsCHROMIUM(first_path, big_range);
209 ASSERT_GL_NO_ERROR();
210
211 // Test glIsPathCHROMIUM(). A path object is not considered a path untill
212 // it has actually been specified with a path data.
213
214 path = glGenPathsCHROMIUM(1);
215 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
216
217 // specify the data.
218 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
219 GLfloat coords[] = {50.0f, 50.0f};
220 glPathCommandsCHROMIUM(path, 2, commands, 2, GL_FLOAT, coords);
221 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE);
222 glDeletePathsCHROMIUM(path, 1);
223 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
224}
225
226// Test incorrect path creation and deletion and expect GL errors.
227TEST_P(CHROMIUMPathRenderingTest, TestGenDeleteErrors)
228{
229 if (!isApplicable())
230 return;
231
232 // GenPaths / DeletePaths tests.
233 // std::numeric_limits<GLuint>::max() is wrong for GLsizei.
234 GLuint first_path = glGenPathsCHROMIUM(std::numeric_limits<GLuint>::max());
235 EXPECT_EQ(first_path, 0u);
236 EXPECT_GL_ERROR(GL_INVALID_VALUE);
237
238 first_path = glGenPathsCHROMIUM(-1);
239 EXPECT_EQ(0u, first_path);
240 EXPECT_GL_ERROR(GL_INVALID_VALUE);
241
242 glDeletePathsCHROMIUM(1, -5);
243 EXPECT_GL_ERROR(GL_INVALID_VALUE);
244
245 first_path = glGenPathsCHROMIUM(-1);
246 EXPECT_EQ(0u, first_path);
247 EXPECT_GL_ERROR(GL_INVALID_VALUE);
248}
249
250// Test setting and getting path parameters.
251TEST_P(CHROMIUMPathRenderingTest, TestPathParameter)
252{
253 if (!isApplicable())
254 return;
255
256 GLuint path = glGenPathsCHROMIUM(1);
257
258 // specify the data.
259 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
260 GLfloat coords[] = {50.0f, 50.0f};
261 glPathCommandsCHROMIUM(path, 2, commands, 2, GL_FLOAT, coords);
262 ASSERT_GL_NO_ERROR();
263 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE);
264
265 static const GLenum kEndCaps[] = {GL_FLAT_CHROMIUM, GL_SQUARE_CHROMIUM, GL_ROUND_CHROMIUM};
266 for (std::size_t i = 0; i < 3; ++i)
267 {
268 GLint x;
269 glPathParameteriCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, static_cast<GLenum>(kEndCaps[i]));
270 ASSERT_GL_NO_ERROR();
271 glGetPathParameterivCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, &x);
272 ASSERT_GL_NO_ERROR();
273 EXPECT_EQ(kEndCaps[i], static_cast<GLenum>(x));
274
275 GLfloat f;
276 glPathParameterfCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM,
277 static_cast<GLenum>(kEndCaps[(i + 1) % 3]));
278 glGetPathParameterfvCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, &f);
279 ASSERT_GL_NO_ERROR();
280 EXPECT_EQ(kEndCaps[(i + 1) % 3], static_cast<GLenum>(f));
281 }
282
283 static const GLenum kJoinStyles[] = {GL_MITER_REVERT_CHROMIUM, GL_BEVEL_CHROMIUM,
284 GL_ROUND_CHROMIUM};
285 for (std::size_t i = 0; i < 3; ++i)
286 {
287 GLint x;
288 glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM,
289 static_cast<GLenum>(kJoinStyles[i]));
290 ASSERT_GL_NO_ERROR();
291 glGetPathParameterivCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, &x);
292 ASSERT_GL_NO_ERROR();
293 EXPECT_EQ(kJoinStyles[i], static_cast<GLenum>(x));
294
295 GLfloat f;
296 glPathParameterfCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM,
297 static_cast<GLenum>(kJoinStyles[(i + 1) % 3]));
298 ASSERT_GL_NO_ERROR();
299 glGetPathParameterfvCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, &f);
300 ASSERT_GL_NO_ERROR();
301 EXPECT_EQ(kJoinStyles[(i + 1) % 3], static_cast<GLenum>(f));
302 }
303
304 {
305 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f);
306 ASSERT_GL_NO_ERROR();
307
308 GLfloat f;
309 glGetPathParameterfvCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, &f);
310 EXPECT_EQ(5.0f, f);
311 }
312
313 glDeletePathsCHROMIUM(path, 1);
314}
315
316// Test that setting incorrect path parameter generates GL error.
317TEST_P(CHROMIUMPathRenderingTest, TestPathParameterErrors)
318{
319 if (!isApplicable())
320 return;
321
322 GLuint path = glGenPathsCHROMIUM(1);
323
324 // PathParameter*: Wrong value for the pname should fail.
325 glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, GL_FLAT_CHROMIUM);
326 EXPECT_GL_ERROR(GL_INVALID_ENUM);
327
328 glPathParameterfCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, GL_MITER_REVERT_CHROMIUM);
329 EXPECT_GL_ERROR(GL_INVALID_ENUM);
330
331 // PathParameter*: Wrong floating-point value should fail.
332 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, -0.1f);
333 EXPECT_GL_ERROR(GL_INVALID_VALUE);
334
335 // PathParameter*: Wrong pname should fail.
336 glPathParameteriCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM - 1, 5);
337 EXPECT_GL_ERROR(GL_INVALID_ENUM);
338
339 glDeletePathsCHROMIUM(path, 1);
340}
341
342// Test expected path object state.
343TEST_P(CHROMIUMPathRenderingTest, TestPathObjectState)
344{
345 if (!isApplicable())
346 return;
347
348 glViewport(0, 0, kResolution, kResolution);
349 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
350 glStencilMask(0xffffffff);
351 glClearStencil(0);
352 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
353 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
354 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
355 ASSERT_GL_NO_ERROR();
356
357 // Test that trying to draw non-existing paths does not produce errors or results.
358 GLuint non_existing_paths[] = {0, 55, 74744};
359 for (auto &p : non_existing_paths)
360 {
361 EXPECT_TRUE(glIsPathCHROMIUM(p) == GL_FALSE);
362 ASSERT_GL_NO_ERROR();
363 tryAllDrawFunctions(p, GL_NO_ERROR);
364 }
365
366 // Path name marked as used but without path object state causes
367 // a GL error upon any draw command.
368 GLuint path = glGenPathsCHROMIUM(1);
369 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
370 tryAllDrawFunctions(path, GL_INVALID_OPERATION);
371 glDeletePathsCHROMIUM(path, 1);
372
373 // Document a bit of an inconsistency: path name marked as used but without
374 // path object state causes a GL error upon any draw command (tested above).
375 // Path name that had path object state, but then was "cleared", still has a
376 // path object state, even though the state is empty.
377 path = glGenPathsCHROMIUM(1);
378 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_FALSE);
379
380 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
381 GLfloat coords[] = {50.0f, 50.0f};
382 glPathCommandsCHROMIUM(path, 2, commands, 2, GL_FLOAT, coords);
383 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE);
384
385 glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL);
386 EXPECT_TRUE(glIsPathCHROMIUM(path) == GL_TRUE); // The surprise.
387
388 tryAllDrawFunctions(path, GL_NO_ERROR);
389 glDeletePathsCHROMIUM(path, 1);
390
391 // Make sure nothing got drawn by the drawing commands that should not produce
392 // anything.
393 const angle::GLColor black = {0, 0, 0, 0};
394 EXPECT_TRUE(CheckPixels(0, 0, kResolution, kResolution, 0, black));
395}
396
397// Test that trying to use path object that doesn't exist generates
398// a GL error.
399TEST_P(CHROMIUMPathRenderingTest, TestUnnamedPathsErrors)
400{
401 if (!isApplicable())
402 return;
403
404 // Unnamed paths: Trying to create a path object with non-existing path name
405 // produces error. (Not a error in real NV_path_rendering).
406 ASSERT_GL_NO_ERROR();
407 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
408 GLfloat coords[] = {50.0f, 50.0f};
409 glPathCommandsCHROMIUM(555, 2, commands, 2, GL_FLOAT, coords);
410 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
411
412 // PathParameter*: Using non-existing path object produces error.
413 ASSERT_GL_NO_ERROR();
414 glPathParameterfCHROMIUM(555, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f);
415 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
416
417 ASSERT_GL_NO_ERROR();
418 glPathParameteriCHROMIUM(555, GL_PATH_JOIN_STYLE_CHROMIUM, GL_ROUND_CHROMIUM);
419 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
420}
421
422// Test that setting incorrect path data generates a GL error.
423TEST_P(CHROMIUMPathRenderingTest, TestPathCommandsErrors)
424{
425 if (!isApplicable())
426 return;
427
428 static const GLenum kInvalidCoordType = GL_NONE;
429
430 GLuint path = glGenPathsCHROMIUM(1);
431 GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
432 GLfloat coords[] = {50.0f, 50.0f};
433
434 glPathCommandsCHROMIUM(path, 2, commands, -4, GL_FLOAT, coords);
435 EXPECT_GL_ERROR(GL_INVALID_VALUE);
436
437 glPathCommandsCHROMIUM(path, -1, commands, 2, GL_FLOAT, coords);
438 EXPECT_GL_ERROR(GL_INVALID_VALUE);
439
440 glPathCommandsCHROMIUM(path, 2, commands, 2, kInvalidCoordType, coords);
441 EXPECT_GL_ERROR(GL_INVALID_ENUM);
442
443 // incorrect number of coordinates
444 glPathCommandsCHROMIUM(path, 2, commands, std::numeric_limits<GLsizei>::max(), GL_FLOAT,
445 coords);
446 EXPECT_GL_ERROR(GL_INVALID_VALUE);
447
448 // This should fail due to cmd count + coord count * short size.
449 glPathCommandsCHROMIUM(path, 2, commands, std::numeric_limits<GLsizei>::max(), GL_SHORT,
450 coords);
451 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
452
453 glDeletePathsCHROMIUM(path, 1);
454}
455
456// Test that trying to render a path with invalid arguments
457// generates a GL error.
458TEST_P(CHROMIUMPathRenderingTest, TestPathRenderingInvalidArgs)
459{
460 if (!isApplicable())
461 return;
462
463 GLuint path = glGenPathsCHROMIUM(1);
464 glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL);
465
466 // Verify that normal calls work.
467 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F);
468 ASSERT_GL_NO_ERROR();
469 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, GL_BOUNDING_BOX_CHROMIUM);
470 ASSERT_GL_NO_ERROR();
471
472 // Using invalid fill mode causes INVALID_ENUM.
473 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM - 1, 0x7F);
474 EXPECT_GL_ERROR(GL_INVALID_ENUM);
475 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM - 1, 0x7F,
476 GL_BOUNDING_BOX_CHROMIUM);
477 EXPECT_GL_ERROR(GL_INVALID_ENUM);
478
479 // Using invalid cover mode causes INVALID_ENUM.
480 glCoverFillPathCHROMIUM(path, GL_CONVEX_HULL_CHROMIUM - 1);
481 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError());
482 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F,
483 GL_BOUNDING_BOX_CHROMIUM + 1);
484 EXPECT_GL_ERROR(GL_INVALID_ENUM);
485
486 // For instanced variants, we need this to error the same way
487 // regardless of whether # of paths == 0 would cause an early return.
488
489 // TODO: enable this once instanced path rendering is implemented.
490 // for (int path_count = 0; path_count <= 1; ++path_count)
491 // {
492 // glStencilFillPathInstancedCHROMIUM(path_count, GL_UNSIGNED_INT, &path, 0,
493 // GL_COUNT_UP_CHROMIUM - 1, 0x7F, GL_NONE, NULL);
494 // EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError());
495 // glStencilThenCoverFillPathInstancedCHROMIUM(
496 // path_count, GL_UNSIGNED_INT, &path, 0, GL_COUNT_UP_CHROMIUM - 1, 0x7F,
497 // GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, NULL);
498 // EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError());
499 // }
500
501 // Using mask+1 not being power of two causes INVALID_VALUE with up/down fill mode
502 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x40);
503 EXPECT_GL_ERROR(GL_INVALID_VALUE);
504 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_DOWN_CHROMIUM, 12, GL_BOUNDING_BOX_CHROMIUM);
505 EXPECT_GL_ERROR(GL_INVALID_VALUE);
506
507 // TODO: enable this once instanced path rendering is implemented.
508 // for (int path_count = 0; path_count <= 1; ++path_count)
509 // {
510 // glStencilFillPathInstancedCHROMIUM(path_count, GL_UNSIGNED_INT, &path, 0,
511 // GL_COUNT_UP_CHROMIUM, 0x30, GL_NONE, NULL);
512 // EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError());
513 // glStencilThenCoverFillPathInstancedCHROMIUM(
514 // path_count, GL_UNSIGNED_INT, &path, 0, GL_COUNT_DOWN_CHROMIUM, 0xFE,
515 // GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, NULL);
516 // EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError());
517 // }
518
519 glDeletePathsCHROMIUM(path, 1);
520}
521
522const GLfloat kProjectionMatrix[16] = {2.0f / kResolution,
523 0.0f,
524 0.0f,
525 0.0f,
526 0.0f,
527 2.0f / kResolution,
528 0.0f,
529 0.0f,
530 0.0f,
531 0.0f,
532 -1.0f,
533 0.0f,
534 -1.0f,
535 -1.0f,
536 0.0f,
537 1.0f};
538
539class CHROMIUMPathRenderingDrawTest : public ANGLETest
540{
541 protected:
542 CHROMIUMPathRenderingDrawTest()
543 {
544 setWindowWidth(kResolution);
545 setWindowHeight(kResolution);
546 setConfigRedBits(8);
547 setConfigGreenBits(8);
548 setConfigBlueBits(8);
549 setConfigAlphaBits(8);
550 setConfigDepthBits(8);
551 setConfigStencilBits(8);
552 }
553
554 bool isApplicable() const { return extensionEnabled("GL_CHROMIUM_path_rendering"); }
555
556 void setupStateForTestPattern()
557 {
558 glViewport(0, 0, kResolution, kResolution);
559 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
560 glStencilMask(0xffffffff);
561 glClearStencil(0);
562 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
563 glEnable(GL_STENCIL_TEST);
564
565 static const char *kVertexShaderSource =
566 "void main() {\n"
567 " gl_Position = vec4(1.0); \n"
568 "}";
569
570 static const char *kFragmentShaderSource =
571 "precision mediump float;\n"
572 "uniform vec4 color;\n"
573 "void main() {\n"
574 " gl_FragColor = color;\n"
575 "}";
576
577 GLuint program = CompileProgram(kVertexShaderSource, kFragmentShaderSource);
578 glUseProgram(program);
579 mColorLoc = glGetUniformLocation(program, "color");
580 glDeleteProgram(program);
581
582 // Set up orthogonal projection with near/far plane distance of 2.
583 glMatrixLoadfCHROMIUM(GL_PATH_PROJECTION_CHROMIUM, kProjectionMatrix);
584 glMatrixLoadIdentityCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM);
585
586 ASSERT_GL_NO_ERROR();
587 }
588
589 void setupPathStateForTestPattern(GLuint path)
590 {
591 static const GLubyte kCommands[] = {GL_MOVE_TO_CHROMIUM, GL_LINE_TO_CHROMIUM,
592 GL_QUADRATIC_CURVE_TO_CHROMIUM,
593 GL_CUBIC_CURVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM};
594
595 static const GLfloat kCoords[] = {50.0f, 50.0f, 75.0f, 75.0f, 100.0f, 62.5f, 50.0f,
596 25.5f, 0.0f, 62.5f, 50.0f, 50.0f, 25.0f, 75.0f};
597
598 glPathCommandsCHROMIUM(path, 5, kCommands, 14, GL_FLOAT, kCoords);
599 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f);
600 glPathParameterfCHROMIUM(path, GL_PATH_MITER_LIMIT_CHROMIUM, 1.0f);
601 glPathParameterfCHROMIUM(path, GL_PATH_STROKE_BOUND_CHROMIUM, .02f);
602 glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, GL_ROUND_CHROMIUM);
603 glPathParameteriCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, GL_SQUARE_CHROMIUM);
604 ASSERT_GL_NO_ERROR();
605 }
606
607 void verifyTestPatternFill(float x, float y)
608 {
609 static const float kFillCoords[] = {55.0f, 54.0f, 50.0f, 28.0f, 66.0f, 63.0f};
610 static const angle::GLColor kBlue = {0, 0, 255, 255};
611
612 for (size_t i = 0; i < 6; i += 2)
613 {
614 float fx = kFillCoords[i];
615 float fy = kFillCoords[i + 1];
616 EXPECT_TRUE(CheckPixels(x + fx, y + fy, 1, 1, 0, kBlue));
617 }
618 }
619 void verifyTestPatternBg(float x, float y)
620 {
621 static const float kBackgroundCoords[] = {80.0f, 80.0f, 20.0f, 20.0f, 90.0f, 1.0f};
622 static const angle::GLColor kExpectedColor = {0, 0, 0, 0};
623
624 for (size_t i = 0; i < 6; i += 2)
625 {
626 float bx = kBackgroundCoords[i];
627 float by = kBackgroundCoords[i + 1];
628 EXPECT_TRUE(CheckPixels(x + bx, y + by, 1, 1, 0, kExpectedColor));
629 }
630 }
631
632 void verifyTestPatternStroke(float x, float y)
633 {
634 // Inside the stroke we should have green.
635 static const angle::GLColor kGreen = {0, 255, 0, 255};
636 EXPECT_TRUE(CheckPixels(x + 50, y + 53, 1, 1, 0, kGreen));
637 EXPECT_TRUE(CheckPixels(x + 26, y + 76, 1, 1, 0, kGreen));
638
639 // Outside the path we should have black.
640 static const angle::GLColor black = {0, 0, 0, 0};
641 EXPECT_TRUE(CheckPixels(x + 10, y + 10, 1, 1, 0, black));
642 EXPECT_TRUE(CheckPixels(x + 80, y + 80, 1, 1, 0, black));
643 }
644
645 GLuint mColorLoc;
646};
647
648// Tests that basic path rendering functions work.
649TEST_P(CHROMIUMPathRenderingDrawTest, TestPathRendering)
650{
651 if (!isApplicable())
652 return;
653
654 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
655 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
656
657 setupStateForTestPattern();
658
659 GLuint path = glGenPathsCHROMIUM(1);
660 setupPathStateForTestPattern(path);
661
662 // Do the stencil fill, cover fill, stencil stroke, cover stroke
663 // in unconventional order:
664 // 1) stencil the stroke in stencil high bit
665 // 2) stencil the fill in low bits
666 // 3) cover the fill
667 // 4) cover the stroke
668 // This is done to check that glPathStencilFunc works, eg the mask
669 // goes through. Stencil func is not tested ATM, for simplicity.
670
671 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
672 glStencilStrokePathCHROMIUM(path, 0x80, 0x80);
673
674 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
675 glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F);
676
677 glStencilFunc(GL_LESS, 0, 0x7F);
678 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
679 glUniform4fv(mColorLoc, 1, kBlue);
680 glCoverFillPathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM);
681
682 glStencilFunc(GL_EQUAL, 0x80, 0x80);
683 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
684 glUniform4fv(mColorLoc, 1, kGreen);
685 glCoverStrokePathCHROMIUM(path, GL_CONVEX_HULL_CHROMIUM);
686
687 glDeletePathsCHROMIUM(path, 1);
688
689 ASSERT_GL_NO_ERROR();
690
691 // Verify the image.
692 verifyTestPatternFill(0.0f, 0.0f);
693 verifyTestPatternBg(0.0f, 0.0f);
694 verifyTestPatternStroke(0.0f, 0.0f);
695}
696
697// Test that StencilThen{Stroke,Fill} path rendering functions work
698TEST_P(CHROMIUMPathRenderingDrawTest, TestPathRenderingThenFunctions)
699{
700 if (!isApplicable())
701 return;
702
703 static float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
704 static float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
705
706 setupStateForTestPattern();
707
708 GLuint path = glGenPathsCHROMIUM(1);
709 setupPathStateForTestPattern(path);
710
711 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF);
712 glStencilFunc(GL_EQUAL, 0x80, 0x80);
713 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
714 glUniform4fv(mColorLoc, 1, kGreen);
715 glStencilThenCoverStrokePathCHROMIUM(path, 0x80, 0x80, GL_BOUNDING_BOX_CHROMIUM);
716
717 glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F);
718 glStencilFunc(GL_LESS, 0, 0x7F);
719 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
720 glUniform4fv(mColorLoc, 1, kBlue);
721 glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, GL_CONVEX_HULL_CHROMIUM);
722
723 glDeletePathsCHROMIUM(path, 1);
724
725 // Verify the image.
726 verifyTestPatternFill(0.0f, 0.0f);
727 verifyTestPatternBg(0.0f, 0.0f);
728 verifyTestPatternStroke(0.0f, 0.0f);
729}
730
731} // namespace
732
733ANGLE_INSTANTIATE_TEST(CHROMIUMPathRenderingTest,
734 ES2_OPENGL(),
735 ES2_OPENGLES(),
736 ES3_OPENGL(),
737 ES3_OPENGLES());
738ANGLE_INSTANTIATE_TEST(CHROMIUMPathRenderingDrawTest,
739 ES2_OPENGL(),
740 ES2_OPENGLES(),
741 ES3_OPENGL(),
742 ES3_OPENGLES());