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