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 
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9 
10 using namespace angle;
11 
12 namespace
13 {
14 enum Geometry
15 {
16     Quad,
17     Point,
18     TriFan,
19 };
20 enum Storage
21 {
22     Buffer,
23     Memory
24 };
25 enum Draw
26 {
27     Indexed,
28     NonIndexed
29 };
30 enum Vendor
31 {
32     Angle,
33     Ext
34 };
35 }  // namespace
36 
37 class InstancingTest : public ANGLETest
38 {
39   protected:
InstancingTest()40     InstancingTest()
41     {
42         setWindowWidth(256);
43         setWindowHeight(256);
44         setConfigRedBits(8);
45         setConfigGreenBits(8);
46         setConfigBlueBits(8);
47         setConfigAlphaBits(8);
48     }
49 
testTearDown()50     void testTearDown() override
51     {
52         glDeleteBuffers(1, &mInstanceBuffer);
53         glDeleteProgram(mProgram[0]);
54         glDeleteProgram(mProgram[1]);
55     }
56 
testSetUp()57     void testSetUp() override
58     {
59         for (unsigned i = 0; i < kMaxDrawn; ++i)
60         {
61             mInstanceData[i] = i * kDrawSize;
62         }
63         glGenBuffers(1, &mInstanceBuffer);
64         glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
65         glBufferData(GL_ARRAY_BUFFER, sizeof(mInstanceData), mInstanceData, GL_STATIC_DRAW);
66         glBindBuffer(GL_ARRAY_BUFFER, 0);
67 
68         const std::string inst = "attribute float a_instance;";
69         const std::string pos  = "attribute vec2 a_position;";
70         const std::string main = R"(
71             void main()
72             {
73                 gl_PointSize = 6.0;
74                 gl_Position = vec4(a_position.x, a_position.y + a_instance, 0, 1);
75             }
76         )";
77 
78         // attrib 0 is instanced
79         const std::string inst0 = inst + pos + main;
80         mProgram[0]             = CompileProgram(inst0.c_str(), essl1_shaders::fs::Red());
81         ASSERT_NE(0u, mProgram[0]);
82         ASSERT_EQ(0, glGetAttribLocation(mProgram[0], "a_instance"));
83         ASSERT_EQ(1, glGetAttribLocation(mProgram[0], "a_position"));
84 
85         // attrib 1 is instanced
86         const std::string inst1 = pos + inst + main;
87         mProgram[1]             = CompileProgram(inst1.c_str(), essl1_shaders::fs::Red());
88         ASSERT_NE(0u, mProgram[1]);
89         ASSERT_EQ(1, glGetAttribLocation(mProgram[1], "a_instance"));
90         ASSERT_EQ(0, glGetAttribLocation(mProgram[1], "a_position"));
91 
92         glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
93     }
94 
runTest(unsigned numInstance,unsigned divisor,const int instanceAttrib,Geometry geometry,Draw draw,Storage storage,Vendor vendor,unsigned offset)95     void runTest(unsigned numInstance,
96                  unsigned divisor,
97                  const int instanceAttrib,  // which attrib is instanced: 0 or 1
98                  Geometry geometry,
99                  Draw draw,
100                  Storage storage,
101                  Vendor vendor,
102                  unsigned offset)  // for NonIndexed/DrawArrays only
103     {
104         if (vendor == Angle)
105         {
106             ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
107         }
108         else if (vendor == Ext)
109         {
110             ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_instanced_arrays"));
111         }
112 
113         // TODO: Fix these.  http://anglebug.com/3129
114         ANGLE_SKIP_TEST_IF(IsD3D9() && draw == Indexed && geometry == Point);
115         ANGLE_SKIP_TEST_IF(IsD3D9() && IsAMD());
116 
117         // D3D11 FL9_3 has a special codepath that emulates instanced points rendering
118         // but it has bugs and was only implemented for vertex positions in a buffer object,
119         // not client memory as used in this test.
120         ANGLE_SKIP_TEST_IF(IsD3D11_FL93() && geometry == Point);
121 
122         // Unknown problem.  FL9_3 is not officially supported anyway.
123         ANGLE_SKIP_TEST_IF(IsD3D11_FL93() && geometry == Quad && draw == NonIndexed);
124 
125         // The window is divided into kMaxDrawn slices of size kDrawSize.
126         // The slice drawn into is determined by the instance datum.
127         // The instance data array selects all the slices in order.
128         // 'lastDrawn' is the index (zero-based) of the last slice into which we draw.
129         const unsigned lastDrawn = (numInstance - 1) / divisor;
130 
131         // Ensure the numInstance and divisor parameters are valid.
132         ASSERT_TRUE(lastDrawn < kMaxDrawn);
133 
134         ASSERT_TRUE(instanceAttrib == 0 || instanceAttrib == 1);
135         const int positionAttrib = 1 - instanceAttrib;
136 
137         glUseProgram(mProgram[instanceAttrib]);
138 
139         glBindBuffer(GL_ARRAY_BUFFER, storage == Buffer ? mInstanceBuffer : 0);
140         glVertexAttribPointer(instanceAttrib, 1, GL_FLOAT, GL_FALSE, 0,
141                               storage == Buffer ? nullptr : mInstanceData);
142         glEnableVertexAttribArray(instanceAttrib);
143         if (vendor == Angle)
144             glVertexAttribDivisorANGLE(instanceAttrib, divisor);
145         else if (vendor == Ext)
146             glVertexAttribDivisorEXT(instanceAttrib, divisor);
147 
148         glBindBuffer(GL_ARRAY_BUFFER, 0);
149         const void *vertices;
150         switch (geometry)
151         {
152             case Point:
153                 vertices = kPointVertices;
154                 break;
155             case Quad:
156                 vertices = kQuadVertices;
157                 break;
158             case TriFan:
159                 vertices = kTriFanVertices;
160                 break;
161         }
162         glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 0, vertices);
163         glEnableVertexAttribArray(positionAttrib);
164         if (vendor == Angle)
165             glVertexAttribDivisorANGLE(positionAttrib, 0);
166         else if (vendor == Ext)
167             glVertexAttribDivisorEXT(positionAttrib, 0);
168 
169         glClear(GL_COLOR_BUFFER_BIT);
170 
171         if (geometry == Point)
172         {
173             if (draw == Indexed)
174                 if (vendor == Angle)
175                     glDrawElementsInstancedANGLE(GL_POINTS, ArraySize(kPointIndices),
176                                                  GL_UNSIGNED_SHORT, kPointIndices, numInstance);
177                 else
178                     glDrawElementsInstancedEXT(GL_POINTS, ArraySize(kPointIndices),
179                                                GL_UNSIGNED_SHORT, kPointIndices, numInstance);
180             else if (vendor == Angle)
181                 glDrawArraysInstancedANGLE(GL_POINTS, offset, 4 /*vertices*/, numInstance);
182             else
183                 glDrawArraysInstancedEXT(GL_POINTS, offset, 4 /*vertices*/, numInstance);
184         }
185         else if (geometry == Quad)
186         {
187             if (draw == Indexed)
188                 if (vendor == Angle)
189                     glDrawElementsInstancedANGLE(GL_TRIANGLES, ArraySize(kQuadIndices),
190                                                  GL_UNSIGNED_SHORT, kQuadIndices, numInstance);
191                 else
192                     glDrawElementsInstancedEXT(GL_TRIANGLES, ArraySize(kQuadIndices),
193                                                GL_UNSIGNED_SHORT, kQuadIndices, numInstance);
194             else if (vendor == Angle)
195                 glDrawArraysInstancedANGLE(GL_TRIANGLES, offset, 6 /*vertices*/, numInstance);
196             else
197                 glDrawArraysInstancedEXT(GL_TRIANGLES, offset, 6 /*vertices*/, numInstance);
198         }
199         else if (geometry == TriFan)
200         {
201             if (draw == Indexed)
202             {
203                 if (storage == Buffer)
204                 {
205                     GLBuffer indexBuffer;
206                     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
207                     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kTriFanIndices), kTriFanIndices,
208                                  GL_STATIC_DRAW);
209 
210                     if (vendor == Angle)
211                         glDrawElementsInstancedANGLE(GL_TRIANGLE_FAN, ArraySize(kTriFanIndices),
212                                                      GL_UNSIGNED_BYTE, 0, numInstance);
213                     else
214                         glDrawElementsInstancedEXT(GL_TRIANGLE_FAN, ArraySize(kTriFanIndices),
215                                                    GL_UNSIGNED_BYTE, 0, numInstance);
216                 }
217                 else
218                 {
219                     if (vendor == Angle)
220                         glDrawElementsInstancedANGLE(GL_TRIANGLE_FAN, ArraySize(kTriFanIndices),
221                                                      GL_UNSIGNED_BYTE, kTriFanIndices, numInstance);
222                     else
223                         glDrawElementsInstancedEXT(GL_TRIANGLE_FAN, ArraySize(kTriFanIndices),
224                                                    GL_UNSIGNED_BYTE, kTriFanIndices, numInstance);
225                 }
226             }
227             else if (vendor == Angle)
228                 glDrawArraysInstancedANGLE(GL_TRIANGLE_FAN, offset, 8 /*vertices*/, numInstance);
229             else
230                 glDrawArraysInstancedEXT(GL_TRIANGLE_FAN, offset, 8 /*vertices*/, numInstance);
231         }
232 
233         ASSERT_GL_NO_ERROR();
234         checkDrawing(lastDrawn);
235     }
236 
checkDrawing(unsigned lastDrawn)237     void checkDrawing(unsigned lastDrawn)
238     {
239         for (unsigned i = 0; i < kMaxDrawn; ++i)
240         {
241             float y =
242                 -1.0f + static_cast<float>(kDrawSize) / 2.0f + static_cast<float>(i * kDrawSize);
243             int iy = static_cast<int>((y + 1.0f) / 2.0f * getWindowHeight());
244             for (unsigned j = 0; j < 8; j += 2)
245             {
246                 int ix = static_cast<int>((kPointVertices[j] + 1.0f) / 2.0f * getWindowWidth());
247                 EXPECT_PIXEL_COLOR_EQ(ix, iy, i <= lastDrawn ? GLColor::red : GLColor::blue)
248                     << std::endl;
249             }
250         }
251     }
252 
253     GLuint mProgram[2];
254     GLuint mInstanceBuffer;
255 
256     static constexpr unsigned kMaxDrawn = 16;
257     static constexpr float kDrawSize    = 2.0 / kMaxDrawn;
258     GLfloat mInstanceData[kMaxDrawn];
259 
260     // clang-format off
261 
262     // Vertices 0-5 are two triangles that form a quad filling the first "slice" of the window.
263     // See above about slices.  Vertices 4-9 are the same two triangles.
264     static constexpr GLfloat kQuadVertices[] = {
265         -1, -1,
266          1, -1,
267         -1, -1 + kDrawSize,
268          1, -1,
269          1, -1 + kDrawSize,
270         -1, -1 + kDrawSize,
271          1, -1,
272          1, -1,
273         -1, -1 + kDrawSize,
274         -1, -1,
275     };
276 
277     // Vertices 0-7 form a quad (triangle fan) filling the first "slice" of the window.
278     // Vertices 8-15 are the same.
279     static constexpr GLfloat kTriFanVertices[] = {
280         -1, -1,
281          1, -1,
282         1, -1 + 0.5f * kDrawSize,
283         1, -1 + kDrawSize,
284         0.5f, -1 + kDrawSize,
285         0, -1 + kDrawSize,
286         -0.5f, -1 + kDrawSize,
287         -1, -1 + kDrawSize,
288 
289         -1, -1,
290          1, -1,
291         1, -1 + 0.5f * kDrawSize,
292         1, -1 + kDrawSize,
293         0.5f, -1 + kDrawSize,
294         0, -1 + kDrawSize,
295         -0.5f, -1 + kDrawSize,
296         -1, -1 + kDrawSize,
297     };
298 
299     // Points 0-3 are spread across the first "slice."
300     // Points 2-4 are the same.
301     static constexpr GLfloat kPointVertices[] = {
302         -0.6f, -1 + kDrawSize / 2.0,
303         -0.2f, -1 + kDrawSize / 2.0,
304          0.2f, -1 + kDrawSize / 2.0,
305          0.6f, -1 + kDrawSize / 2.0,
306         -0.2f, -1 + kDrawSize / 2.0,
307         -0.6f, -1 + kDrawSize / 2.0,
308     };
309     // clang-format on
310 
311     // Same two triangles as described above.
312     static constexpr GLushort kQuadIndices[] = {2, 9, 7, 5, 6, 4};
313 
314     // Same triangle fan as described above.
315     static constexpr GLubyte kTriFanIndices[] = {0, 9, 10, 3, 4, 5, 14, 7};
316 
317     // Same four points as described above.
318     static constexpr GLushort kPointIndices[] = {1, 5, 3, 2};
319 };
320 
321 constexpr unsigned InstancingTest::kMaxDrawn;
322 constexpr float InstancingTest::kDrawSize;
323 constexpr GLfloat InstancingTest::kQuadVertices[];
324 constexpr GLfloat InstancingTest::kTriFanVertices[];
325 constexpr GLfloat InstancingTest::kPointVertices[];
326 constexpr GLushort InstancingTest::kQuadIndices[];
327 constexpr GLubyte InstancingTest::kTriFanIndices[];
328 constexpr GLushort InstancingTest::kPointIndices[];
329 
330 #define TEST_INDEXED(attrib, geometry, storage, vendor)                      \
331     TEST_P(InstancingTest, IndexedAttrib##attrib##geometry##storage##vendor) \
332     {                                                                        \
333         runTest(11, 2, attrib, geometry, Indexed, storage, vendor, 0);       \
334     }
335 
336 #define TEST_NONINDEXED(attrib, geometry, storage, vendor, offset)                              \
337     TEST_P(InstancingTest, NonIndexedAttrib##attrib##geometry##storage##vendor##Offset##offset) \
338     {                                                                                           \
339         runTest(11, 2, attrib, geometry, NonIndexed, storage, vendor, offset);                  \
340     }
341 
342 #define TEST_DIVISOR(numInstance, divisor)                                    \
343     TEST_P(InstancingTest, Instances##numInstance##Divisor##divisor)          \
344     {                                                                         \
345         runTest(numInstance, divisor, 1, Quad, NonIndexed, Buffer, Angle, 0); \
346     }
347 
348 // D3D9 and D3D11 FL9_3, have a special codepath that rearranges the input layout sent to D3D,
349 // to ensure that slot/stream zero of the input layout doesn't contain per-instance data, so
350 // we test with attribute 0 being instanced, as will as attribute 1 being instanced.
351 //
352 // Tests with a non-zero 'offset' check that "first" parameter to glDrawArraysInstancedANGLE is only
353 // an offset into the non-instanced vertex attributes.
354 TEST_INDEXED(0, TriFan, Buffer, Angle)
355 TEST_INDEXED(0, TriFan, Memory, Angle)
356 TEST_INDEXED(1, TriFan, Buffer, Angle)
357 TEST_INDEXED(1, TriFan, Memory, Angle)
358 TEST_INDEXED(0, TriFan, Buffer, Ext)
359 TEST_INDEXED(0, TriFan, Memory, Ext)
360 TEST_INDEXED(1, TriFan, Buffer, Ext)
361 TEST_INDEXED(1, TriFan, Memory, Ext)
362 TEST_INDEXED(0, Quad, Buffer, Angle)
363 TEST_INDEXED(0, Quad, Memory, Angle)
364 TEST_INDEXED(1, Quad, Buffer, Angle)
365 TEST_INDEXED(1, Quad, Memory, Angle)
366 TEST_INDEXED(0, Point, Buffer, Angle)
367 TEST_INDEXED(0, Point, Memory, Angle)
368 TEST_INDEXED(1, Point, Buffer, Angle)
369 TEST_INDEXED(1, Point, Memory, Angle)
370 TEST_INDEXED(0, Quad, Buffer, Ext)
371 TEST_INDEXED(0, Quad, Memory, Ext)
372 TEST_INDEXED(1, Quad, Buffer, Ext)
373 TEST_INDEXED(1, Quad, Memory, Ext)
374 TEST_INDEXED(0, Point, Buffer, Ext)
375 TEST_INDEXED(0, Point, Memory, Ext)
376 TEST_INDEXED(1, Point, Buffer, Ext)
377 TEST_INDEXED(1, Point, Memory, Ext)
378 
379 // offset should be 0 or 4 for quads, 0 or 8 for triangle fan
380 TEST_NONINDEXED(0, TriFan, Buffer, Angle, 0)
381 TEST_NONINDEXED(0, TriFan, Buffer, Angle, 8)
382 TEST_NONINDEXED(0, TriFan, Memory, Angle, 0)
383 TEST_NONINDEXED(0, TriFan, Memory, Angle, 8)
384 TEST_NONINDEXED(1, TriFan, Buffer, Angle, 0)
385 TEST_NONINDEXED(1, TriFan, Buffer, Angle, 8)
386 TEST_NONINDEXED(1, TriFan, Memory, Angle, 0)
387 TEST_NONINDEXED(1, TriFan, Memory, Angle, 8)
388 TEST_NONINDEXED(0, TriFan, Buffer, Ext, 0)
389 TEST_NONINDEXED(0, TriFan, Buffer, Ext, 8)
390 TEST_NONINDEXED(0, TriFan, Memory, Ext, 0)
391 TEST_NONINDEXED(0, TriFan, Memory, Ext, 8)
392 TEST_NONINDEXED(1, TriFan, Buffer, Ext, 0)
393 TEST_NONINDEXED(1, TriFan, Buffer, Ext, 8)
394 TEST_NONINDEXED(1, TriFan, Memory, Ext, 0)
395 TEST_NONINDEXED(1, TriFan, Memory, Ext, 8)
396 TEST_NONINDEXED(0, Quad, Buffer, Angle, 0)
397 TEST_NONINDEXED(0, Quad, Buffer, Angle, 4)
398 TEST_NONINDEXED(0, Quad, Memory, Angle, 0)
399 TEST_NONINDEXED(0, Quad, Memory, Angle, 4)
400 TEST_NONINDEXED(1, Quad, Buffer, Angle, 0)
401 TEST_NONINDEXED(1, Quad, Buffer, Angle, 4)
402 TEST_NONINDEXED(1, Quad, Memory, Angle, 0)
403 TEST_NONINDEXED(1, Quad, Memory, Angle, 4)
404 TEST_NONINDEXED(0, Quad, Buffer, Ext, 0)
405 TEST_NONINDEXED(0, Quad, Buffer, Ext, 4)
406 TEST_NONINDEXED(0, Quad, Memory, Ext, 0)
407 TEST_NONINDEXED(0, Quad, Memory, Ext, 4)
408 TEST_NONINDEXED(1, Quad, Buffer, Ext, 0)
409 TEST_NONINDEXED(1, Quad, Buffer, Ext, 4)
410 TEST_NONINDEXED(1, Quad, Memory, Ext, 0)
411 TEST_NONINDEXED(1, Quad, Memory, Ext, 4)
412 
413 // offset should be 0 or 2 for points
414 TEST_NONINDEXED(0, Point, Buffer, Angle, 0)
415 TEST_NONINDEXED(0, Point, Buffer, Angle, 2)
416 TEST_NONINDEXED(0, Point, Memory, Angle, 0)
417 TEST_NONINDEXED(0, Point, Memory, Angle, 2)
418 TEST_NONINDEXED(1, Point, Buffer, Angle, 0)
419 TEST_NONINDEXED(1, Point, Buffer, Angle, 2)
420 TEST_NONINDEXED(1, Point, Memory, Angle, 0)
421 TEST_NONINDEXED(1, Point, Memory, Angle, 2)
422 TEST_NONINDEXED(0, Point, Buffer, Ext, 0)
423 TEST_NONINDEXED(0, Point, Buffer, Ext, 2)
424 TEST_NONINDEXED(0, Point, Memory, Ext, 0)
425 TEST_NONINDEXED(0, Point, Memory, Ext, 2)
426 TEST_NONINDEXED(1, Point, Buffer, Ext, 0)
427 TEST_NONINDEXED(1, Point, Buffer, Ext, 2)
428 TEST_NONINDEXED(1, Point, Memory, Ext, 0)
429 TEST_NONINDEXED(1, Point, Memory, Ext, 2)
430 
431 // The following tests produce each value of 'lastDrawn' in runTest() from 1 to kMaxDrawn, a few
432 // different ways.
433 TEST_DIVISOR(1, 1)
434 TEST_DIVISOR(1, 2)
435 TEST_DIVISOR(2, 1)
436 TEST_DIVISOR(3, 1)
437 TEST_DIVISOR(3, 2)
438 TEST_DIVISOR(4, 1)
439 TEST_DIVISOR(5, 1)
440 TEST_DIVISOR(5, 2)
441 TEST_DIVISOR(6, 1)
442 TEST_DIVISOR(6, 2)
443 TEST_DIVISOR(7, 1)
444 TEST_DIVISOR(7, 2)
445 TEST_DIVISOR(8, 1)
446 TEST_DIVISOR(8, 2)
447 TEST_DIVISOR(8, 4)
448 TEST_DIVISOR(9, 1)
449 TEST_DIVISOR(9, 2)
450 TEST_DIVISOR(10, 1)
451 TEST_DIVISOR(11, 1)
452 TEST_DIVISOR(11, 2)
453 TEST_DIVISOR(12, 1)
454 TEST_DIVISOR(12, 11)
455 TEST_DIVISOR(13, 1)
456 TEST_DIVISOR(13, 2)
457 TEST_DIVISOR(14, 1)
458 TEST_DIVISOR(15, 1)
459 TEST_DIVISOR(15, 2)
460 TEST_DIVISOR(16, 1)
461 TEST_DIVISOR(16, 3)
462 TEST_DIVISOR(16, 7)
463 TEST_DIVISOR(17, 2)
464 TEST_DIVISOR(20, 2)
465 TEST_DIVISOR(21, 2)
466 TEST_DIVISOR(23, 2)
467 TEST_DIVISOR(25, 5)
468 TEST_DIVISOR(25, 33)
469 TEST_DIVISOR(26, 2)
470 TEST_DIVISOR(26, 3)
471 TEST_DIVISOR(27, 2)
472 TEST_DIVISOR(27, 4)
473 TEST_DIVISOR(28, 3)
474 TEST_DIVISOR(29, 2)
475 TEST_DIVISOR(29, 11)
476 TEST_DIVISOR(30, 4)
477 TEST_DIVISOR(31, 6)
478 TEST_DIVISOR(32, 2)
479 TEST_DIVISOR(32, 3)
480 TEST_DIVISOR(32, 8)
481 TEST_DIVISOR(34, 3)
482 TEST_DIVISOR(34, 30)
483 
484 // Test line loop instanced draw
TEST_P(InstancingTest,LineLoop)485 TEST_P(InstancingTest, LineLoop)
486 {
487     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
488 
489     constexpr char kVS[] = R"(
490 attribute vec2 a_position;
491 // x,y = offset, z = scale
492 attribute vec3 a_transform;
493 
494 attribute vec4 a_color;
495 
496 varying vec4 v_color;
497 
498 invariant gl_Position;
499 void main()
500 {
501     vec2 v_position = a_transform.z * a_position + a_transform.xy;
502     gl_Position = vec4(v_position, 0.0, 1.0);
503 
504     v_color = a_color;
505 })";
506 
507     constexpr char kFS[] = R"(
508 precision highp float;
509 varying vec4 v_color;
510 void main()
511 {
512     gl_FragColor = v_color;
513 })";
514 
515     ANGLE_GL_PROGRAM(program, kVS, kFS);
516     glBindAttribLocation(program, 0, "a_position");
517     glBindAttribLocation(program, 1, "a_transform");
518     glBindAttribLocation(program, 2, "a_color");
519     glLinkProgram(program);
520     glUseProgram(program);
521     ASSERT_GL_NO_ERROR();
522 
523     constexpr GLfloat vertices[] = {
524         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
525     };
526 
527     constexpr GLfloat transform[] = {
528         0, 0, 9, 0.2, 0.1, 2, 0.5, -0.2, 3, -0.8, -0.5, 1, -0.4, 0.4, 6,
529     };
530 
531     constexpr GLsizei instances = ArraySize(transform) / 3;
532 
533     const GLfloat colors[instances * 3] = {
534         1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
535     };
536 
537     constexpr GLushort lineloopAsStripIndices[] = {0, 1, 2, 3, 0};
538 
539     std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight());
540 
541     // Draw in non-instanced way
542     glClearColor(0, 0, 0, 1);
543     glClear(GL_COLOR_BUFFER_BIT);
544 
545     glEnableVertexAttribArray(0);
546     glDisableVertexAttribArray(1);
547 
548     glVertexAttribDivisorANGLE(0, 0);
549 
550     glBindBuffer(GL_ARRAY_BUFFER, 0);
551     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
552     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
553 
554     for (size_t i = 0; i < instances; ++i)
555     {
556         glVertexAttrib3fv(1, transform + 3 * i);
557         glVertexAttrib3fv(2, colors + 3 * i);
558 
559         glDrawElements(GL_LINE_STRIP, ArraySize(lineloopAsStripIndices), GL_UNSIGNED_SHORT,
560                        lineloopAsStripIndices);
561     }
562 
563     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
564                  expectedPixels.data());
565     ASSERT_GL_NO_ERROR();
566 
567     // Draw in instanced way:
568     glClear(GL_COLOR_BUFFER_BIT);
569 
570     GLBuffer vertexBuffer[3];
571     GLBuffer indexBuffer;
572 
573     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
574     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineloopAsStripIndices), lineloopAsStripIndices,
575                  GL_STATIC_DRAW);
576 
577     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
578     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
579     glEnableVertexAttribArray(0);
580     glVertexAttribDivisorANGLE(0, 0);
581     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
582 
583     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
584     glBufferData(GL_ARRAY_BUFFER, sizeof(transform), transform, GL_STATIC_DRAW);
585     glEnableVertexAttribArray(1);
586     glVertexAttribDivisorANGLE(1, 1);
587     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
588 
589     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
590     glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
591     glEnableVertexAttribArray(2);
592     glVertexAttribDivisorANGLE(2, 1);
593     glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
594 
595     glDrawArraysInstancedANGLE(GL_LINE_LOOP, 0, ArraySize(vertices) / 2, instances);
596 
597     std::vector<GLColor> actualPixels(getWindowWidth() * getWindowHeight());
598     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
599                  actualPixels.data());
600     EXPECT_EQ(expectedPixels, actualPixels);
601 
602     glClear(GL_COLOR_BUFFER_BIT);
603     glDrawElementsInstancedANGLE(GL_LINE_LOOP, ArraySize(lineloopAsStripIndices) - 1,
604                                  GL_UNSIGNED_SHORT, 0, instances);
605 
606     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
607                  actualPixels.data());
608     EXPECT_EQ(expectedPixels, actualPixels);
609 }
610 
611 class InstancingTestES3 : public InstancingTest
612 {
613   public:
InstancingTestES3()614     InstancingTestES3() {}
615 };
616 
617 class InstancingTestES31 : public InstancingTest
618 {
619   public:
InstancingTestES31()620     InstancingTestES31() {}
621 };
622 
623 // Verify that VertexAttribDivisor can update both binding divisor and attribBinding.
TEST_P(InstancingTestES31,UpdateAttribBindingByVertexAttribDivisor)624 TEST_P(InstancingTestES31, UpdateAttribBindingByVertexAttribDivisor)
625 {
626     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
627 
628     glUseProgram(mProgram[0]);
629 
630     // Get the attribute locations
631     GLint positionLoc    = glGetAttribLocation(mProgram[0], "a_position");
632     GLint instancePosLoc = glGetAttribLocation(mProgram[0], "a_instance");
633     ASSERT_NE(-1, positionLoc);
634     ASSERT_NE(-1, instancePosLoc);
635     ASSERT_GL_NO_ERROR();
636 
637     GLuint vao;
638     glGenVertexArrays(1, &vao);
639     glBindVertexArray(vao);
640 
641     GLBuffer quadBuffer;
642     glBindBuffer(GL_ARRAY_BUFFER, quadBuffer);
643     glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
644 
645     const unsigned numInstance = 4;
646     const unsigned divisor     = 1;
647     const unsigned lastDrawn   = (numInstance - 1) / divisor;
648 
649     // Ensure the numInstance and divisor parameters are valid.
650     ASSERT_TRUE(lastDrawn < kMaxDrawn);
651 
652     // Set the formats by VertexAttribFormat
653     glVertexAttribFormat(positionLoc, 2, GL_FLOAT, GL_FALSE, 0);
654     glVertexAttribFormat(instancePosLoc, 1, GL_FLOAT, GL_FALSE, 0);
655     glEnableVertexAttribArray(positionLoc);
656     glEnableVertexAttribArray(instancePosLoc);
657 
658     const GLint positionBinding = instancePosLoc;
659     const GLint instanceBinding = positionLoc;
660 
661     // Load the vertex position into the binding indexed positionBinding (== instancePosLoc)
662     // Load the instance position into the binding indexed instanceBinding (== positionLoc)
663     glBindVertexBuffer(positionBinding, quadBuffer, 0, 2 * sizeof(kQuadVertices[0]));
664     glBindVertexBuffer(instanceBinding, mInstanceBuffer, 0, sizeof(mInstanceData[0]));
665 
666     // The attribute indexed positionLoc is using the binding indexed positionBinding
667     // The attribute indexed instancePosLoc is using the binding indexed instanceBinding
668     glVertexAttribBinding(positionLoc, positionBinding);
669     glVertexAttribBinding(instancePosLoc, instanceBinding);
670 
671     // Enable instancing on the binding indexed instanceBinding
672     glVertexBindingDivisor(instanceBinding, divisor);
673 
674     // Do the first instanced draw
675     glClear(GL_COLOR_BUFFER_BIT);
676     glDrawElementsInstanced(GL_TRIANGLES, ArraySize(kQuadIndices), GL_UNSIGNED_SHORT, kQuadIndices,
677                             numInstance);
678     checkDrawing(lastDrawn);
679 
680     // Disable instancing.
681     glVertexBindingDivisor(instanceBinding, 0);
682 
683     // Load the vertex position into the binding indexed positionLoc.
684     // Load the instance position into the binding indexed instancePosLoc.
685     glBindVertexBuffer(positionLoc, quadBuffer, 0, 2 * sizeof(kQuadVertices[0]));
686     glBindVertexBuffer(instancePosLoc, mInstanceBuffer, 0, sizeof(mInstanceData[0]));
687 
688     // The attribute indexed positionLoc is using the binding indexed positionLoc.
689     glVertexAttribBinding(positionLoc, positionLoc);
690 
691     // Call VertexAttribDivisor to both enable instancing on instancePosLoc and set the attribute
692     // indexed instancePosLoc using the binding indexed instancePosLoc.
693     glVertexAttribDivisor(instancePosLoc, divisor);
694 
695     // Do the second instanced draw
696     glClear(GL_COLOR_BUFFER_BIT);
697     glDrawElementsInstanced(GL_TRIANGLES, ArraySize(kQuadIndices), GL_UNSIGNED_SHORT, kQuadIndices,
698                             numInstance);
699     checkDrawing(lastDrawn);
700 
701     glDeleteVertexArrays(1, &vao);
702 }
703 
704 // Verify that a large divisor that also changes doesn't cause issues and renders correctly.
TEST_P(InstancingTestES3,LargeDivisor)705 TEST_P(InstancingTestES3, LargeDivisor)
706 {
707     // http://anglebug.com/4092
708     ANGLE_SKIP_TEST_IF(isSwiftshader());
709     constexpr char kVS[] = R"(#version 300 es
710 layout(location = 0) in vec4 a_position;
711 layout(location = 1) in vec4 a_color;
712 out vec4 v_color;
713 void main()
714 {
715     gl_Position = a_position;
716     gl_PointSize = 4.0f;
717     v_color = a_color;
718 })";
719 
720     constexpr char kFS[] = R"(#version 300 es
721 precision highp float;
722 in vec4 v_color;
723 out vec4 my_FragColor;
724 void main()
725 {
726     my_FragColor = v_color;
727 })";
728 
729     ANGLE_GL_PROGRAM(program, kVS, kFS);
730     glUseProgram(program);
731 
732     glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
733 
734     GLBuffer buf;
735     glBindBuffer(GL_ARRAY_BUFFER, buf);
736     std::vector<GLfloat> vertices;
737     for (size_t i = 0u; i < 4u; ++i)
738     {
739         vertices.push_back(0.0f + i * 0.25f);
740         vertices.push_back(0.0f);
741         vertices.push_back(0.0f);
742         vertices.push_back(1.0f);
743     }
744     glBufferData(GL_ARRAY_BUFFER, vertices.size() * 4u, vertices.data(), GL_DYNAMIC_DRAW);
745 
746     glEnableVertexAttribArray(0);
747     glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
748     ASSERT_GL_NO_ERROR();
749 
750     GLBuffer colorBuf;
751     glBindBuffer(GL_ARRAY_BUFFER, colorBuf);
752 
753     std::array<GLColor, 4> ubyteColors = {GLColor::red, GLColor::green};
754     std::vector<float> floatColors;
755     for (const GLColor &color : ubyteColors)
756     {
757         floatColors.push_back(color.R / 255.0f);
758         floatColors.push_back(color.G / 255.0f);
759         floatColors.push_back(color.B / 255.0f);
760         floatColors.push_back(color.A / 255.0f);
761     }
762     glBufferData(GL_ARRAY_BUFFER, floatColors.size() * 4u, floatColors.data(), GL_DYNAMIC_DRAW);
763 
764     const GLuint kColorDivisor = 65536u * 2u;
765     glEnableVertexAttribArray(1);
766     glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, nullptr);
767     glVertexAttribDivisor(1, kColorDivisor);
768 
769     std::array<GLuint, 1u> indices       = {0u};
770     std::array<GLuint, 3u> divisorsToTry = {256u, 65536u, 65536u * 2u};
771 
772     for (GLuint divisorToTry : divisorsToTry)
773     {
774         glClear(GL_COLOR_BUFFER_BIT);
775         glVertexAttribDivisor(0, divisorToTry);
776 
777         GLuint instanceCount        = divisorToTry + 1u;
778         unsigned int pointsRendered = (instanceCount - 1u) / divisorToTry + 1u;
779 
780         glDrawElementsInstanced(GL_POINTS, indices.size(), GL_UNSIGNED_INT, indices.data(),
781                                 instanceCount);
782         ASSERT_GL_NO_ERROR();
783 
784         // Check that the intended number of points has been rendered.
785         for (unsigned int pointIndex = 0u; pointIndex < pointsRendered + 1u; ++pointIndex)
786         {
787             GLint pointx = static_cast<GLint>((pointIndex * 0.125f + 0.5f) * getWindowWidth());
788             GLint pointy = static_cast<GLint>(0.5f * getWindowHeight());
789 
790             if (pointIndex < pointsRendered)
791             {
792                 GLuint pointColorIndex = (pointIndex * divisorToTry) / kColorDivisor;
793                 EXPECT_PIXEL_COLOR_EQ(pointx, pointy, ubyteColors[pointColorIndex]);
794             }
795             else
796             {
797                 // Clear color.
798                 EXPECT_PIXEL_COLOR_EQ(pointx, pointy, GLColor::blue);
799             }
800         }
801     }
802 }
803 
804 // This is a regression test. If VertexAttribDivisor was returned as a signed integer, it would be
805 // incorrectly clamped down to the maximum signed integer.
TEST_P(InstancingTestES3,LargestDivisor)806 TEST_P(InstancingTestES3, LargestDivisor)
807 {
808     // http://anglebug.com/4092
809     ANGLE_SKIP_TEST_IF(isSwiftshader());
810     constexpr GLuint kLargeDivisor = std::numeric_limits<GLuint>::max();
811     glVertexAttribDivisor(0, kLargeDivisor);
812 
813     GLuint divisor = 0;
814     glGetVertexAttribIuiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
815     EXPECT_EQ(kLargeDivisor, divisor)
816         << "Vertex attrib divisor read was not the same that was passed in.";
817 }
818 
819 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InstancingTestES3);
820 ANGLE_INSTANTIATE_TEST_ES3(InstancingTestES3);
821 
822 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InstancingTestES31);
823 ANGLE_INSTANTIATE_TEST_ES31(InstancingTestES31);
824 
825 ANGLE_INSTANTIATE_TEST_ES2(InstancingTest);
826