1 //
2 // Copyright 2015 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 // SimpleOperationTest:
7 // Basic GL commands such as linking a program, initializing a buffer, etc.
8
9 #include "test_utils/ANGLETest.h"
10
11 #include <vector>
12
13 #include "test_utils/gl_raii.h"
14 #include "util/EGLWindow.h"
15 #include "util/random_utils.h"
16
17 using namespace angle;
18
19 namespace
20 {
21 constexpr char kBasicVertexShader[] =
22 R"(attribute vec3 position;
23 void main()
24 {
25 gl_Position = vec4(position, 1);
26 })";
27
28 constexpr char kGreenFragmentShader[] =
29 R"(void main()
30 {
31 gl_FragColor = vec4(0, 1, 0, 1);
32 })";
33
34 class SimpleOperationTest : public ANGLETest
35 {
36 protected:
SimpleOperationTest()37 SimpleOperationTest()
38 {
39 setWindowWidth(128);
40 setWindowHeight(128);
41 setConfigRedBits(8);
42 setConfigGreenBits(8);
43 setConfigBlueBits(8);
44 setConfigAlphaBits(8);
45 }
46
47 void verifyBuffer(const std::vector<uint8_t> &data, GLenum binding);
48
49 template <typename T>
50 void testDrawElementsLineLoopUsingClientSideMemory(GLenum indexType,
51 int windowWidth,
52 int windowHeight);
53 };
54
verifyBuffer(const std::vector<uint8_t> & data,GLenum binding)55 void SimpleOperationTest::verifyBuffer(const std::vector<uint8_t> &data, GLenum binding)
56 {
57 if (!IsGLExtensionEnabled("GL_EXT_map_buffer_range"))
58 {
59 return;
60 }
61
62 uint8_t *mapPointer =
63 static_cast<uint8_t *>(glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, 1024, GL_MAP_READ_BIT));
64 ASSERT_GL_NO_ERROR();
65
66 std::vector<uint8_t> readbackData(data.size());
67 memcpy(readbackData.data(), mapPointer, data.size());
68 glUnmapBufferOES(GL_ARRAY_BUFFER);
69
70 EXPECT_EQ(data, readbackData);
71 }
72
73 // Validates if culling rasterization states work. Simply draws a quad with
74 // cull face enabled and make sure we still render correctly.
TEST_P(SimpleOperationTest,CullFaceEnabledState)75 TEST_P(SimpleOperationTest, CullFaceEnabledState)
76 {
77 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
78 glUseProgram(program);
79
80 glClear(GL_COLOR_BUFFER_BIT);
81 glEnable(GL_CULL_FACE);
82
83 drawQuad(program.get(), "position", 0.0f, 1.0f, true);
84
85 ASSERT_GL_NO_ERROR();
86
87 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
88 }
89
90 // Validates if culling rasterization states work. Simply draws a quad with
91 // cull face enabled with cullface front and make sure the face have not been rendered.
TEST_P(SimpleOperationTest,CullFaceFrontEnabledState)92 TEST_P(SimpleOperationTest, CullFaceFrontEnabledState)
93 {
94 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
95 glUseProgram(program);
96
97 glClear(GL_COLOR_BUFFER_BIT);
98 glEnable(GL_CULL_FACE);
99
100 // Should make the quad disappear since we draw it front facing.
101 glCullFace(GL_FRONT);
102
103 drawQuad(program.get(), "position", 0.0f, 1.0f, true);
104
105 ASSERT_GL_NO_ERROR();
106
107 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
108 }
109
110 // Validates if blending render states work. Simply draws twice and verify the color have been
111 // added in the final output.
TEST_P(SimpleOperationTest,BlendingRenderState)112 TEST_P(SimpleOperationTest, BlendingRenderState)
113 {
114 // The precision when blending isn't perfect and some tests fail with a color of 254 instead
115 // of 255 on the green component. This is why we need 0.51 green instead of .5
116 constexpr char halfGreenFragmentShader[] =
117 R"(void main()
118 {
119 gl_FragColor = vec4(0, 0.51, 0, 1);
120 })";
121
122 ANGLE_GL_PROGRAM(program, kBasicVertexShader, halfGreenFragmentShader);
123 glUseProgram(program);
124
125 glClear(GL_COLOR_BUFFER_BIT);
126 glEnable(GL_BLEND);
127 glBlendFunc(GL_ONE, GL_ONE);
128 glBlendEquation(GL_FUNC_ADD);
129
130 auto vertices = GetQuadVertices();
131
132 const GLint positionLocation = glGetAttribLocation(program, "position");
133 ASSERT_NE(-1, positionLocation);
134
135 GLBuffer vertexBuffer;
136 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
137 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
138 GL_STATIC_DRAW);
139 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
140
141 glEnableVertexAttribArray(positionLocation);
142
143 // Drawing a quad once will give 0.51 green, but if we enable blending
144 // with additive function we should end up with full green of 1.0 with
145 // a clamping func of 1.0.
146 glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(vertices.size()));
147 glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(vertices.size()));
148
149 ASSERT_GL_NO_ERROR();
150
151 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
152 }
153
TEST_P(SimpleOperationTest,CompileVertexShader)154 TEST_P(SimpleOperationTest, CompileVertexShader)
155 {
156 GLuint shader = CompileShader(GL_VERTEX_SHADER, kBasicVertexShader);
157 EXPECT_NE(shader, 0u);
158 glDeleteShader(shader);
159
160 ASSERT_GL_NO_ERROR();
161 }
162
TEST_P(SimpleOperationTest,CompileFragmentShaderSingleVaryingInput)163 TEST_P(SimpleOperationTest, CompileFragmentShaderSingleVaryingInput)
164 {
165 constexpr char kFS[] = R"(precision mediump float;
166 varying vec4 v_input;
167 void main()
168 {
169 gl_FragColor = v_input;
170 })";
171
172 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
173 EXPECT_NE(shader, 0u);
174 glDeleteShader(shader);
175
176 ASSERT_GL_NO_ERROR();
177 }
178
179 // Covers a simple bug in Vulkan to do with dependencies between the Surface and the default
180 // Framebuffer.
TEST_P(SimpleOperationTest,ClearAndSwap)181 TEST_P(SimpleOperationTest, ClearAndSwap)
182 {
183 glClearColor(1.0, 0.0, 0.0, 1.0);
184 glClear(GL_COLOR_BUFFER_BIT);
185 swapBuffers();
186
187 // Can't check the pixel result after the swap, and checking the pixel result affects the
188 // behaviour of the test on the Vulkan back-end, so don't bother checking correctness.
189 ASSERT_GL_NO_ERROR();
190 ASSERT_FALSE(getGLWindow()->hasError());
191 }
192
193 // Simple case of setting a scissor, enabled or disabled.
TEST_P(SimpleOperationTest,ScissorTest)194 TEST_P(SimpleOperationTest, ScissorTest)
195 {
196 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
197
198 glClear(GL_COLOR_BUFFER_BIT);
199 glEnable(GL_SCISSOR_TEST);
200 glScissor(getWindowWidth() / 4, getWindowHeight() / 4, getWindowWidth() / 2,
201 getWindowHeight() / 2);
202
203 // Fill the whole screen with a quad.
204 drawQuad(program.get(), "position", 0.0f, 1.0f, true);
205
206 ASSERT_GL_NO_ERROR();
207
208 // Test outside the scissor test, pitch black.
209 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
210
211 // Test inside, green of the fragment shader.
212 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
213 }
214
TEST_P(SimpleOperationTest,LinkProgramShadersNoInputs)215 TEST_P(SimpleOperationTest, LinkProgramShadersNoInputs)
216 {
217 constexpr char kVS[] = "void main() { gl_Position = vec4(1.0, 1.0, 1.0, 1.0); }";
218 constexpr char kFS[] = "void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }";
219
220 ANGLE_GL_PROGRAM(program, kVS, kFS);
221 ASSERT_GL_NO_ERROR();
222 }
223
TEST_P(SimpleOperationTest,LinkProgramWithUniforms)224 TEST_P(SimpleOperationTest, LinkProgramWithUniforms)
225 {
226 constexpr char kVS[] = R"(void main()
227 {
228 gl_Position = vec4(1.0, 1.0, 1.0, 1.0);
229 })";
230 constexpr char kFS[] = R"(precision mediump float;
231 uniform vec4 u_input;
232 void main()
233 {
234 gl_FragColor = u_input;
235 })";
236
237 ANGLE_GL_PROGRAM(program, kVS, kFS);
238
239 const GLint uniformLoc = glGetUniformLocation(program, "u_input");
240 EXPECT_NE(-1, uniformLoc);
241
242 ASSERT_GL_NO_ERROR();
243 }
244
TEST_P(SimpleOperationTest,LinkProgramWithAttributes)245 TEST_P(SimpleOperationTest, LinkProgramWithAttributes)
246 {
247 constexpr char kVS[] = R"(attribute vec4 a_input;
248 void main()
249 {
250 gl_Position = a_input;
251 })";
252
253 ANGLE_GL_PROGRAM(program, kVS, kGreenFragmentShader);
254
255 const GLint attribLoc = glGetAttribLocation(program, "a_input");
256 EXPECT_NE(-1, attribLoc);
257
258 ASSERT_GL_NO_ERROR();
259 }
260
TEST_P(SimpleOperationTest,BufferDataWithData)261 TEST_P(SimpleOperationTest, BufferDataWithData)
262 {
263 GLBuffer buffer;
264 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
265
266 std::vector<uint8_t> data(1024);
267 FillVectorWithRandomUBytes(&data);
268 glBufferData(GL_ARRAY_BUFFER, data.size(), &data[0], GL_STATIC_DRAW);
269
270 verifyBuffer(data, GL_ARRAY_BUFFER);
271
272 ASSERT_GL_NO_ERROR();
273 }
274
TEST_P(SimpleOperationTest,BufferDataWithNoData)275 TEST_P(SimpleOperationTest, BufferDataWithNoData)
276 {
277 GLBuffer buffer;
278 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
279 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
280
281 ASSERT_GL_NO_ERROR();
282 }
283
TEST_P(SimpleOperationTest,BufferSubData)284 TEST_P(SimpleOperationTest, BufferSubData)
285 {
286 GLBuffer buffer;
287 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
288
289 constexpr size_t bufferSize = 1024;
290 std::vector<uint8_t> data(bufferSize);
291 FillVectorWithRandomUBytes(&data);
292
293 glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW);
294
295 constexpr size_t subDataCount = 16;
296 constexpr size_t sliceSize = bufferSize / subDataCount;
297 for (size_t i = 0; i < subDataCount; i++)
298 {
299 size_t offset = i * sliceSize;
300 glBufferSubData(GL_ARRAY_BUFFER, offset, sliceSize, &data[offset]);
301 }
302
303 verifyBuffer(data, GL_ARRAY_BUFFER);
304
305 ASSERT_GL_NO_ERROR();
306 }
307
308 // Simple quad test.
TEST_P(SimpleOperationTest,DrawQuad)309 TEST_P(SimpleOperationTest, DrawQuad)
310 {
311 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
312
313 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
314
315 ASSERT_GL_NO_ERROR();
316
317 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
318 }
319
320 // Simple quad test with data in client memory, not vertex buffer.
TEST_P(SimpleOperationTest,DrawQuadFromClientMemory)321 TEST_P(SimpleOperationTest, DrawQuadFromClientMemory)
322 {
323 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
324
325 drawQuad(program.get(), "position", 0.5f, 1.0f, false);
326
327 ASSERT_GL_NO_ERROR();
328
329 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
330 }
331
332 // Simple double quad test.
TEST_P(SimpleOperationTest,DrawQuadTwice)333 TEST_P(SimpleOperationTest, DrawQuadTwice)
334 {
335 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
336
337 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
338 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
339
340 ASSERT_GL_NO_ERROR();
341
342 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
343 }
344
345 // Simple line test.
TEST_P(SimpleOperationTest,DrawLine)346 TEST_P(SimpleOperationTest, DrawLine)
347 {
348 // We assume in the test the width and height are equal and we are tracing
349 // the line from bottom left to top right. Verify that all pixels along that line
350 // have been traced with green.
351 ASSERT_EQ(getWindowWidth(), getWindowHeight());
352
353 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
354 glUseProgram(program);
355
356 std::vector<Vector3> vertices = {{-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}};
357
358 const GLint positionLocation = glGetAttribLocation(program, "position");
359 ASSERT_NE(-1, positionLocation);
360
361 GLBuffer vertexBuffer;
362 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
363 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
364 GL_STATIC_DRAW);
365 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
366 glEnableVertexAttribArray(positionLocation);
367
368 glClear(GL_COLOR_BUFFER_BIT);
369 glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(vertices.size()));
370
371 glDisableVertexAttribArray(positionLocation);
372
373 ASSERT_GL_NO_ERROR();
374
375 for (int x = 0; x < getWindowWidth(); x++)
376 {
377 EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
378 }
379 }
380
381 // Simple line test that will use a very large offset in the vertex attributes.
TEST_P(SimpleOperationTest,DrawLineWithLargeAttribPointerOffset)382 TEST_P(SimpleOperationTest, DrawLineWithLargeAttribPointerOffset)
383 {
384 // We assume in the test the width and height are equal and we are tracing
385 // the line from bottom left to top right. Verify that all pixels along that line
386 // have been traced with green.
387 ASSERT_EQ(getWindowWidth(), getWindowHeight());
388
389 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
390 glUseProgram(program);
391
392 int kOffset = 3315;
393 std::vector<Vector3> vertices(kOffset);
394 Vector3 vector1{-1.0f, -1.0f, 0.0f};
395 Vector3 vector2{1.0f, 1.0f, 0.0f};
396 vertices.emplace_back(vector1);
397 vertices.emplace_back(vector2);
398
399 const GLint positionLocation = glGetAttribLocation(program, "position");
400 ASSERT_NE(-1, positionLocation);
401
402 GLBuffer vertexBuffer;
403 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
404 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
405 GL_STATIC_DRAW);
406 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0,
407 reinterpret_cast<const void *>(kOffset * sizeof(vertices[0])));
408 glEnableVertexAttribArray(positionLocation);
409
410 glClear(GL_COLOR_BUFFER_BIT);
411 glDrawArrays(GL_LINES, 0, 2);
412
413 glDisableVertexAttribArray(positionLocation);
414
415 ASSERT_GL_NO_ERROR();
416
417 for (auto x = 0; x < getWindowWidth(); x++)
418 {
419 EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
420 }
421 }
422
423 // Simple line strip test.
TEST_P(SimpleOperationTest,DrawLineStrip)424 TEST_P(SimpleOperationTest, DrawLineStrip)
425 {
426 // We assume in the test the width and height are equal and we are tracing
427 // the line from bottom left to center, then from center to bottom right.
428 // Verify that all pixels along these lines have been traced with green.
429 ASSERT_EQ(getWindowWidth(), getWindowHeight());
430
431 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
432 glUseProgram(program);
433
434 auto vertices =
435 std::vector<Vector3>{{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, -1.0f, 0.0f}};
436
437 const GLint positionLocation = glGetAttribLocation(program, "position");
438 ASSERT_NE(-1, positionLocation);
439
440 GLBuffer vertexBuffer;
441 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
442 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
443 GL_STATIC_DRAW);
444 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
445
446 glEnableVertexAttribArray(positionLocation);
447
448 glClear(GL_COLOR_BUFFER_BIT);
449 glDrawArrays(GL_LINE_STRIP, 0, static_cast<GLsizei>(vertices.size()));
450
451 ASSERT_GL_NO_ERROR();
452
453 const auto centerX = getWindowWidth() / 2;
454 const auto centerY = getWindowHeight() / 2;
455
456 for (auto x = 0; x < centerX; x++)
457 {
458 EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
459 }
460
461 for (auto x = centerX, y = centerY - 1; x < getWindowWidth() && y >= 0; x++, y--)
462 {
463 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
464 }
465 }
466
467 // Simple triangle fans test.
TEST_P(SimpleOperationTest,DrawTriangleFan)468 TEST_P(SimpleOperationTest, DrawTriangleFan)
469 {
470 // We assume in the test the width and height are equal and we are tracing
471 // 2 triangles to cover half the surface like this:
472 ASSERT_EQ(getWindowWidth(), getWindowHeight());
473
474 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
475 glUseProgram(program);
476
477 auto vertices = std::vector<Vector3>{
478 {-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}};
479
480 const GLint positionLocation = glGetAttribLocation(program, "position");
481 ASSERT_NE(-1, positionLocation);
482
483 GLBuffer vertexBuffer;
484 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
485 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
486 GL_STATIC_DRAW);
487 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
488 glEnableVertexAttribArray(positionLocation);
489
490 glClear(GL_COLOR_BUFFER_BIT);
491 glDrawArrays(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(vertices.size()));
492
493 glDisableVertexAttribArray(positionLocation);
494
495 EXPECT_GL_NO_ERROR();
496
497 // Check 4 lines accross de triangles to make sure we filled it.
498 // Don't check every pixel as it would slow down our tests.
499 for (auto x = 0; x < getWindowWidth(); x++)
500 {
501 EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
502 }
503
504 for (auto x = getWindowWidth() / 3, y = 0; x < getWindowWidth(); x++, y++)
505 {
506 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
507 }
508
509 for (auto x = getWindowWidth() / 2, y = 0; x < getWindowWidth(); x++, y++)
510 {
511 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
512 }
513
514 for (auto x = (getWindowWidth() / 4) * 3, y = 0; x < getWindowWidth(); x++, y++)
515 {
516 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
517 }
518 }
519
520 // Simple repeated draw and swap test.
TEST_P(SimpleOperationTest,DrawQuadAndSwap)521 TEST_P(SimpleOperationTest, DrawQuadAndSwap)
522 {
523 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
524
525 for (int i = 0; i < 8; ++i)
526 {
527 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
528 ASSERT_GL_NO_ERROR();
529 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
530 swapBuffers();
531 }
532
533 ASSERT_GL_NO_ERROR();
534 }
535
536 // Simple indexed quad test.
TEST_P(SimpleOperationTest,DrawIndexedQuad)537 TEST_P(SimpleOperationTest, DrawIndexedQuad)
538 {
539 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
540
541 drawIndexedQuad(program.get(), "position", 0.5f, 1.0f, true);
542
543 ASSERT_GL_NO_ERROR();
544 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
545 }
546
547 // Simple repeated indexed draw and swap test.
TEST_P(SimpleOperationTest,DrawIndexedQuadAndSwap)548 TEST_P(SimpleOperationTest, DrawIndexedQuadAndSwap)
549 {
550 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
551
552 // 32 iterations is an arbitrary number. The more iterations, the more flaky syncronization
553 // issues will reproduce consistently.
554 for (int i = 0; i < 32; ++i)
555 {
556 drawIndexedQuad(program.get(), "position", 0.5f, 1.0f, true);
557 ASSERT_GL_NO_ERROR();
558 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
559 swapBuffers();
560 }
561
562 ASSERT_GL_NO_ERROR();
563 }
564
565 // Draw with a fragment uniform.
TEST_P(SimpleOperationTest,DrawQuadWithFragmentUniform)566 TEST_P(SimpleOperationTest, DrawQuadWithFragmentUniform)
567 {
568 constexpr char kFS[] =
569 "uniform mediump vec4 color;\n"
570 "void main()\n"
571 "{\n"
572 " gl_FragColor = color;\n"
573 "}";
574 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kFS);
575
576 GLint location = glGetUniformLocation(program, "color");
577 ASSERT_NE(-1, location);
578
579 glUseProgram(program);
580 glUniform4f(location, 0.0f, 1.0f, 0.0f, 1.0f);
581
582 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
583
584 ASSERT_GL_NO_ERROR();
585 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
586 }
587
588 // Draw with a vertex uniform.
TEST_P(SimpleOperationTest,DrawQuadWithVertexUniform)589 TEST_P(SimpleOperationTest, DrawQuadWithVertexUniform)
590 {
591 constexpr char kVS[] =
592 "attribute vec3 position;\n"
593 "uniform vec4 color;\n"
594 "varying vec4 vcolor;\n"
595 "void main()\n"
596 "{\n"
597 " gl_Position = vec4(position, 1);\n"
598 " vcolor = color;\n"
599 "}";
600 constexpr char kFS[] =
601 "varying mediump vec4 vcolor;\n"
602 "void main()\n"
603 "{\n"
604 " gl_FragColor = vcolor;\n"
605 "}";
606 ANGLE_GL_PROGRAM(program, kVS, kFS);
607
608 const GLint location = glGetUniformLocation(program, "color");
609 ASSERT_NE(-1, location);
610
611 glUseProgram(program);
612 glUniform4f(location, 0.0f, 1.0f, 0.0f, 1.0f);
613
614 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
615
616 ASSERT_GL_NO_ERROR();
617 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
618 }
619
620 // Draw with two uniforms.
TEST_P(SimpleOperationTest,DrawQuadWithTwoUniforms)621 TEST_P(SimpleOperationTest, DrawQuadWithTwoUniforms)
622 {
623 constexpr char kVS[] =
624 "attribute vec3 position;\n"
625 "uniform vec4 color1;\n"
626 "varying vec4 vcolor1;\n"
627 "void main()\n"
628 "{\n"
629 " gl_Position = vec4(position, 1);\n"
630 " vcolor1 = color1;\n"
631 "}";
632 constexpr char kFS[] =
633 "uniform mediump vec4 color2;\n"
634 "varying mediump vec4 vcolor1;\n"
635 "void main()\n"
636 "{\n"
637 " gl_FragColor = vcolor1 + color2;\n"
638 "}";
639 ANGLE_GL_PROGRAM(program, kVS, kFS);
640
641 const GLint location1 = glGetUniformLocation(program, "color1");
642 ASSERT_NE(-1, location1);
643
644 const GLint location2 = glGetUniformLocation(program, "color2");
645 ASSERT_NE(-1, location2);
646
647 glUseProgram(program);
648 glUniform4f(location1, 0.0f, 1.0f, 0.0f, 1.0f);
649 glUniform4f(location2, 1.0f, 0.0f, 0.0f, 1.0f);
650
651 drawQuad(program.get(), "position", 0.5f, 1.0f, true);
652
653 ASSERT_GL_NO_ERROR();
654 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
655 }
656
657 // Tests a shader program with more than one vertex attribute, with vertex buffers.
TEST_P(SimpleOperationTest,ThreeVertexAttributes)658 TEST_P(SimpleOperationTest, ThreeVertexAttributes)
659 {
660 constexpr char kVS[] = R"(attribute vec2 position;
661 attribute vec4 color1;
662 attribute vec4 color2;
663 varying vec4 color;
664 void main()
665 {
666 gl_Position = vec4(position, 0, 1);
667 color = color1 + color2;
668 })";
669
670 constexpr char kFS[] = R"(precision mediump float;
671 varying vec4 color;
672 void main()
673 {
674 gl_FragColor = color;
675 }
676 )";
677
678 ANGLE_GL_PROGRAM(program, kVS, kFS);
679
680 glUseProgram(program);
681
682 const GLint color1Loc = glGetAttribLocation(program, "color1");
683 const GLint color2Loc = glGetAttribLocation(program, "color2");
684 ASSERT_NE(-1, color1Loc);
685 ASSERT_NE(-1, color2Loc);
686
687 const auto &indices = GetQuadIndices();
688
689 // Make colored corners with red == x or 1 -x , and green = y or 1 - y.
690
691 std::array<GLColor, 4> baseColors1 = {
692 {GLColor::black, GLColor::red, GLColor::green, GLColor::yellow}};
693 std::array<GLColor, 4> baseColors2 = {
694 {GLColor::yellow, GLColor::green, GLColor::red, GLColor::black}};
695
696 std::vector<GLColor> colors1;
697 std::vector<GLColor> colors2;
698
699 for (GLushort index : indices)
700 {
701 colors1.push_back(baseColors1[index]);
702 colors2.push_back(baseColors2[index]);
703 }
704
705 GLBuffer color1Buffer;
706 glBindBuffer(GL_ARRAY_BUFFER, color1Buffer);
707 glBufferData(GL_ARRAY_BUFFER, colors1.size() * sizeof(GLColor), colors1.data(), GL_STATIC_DRAW);
708 glVertexAttribPointer(color1Loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
709 glEnableVertexAttribArray(color1Loc);
710
711 GLBuffer color2Buffer;
712 glBindBuffer(GL_ARRAY_BUFFER, color2Buffer);
713 glBufferData(GL_ARRAY_BUFFER, colors2.size() * sizeof(GLColor), colors2.data(), GL_STATIC_DRAW);
714 glVertexAttribPointer(color2Loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
715 glEnableVertexAttribArray(color2Loc);
716
717 // Draw a non-indexed quad with all vertex buffers. Should draw yellow to the entire window.
718 drawQuad(program, "position", 0.5f, 1.0f, true);
719 ASSERT_GL_NO_ERROR();
720 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
721 }
722
723 // Creates a 2D texture, no other operations.
TEST_P(SimpleOperationTest,CreateTexture2DNoData)724 TEST_P(SimpleOperationTest, CreateTexture2DNoData)
725 {
726 GLTexture texture;
727 glBindTexture(GL_TEXTURE_2D, texture);
728 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
729 ASSERT_GL_NO_ERROR();
730 }
731
732 // Creates a 2D texture, no other operations.
TEST_P(SimpleOperationTest,CreateTexture2DWithData)733 TEST_P(SimpleOperationTest, CreateTexture2DWithData)
734 {
735 std::vector<GLColor> colors(16 * 16, GLColor::red);
736
737 GLTexture texture;
738 glBindTexture(GL_TEXTURE_2D, texture);
739 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
740 ASSERT_GL_NO_ERROR();
741 }
742
743 // Creates a cube texture, no other operations.
TEST_P(SimpleOperationTest,CreateTextureCubeNoData)744 TEST_P(SimpleOperationTest, CreateTextureCubeNoData)
745 {
746 GLTexture texture;
747 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
748 for (GLenum cubeFace : kCubeFaces)
749 {
750 glTexImage2D(cubeFace, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
751 }
752 ASSERT_GL_NO_ERROR();
753 }
754
755 // Creates a cube texture, no other operations.
TEST_P(SimpleOperationTest,CreateTextureCubeWithData)756 TEST_P(SimpleOperationTest, CreateTextureCubeWithData)
757 {
758 std::vector<GLColor> colors(16 * 16, GLColor::red);
759
760 GLTexture texture;
761 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
762 for (GLenum cubeFace : kCubeFaces)
763 {
764 glTexImage2D(cubeFace, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
765 }
766 ASSERT_GL_NO_ERROR();
767 }
768
769 // Creates a program with a texture.
TEST_P(SimpleOperationTest,LinkProgramWithTexture)770 TEST_P(SimpleOperationTest, LinkProgramWithTexture)
771 {
772 ASSERT_NE(0u, get2DTexturedQuadProgram());
773 ASSERT_GL_NO_ERROR();
774 }
775
776 // Creates a program with a 2D texture and renders with it.
TEST_P(SimpleOperationTest,DrawWith2DTexture)777 TEST_P(SimpleOperationTest, DrawWith2DTexture)
778 {
779 std::array<GLColor, 4> colors = {
780 {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
781
782 GLTexture tex;
783 glBindTexture(GL_TEXTURE_2D, tex);
784 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
785 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
786 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
787
788 draw2DTexturedQuad(0.5f, 1.0f, true);
789 ASSERT_GL_NO_ERROR();
790
791 int w = getWindowWidth() - 2;
792 int h = getWindowHeight() - 2;
793
794 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
795 EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
796 EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
797 EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
798 }
799
800 template <typename T>
testDrawElementsLineLoopUsingClientSideMemory(GLenum indexType,int windowWidth,int windowHeight)801 void SimpleOperationTest::testDrawElementsLineLoopUsingClientSideMemory(GLenum indexType,
802 int windowWidth,
803 int windowHeight)
804 {
805 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
806 glUseProgram(program);
807
808 // We expect to draw a square with these 4 vertices with a drawArray call.
809 std::vector<Vector3> vertices;
810 CreatePixelCenterWindowCoords({{32, 96}, {32, 32}, {96, 32}, {96, 96}}, windowWidth,
811 windowHeight, &vertices);
812
813 // If we use these indices to draw however, we should be drawing an hourglass.
814 std::vector<T> indices{3, 2, 1, 0};
815
816 GLint positionLocation = glGetAttribLocation(program, "position");
817 ASSERT_NE(-1, positionLocation);
818
819 GLBuffer vertexBuffer;
820 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
821 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
822 GL_STATIC_DRAW);
823
824 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
825 glEnableVertexAttribArray(positionLocation);
826 glClear(GL_COLOR_BUFFER_BIT);
827 glDrawElements(GL_LINE_LOOP, 4, indexType, indices.data());
828 glDisableVertexAttribArray(positionLocation);
829
830 ASSERT_GL_NO_ERROR();
831
832 int quarterWidth = windowWidth / 4;
833 int quarterHeight = windowHeight / 4;
834
835 // Bottom left
836 EXPECT_PIXEL_COLOR_EQ(quarterWidth, quarterHeight, GLColor::green);
837
838 // Top left
839 EXPECT_PIXEL_COLOR_EQ(quarterWidth, (quarterHeight * 3), GLColor::green);
840
841 // Top right
842 EXPECT_PIXEL_COLOR_EQ((quarterWidth * 3), (quarterHeight * 3) - 1, GLColor::green);
843
844 // Verify line is closed between the 2 last vertices
845 EXPECT_PIXEL_COLOR_EQ((quarterWidth * 2), quarterHeight, GLColor::green);
846 }
847
848 // Draw a line loop using a drawElement call and client side memory.
TEST_P(SimpleOperationTest,DrawElementsLineLoopUsingUShortClientSideMemory)849 TEST_P(SimpleOperationTest, DrawElementsLineLoopUsingUShortClientSideMemory)
850 {
851 testDrawElementsLineLoopUsingClientSideMemory<GLushort>(GL_UNSIGNED_SHORT, getWindowWidth(),
852 getWindowHeight());
853 }
854
855 // Draw a line loop using a drawElement call and client side memory.
TEST_P(SimpleOperationTest,DrawElementsLineLoopUsingUByteClientSideMemory)856 TEST_P(SimpleOperationTest, DrawElementsLineLoopUsingUByteClientSideMemory)
857 {
858 testDrawElementsLineLoopUsingClientSideMemory<GLubyte>(GL_UNSIGNED_BYTE, getWindowWidth(),
859 getWindowHeight());
860 }
861
862 // Creates a program with a cube texture and renders with it.
TEST_P(SimpleOperationTest,DrawWithCubeTexture)863 TEST_P(SimpleOperationTest, DrawWithCubeTexture)
864 {
865 std::array<Vector2, 6 * 4> positions = {{
866 {0, 1}, {1, 1}, {1, 2}, {0, 2} /* first face */,
867 {1, 0}, {2, 0}, {2, 1}, {1, 1} /* second face */,
868 {1, 1}, {2, 1}, {2, 2}, {1, 2} /* third face */,
869 {1, 2}, {2, 2}, {2, 3}, {1, 3} /* fourth face */,
870 {2, 1}, {3, 1}, {3, 2}, {2, 2} /* fifth face */,
871 {3, 1}, {4, 1}, {4, 2}, {3, 2} /* sixth face */,
872 }};
873
874 const float w4 = 1.0f / 4.0f;
875 const float h3 = 1.0f / 3.0f;
876
877 // This draws a "T" shape based on the four faces of the cube. The window is divided into four
878 // tiles horizontally and three tiles vertically (hence the w4 and h3 variable naming).
879 for (Vector2 &pos : positions)
880 {
881 pos.data()[0] = pos.data()[0] * w4 * 2.0f - 1.0f;
882 pos.data()[1] = pos.data()[1] * h3 * 2.0f - 1.0f;
883 }
884
885 const Vector3 posX(1, 0, 0);
886 const Vector3 negX(-1, 0, 0);
887 const Vector3 posY(0, 1, 0);
888 const Vector3 negY(0, -1, 0);
889 const Vector3 posZ(0, 0, 1);
890 const Vector3 negZ(0, 0, -1);
891
892 std::array<Vector3, 6 * 4> coords = {{
893 posX, posX, posX, posX /* first face */, negX, negX, negX, negX /* second face */,
894 posY, posY, posY, posY /* third face */, negY, negY, negY, negY /* fourth face */,
895 posZ, posZ, posZ, posZ /* fifth face */, negZ, negZ, negZ, negZ /* sixth face */,
896 }};
897
898 const std::array<std::array<GLColor, 4>, 6> colors = {{
899 {GLColor::red, GLColor::red, GLColor::red, GLColor::red},
900 {GLColor::green, GLColor::green, GLColor::green, GLColor::green},
901 {GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue},
902 {GLColor::yellow, GLColor::yellow, GLColor::yellow, GLColor::yellow},
903 {GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan},
904 {GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta},
905 }};
906
907 GLTexture texture;
908 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
909
910 for (size_t faceIndex = 0; faceIndex < kCubeFaces.size(); ++faceIndex)
911 {
912 glTexImage2D(kCubeFaces[faceIndex], 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
913 colors[faceIndex].data());
914 }
915 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
916 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
917
918 constexpr char kVertexShader[] = R"(attribute vec2 pos;
919 attribute vec3 coord;
920 varying vec3 texCoord;
921 void main()
922 {
923 gl_Position = vec4(pos, 0, 1);
924 texCoord = coord;
925 })";
926
927 constexpr char kFragmentShader[] = R"(precision mediump float;
928 varying vec3 texCoord;
929 uniform samplerCube tex;
930 void main()
931 {
932 gl_FragColor = textureCube(tex, texCoord);
933 })";
934
935 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
936 GLint samplerLoc = glGetUniformLocation(program, "tex");
937 ASSERT_EQ(samplerLoc, 0);
938
939 glUseProgram(program);
940
941 GLint posLoc = glGetAttribLocation(program, "pos");
942 ASSERT_NE(-1, posLoc);
943
944 GLint coordLoc = glGetAttribLocation(program, "coord");
945 ASSERT_NE(-1, coordLoc);
946
947 GLBuffer posBuffer;
948 glBindBuffer(GL_ARRAY_BUFFER, posBuffer);
949 glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(Vector2), positions.data(),
950 GL_STATIC_DRAW);
951 glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
952 glEnableVertexAttribArray(posLoc);
953
954 GLBuffer coordBuffer;
955 glBindBuffer(GL_ARRAY_BUFFER, coordBuffer);
956 glBufferData(GL_ARRAY_BUFFER, coords.size() * sizeof(Vector3), coords.data(), GL_STATIC_DRAW);
957 glVertexAttribPointer(coordLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
958 glEnableVertexAttribArray(coordLoc);
959
960 auto quadIndices = GetQuadIndices();
961 std::array<GLushort, 6 * 6> kElementsData;
962 for (GLushort quadIndex = 0; quadIndex < 6; ++quadIndex)
963 {
964 for (GLushort elementIndex = 0; elementIndex < 6; ++elementIndex)
965 {
966 kElementsData[quadIndex * 6 + elementIndex] = quadIndices[elementIndex] + 4 * quadIndex;
967 }
968 }
969
970 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
971 glClear(GL_COLOR_BUFFER_BIT);
972
973 GLBuffer elementBuffer;
974 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
975 glBufferData(GL_ELEMENT_ARRAY_BUFFER, kElementsData.size() * sizeof(GLushort),
976 kElementsData.data(), GL_STATIC_DRAW);
977 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(kElementsData.size()), GL_UNSIGNED_SHORT,
978 nullptr);
979 ASSERT_GL_NO_ERROR();
980
981 for (int faceIndex = 0; faceIndex < 6; ++faceIndex)
982 {
983 int index = faceIndex * 4;
984 Vector2 center = (positions[index] + positions[index + 1] + positions[index + 2] +
985 positions[index + 3]) /
986 4.0f;
987 center *= 0.5f;
988 center += Vector2(0.5f);
989 center *= Vector2(getWindowWidth(), getWindowHeight());
990 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(center.x()), static_cast<GLint>(center.y()),
991 colors[faceIndex][0]);
992 }
993 }
994
995 // Tests rendering to a user framebuffer.
TEST_P(SimpleOperationTest,RenderToTexture)996 TEST_P(SimpleOperationTest, RenderToTexture)
997 {
998 constexpr int kSize = 16;
999
1000 GLTexture texture;
1001 glBindTexture(GL_TEXTURE_2D, texture);
1002 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1003 ASSERT_GL_NO_ERROR();
1004
1005 GLFramebuffer framebuffer;
1006 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1007 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1008 ASSERT_GL_NO_ERROR();
1009 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1010
1011 glViewport(0, 0, kSize, kSize);
1012
1013 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
1014 drawQuad(program, "position", 0.5f, 1.0f, true);
1015 ASSERT_GL_NO_ERROR();
1016 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1017 }
1018
1019 // Create a simple basic Renderbuffer.
TEST_P(SimpleOperationTest,CreateRenderbuffer)1020 TEST_P(SimpleOperationTest, CreateRenderbuffer)
1021 {
1022 GLRenderbuffer renderbuffer;
1023 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1024 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
1025 ASSERT_GL_NO_ERROR();
1026 }
1027
1028 // Render to a simple color Renderbuffer.
TEST_P(SimpleOperationTest,RenderbufferAttachment)1029 TEST_P(SimpleOperationTest, RenderbufferAttachment)
1030 {
1031 constexpr int kSize = 16;
1032
1033 GLRenderbuffer renderbuffer;
1034 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1035 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize);
1036
1037 GLFramebuffer framebuffer;
1038 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1039 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
1040 ASSERT_GL_NO_ERROR();
1041 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1042
1043 glViewport(0, 0, kSize, kSize);
1044
1045 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
1046 drawQuad(program, "position", 0.5f, 1.0f, true);
1047 ASSERT_GL_NO_ERROR();
1048 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1049 }
1050
1051 // Tests that using desktop GL_QUADS/GL_POLYGONS enums generate the correct error.
TEST_P(SimpleOperationTest,PrimitiveModeNegativeTest)1052 TEST_P(SimpleOperationTest, PrimitiveModeNegativeTest)
1053 {
1054 // Draw a correct quad.
1055 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
1056 glUseProgram(program);
1057
1058 GLint positionLocation = glGetAttribLocation(program, "position");
1059 ASSERT_NE(-1, positionLocation);
1060
1061 setupQuadVertexBuffer(0.5f, 1.0f);
1062 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1063 glEnableVertexAttribArray(positionLocation);
1064
1065 // Tests that TRIANGLES works.
1066 glDrawArrays(GL_TRIANGLES, 0, 6);
1067 ASSERT_GL_NO_ERROR();
1068 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1069
1070 // Tests that specific invalid enums don't work.
1071 glDrawArrays(static_cast<GLenum>(7), 0, 6);
1072 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1073
1074 glDrawArrays(static_cast<GLenum>(8), 0, 6);
1075 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1076
1077 glDrawArrays(static_cast<GLenum>(9), 0, 6);
1078 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1079 }
1080
1081 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
1082 // tests should be run against.
1083 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SimpleOperationTest);
1084
1085 } // namespace
1086