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 #include "anglebase/numerics/safe_conversions.h"
7 #include "common/mathutil.h"
8 #include "test_utils/ANGLETest.h"
9 #include "test_utils/gl_raii.h"
10 #include "util/random_utils.h"
11
12 using namespace angle;
13
14 namespace
15 {
16
TypeStride(GLenum attribType)17 GLsizei TypeStride(GLenum attribType)
18 {
19 switch (attribType)
20 {
21 case GL_UNSIGNED_BYTE:
22 case GL_BYTE:
23 return 1;
24 case GL_UNSIGNED_SHORT:
25 case GL_SHORT:
26 case GL_HALF_FLOAT:
27 case GL_HALF_FLOAT_OES:
28 return 2;
29 case GL_UNSIGNED_INT:
30 case GL_INT:
31 case GL_FLOAT:
32 case GL_UNSIGNED_INT_10_10_10_2_OES:
33 case GL_INT_10_10_10_2_OES:
34 return 4;
35 default:
36 EXPECT_TRUE(false);
37 return 0;
38 }
39 }
40
41 template <typename T>
Normalize(T value)42 GLfloat Normalize(T value)
43 {
44 static_assert(std::is_integral<T>::value, "Integer required.");
45 if (std::is_signed<T>::value)
46 {
47 typedef typename std::make_unsigned<T>::type unsigned_type;
48 return (2.0f * static_cast<GLfloat>(value) + 1.0f) /
49 static_cast<GLfloat>(std::numeric_limits<unsigned_type>::max());
50 }
51 else
52 {
53 return static_cast<GLfloat>(value) / static_cast<GLfloat>(std::numeric_limits<T>::max());
54 }
55 }
56
57 // Normalization for each channel of signed/unsigned 10_10_10_2 types
58 template <typename T>
Normalize10(T value)59 GLfloat Normalize10(T value)
60 {
61 static_assert(std::is_integral<T>::value, "Integer required.");
62 GLfloat floatOutput;
63 if (std::is_signed<T>::value)
64 {
65 const uint32_t signMask = 0x200; // 1 set at the 9th bit
66 const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1
67
68 if (value & signMask)
69 {
70 int negativeNumber = value | negativeMask;
71 floatOutput = static_cast<GLfloat>(negativeNumber);
72 }
73 else
74 {
75 floatOutput = static_cast<GLfloat>(value);
76 }
77
78 const int32_t maxValue = 0x1FF; // 1 set in bits 0 through 8
79 const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue
80
81 // A 10-bit two's complement number has the possibility of being minValue - 1 but
82 // OpenGL's normalization rules dictate that it should be clamped to minValue in
83 // this case.
84 if (floatOutput < minValue)
85 floatOutput = minValue;
86
87 const int32_t halfRange = (maxValue - minValue) >> 1;
88 floatOutput = ((floatOutput - minValue) / halfRange) - 1.0f;
89 }
90 else
91 {
92 const GLfloat maxValue = 1023.0f; // 1 set in bits 0 through 9
93 floatOutput = static_cast<GLfloat>(value) / maxValue;
94 }
95 return floatOutput;
96 }
97
98 template <typename T>
Normalize2(T value)99 GLfloat Normalize2(T value)
100 {
101 static_assert(std::is_integral<T>::value, "Integer required.");
102 if (std::is_signed<T>::value)
103 {
104 GLfloat outputValue = static_cast<float>(value) / 1.0f;
105 outputValue = (outputValue >= -1.0f) ? (outputValue) : (-1.0f);
106 return outputValue;
107 }
108 else
109 {
110 return static_cast<float>(value) / 3.0f;
111 }
112 }
113
114 template <typename DestT, typename SrcT>
Pack1010102(std::array<SrcT,4> input)115 DestT Pack1010102(std::array<SrcT, 4> input)
116 {
117 static_assert(std::is_integral<SrcT>::value, "Integer required.");
118 static_assert(std::is_integral<DestT>::value, "Integer required.");
119 static_assert(std::is_unsigned<SrcT>::value == std::is_unsigned<DestT>::value,
120 "Signedness should be equal.");
121 DestT rOut, gOut, bOut, aOut;
122 rOut = static_cast<DestT>(input[0]);
123 gOut = static_cast<DestT>(input[1]);
124 bOut = static_cast<DestT>(input[2]);
125 aOut = static_cast<DestT>(input[3]);
126
127 if (std::is_unsigned<SrcT>::value)
128 {
129 return rOut << 22 | gOut << 12 | bOut << 2 | aOut;
130 }
131 else
132 {
133 // Need to apply bit mask to account for sign extension
134 return (0xFFC00000u & rOut << 22) | (0x003FF000u & gOut << 12) | (0x00000FFCu & bOut << 2) |
135 (0x00000003u & aOut);
136 }
137 }
138
139 class VertexAttributeTest : public ANGLETest<>
140 {
141 protected:
VertexAttributeTest()142 VertexAttributeTest() : mProgram(0), mTestAttrib(-1), mExpectedAttrib(-1), mBuffer(0)
143 {
144 setWindowWidth(128);
145 setWindowHeight(128);
146 setConfigRedBits(8);
147 setConfigGreenBits(8);
148 setConfigBlueBits(8);
149 setConfigAlphaBits(8);
150 setConfigDepthBits(24);
151 }
152
153 enum class Source
154 {
155 BUFFER,
156 IMMEDIATE,
157 };
158
159 struct TestData final : private angle::NonCopyable
160 {
TestData__anon8ff86acd0111::VertexAttributeTest::TestData161 TestData(GLenum typeIn,
162 GLboolean normalizedIn,
163 Source sourceIn,
164 const void *inputDataIn,
165 const GLfloat *expectedDataIn)
166 : type(typeIn),
167 normalized(normalizedIn),
168 bufferOffset(0),
169 source(sourceIn),
170 inputData(inputDataIn),
171 expectedData(expectedDataIn),
172 clearBeforeDraw(false)
173 {}
174
175 GLenum type;
176 GLboolean normalized;
177 size_t bufferOffset;
178 Source source;
179
180 const void *inputData;
181 const GLfloat *expectedData;
182
183 bool clearBeforeDraw;
184 };
185
setupTest(const TestData & test,GLint typeSize)186 void setupTest(const TestData &test, GLint typeSize)
187 {
188 if (mProgram == 0)
189 {
190 initBasicProgram();
191 }
192
193 if (test.source == Source::BUFFER)
194 {
195 GLsizei dataSize = kVertexCount * TypeStride(test.type);
196 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
197 glBufferData(GL_ARRAY_BUFFER, dataSize, test.inputData, GL_STATIC_DRAW);
198 glVertexAttribPointer(mTestAttrib, typeSize, test.type, test.normalized, 0,
199 reinterpret_cast<void *>(test.bufferOffset));
200 glBindBuffer(GL_ARRAY_BUFFER, 0);
201 }
202 else
203 {
204 ASSERT_EQ(Source::IMMEDIATE, test.source);
205 glBindBuffer(GL_ARRAY_BUFFER, 0);
206 glVertexAttribPointer(mTestAttrib, typeSize, test.type, test.normalized, 0,
207 test.inputData);
208 }
209
210 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, test.expectedData);
211
212 glEnableVertexAttribArray(mTestAttrib);
213 glEnableVertexAttribArray(mExpectedAttrib);
214 }
215
checkPixels()216 void checkPixels()
217 {
218 GLint viewportSize[4];
219 glGetIntegerv(GL_VIEWPORT, viewportSize);
220
221 GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
222 GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
223
224 // We need to offset our checks from triangle edges to ensure we don't fall on a single tri
225 // Avoid making assumptions of drawQuad with four checks to check the four possible tri
226 // regions
227 EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
228 EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
229 EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
230 EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
231 }
232
checkPixelsUnEqual()233 void checkPixelsUnEqual()
234 {
235 GLint viewportSize[4];
236 glGetIntegerv(GL_VIEWPORT, viewportSize);
237
238 GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
239 GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
240
241 // We need to offset our checks from triangle edges to ensure we don't fall on a single tri
242 // Avoid making assumptions of drawQuad with four checks to check the four possible tri
243 // regions
244 EXPECT_PIXEL_NE((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
245 EXPECT_PIXEL_NE((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
246 EXPECT_PIXEL_NE(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
247 EXPECT_PIXEL_NE(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
248 }
249
runTest(const TestData & test)250 void runTest(const TestData &test) { runTest(test, true); }
251
runTest(const TestData & test,bool checkPixelEqual)252 void runTest(const TestData &test, bool checkPixelEqual)
253 {
254 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
255 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
256
257 for (GLint i = 0; i < 4; i++)
258 {
259 GLint typeSize = i + 1;
260 setupTest(test, typeSize);
261
262 if (test.clearBeforeDraw)
263 {
264 glClear(GL_COLOR_BUFFER_BIT);
265 }
266
267 drawQuad(mProgram, "position", 0.5f);
268
269 glDisableVertexAttribArray(mTestAttrib);
270 glDisableVertexAttribArray(mExpectedAttrib);
271
272 if (checkPixelEqual)
273 {
274 checkPixels();
275 }
276 else
277 {
278 checkPixelsUnEqual();
279 }
280 }
281 }
282
testSetUp()283 void testSetUp() override
284 {
285 glClearColor(0, 0, 0, 0);
286 glClearDepthf(0.0);
287 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
288
289 glDisable(GL_DEPTH_TEST);
290
291 glGenBuffers(1, &mBuffer);
292 }
293
testTearDown()294 void testTearDown() override
295 {
296 glDeleteProgram(mProgram);
297 glDeleteBuffers(1, &mBuffer);
298 }
299
compileMultiAttribProgram(GLint attribCount)300 GLuint compileMultiAttribProgram(GLint attribCount)
301 {
302 std::stringstream shaderStream;
303
304 shaderStream << "attribute mediump vec4 position;" << std::endl;
305 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
306 {
307 shaderStream << "attribute float a" << attribIndex << ";" << std::endl;
308 }
309 shaderStream << "varying mediump float color;" << std::endl
310 << "void main() {" << std::endl
311 << " gl_Position = position;" << std::endl
312 << " color = 0.0;" << std::endl;
313 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
314 {
315 shaderStream << " color += a" << attribIndex << ";" << std::endl;
316 }
317 shaderStream << "}" << std::endl;
318
319 constexpr char kFS[] =
320 "varying mediump float color;\n"
321 "void main(void)\n"
322 "{\n"
323 " gl_FragColor = vec4(color, 0.0, 0.0, 1.0);\n"
324 "}\n";
325
326 return CompileProgram(shaderStream.str().c_str(), kFS);
327 }
328
setupMultiAttribs(GLuint program,GLint attribCount,GLfloat value)329 void setupMultiAttribs(GLuint program, GLint attribCount, GLfloat value)
330 {
331 glUseProgram(program);
332 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
333 {
334 std::stringstream attribStream;
335 attribStream << "a" << attribIndex;
336 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
337 ASSERT_NE(-1, location);
338 glVertexAttrib1f(location, value);
339 glDisableVertexAttribArray(location);
340 }
341 }
342
initBasicProgram()343 void initBasicProgram()
344 {
345 constexpr char kVS[] =
346 "attribute mediump vec4 position;\n"
347 "attribute highp vec4 test;\n"
348 "attribute highp vec4 expected;\n"
349 "varying mediump vec4 color;\n"
350 "void main(void)\n"
351 "{\n"
352 " gl_Position = position;\n"
353 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
354 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
355 "}\n";
356
357 constexpr char kFS[] =
358 "varying mediump vec4 color;\n"
359 "void main(void)\n"
360 "{\n"
361 " gl_FragColor = color;\n"
362 "}\n";
363
364 mProgram = CompileProgram(kVS, kFS);
365 ASSERT_NE(0u, mProgram);
366
367 mTestAttrib = glGetAttribLocation(mProgram, "test");
368 ASSERT_NE(-1, mTestAttrib);
369 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
370 ASSERT_NE(-1, mExpectedAttrib);
371
372 glUseProgram(mProgram);
373 }
374
375 static constexpr size_t kVertexCount = 24;
376
InitTestData(std::array<GLfloat,kVertexCount> & inputData,std::array<GLfloat,kVertexCount> & expectedData)377 static void InitTestData(std::array<GLfloat, kVertexCount> &inputData,
378 std::array<GLfloat, kVertexCount> &expectedData)
379 {
380 for (size_t count = 0; count < kVertexCount; ++count)
381 {
382 inputData[count] = static_cast<GLfloat>(count);
383 expectedData[count] = inputData[count];
384 }
385 }
386
InitQuadVertexBuffer(GLBuffer * buffer)387 static void InitQuadVertexBuffer(GLBuffer *buffer)
388 {
389 auto quadVertices = GetQuadVertices();
390 GLsizei quadVerticesSize =
391 static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
392
393 glBindBuffer(GL_ARRAY_BUFFER, *buffer);
394 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, nullptr, GL_STATIC_DRAW);
395 glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
396 }
397
InitQuadPlusOneVertexBuffer(GLBuffer * buffer)398 static void InitQuadPlusOneVertexBuffer(GLBuffer *buffer)
399 {
400 auto quadVertices = GetQuadVertices();
401 GLsizei quadVerticesSize =
402 static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
403
404 glBindBuffer(GL_ARRAY_BUFFER, *buffer);
405 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
406 glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
407 glBufferSubData(GL_ARRAY_BUFFER, quadVerticesSize, sizeof(Vector3), &quadVertices[0]);
408 }
409
410 GLuint mProgram;
411 GLint mTestAttrib;
412 GLint mExpectedAttrib;
413 GLuint mBuffer;
414 };
415
TEST_P(VertexAttributeTest,UnsignedByteUnnormalized)416 TEST_P(VertexAttributeTest, UnsignedByteUnnormalized)
417 {
418 std::array<GLubyte, kVertexCount> inputData = {
419 {0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255}};
420 std::array<GLfloat, kVertexCount> expectedData;
421 for (size_t i = 0; i < kVertexCount; i++)
422 {
423 expectedData[i] = inputData[i];
424 }
425
426 TestData data(GL_UNSIGNED_BYTE, GL_FALSE, Source::IMMEDIATE, inputData.data(),
427 expectedData.data());
428 runTest(data);
429 }
430
TEST_P(VertexAttributeTest,UnsignedByteNormalized)431 TEST_P(VertexAttributeTest, UnsignedByteNormalized)
432 {
433 std::array<GLubyte, kVertexCount> inputData = {
434 {0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255}};
435 std::array<GLfloat, kVertexCount> expectedData;
436 for (size_t i = 0; i < kVertexCount; i++)
437 {
438 expectedData[i] = Normalize(inputData[i]);
439 }
440
441 TestData data(GL_UNSIGNED_BYTE, GL_TRUE, Source::IMMEDIATE, inputData.data(),
442 expectedData.data());
443 runTest(data);
444 }
445
TEST_P(VertexAttributeTest,ByteUnnormalized)446 TEST_P(VertexAttributeTest, ByteUnnormalized)
447 {
448 std::array<GLbyte, kVertexCount> inputData = {
449 {0, 1, 2, 3, 4, -1, -2, -3, -4, 125, 126, 127, -128, -127, -126}};
450 std::array<GLfloat, kVertexCount> expectedData;
451 for (size_t i = 0; i < kVertexCount; i++)
452 {
453 expectedData[i] = inputData[i];
454 }
455
456 TestData data(GL_BYTE, GL_FALSE, Source::IMMEDIATE, inputData.data(), expectedData.data());
457 runTest(data);
458 }
459
TEST_P(VertexAttributeTest,ByteNormalized)460 TEST_P(VertexAttributeTest, ByteNormalized)
461 {
462 std::array<GLbyte, kVertexCount> inputData = {
463 {0, 1, 2, 3, 4, -1, -2, -3, -4, 125, 126, 127, -128, -127, -126}};
464 std::array<GLfloat, kVertexCount> expectedData;
465 for (size_t i = 0; i < kVertexCount; i++)
466 {
467 expectedData[i] = Normalize(inputData[i]);
468 }
469
470 TestData data(GL_BYTE, GL_TRUE, Source::IMMEDIATE, inputData.data(), expectedData.data());
471 runTest(data);
472 }
473
TEST_P(VertexAttributeTest,UnsignedShortUnnormalized)474 TEST_P(VertexAttributeTest, UnsignedShortUnnormalized)
475 {
476 std::array<GLushort, kVertexCount> inputData = {
477 {0, 1, 2, 3, 254, 255, 256, 32766, 32767, 32768, 65533, 65534, 65535}};
478 std::array<GLfloat, kVertexCount> expectedData;
479 for (size_t i = 0; i < kVertexCount; i++)
480 {
481 expectedData[i] = inputData[i];
482 }
483
484 TestData data(GL_UNSIGNED_SHORT, GL_FALSE, Source::IMMEDIATE, inputData.data(),
485 expectedData.data());
486 runTest(data);
487 }
488
TEST_P(VertexAttributeTest,UnsignedShortNormalized)489 TEST_P(VertexAttributeTest, UnsignedShortNormalized)
490 {
491 std::array<GLushort, kVertexCount> inputData = {
492 {0, 1, 2, 3, 254, 255, 256, 32766, 32767, 32768, 65533, 65534, 65535}};
493 std::array<GLfloat, kVertexCount> expectedData;
494 for (size_t i = 0; i < kVertexCount; i++)
495 {
496 expectedData[i] = Normalize(inputData[i]);
497 }
498
499 TestData data(GL_UNSIGNED_SHORT, GL_TRUE, Source::IMMEDIATE, inputData.data(),
500 expectedData.data());
501 runTest(data);
502 }
503
TEST_P(VertexAttributeTest,ShortUnnormalized)504 TEST_P(VertexAttributeTest, ShortUnnormalized)
505 {
506 std::array<GLshort, kVertexCount> inputData = {
507 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
508 std::array<GLfloat, kVertexCount> expectedData;
509 for (size_t i = 0; i < kVertexCount; i++)
510 {
511 expectedData[i] = inputData[i];
512 }
513
514 TestData data(GL_SHORT, GL_FALSE, Source::IMMEDIATE, inputData.data(), expectedData.data());
515 runTest(data);
516 }
517
TEST_P(VertexAttributeTest,ShortNormalized)518 TEST_P(VertexAttributeTest, ShortNormalized)
519 {
520 std::array<GLshort, kVertexCount> inputData = {
521 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
522 std::array<GLfloat, kVertexCount> expectedData;
523 for (size_t i = 0; i < kVertexCount; i++)
524 {
525 expectedData[i] = Normalize(inputData[i]);
526 }
527
528 TestData data(GL_SHORT, GL_TRUE, Source::IMMEDIATE, inputData.data(), expectedData.data());
529 runTest(data);
530 }
531
532 // Verify that vertex data is updated correctly when using a float/half-float client memory pointer.
TEST_P(VertexAttributeTest,HalfFloatClientMemoryPointer)533 TEST_P(VertexAttributeTest, HalfFloatClientMemoryPointer)
534 {
535 std::array<GLhalf, kVertexCount> inputData;
536 std::array<GLfloat, kVertexCount> expectedData = {
537 {0.f, 1.5f, 2.3f, 3.2f, -1.8f, -2.2f, -3.9f, -4.f, 34.5f, 32.2f, -78.8f, -77.4f, -76.1f}};
538
539 for (size_t i = 0; i < kVertexCount; i++)
540 {
541 inputData[i] = gl::float32ToFloat16(expectedData[i]);
542 }
543
544 // If the extension is enabled run the test on all contexts
545 if (IsGLExtensionEnabled("GL_OES_vertex_half_float"))
546 {
547 TestData imediateData(GL_HALF_FLOAT_OES, GL_FALSE, Source::IMMEDIATE, inputData.data(),
548 expectedData.data());
549 runTest(imediateData);
550 }
551 // Otherwise run the test only if it is an ES3 context
552 else if (getClientMajorVersion() >= 3)
553 {
554 TestData imediateData(GL_HALF_FLOAT, GL_FALSE, Source::IMMEDIATE, inputData.data(),
555 expectedData.data());
556 runTest(imediateData);
557 }
558 }
559
560 // Verify that vertex data is updated correctly when using a float/half-float buffer.
TEST_P(VertexAttributeTest,HalfFloatBuffer)561 TEST_P(VertexAttributeTest, HalfFloatBuffer)
562 {
563 std::array<GLhalf, kVertexCount> inputData;
564 std::array<GLfloat, kVertexCount> expectedData = {
565 {0.f, 1.5f, 2.3f, 3.2f, -1.8f, -2.2f, -3.9f, -4.f, 34.5f, 32.2f, -78.8f, -77.4f, -76.1f}};
566
567 for (size_t i = 0; i < kVertexCount; i++)
568 {
569 inputData[i] = gl::float32ToFloat16(expectedData[i]);
570 }
571
572 // If the extension is enabled run the test on all contexts
573 if (IsGLExtensionEnabled("GL_OES_vertex_half_float"))
574 {
575 TestData bufferData(GL_HALF_FLOAT_OES, GL_FALSE, Source::BUFFER, inputData.data(),
576 expectedData.data());
577 runTest(bufferData);
578 }
579 // Otherwise run the test only if it is an ES3 context
580 else if (getClientMajorVersion() >= 3)
581 {
582 TestData bufferData(GL_HALF_FLOAT, GL_FALSE, Source::BUFFER, inputData.data(),
583 expectedData.data());
584 runTest(bufferData);
585 }
586 }
587
588 // Verify that using the same client memory pointer in different format won't mess up the draw.
TEST_P(VertexAttributeTest,UsingDifferentFormatAndSameClientMemoryPointer)589 TEST_P(VertexAttributeTest, UsingDifferentFormatAndSameClientMemoryPointer)
590 {
591 std::array<GLshort, kVertexCount> inputData = {
592 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
593
594 std::array<GLfloat, kVertexCount> unnormalizedExpectedData;
595 for (size_t i = 0; i < kVertexCount; i++)
596 {
597 unnormalizedExpectedData[i] = inputData[i];
598 }
599
600 TestData unnormalizedData(GL_SHORT, GL_FALSE, Source::IMMEDIATE, inputData.data(),
601 unnormalizedExpectedData.data());
602 runTest(unnormalizedData);
603
604 std::array<GLfloat, kVertexCount> normalizedExpectedData;
605 for (size_t i = 0; i < kVertexCount; i++)
606 {
607 inputData[i] = -inputData[i];
608 normalizedExpectedData[i] = Normalize(inputData[i]);
609 }
610
611 TestData normalizedData(GL_SHORT, GL_TRUE, Source::IMMEDIATE, inputData.data(),
612 normalizedExpectedData.data());
613 runTest(normalizedData);
614 }
615
616 // Verify that vertex format is updated correctly when the client memory pointer is same.
TEST_P(VertexAttributeTest,NegativeUsingDifferentFormatAndSameClientMemoryPointer)617 TEST_P(VertexAttributeTest, NegativeUsingDifferentFormatAndSameClientMemoryPointer)
618 {
619 std::array<GLshort, kVertexCount> inputData = {
620 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
621
622 std::array<GLfloat, kVertexCount> unnormalizedExpectedData;
623 for (size_t i = 0; i < kVertexCount; i++)
624 {
625 unnormalizedExpectedData[i] = inputData[i];
626 }
627
628 // Use unnormalized short as the format of the data in client memory pointer in the first draw.
629 TestData unnormalizedData(GL_SHORT, GL_FALSE, Source::IMMEDIATE, inputData.data(),
630 unnormalizedExpectedData.data());
631 runTest(unnormalizedData);
632
633 // Use normalized short as the format of the data in client memory pointer in the second draw,
634 // but mExpectedAttrib is the same as the first draw.
635 TestData normalizedData(GL_SHORT, GL_TRUE, Source::IMMEDIATE, inputData.data(),
636 unnormalizedExpectedData.data());
637 runTest(normalizedData, false);
638 }
639
640 // Verify that using different vertex format and same buffer won't mess up the draw.
TEST_P(VertexAttributeTest,UsingDifferentFormatAndSameBuffer)641 TEST_P(VertexAttributeTest, UsingDifferentFormatAndSameBuffer)
642 {
643 std::array<GLshort, kVertexCount> inputData = {
644 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
645
646 std::array<GLfloat, kVertexCount> unnormalizedExpectedData;
647 std::array<GLfloat, kVertexCount> normalizedExpectedData;
648 for (size_t i = 0; i < kVertexCount; i++)
649 {
650 unnormalizedExpectedData[i] = inputData[i];
651 normalizedExpectedData[i] = Normalize(inputData[i]);
652 }
653
654 // Use unnormalized short as the format of the data in mBuffer in the first draw.
655 TestData unnormalizedData(GL_SHORT, GL_FALSE, Source::BUFFER, inputData.data(),
656 unnormalizedExpectedData.data());
657 runTest(unnormalizedData);
658
659 // Use normalized short as the format of the data in mBuffer in the second draw.
660 TestData normalizedData(GL_SHORT, GL_TRUE, Source::BUFFER, inputData.data(),
661 normalizedExpectedData.data());
662 runTest(normalizedData);
663 }
664
665 // Verify that vertex format is updated correctly when the buffer is same.
TEST_P(VertexAttributeTest,NegativeUsingDifferentFormatAndSameBuffer)666 TEST_P(VertexAttributeTest, NegativeUsingDifferentFormatAndSameBuffer)
667 {
668 std::array<GLshort, kVertexCount> inputData = {
669 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
670
671 std::array<GLfloat, kVertexCount> unnormalizedExpectedData;
672 for (size_t i = 0; i < kVertexCount; i++)
673 {
674 unnormalizedExpectedData[i] = inputData[i];
675 }
676
677 // Use unnormalized short as the format of the data in mBuffer in the first draw.
678 TestData unnormalizedData(GL_SHORT, GL_FALSE, Source::BUFFER, inputData.data(),
679 unnormalizedExpectedData.data());
680 runTest(unnormalizedData);
681
682 // Use normalized short as the format of the data in mBuffer in the second draw, but
683 // mExpectedAttrib is the same as the first draw.
684 TestData normalizedData(GL_SHORT, GL_TRUE, Source::BUFFER, inputData.data(),
685 unnormalizedExpectedData.data());
686
687 // The check should fail because the test data is changed while the expected data is the same.
688 runTest(normalizedData, false);
689 }
690
691 // Verify that mixed using buffer and client memory pointer won't mess up the draw.
TEST_P(VertexAttributeTest,MixedUsingBufferAndClientMemoryPointer)692 TEST_P(VertexAttributeTest, MixedUsingBufferAndClientMemoryPointer)
693 {
694 std::array<GLshort, kVertexCount> inputData = {
695 {0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766}};
696
697 std::array<GLfloat, kVertexCount> unnormalizedExpectedData;
698 std::array<GLfloat, kVertexCount> normalizedExpectedData;
699 for (size_t i = 0; i < kVertexCount; i++)
700 {
701 unnormalizedExpectedData[i] = inputData[i];
702 normalizedExpectedData[i] = Normalize(inputData[i]);
703 }
704
705 TestData unnormalizedData(GL_SHORT, GL_FALSE, Source::IMMEDIATE, inputData.data(),
706 unnormalizedExpectedData.data());
707 runTest(unnormalizedData);
708
709 TestData unnormalizedBufferData(GL_SHORT, GL_FALSE, Source::BUFFER, inputData.data(),
710 unnormalizedExpectedData.data());
711 runTest(unnormalizedBufferData);
712
713 TestData normalizedData(GL_SHORT, GL_TRUE, Source::IMMEDIATE, inputData.data(),
714 normalizedExpectedData.data());
715 runTest(normalizedData);
716 }
717
718 // Verify signed unnormalized INT_10_10_10_2 vertex type
TEST_P(VertexAttributeTest,SignedPacked1010102ExtensionUnnormalized)719 TEST_P(VertexAttributeTest, SignedPacked1010102ExtensionUnnormalized)
720 {
721 std::string extensionList(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
722 ANGLE_SKIP_TEST_IF((extensionList.find("OES_vertex_type_10_10_10_2") == std::string::npos));
723
724 // RGB channels are 10-bits, alpha is 2-bits
725 std::array<std::array<GLshort, 4>, kVertexCount / 4> unpackedInput = {{{0, 1, 2, 0},
726 {254, 255, 256, 1},
727 {256, 255, 254, -2},
728 {511, 510, 509, -1},
729 {-512, -511, -500, -2},
730 {-1, -2, -3, 1}}};
731
732 std::array<GLint, kVertexCount> packedInput;
733 std::array<GLfloat, kVertexCount> expectedTypeSize4;
734 std::array<GLfloat, kVertexCount> expectedTypeSize3;
735
736 for (size_t i = 0; i < kVertexCount / 4; i++)
737 {
738 packedInput[i] = Pack1010102<GLint, GLshort>(unpackedInput[i]);
739
740 expectedTypeSize3[i * 3 + 0] = expectedTypeSize4[i * 4 + 0] = unpackedInput[i][0];
741 expectedTypeSize3[i * 3 + 1] = expectedTypeSize4[i * 4 + 1] = unpackedInput[i][1];
742 expectedTypeSize3[i * 3 + 2] = expectedTypeSize4[i * 4 + 2] = unpackedInput[i][2];
743
744 // when the type size is 3, alpha will be 1.0f by GLES driver
745 expectedTypeSize4[i * 4 + 3] = unpackedInput[i][3];
746 }
747
748 TestData data4(GL_INT_10_10_10_2_OES, GL_FALSE, Source::IMMEDIATE, packedInput.data(),
749 expectedTypeSize4.data());
750 TestData bufferedData4(GL_INT_10_10_10_2_OES, GL_FALSE, Source::BUFFER, packedInput.data(),
751 expectedTypeSize4.data());
752 TestData data3(GL_INT_10_10_10_2_OES, GL_FALSE, Source::IMMEDIATE, packedInput.data(),
753 expectedTypeSize3.data());
754 TestData bufferedData3(GL_INT_10_10_10_2_OES, GL_FALSE, Source::BUFFER, packedInput.data(),
755 expectedTypeSize3.data());
756
757 std::array<std::pair<const TestData &, GLint>, 4> dataSet = {
758 {{data4, 4}, {bufferedData4, 4}, {data3, 3}, {bufferedData3, 3}}};
759
760 for (auto data : dataSet)
761 {
762 setupTest(data.first, data.second);
763 drawQuad(mProgram, "position", 0.5f);
764 glDisableVertexAttribArray(mTestAttrib);
765 glDisableVertexAttribArray(mExpectedAttrib);
766 checkPixels();
767 }
768 }
769
770 // Verify signed normalized INT_10_10_10_2 vertex type
TEST_P(VertexAttributeTest,SignedPacked1010102ExtensionNormalized)771 TEST_P(VertexAttributeTest, SignedPacked1010102ExtensionNormalized)
772 {
773 std::string extensionList(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
774 ANGLE_SKIP_TEST_IF((extensionList.find("OES_vertex_type_10_10_10_2") == std::string::npos));
775
776 // RGB channels are 10-bits, alpha is 2-bits
777 std::array<std::array<GLshort, 4>, kVertexCount / 4> unpackedInput = {{{0, 1, 2, 0},
778 {254, 255, 256, 1},
779 {256, 255, 254, -2},
780 {511, 510, 509, -1},
781 {-512, -511, -500, -2},
782 {-1, -2, -3, 1}}};
783 std::array<GLint, kVertexCount> packedInput;
784 std::array<GLfloat, kVertexCount> expectedNormalizedTypeSize4;
785 std::array<GLfloat, kVertexCount> expectedNormalizedTypeSize3;
786
787 for (size_t i = 0; i < kVertexCount / 4; i++)
788 {
789 packedInput[i] = Pack1010102<GLint, GLshort>(unpackedInput[i]);
790
791 expectedNormalizedTypeSize3[i * 3 + 0] = expectedNormalizedTypeSize4[i * 4 + 0] =
792 Normalize10<GLshort>(unpackedInput[i][0]);
793 expectedNormalizedTypeSize3[i * 3 + 1] = expectedNormalizedTypeSize4[i * 4 + 1] =
794 Normalize10<GLshort>(unpackedInput[i][1]);
795 expectedNormalizedTypeSize3[i * 3 + 2] = expectedNormalizedTypeSize4[i * 4 + 2] =
796 Normalize10<GLshort>(unpackedInput[i][2]);
797
798 // when the type size is 3, alpha will be 1.0f by GLES driver
799 expectedNormalizedTypeSize4[i * 4 + 3] = Normalize2<GLshort>(unpackedInput[i][3]);
800 }
801
802 TestData data4(GL_INT_10_10_10_2_OES, GL_TRUE, Source::IMMEDIATE, packedInput.data(),
803 expectedNormalizedTypeSize4.data());
804 TestData bufferedData4(GL_INT_10_10_10_2_OES, GL_TRUE, Source::BUFFER, packedInput.data(),
805 expectedNormalizedTypeSize4.data());
806 TestData data3(GL_INT_10_10_10_2_OES, GL_TRUE, Source::IMMEDIATE, packedInput.data(),
807 expectedNormalizedTypeSize3.data());
808 TestData bufferedData3(GL_INT_10_10_10_2_OES, GL_TRUE, Source::BUFFER, packedInput.data(),
809 expectedNormalizedTypeSize3.data());
810
811 std::array<std::pair<const TestData &, GLint>, 4> dataSet = {
812 {{data4, 4}, {bufferedData4, 4}, {data3, 3}, {bufferedData3, 3}}};
813
814 for (auto data : dataSet)
815 {
816 setupTest(data.first, data.second);
817 drawQuad(mProgram, "position", 0.5f);
818 glDisableVertexAttribArray(mTestAttrib);
819 glDisableVertexAttribArray(mExpectedAttrib);
820 checkPixels();
821 }
822 }
823
824 // Verify unsigned unnormalized INT_10_10_10_2 vertex type
TEST_P(VertexAttributeTest,UnsignedPacked1010102ExtensionUnnormalized)825 TEST_P(VertexAttributeTest, UnsignedPacked1010102ExtensionUnnormalized)
826 {
827 std::string extensionList(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
828 ANGLE_SKIP_TEST_IF((extensionList.find("OES_vertex_type_10_10_10_2") == std::string::npos));
829
830 // RGB channels are 10-bits, alpha is 2-bits
831 std::array<std::array<GLushort, 4>, kVertexCount / 4> unpackedInput = {{{0, 1, 2, 0},
832 {511, 512, 513, 1},
833 {1023, 1022, 1021, 3},
834 {513, 512, 511, 2},
835 {2, 1, 0, 3},
836 {1023, 1022, 1022, 0}}};
837
838 std::array<GLuint, kVertexCount> packedInput;
839 std::array<GLfloat, kVertexCount> expectedTypeSize3;
840 std::array<GLfloat, kVertexCount> expectedTypeSize4;
841
842 for (size_t i = 0; i < kVertexCount / 4; i++)
843 {
844 packedInput[i] = Pack1010102<GLuint, GLushort>(unpackedInput[i]);
845
846 expectedTypeSize3[i * 3 + 0] = expectedTypeSize4[i * 4 + 0] = unpackedInput[i][0];
847 expectedTypeSize3[i * 3 + 1] = expectedTypeSize4[i * 4 + 1] = unpackedInput[i][1];
848 expectedTypeSize3[i * 3 + 2] = expectedTypeSize4[i * 4 + 2] = unpackedInput[i][2];
849
850 // when the type size is 3, alpha will be 1.0f by GLES driver
851 expectedTypeSize4[i * 4 + 3] = unpackedInput[i][3];
852 }
853
854 TestData data4(GL_UNSIGNED_INT_10_10_10_2_OES, GL_FALSE, Source::IMMEDIATE, packedInput.data(),
855 expectedTypeSize4.data());
856 TestData bufferedData4(GL_UNSIGNED_INT_10_10_10_2_OES, GL_FALSE, Source::BUFFER,
857 packedInput.data(), expectedTypeSize4.data());
858 TestData data3(GL_UNSIGNED_INT_10_10_10_2_OES, GL_FALSE, Source::BUFFER, packedInput.data(),
859 expectedTypeSize3.data());
860 TestData bufferedData3(GL_UNSIGNED_INT_10_10_10_2_OES, GL_FALSE, Source::BUFFER,
861 packedInput.data(), expectedTypeSize3.data());
862
863 std::array<std::pair<const TestData &, GLint>, 4> dataSet = {
864 {{data4, 4}, {bufferedData4, 4}, {data3, 3}, {bufferedData3, 3}}};
865
866 for (auto data : dataSet)
867 {
868 setupTest(data.first, data.second);
869 drawQuad(mProgram, "position", 0.5f);
870 glDisableVertexAttribArray(mTestAttrib);
871 glDisableVertexAttribArray(mExpectedAttrib);
872 checkPixels();
873 }
874 }
875
876 // Verify unsigned normalized INT_10_10_10_2 vertex type
TEST_P(VertexAttributeTest,UnsignedPacked1010102ExtensionNormalized)877 TEST_P(VertexAttributeTest, UnsignedPacked1010102ExtensionNormalized)
878 {
879 std::string extensionList(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
880 ANGLE_SKIP_TEST_IF((extensionList.find("OES_vertex_type_10_10_10_2") == std::string::npos));
881
882 // RGB channels are 10-bits, alpha is 2-bits
883 std::array<std::array<GLushort, 4>, kVertexCount / 4> unpackedInput = {{{0, 1, 2, 0},
884 {511, 512, 513, 1},
885 {1023, 1022, 1021, 3},
886 {513, 512, 511, 2},
887 {2, 1, 0, 3},
888 {1023, 1022, 1022, 0}}};
889
890 std::array<GLuint, kVertexCount> packedInput;
891 std::array<GLfloat, kVertexCount> expectedTypeSize4;
892 std::array<GLfloat, kVertexCount> expectedTypeSize3;
893
894 for (size_t i = 0; i < kVertexCount / 4; i++)
895 {
896 packedInput[i] = Pack1010102<GLuint, GLushort>(unpackedInput[i]);
897
898 expectedTypeSize3[i * 3 + 0] = expectedTypeSize4[i * 4 + 0] =
899 Normalize10<GLushort>(unpackedInput[i][0]);
900 expectedTypeSize3[i * 3 + 1] = expectedTypeSize4[i * 4 + 1] =
901 Normalize10<GLushort>(unpackedInput[i][1]);
902 expectedTypeSize3[i * 3 + 2] = expectedTypeSize4[i * 4 + 2] =
903 Normalize10<GLushort>(unpackedInput[i][2]);
904
905 // when the type size is 3, alpha will be 1.0f by GLES driver
906 expectedTypeSize4[i * 4 + 3] = Normalize2<GLushort>(unpackedInput[i][3]);
907 }
908
909 TestData data4(GL_UNSIGNED_INT_10_10_10_2_OES, GL_TRUE, Source::IMMEDIATE, packedInput.data(),
910 expectedTypeSize4.data());
911 TestData bufferedData4(GL_UNSIGNED_INT_10_10_10_2_OES, GL_TRUE, Source::BUFFER,
912 packedInput.data(), expectedTypeSize4.data());
913 TestData data3(GL_UNSIGNED_INT_10_10_10_2_OES, GL_TRUE, Source::IMMEDIATE, packedInput.data(),
914 expectedTypeSize3.data());
915 TestData bufferedData3(GL_UNSIGNED_INT_10_10_10_2_OES, GL_TRUE, Source::BUFFER,
916 packedInput.data(), expectedTypeSize3.data());
917
918 std::array<std::pair<const TestData &, GLint>, 4> dataSet = {
919 {{data4, 4}, {bufferedData4, 4}, {data3, 3}, {bufferedData3, 3}}};
920
921 for (auto data : dataSet)
922 {
923 setupTest(data.first, data.second);
924 drawQuad(mProgram, "position", 0.5f);
925 glDisableVertexAttribArray(mTestAttrib);
926 glDisableVertexAttribArray(mExpectedAttrib);
927 checkPixels();
928 };
929 }
930
931 // Test that mixing array and current vertex attribute values works with the same matrix input
TEST_P(VertexAttributeTest,MixedMatrixSources)932 TEST_P(VertexAttributeTest, MixedMatrixSources)
933 {
934 constexpr char kVS[] = R"(
935 attribute vec4 a_position;
936 attribute mat4 a_matrix;
937 varying vec4 v_color;
938 void main() {
939 v_color = vec4(0.5, 0.25, 0.125, 0.0625) * a_matrix;
940 gl_Position = a_position;
941 })";
942
943 constexpr char kFS[] = R"(
944 precision mediump float;
945 varying vec4 v_color;
946 void main() {
947 gl_FragColor = v_color;
948 })";
949
950 ANGLE_GL_PROGRAM(program, kVS, kFS);
951 glBindAttribLocation(program, 0, "a_position");
952 glBindAttribLocation(program, 1, "a_matrix");
953 glLinkProgram(program);
954 glUseProgram(program);
955 ASSERT_GL_NO_ERROR();
956
957 GLBuffer buffer;
958 for (size_t i = 0; i < 4; ++i)
959 {
960 // Setup current attributes for all columns except one
961 for (size_t col = 0; col < 4; ++col)
962 {
963 GLfloat v[4] = {0.0, 0.0, 0.0, 0.0};
964 v[col] = col == i ? 0.0 : 1.0;
965 glVertexAttrib4fv(1 + col, v);
966 glDisableVertexAttribArray(1 + col);
967 }
968
969 // Setup vertex array data for the i-th column
970 GLfloat data[16]{};
971 data[0 * 4 + i] = 1.0;
972 data[1 * 4 + i] = 1.0;
973 data[2 * 4 + i] = 1.0;
974 data[3 * 4 + i] = 1.0;
975 glBindBuffer(GL_ARRAY_BUFFER, buffer);
976 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
977 glVertexAttribPointer(1 + i, 4, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(0));
978 glEnableVertexAttribArray(1 + i);
979 ASSERT_GL_NO_ERROR();
980
981 glClear(GL_COLOR_BUFFER_BIT);
982 drawIndexedQuad(program, "a_position", 0.0f, 1.0f, true);
983 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(128, 64, 32, 16), 1);
984 }
985 }
986
987 // Test that interleaved layout works for drawing one vertex
TEST_P(VertexAttributeTest,InterleavedOneVertex)988 TEST_P(VertexAttributeTest, InterleavedOneVertex)
989 {
990 float pointSizeRange[2] = {};
991 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
992 ANGLE_SKIP_TEST_IF(pointSizeRange[1] < 8);
993
994 constexpr char kVS[] = R"(
995 attribute vec4 a_pos;
996 attribute vec4 a_col;
997 varying mediump vec4 v_col;
998 void main() {
999 gl_PointSize = 8.0;
1000 gl_Position = a_pos;
1001 v_col = a_col;
1002 })";
1003 constexpr char kFS[] = R"(
1004 varying mediump vec4 v_col;
1005 void main() {
1006 gl_FragColor = v_col;
1007 })";
1008 ANGLE_GL_PROGRAM(program, kVS, kFS);
1009 glBindAttribLocation(program, 0, "a_pos");
1010 glBindAttribLocation(program, 1, "a_col");
1011 glUseProgram(program);
1012
1013 GLBuffer buf;
1014 glBindBuffer(GL_ARRAY_BUFFER, buf);
1015
1016 // One vertex, magenta
1017 const GLfloat data1[8] = {
1018 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1019 };
1020
1021 // Two vertices, red and blue
1022 const GLfloat data2[16] = {
1023 -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1024 +0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1025 };
1026
1027 // One vertex, green
1028 const GLfloat data3[8] = {
1029 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
1030 };
1031
1032 glEnableVertexAttribArray(0);
1033 glEnableVertexAttribArray(1);
1034 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 32, reinterpret_cast<void *>(0));
1035 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 32, reinterpret_cast<void *>(16));
1036
1037 // The second attribute stride is reaching beyond the buffer's length.
1038 // It must not cause any errors as there only one vertex to draw.
1039 glBufferData(GL_ARRAY_BUFFER, 32, data1, GL_STATIC_DRAW);
1040 glDrawArrays(GL_POINTS, 0, 1);
1041 ASSERT_GL_NO_ERROR();
1042 EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::magenta);
1043
1044 // Replace data and draw two vertices to ensure that stride has been applied correctly.
1045 glBufferData(GL_ARRAY_BUFFER, 64, data2, GL_STATIC_DRAW);
1046 glDrawArrays(GL_POINTS, 0, 2);
1047 ASSERT_GL_NO_ERROR();
1048 EXPECT_PIXEL_COLOR_EQ(32, 64, GLColor::red);
1049 EXPECT_PIXEL_COLOR_EQ(96, 64, GLColor::blue);
1050
1051 // Replace data reducing the buffer size back to one vertex
1052 glBufferData(GL_ARRAY_BUFFER, 32, data3, GL_STATIC_DRAW);
1053 glDrawArrays(GL_POINTS, 0, 1);
1054 ASSERT_GL_NO_ERROR();
1055 EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::green);
1056 }
1057
1058 class VertexAttributeTestES3 : public VertexAttributeTest
1059 {
1060 protected:
VertexAttributeTestES3()1061 VertexAttributeTestES3() {}
1062 };
1063
TEST_P(VertexAttributeTestES3,IntUnnormalized)1064 TEST_P(VertexAttributeTestES3, IntUnnormalized)
1065 {
1066 GLint lo = std::numeric_limits<GLint>::min();
1067 GLint hi = std::numeric_limits<GLint>::max();
1068 std::array<GLint, kVertexCount> inputData = {
1069 {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1}};
1070 std::array<GLfloat, kVertexCount> expectedData;
1071 for (size_t i = 0; i < kVertexCount; i++)
1072 {
1073 expectedData[i] = static_cast<GLfloat>(inputData[i]);
1074 }
1075
1076 TestData data(GL_INT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1077 runTest(data);
1078 }
1079
TEST_P(VertexAttributeTestES3,IntNormalized)1080 TEST_P(VertexAttributeTestES3, IntNormalized)
1081 {
1082 GLint lo = std::numeric_limits<GLint>::min();
1083 GLint hi = std::numeric_limits<GLint>::max();
1084 std::array<GLint, kVertexCount> inputData = {
1085 {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1}};
1086 std::array<GLfloat, kVertexCount> expectedData;
1087 for (size_t i = 0; i < kVertexCount; i++)
1088 {
1089 expectedData[i] = Normalize(inputData[i]);
1090 }
1091
1092 TestData data(GL_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
1093 runTest(data);
1094 }
1095
1096 // Same as IntUnnormalized but with glClear() before running the test to force
1097 // starting a render pass. This to verify that buffer format conversion within
1098 // an active render pass works as expected in Metal back-end.
TEST_P(VertexAttributeTestES3,IntUnnormalizedWithClear)1099 TEST_P(VertexAttributeTestES3, IntUnnormalizedWithClear)
1100 {
1101 GLint lo = std::numeric_limits<GLint>::min();
1102 GLint hi = std::numeric_limits<GLint>::max();
1103 std::array<GLint, kVertexCount> inputData = {
1104 {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1}};
1105 std::array<GLfloat, kVertexCount> expectedData;
1106 for (size_t i = 0; i < kVertexCount; i++)
1107 {
1108 expectedData[i] = static_cast<GLfloat>(inputData[i]);
1109 }
1110
1111 TestData data(GL_INT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1112 data.clearBeforeDraw = true;
1113
1114 runTest(data);
1115 }
1116
1117 // Same as IntNormalized but with glClear() before running the test to force
1118 // starting a render pass. This to verify that buffer format conversion within
1119 // an active render pass works as expected in Metal back-end.
TEST_P(VertexAttributeTestES3,IntNormalizedWithClear)1120 TEST_P(VertexAttributeTestES3, IntNormalizedWithClear)
1121 {
1122 GLint lo = std::numeric_limits<GLint>::min();
1123 GLint hi = std::numeric_limits<GLint>::max();
1124 std::array<GLint, kVertexCount> inputData = {
1125 {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1}};
1126 std::array<GLfloat, kVertexCount> expectedData;
1127 for (size_t i = 0; i < kVertexCount; i++)
1128 {
1129 expectedData[i] = Normalize(inputData[i]);
1130 }
1131
1132 TestData data(GL_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
1133 data.clearBeforeDraw = true;
1134
1135 runTest(data);
1136 }
1137
TEST_P(VertexAttributeTestES3,UnsignedIntUnnormalized)1138 TEST_P(VertexAttributeTestES3, UnsignedIntUnnormalized)
1139 {
1140 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
1141 GLuint hi = std::numeric_limits<GLuint>::max();
1142 std::array<GLuint, kVertexCount> inputData = {
1143 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
1144 std::array<GLfloat, kVertexCount> expectedData;
1145 for (size_t i = 0; i < kVertexCount; i++)
1146 {
1147 expectedData[i] = static_cast<GLfloat>(inputData[i]);
1148 }
1149
1150 TestData data(GL_UNSIGNED_INT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1151 runTest(data);
1152 }
1153
TEST_P(VertexAttributeTestES3,UnsignedIntNormalized)1154 TEST_P(VertexAttributeTestES3, UnsignedIntNormalized)
1155 {
1156 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
1157 GLuint hi = std::numeric_limits<GLuint>::max();
1158 std::array<GLuint, kVertexCount> inputData = {
1159 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
1160 std::array<GLfloat, kVertexCount> expectedData;
1161 for (size_t i = 0; i < kVertexCount; i++)
1162 {
1163 expectedData[i] = Normalize(inputData[i]);
1164 }
1165
1166 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
1167 runTest(data);
1168 }
1169
1170 // Same as UnsignedIntNormalized but with glClear() before running the test to force
1171 // starting a render pass. This to verify that buffer format conversion within
1172 // an active render pass works as expected in Metal back-end.
TEST_P(VertexAttributeTestES3,UnsignedIntNormalizedWithClear)1173 TEST_P(VertexAttributeTestES3, UnsignedIntNormalizedWithClear)
1174 {
1175 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
1176 GLuint hi = std::numeric_limits<GLuint>::max();
1177 std::array<GLuint, kVertexCount> inputData = {
1178 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
1179 std::array<GLfloat, kVertexCount> expectedData;
1180 for (size_t i = 0; i < kVertexCount; i++)
1181 {
1182 expectedData[i] = Normalize(inputData[i]);
1183 }
1184
1185 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
1186 data.clearBeforeDraw = true;
1187 runTest(data);
1188 }
1189
SetupColorsForUnitQuad(GLint location,const GLColor32F & color,GLenum usage,GLBuffer * vbo)1190 void SetupColorsForUnitQuad(GLint location, const GLColor32F &color, GLenum usage, GLBuffer *vbo)
1191 {
1192 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
1193 std::vector<GLColor32F> vertices(6, color);
1194 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLColor32F), vertices.data(), usage);
1195 glEnableVertexAttribArray(location);
1196 glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, 0);
1197 }
1198
1199 // Tests that rendering works as expected with VAOs.
TEST_P(VertexAttributeTestES3,VertexArrayObjectRendering)1200 TEST_P(VertexAttributeTestES3, VertexArrayObjectRendering)
1201 {
1202 constexpr char kVertexShader[] =
1203 "attribute vec4 a_position;\n"
1204 "attribute vec4 a_color;\n"
1205 "varying vec4 v_color;\n"
1206 "void main()\n"
1207 "{\n"
1208 " gl_Position = a_position;\n"
1209 " v_color = a_color;\n"
1210 "}";
1211
1212 constexpr char kFragmentShader[] =
1213 "precision mediump float;\n"
1214 "varying vec4 v_color;\n"
1215 "void main()\n"
1216 "{\n"
1217 " gl_FragColor = v_color;\n"
1218 "}";
1219
1220 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
1221
1222 GLint positionLoc = glGetAttribLocation(program, "a_position");
1223 ASSERT_NE(-1, positionLoc);
1224 GLint colorLoc = glGetAttribLocation(program, "a_color");
1225 ASSERT_NE(-1, colorLoc);
1226
1227 GLVertexArray vaos[2];
1228 GLBuffer positionBuffer;
1229 GLBuffer colorBuffers[2];
1230
1231 const auto &quadVertices = GetQuadVertices();
1232
1233 glBindVertexArray(vaos[0]);
1234 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
1235 glBufferData(GL_ARRAY_BUFFER, quadVertices.size() * sizeof(Vector3), quadVertices.data(),
1236 GL_STATIC_DRAW);
1237 glEnableVertexAttribArray(positionLoc);
1238 glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1239 SetupColorsForUnitQuad(colorLoc, kFloatRed, GL_STREAM_DRAW, &colorBuffers[0]);
1240
1241 glBindVertexArray(vaos[1]);
1242 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
1243 glEnableVertexAttribArray(positionLoc);
1244 glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1245 SetupColorsForUnitQuad(colorLoc, kFloatGreen, GL_STATIC_DRAW, &colorBuffers[1]);
1246
1247 glUseProgram(program);
1248 ASSERT_GL_NO_ERROR();
1249
1250 for (int ii = 0; ii < 2; ++ii)
1251 {
1252 glBindVertexArray(vaos[0]);
1253 glDrawArrays(GL_TRIANGLES, 0, 6);
1254 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1255
1256 glBindVertexArray(vaos[1]);
1257 glDrawArrays(GL_TRIANGLES, 0, 6);
1258 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1259 }
1260
1261 ASSERT_GL_NO_ERROR();
1262 }
1263
1264 // Validate that we can support GL_MAX_ATTRIBS attribs
TEST_P(VertexAttributeTest,MaxAttribs)1265 TEST_P(VertexAttributeTest, MaxAttribs)
1266 {
1267 // TODO(jmadill): Figure out why we get this error on AMD/OpenGL.
1268 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
1269
1270 GLint maxAttribs;
1271 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
1272 ASSERT_GL_NO_ERROR();
1273
1274 // Reserve one attrib for position
1275 GLint drawAttribs = maxAttribs - 1;
1276
1277 GLuint program = compileMultiAttribProgram(drawAttribs);
1278 ASSERT_NE(0u, program);
1279
1280 setupMultiAttribs(program, drawAttribs, 0.5f / static_cast<float>(drawAttribs));
1281 drawQuad(program, "position", 0.5f);
1282
1283 EXPECT_GL_NO_ERROR();
1284 EXPECT_PIXEL_NEAR(0, 0, 128, 0, 0, 255, 1);
1285 }
1286
1287 // Validate that we cannot support GL_MAX_ATTRIBS+1 attribs
TEST_P(VertexAttributeTest,MaxAttribsPlusOne)1288 TEST_P(VertexAttributeTest, MaxAttribsPlusOne)
1289 {
1290 // TODO(jmadill): Figure out why we get this error on AMD/ES2/OpenGL
1291 ANGLE_SKIP_TEST_IF(IsAMD() && GetParam() == ES2_OPENGL());
1292
1293 GLint maxAttribs;
1294 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
1295 ASSERT_GL_NO_ERROR();
1296
1297 // Exceed attrib count by one (counting position)
1298 GLint drawAttribs = maxAttribs;
1299
1300 GLuint program = compileMultiAttribProgram(drawAttribs);
1301 ASSERT_EQ(0u, program);
1302 }
1303
1304 // Simple test for when we use glBindAttribLocation
TEST_P(VertexAttributeTest,SimpleBindAttribLocation)1305 TEST_P(VertexAttributeTest, SimpleBindAttribLocation)
1306 {
1307 // Re-use the multi-attrib program, binding attribute 0
1308 GLuint program = compileMultiAttribProgram(1);
1309 glBindAttribLocation(program, 2, "position");
1310 glBindAttribLocation(program, 3, "a0");
1311 glLinkProgram(program);
1312
1313 // Setup and draw the quad
1314 setupMultiAttribs(program, 1, 0.5f);
1315 drawQuad(program, "position", 0.5f);
1316 EXPECT_GL_NO_ERROR();
1317 EXPECT_PIXEL_NEAR(0, 0, 128, 0, 0, 255, 1);
1318 }
1319
1320 class VertexAttributeOORTest : public VertexAttributeTest
1321 {
1322 public:
VertexAttributeOORTest()1323 VertexAttributeOORTest()
1324 {
1325 setWebGLCompatibilityEnabled(true);
1326 setRobustAccess(false);
1327 }
1328 };
1329
1330 class RobustVertexAttributeTest : public VertexAttributeTest
1331 {
1332 public:
RobustVertexAttributeTest()1333 RobustVertexAttributeTest()
1334 {
1335 // mac GL and metal do not support robustness.
1336 if (!IsMac() && !IsIOS())
1337 {
1338 setRobustAccess(true);
1339 }
1340 }
1341 };
1342
1343 // Verify that drawing with a large out-of-range offset generates INVALID_OPERATION.
1344 // Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest,ANGLEDrawArraysBufferTooSmall)1345 TEST_P(VertexAttributeOORTest, ANGLEDrawArraysBufferTooSmall)
1346 {
1347 // Test skipped due to supporting GL_KHR_robust_buffer_access_behavior
1348 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior"));
1349
1350 std::array<GLfloat, kVertexCount> inputData;
1351 std::array<GLfloat, kVertexCount> expectedData;
1352 InitTestData(inputData, expectedData);
1353
1354 TestData data(GL_FLOAT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1355 data.bufferOffset = kVertexCount * TypeStride(GL_FLOAT);
1356
1357 setupTest(data, 1);
1358 drawQuad(mProgram, "position", 0.5f);
1359 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1360 }
1361
1362 // Verify that index draw with an out-of-range offset generates INVALID_OPERATION.
1363 // Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest,ANGLEDrawElementsBufferTooSmall)1364 TEST_P(VertexAttributeOORTest, ANGLEDrawElementsBufferTooSmall)
1365 {
1366 // Test skipped due to supporting GL_KHR_robust_buffer_access_behavior
1367 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior"));
1368
1369 std::array<GLfloat, kVertexCount> inputData;
1370 std::array<GLfloat, kVertexCount> expectedData;
1371 InitTestData(inputData, expectedData);
1372
1373 TestData data(GL_FLOAT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1374 data.bufferOffset = (kVertexCount - 3) * TypeStride(GL_FLOAT);
1375
1376 setupTest(data, 1);
1377 drawIndexedQuad(mProgram, "position", 0.5f, 1.0f, true);
1378 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1379 }
1380
1381 // Verify that DrawArarys with an out-of-range offset generates INVALID_OPERATION.
1382 // Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest,ANGLEDrawArraysOutOfBoundsCases)1383 TEST_P(VertexAttributeOORTest, ANGLEDrawArraysOutOfBoundsCases)
1384 {
1385 // Test skipped due to supporting GL_KHR_robust_buffer_access_behavior
1386 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior"));
1387
1388 initBasicProgram();
1389
1390 GLfloat singleFloat = 1.0f;
1391 GLsizei dataSize = TypeStride(GL_FLOAT);
1392
1393 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1394 glBufferData(GL_ARRAY_BUFFER, dataSize, &singleFloat, GL_STATIC_DRAW);
1395 glVertexAttribPointer(mTestAttrib, 2, GL_FLOAT, GL_FALSE, 8, 0);
1396 glEnableVertexAttribArray(mTestAttrib);
1397 glBindBuffer(GL_ARRAY_BUFFER, 0);
1398
1399 drawIndexedQuad(mProgram, "position", 0.5f, 1.0f, true);
1400 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1401 }
1402
1403 // Test that enabling a buffer in an unused attribute doesn't crash. There should be an active
1404 // attribute after that.
TEST_P(RobustVertexAttributeTest,BoundButUnusedBuffer)1405 TEST_P(RobustVertexAttributeTest, BoundButUnusedBuffer)
1406 {
1407 constexpr char kVS[] = R"(attribute vec2 offset;
1408 void main()
1409 {
1410 gl_Position = vec4(offset.xy, 0, 1);
1411 gl_PointSize = 1.0;
1412 })";
1413
1414 constexpr char kFS[] = R"(precision mediump float;
1415 void main()
1416 {
1417 gl_FragColor = vec4(1.0, 0, 0, 1.0);
1418 })";
1419
1420 const GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
1421 const GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
1422
1423 GLuint program = glCreateProgram();
1424 glBindAttribLocation(program, 1, "offset");
1425 glAttachShader(program, vs);
1426 glAttachShader(program, fs);
1427 glLinkProgram(program);
1428
1429 GLBuffer buffer;
1430 glBindBuffer(GL_ARRAY_BUFFER, buffer);
1431 glBufferData(GL_ARRAY_BUFFER, 100, nullptr, GL_STATIC_DRAW);
1432
1433 // Enable an unused attribute that is within the range of active attributes (not beyond it)
1434 glEnableVertexAttribArray(0);
1435 glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);
1436
1437 glUseProgram(program);
1438 glDrawArrays(GL_TRIANGLES, 0, 6);
1439
1440 // Destroy the buffer. Regression test for a tracking bug where the buffer was used by
1441 // SwiftShader (even though location 1 is inactive), but not marked as used by ANGLE.
1442 buffer.reset();
1443 }
1444
1445 // Verify that using a different start vertex doesn't mess up the draw.
TEST_P(VertexAttributeTest,DrawArraysWithBufferOffset)1446 TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
1447 {
1448 initBasicProgram();
1449 glUseProgram(mProgram);
1450
1451 std::array<GLfloat, kVertexCount> inputData;
1452 std::array<GLfloat, kVertexCount> expectedData;
1453 InitTestData(inputData, expectedData);
1454
1455 GLBuffer quadBuffer;
1456 InitQuadPlusOneVertexBuffer(&quadBuffer);
1457
1458 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1459 ASSERT_NE(-1, positionLocation);
1460 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1461 glEnableVertexAttribArray(positionLocation);
1462
1463 GLsizei dataSize = kVertexCount * TypeStride(GL_FLOAT);
1464 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1465 glBufferData(GL_ARRAY_BUFFER, dataSize + TypeStride(GL_FLOAT), nullptr, GL_STATIC_DRAW);
1466 glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, inputData.data());
1467 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1468 glEnableVertexAttribArray(mTestAttrib);
1469
1470 glBindBuffer(GL_ARRAY_BUFFER, 0);
1471 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1472 glEnableVertexAttribArray(mExpectedAttrib);
1473
1474 // Vertex draw with no start vertex offset (second argument is zero).
1475 glDrawArrays(GL_TRIANGLES, 0, 6);
1476 checkPixels();
1477
1478 // Draw offset by one vertex.
1479 glDrawArrays(GL_TRIANGLES, 1, 6);
1480 checkPixels();
1481
1482 EXPECT_GL_NO_ERROR();
1483 }
1484
1485 // Verify that using an unaligned offset doesn't mess up the draw.
TEST_P(VertexAttributeTest,DrawArraysWithUnalignedBufferOffset)1486 TEST_P(VertexAttributeTest, DrawArraysWithUnalignedBufferOffset)
1487 {
1488 initBasicProgram();
1489 glUseProgram(mProgram);
1490
1491 std::array<GLfloat, kVertexCount> inputData;
1492 std::array<GLfloat, kVertexCount> expectedData;
1493 InitTestData(inputData, expectedData);
1494
1495 GLBuffer quadBuffer;
1496 InitQuadPlusOneVertexBuffer(&quadBuffer);
1497
1498 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1499 ASSERT_NE(-1, positionLocation);
1500 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1501 glEnableVertexAttribArray(positionLocation);
1502
1503 // Unaligned buffer offset (3)
1504 GLsizei dataSize = kVertexCount * TypeStride(GL_FLOAT) + 3;
1505 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1506 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1507 glBufferSubData(GL_ARRAY_BUFFER, 3, dataSize - 3, inputData.data());
1508 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(3));
1509 glEnableVertexAttribArray(mTestAttrib);
1510
1511 glBindBuffer(GL_ARRAY_BUFFER, 0);
1512 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1513 glEnableVertexAttribArray(mExpectedAttrib);
1514
1515 // Vertex draw with no start vertex offset (second argument is zero).
1516 glDrawArrays(GL_TRIANGLES, 0, 6);
1517 checkPixels();
1518
1519 // Draw offset by one vertex.
1520 glDrawArrays(GL_TRIANGLES, 1, 6);
1521 checkPixels();
1522
1523 EXPECT_GL_NO_ERROR();
1524 }
1525
1526 // Verify that using an unaligned offset & GL_SHORT vertex attribute doesn't mess up the draw.
1527 // In Metal backend, GL_SHORTx3 is coverted to GL_SHORTx4 if offset is unaligned.
TEST_P(VertexAttributeTest,DrawArraysWithUnalignedShortBufferOffset)1528 TEST_P(VertexAttributeTest, DrawArraysWithUnalignedShortBufferOffset)
1529 {
1530 initBasicProgram();
1531 glUseProgram(mProgram);
1532
1533 // input data is GL_SHORTx3 (6 bytes) but stride=8
1534 std::array<GLshort, 4 * kVertexCount> inputData;
1535 std::array<GLfloat, 3 * kVertexCount> expectedData;
1536 for (size_t i = 0; i < kVertexCount; ++i)
1537 {
1538 inputData[4 * i] = 3 * i;
1539 inputData[4 * i + 1] = 3 * i + 1;
1540 inputData[4 * i + 2] = 3 * i + 2;
1541
1542 expectedData[3 * i] = 3 * i;
1543 expectedData[3 * i + 1] = 3 * i + 1;
1544 expectedData[3 * i + 2] = 3 * i + 2;
1545 }
1546
1547 GLBuffer quadBuffer;
1548 InitQuadPlusOneVertexBuffer(&quadBuffer);
1549
1550 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1551 ASSERT_NE(-1, positionLocation);
1552 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1553 glEnableVertexAttribArray(positionLocation);
1554
1555 // Unaligned buffer offset (8)
1556 GLsizei dataSize = 3 * kVertexCount * TypeStride(GL_SHORT) + 8;
1557 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1558 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1559 glBufferSubData(GL_ARRAY_BUFFER, 8, dataSize - 8, inputData.data());
1560 glVertexAttribPointer(mTestAttrib, 3, GL_SHORT, GL_FALSE, /* stride */ 8,
1561 reinterpret_cast<void *>(8));
1562 glEnableVertexAttribArray(mTestAttrib);
1563
1564 glBindBuffer(GL_ARRAY_BUFFER, 0);
1565 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1566 glEnableVertexAttribArray(mExpectedAttrib);
1567
1568 // Vertex draw with no start vertex offset (second argument is zero).
1569 glDrawArrays(GL_TRIANGLES, 0, 6);
1570 checkPixels();
1571
1572 // Draw offset by one vertex.
1573 glDrawArrays(GL_TRIANGLES, 1, 6);
1574 checkPixels();
1575
1576 EXPECT_GL_NO_ERROR();
1577 }
1578
1579 // Verify that using a GL_FLOATx2 attribute with offset not divisible by 8 works.
TEST_P(VertexAttributeTest,DrawArraysWith2FloatAtOffsetNotDivisbleBy8)1580 TEST_P(VertexAttributeTest, DrawArraysWith2FloatAtOffsetNotDivisbleBy8)
1581 {
1582 initBasicProgram();
1583 glUseProgram(mProgram);
1584
1585 // input data is GL_FLOATx2 (8 bytes) and stride=36
1586 std::array<GLubyte, 36 * kVertexCount> inputData;
1587 std::array<GLfloat, 2 * kVertexCount> expectedData;
1588 for (size_t i = 0; i < kVertexCount; ++i)
1589 {
1590 expectedData[2 * i] = 2 * i;
1591 expectedData[2 * i + 1] = 2 * i + 1;
1592
1593 GLubyte *input = inputData.data() + 36 * i;
1594 memcpy(input, &expectedData[2 * i], sizeof(float));
1595 memcpy(input + sizeof(float), &expectedData[2 * i + 1], sizeof(float));
1596 }
1597
1598 GLBuffer quadBuffer;
1599 InitQuadPlusOneVertexBuffer(&quadBuffer);
1600
1601 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1602 ASSERT_NE(-1, positionLocation);
1603 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1604 glEnableVertexAttribArray(positionLocation);
1605
1606 // offset is not float2 aligned (28)
1607 GLsizei dataSize = 36 * kVertexCount + 28;
1608 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1609 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1610 glBufferSubData(GL_ARRAY_BUFFER, 28, dataSize - 28, inputData.data());
1611 glVertexAttribPointer(mTestAttrib, 2, GL_FLOAT, GL_FALSE, /* stride */ 36,
1612 reinterpret_cast<void *>(28));
1613 glEnableVertexAttribArray(mTestAttrib);
1614
1615 glBindBuffer(GL_ARRAY_BUFFER, 0);
1616 glVertexAttribPointer(mExpectedAttrib, 2, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1617 glEnableVertexAttribArray(mExpectedAttrib);
1618
1619 // Vertex draw with no start vertex offset (second argument is zero).
1620 glDrawArrays(GL_TRIANGLES, 0, 6);
1621 checkPixels();
1622
1623 // Draw offset by one vertex.
1624 glDrawArrays(GL_TRIANGLES, 1, 6);
1625 checkPixels();
1626
1627 EXPECT_GL_NO_ERROR();
1628 }
1629
1630 // Verify that using offset=1 for GL_BYTE vertex attribute doesn't mess up the draw.
1631 // Depending on backend, offset=1 for GL_BYTE could be natively supported or not.
1632 // In the latter case, a vertex data conversion will have to be performed.
TEST_P(VertexAttributeTest,DrawArraysWithByteAtOffset1)1633 TEST_P(VertexAttributeTest, DrawArraysWithByteAtOffset1)
1634 {
1635 initBasicProgram();
1636 glUseProgram(mProgram);
1637
1638 // input data is GL_BYTEx3 (3 bytes) but stride=4
1639 std::array<GLbyte, 4 * kVertexCount> inputData;
1640 std::array<GLfloat, 3 * kVertexCount> expectedData;
1641 for (size_t i = 0; i < kVertexCount; ++i)
1642 {
1643 inputData[4 * i] = 3 * i;
1644 inputData[4 * i + 1] = 3 * i + 1;
1645 inputData[4 * i + 2] = 3 * i + 2;
1646
1647 expectedData[3 * i] = 3 * i;
1648 expectedData[3 * i + 1] = 3 * i + 1;
1649 expectedData[3 * i + 2] = 3 * i + 2;
1650 }
1651
1652 GLBuffer quadBuffer;
1653 InitQuadPlusOneVertexBuffer(&quadBuffer);
1654
1655 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1656 ASSERT_NE(-1, positionLocation);
1657 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1658 glEnableVertexAttribArray(positionLocation);
1659
1660 // Buffer offset (1)
1661 GLsizei dataSize = 4 * kVertexCount + 1;
1662 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1663 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1664 glBufferSubData(GL_ARRAY_BUFFER, 1, dataSize - 1, inputData.data());
1665 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4,
1666 reinterpret_cast<void *>(1));
1667 glEnableVertexAttribArray(mTestAttrib);
1668
1669 glBindBuffer(GL_ARRAY_BUFFER, 0);
1670 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1671 glEnableVertexAttribArray(mExpectedAttrib);
1672
1673 // Vertex draw with no start vertex offset (second argument is zero).
1674 glDrawArrays(GL_TRIANGLES, 0, 6);
1675 checkPixels();
1676
1677 // Draw offset by one vertex.
1678 glDrawArrays(GL_TRIANGLES, 1, 6);
1679 checkPixels();
1680
1681 EXPECT_GL_NO_ERROR();
1682 }
1683
1684 // Verify that using an aligned but non-multiples of 4 offset vertex attribute doesn't mess up the
1685 // draw.
TEST_P(VertexAttributeTest,DrawArraysWithShortBufferOffsetNotMultipleOf4)1686 TEST_P(VertexAttributeTest, DrawArraysWithShortBufferOffsetNotMultipleOf4)
1687 {
1688 // http://anglebug.com/42263937
1689 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
1690
1691 initBasicProgram();
1692 glUseProgram(mProgram);
1693
1694 // input data is GL_SHORTx3 (6 bytes) but stride=8
1695 std::array<GLshort, 4 * kVertexCount> inputData;
1696 std::array<GLfloat, 3 * kVertexCount> expectedData;
1697 for (size_t i = 0; i < kVertexCount; ++i)
1698 {
1699 inputData[4 * i] = 3 * i;
1700 inputData[4 * i + 1] = 3 * i + 1;
1701 inputData[4 * i + 2] = 3 * i + 2;
1702
1703 expectedData[3 * i] = 3 * i;
1704 expectedData[3 * i + 1] = 3 * i + 1;
1705 expectedData[3 * i + 2] = 3 * i + 2;
1706 }
1707
1708 GLBuffer quadBuffer;
1709 InitQuadPlusOneVertexBuffer(&quadBuffer);
1710
1711 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1712 ASSERT_NE(-1, positionLocation);
1713 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1714 glEnableVertexAttribArray(positionLocation);
1715
1716 // Aligned but not multiples of 4 buffer offset (18)
1717 GLsizei dataSize = 4 * kVertexCount * TypeStride(GL_SHORT) + 8;
1718 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1719 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1720 glBufferSubData(GL_ARRAY_BUFFER, 18, dataSize - 18, inputData.data());
1721 glVertexAttribPointer(mTestAttrib, 3, GL_SHORT, GL_FALSE, /* stride */ 8,
1722 reinterpret_cast<void *>(18));
1723 glEnableVertexAttribArray(mTestAttrib);
1724
1725 glBindBuffer(GL_ARRAY_BUFFER, 0);
1726 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1727 glEnableVertexAttribArray(mExpectedAttrib);
1728
1729 // Vertex draw with no start vertex offset (second argument is zero).
1730 glDrawArrays(GL_TRIANGLES, 0, 6);
1731 checkPixels();
1732
1733 // Draw offset by one vertex.
1734 glDrawArrays(GL_TRIANGLES, 1, 6);
1735 checkPixels();
1736
1737 EXPECT_GL_NO_ERROR();
1738 }
1739
1740 // Verify that using both aligned and unaligned offsets doesn't mess up the draw.
TEST_P(VertexAttributeTest,DrawArraysWithAlignedAndUnalignedBufferOffset)1741 TEST_P(VertexAttributeTest, DrawArraysWithAlignedAndUnalignedBufferOffset)
1742 {
1743 initBasicProgram();
1744 glUseProgram(mProgram);
1745
1746 std::array<GLfloat, kVertexCount> inputData;
1747 std::array<GLfloat, kVertexCount> expectedData;
1748 InitTestData(inputData, expectedData);
1749
1750 GLBuffer quadBuffer;
1751 InitQuadPlusOneVertexBuffer(&quadBuffer);
1752
1753 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1754 ASSERT_NE(-1, positionLocation);
1755 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1756 glEnableVertexAttribArray(positionLocation);
1757
1758 // ----------- Aligned buffer offset (4) -------------
1759 GLsizei dataSize = kVertexCount * TypeStride(GL_FLOAT) + 4;
1760 GLBuffer alignedBufer;
1761 glBindBuffer(GL_ARRAY_BUFFER, alignedBufer);
1762 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1763 glBufferSubData(GL_ARRAY_BUFFER, 4, dataSize - 4, inputData.data());
1764 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(4));
1765 glEnableVertexAttribArray(mTestAttrib);
1766
1767 glBindBuffer(GL_ARRAY_BUFFER, 0);
1768 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1769 glEnableVertexAttribArray(mExpectedAttrib);
1770
1771 // Vertex draw with no start vertex offset (second argument is zero).
1772 glDrawArrays(GL_TRIANGLES, 0, 6);
1773 checkPixels();
1774
1775 // Draw offset by one vertex.
1776 glDrawArrays(GL_TRIANGLES, 1, 6);
1777 checkPixels();
1778
1779 // ----------- Unaligned buffer offset (3) -------------
1780 glClear(GL_COLOR_BUFFER_BIT);
1781
1782 dataSize = kVertexCount * TypeStride(GL_FLOAT) + 3;
1783 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1784 glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
1785 glBufferSubData(GL_ARRAY_BUFFER, 3, dataSize - 3, inputData.data());
1786 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(3));
1787 glEnableVertexAttribArray(mTestAttrib);
1788
1789 glBindBuffer(GL_ARRAY_BUFFER, 0);
1790 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1791 glEnableVertexAttribArray(mExpectedAttrib);
1792
1793 // Vertex draw with no start vertex offset (second argument is zero).
1794 glDrawArrays(GL_TRIANGLES, 0, 6);
1795 checkPixels();
1796
1797 // Draw offset by one vertex.
1798 glDrawArrays(GL_TRIANGLES, 1, 6);
1799 checkPixels();
1800
1801 EXPECT_GL_NO_ERROR();
1802 }
1803
1804 // Verify that when we pass a client memory pointer to a disabled attribute the draw is still
1805 // correct.
TEST_P(VertexAttributeTest,DrawArraysWithDisabledAttribute)1806 TEST_P(VertexAttributeTest, DrawArraysWithDisabledAttribute)
1807 {
1808 initBasicProgram();
1809
1810 std::array<GLfloat, kVertexCount> inputData;
1811 std::array<GLfloat, kVertexCount> expectedData;
1812 InitTestData(inputData, expectedData);
1813
1814 GLBuffer buffer;
1815 InitQuadVertexBuffer(&buffer);
1816
1817 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1818 ASSERT_NE(-1, positionLocation);
1819 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1820 glEnableVertexAttribArray(positionLocation);
1821
1822 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1823 glBufferData(GL_ARRAY_BUFFER, sizeof(inputData), inputData.data(), GL_STATIC_DRAW);
1824 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1825 glEnableVertexAttribArray(mTestAttrib);
1826
1827 glBindBuffer(GL_ARRAY_BUFFER, 0);
1828 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1829 glEnableVertexAttribArray(mExpectedAttrib);
1830
1831 // mProgram2 adds an attribute 'disabled' on the basis of mProgram.
1832 constexpr char testVertexShaderSource2[] =
1833 "attribute mediump vec4 position;\n"
1834 "attribute mediump vec4 test;\n"
1835 "attribute mediump vec4 expected;\n"
1836 "attribute mediump vec4 disabled;\n"
1837 "varying mediump vec4 color;\n"
1838 "void main(void)\n"
1839 "{\n"
1840 " gl_Position = position;\n"
1841 " vec4 threshold = max(abs(expected + disabled) * 0.005, 1.0 / 64.0);\n"
1842 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
1843 "}\n";
1844
1845 constexpr char testFragmentShaderSource[] =
1846 "varying mediump vec4 color;\n"
1847 "void main(void)\n"
1848 "{\n"
1849 " gl_FragColor = color;\n"
1850 "}\n";
1851
1852 ANGLE_GL_PROGRAM(program, testVertexShaderSource2, testFragmentShaderSource);
1853 GLuint mProgram2 = program;
1854
1855 ASSERT_EQ(positionLocation, glGetAttribLocation(mProgram2, "position"));
1856 ASSERT_EQ(mTestAttrib, glGetAttribLocation(mProgram2, "test"));
1857 ASSERT_EQ(mExpectedAttrib, glGetAttribLocation(mProgram2, "expected"));
1858
1859 // Pass a client memory pointer to disabledAttribute and disable it.
1860 GLint disabledAttribute = glGetAttribLocation(mProgram2, "disabled");
1861 ASSERT_EQ(-1, glGetAttribLocation(mProgram, "disabled"));
1862 glVertexAttribPointer(disabledAttribute, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1863 glDisableVertexAttribArray(disabledAttribute);
1864
1865 glUseProgram(mProgram);
1866 glDrawArrays(GL_TRIANGLES, 0, 6);
1867 checkPixels();
1868
1869 // Now enable disabledAttribute which should be used in mProgram2.
1870 glEnableVertexAttribArray(disabledAttribute);
1871 glUseProgram(mProgram2);
1872 glDrawArrays(GL_TRIANGLES, 0, 6);
1873 checkPixels();
1874
1875 EXPECT_GL_NO_ERROR();
1876 }
1877
1878 // Test based on WebGL Test attribs/gl-disabled-vertex-attrib.html
TEST_P(VertexAttributeTest,DisabledAttribArrays)1879 TEST_P(VertexAttributeTest, DisabledAttribArrays)
1880 {
1881 // Known failure on Retina MBP: http://crbug.com/635081
1882 ANGLE_SKIP_TEST_IF(IsMac() && IsNVIDIA());
1883
1884 constexpr char kVS[] =
1885 "attribute vec4 a_position;\n"
1886 "attribute vec4 a_color;\n"
1887 "varying vec4 v_color;\n"
1888 "bool isCorrectColor(vec4 v) {\n"
1889 " return v.x == 0.0 && v.y == 0.0 && v.z == 0.0 && v.w == 1.0;\n"
1890 "}"
1891 "void main() {\n"
1892 " gl_Position = a_position;\n"
1893 " v_color = isCorrectColor(a_color) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
1894 "}";
1895
1896 constexpr char kFS[] =
1897 "varying mediump vec4 v_color;\n"
1898 "void main() {\n"
1899 " gl_FragColor = v_color;\n"
1900 "}";
1901
1902 GLint maxVertexAttribs = 0;
1903 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
1904
1905 for (GLint colorIndex = 0; colorIndex < maxVertexAttribs; ++colorIndex)
1906 {
1907 GLuint program = CompileProgram(kVS, kFS, [&](GLuint program) {
1908 glBindAttribLocation(program, colorIndex, "a_color");
1909 });
1910 ASSERT_NE(0u, program);
1911
1912 drawQuad(program, "a_position", 0.5f);
1913 ASSERT_GL_NO_ERROR();
1914
1915 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green) << "color index " << colorIndex;
1916
1917 glDeleteProgram(program);
1918 }
1919 }
1920
1921 // Test that draw with offset larger than vertex attribute's stride can work
TEST_P(VertexAttributeTest,DrawWithLargeBufferOffset)1922 TEST_P(VertexAttributeTest, DrawWithLargeBufferOffset)
1923 {
1924 constexpr size_t kBufferOffset = 10000;
1925 constexpr size_t kQuadVertexCount = 4;
1926
1927 std::array<GLbyte, kQuadVertexCount> validInputData = {{0, 1, 2, 3}};
1928
1929 // 4 components
1930 std::array<GLbyte, 4 * kQuadVertexCount + kBufferOffset> inputData = {};
1931
1932 std::array<GLfloat, 4 * kQuadVertexCount> expectedData;
1933 for (size_t i = 0; i < kQuadVertexCount; i++)
1934 {
1935 for (int j = 0; j < 4; ++j)
1936 {
1937 inputData[kBufferOffset + 4 * i + j] = validInputData[i];
1938 expectedData[4 * i + j] = validInputData[i];
1939 }
1940 }
1941
1942 initBasicProgram();
1943
1944 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1945 glBufferData(GL_ARRAY_BUFFER, inputData.size(), inputData.data(), GL_STATIC_DRAW);
1946 glVertexAttribPointer(mTestAttrib, 4, GL_BYTE, GL_FALSE, 0,
1947 reinterpret_cast<const void *>(kBufferOffset));
1948 glEnableVertexAttribArray(mTestAttrib);
1949 glBindBuffer(GL_ARRAY_BUFFER, 0);
1950
1951 glVertexAttribPointer(mExpectedAttrib, 4, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1952 glEnableVertexAttribArray(mExpectedAttrib);
1953
1954 drawIndexedQuad(mProgram, "position", 0.5f);
1955
1956 checkPixels();
1957 }
1958
1959 // Test that drawing with large vertex attribute pointer offset and less components than
1960 // shader expects is OK
TEST_P(VertexAttributeTest,DrawWithLargeBufferOffsetAndLessComponents)1961 TEST_P(VertexAttributeTest, DrawWithLargeBufferOffsetAndLessComponents)
1962 {
1963 // Shader expects vec4 but glVertexAttribPointer only provides 2 components
1964 constexpr char kVS[] = R"(attribute vec4 a_position;
1965 attribute vec4 a_attrib;
1966 varying vec4 v_attrib;
1967 void main()
1968 {
1969 v_attrib = a_attrib;
1970 gl_Position = a_position;
1971 })";
1972
1973 constexpr char kFS[] = R"(precision mediump float;
1974 varying vec4 v_attrib;
1975 void main()
1976 {
1977 gl_FragColor = v_attrib;
1978 })";
1979
1980 ANGLE_GL_PROGRAM(program, kVS, kFS);
1981 glBindAttribLocation(program, 0, "a_position");
1982 glBindAttribLocation(program, 1, "a_attrib");
1983 glLinkProgram(program);
1984 glUseProgram(program);
1985 ASSERT_GL_NO_ERROR();
1986
1987 constexpr size_t kBufferOffset = 4998;
1988
1989 // Set up color data so yellow is drawn (only R, G components are provided)
1990 std::vector<GLushort> data(kBufferOffset + 12);
1991 for (int i = 0; i < 12; ++i)
1992 {
1993 data[kBufferOffset + i] = 0xffff;
1994 }
1995
1996 GLBuffer buffer;
1997 glBindBuffer(GL_ARRAY_BUFFER, buffer);
1998 glBufferData(GL_ARRAY_BUFFER, sizeof(GLushort) * data.size(), data.data(), GL_STATIC_DRAW);
1999 // Provide only 2 components for the vec4 in the shader
2000 glVertexAttribPointer(1, 2, GL_UNSIGNED_SHORT, GL_TRUE, 0,
2001 reinterpret_cast<const void *>(sizeof(GLushort) * kBufferOffset));
2002 glBindBuffer(GL_ARRAY_BUFFER, 0);
2003 glEnableVertexAttribArray(1);
2004
2005 drawQuad(program, "a_position", 0.5f);
2006 // Verify yellow was drawn
2007 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
2008 }
2009
2010 // Test that drawing with vertex attribute pointer with two non-overlapping BufferSubData calls
2011 // works correctly, especially when vertex conversion is involved.
TEST_P(VertexAttributeTest,DrawArraysWithNonOverlapBufferSubData)2012 TEST_P(VertexAttributeTest, DrawArraysWithNonOverlapBufferSubData)
2013 {
2014 constexpr size_t vertexCount = 6;
2015 initBasicProgram();
2016 glUseProgram(mProgram);
2017
2018 // input data is GL_BYTEx3 (3 bytes) but stride=4
2019 std::array<GLbyte, 4 * vertexCount> inputData;
2020 std::array<GLfloat, 3 * vertexCount> expectedData;
2021 for (size_t i = 0; i < vertexCount; ++i)
2022 {
2023 inputData[4 * i] = 3 * i;
2024 inputData[4 * i + 1] = 3 * i + 1;
2025 inputData[4 * i + 2] = 3 * i + 2;
2026
2027 expectedData[3 * i] = 3 * i;
2028 expectedData[3 * i + 1] = 3 * i + 1;
2029 expectedData[3 * i + 2] = 3 * i + 2;
2030 }
2031
2032 GLBuffer quadBuffer;
2033 InitQuadVertexBuffer(&quadBuffer);
2034 GLint positionLocation = glGetAttribLocation(mProgram, "position");
2035 ASSERT_NE(-1, positionLocation);
2036 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2037 glEnableVertexAttribArray(positionLocation);
2038
2039 GLsizei fullDataSize = 4 * vertexCount;
2040 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2041 glBufferData(GL_ARRAY_BUFFER, fullDataSize, nullptr, GL_STATIC_DRAW);
2042 glBufferSubData(GL_ARRAY_BUFFER, 0, fullDataSize, inputData.data());
2043 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4, nullptr);
2044 glEnableVertexAttribArray(mTestAttrib);
2045
2046 glBindBuffer(GL_ARRAY_BUFFER, 0);
2047 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
2048 glEnableVertexAttribArray(mExpectedAttrib);
2049
2050 // Draw quad and verify data
2051 glClearColor(0, 0, 0, 0);
2052 glClear(GL_COLOR_BUFFER_BIT);
2053 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
2054 checkPixels();
2055
2056 // Update data with two non-overlapping BufferSubData calls with different set of data
2057 for (size_t i = 0; i < vertexCount; ++i)
2058 {
2059 inputData[4 * i] = 3 * (i + vertexCount);
2060 inputData[4 * i + 1] = 3 * (i + vertexCount) + 1;
2061 inputData[4 * i + 2] = 3 * (i + vertexCount) + 2;
2062
2063 expectedData[3 * i] = 3 * (i + vertexCount);
2064 expectedData[3 * i + 1] = 3 * (i + vertexCount) + 1;
2065 expectedData[3 * i + 2] = 3 * (i + vertexCount) + 2;
2066 }
2067 size_t halfDataSize = fullDataSize / 2;
2068 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2069 glBufferSubData(GL_ARRAY_BUFFER, 0, halfDataSize, inputData.data());
2070 glBufferSubData(GL_ARRAY_BUFFER, halfDataSize, fullDataSize - halfDataSize,
2071 inputData.data() + halfDataSize);
2072 glBindBuffer(GL_ARRAY_BUFFER, 0);
2073 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
2074
2075 // Draw quad and verify data
2076 glDrawArrays(GL_TRIANGLES, 0, 6);
2077 checkPixels();
2078
2079 EXPECT_GL_NO_ERROR();
2080 }
2081
2082 // Test that drawing with vertex attribute pointer with two overlapping BufferSubData calls works
2083 // correctly, especially when vertex conversion is involved.
TEST_P(VertexAttributeTest,DrawArraysWithOverlapBufferSubData)2084 TEST_P(VertexAttributeTest, DrawArraysWithOverlapBufferSubData)
2085 {
2086 constexpr size_t vertexCount = 6;
2087 initBasicProgram();
2088 glUseProgram(mProgram);
2089
2090 // input data is GL_BYTEx3 (3 bytes) but stride=4
2091 std::array<GLbyte, 4 * vertexCount> inputData;
2092 std::array<GLfloat, 3 * vertexCount> expectedData;
2093 for (size_t i = 0; i < vertexCount; ++i)
2094 {
2095 inputData[4 * i] = 3 * i;
2096 inputData[4 * i + 1] = 3 * i + 1;
2097 inputData[4 * i + 2] = 3 * i + 2;
2098
2099 expectedData[3 * i] = 3 * i;
2100 expectedData[3 * i + 1] = 3 * i + 1;
2101 expectedData[3 * i + 2] = 3 * i + 2;
2102 }
2103
2104 GLBuffer quadBuffer;
2105 InitQuadVertexBuffer(&quadBuffer);
2106 GLint positionLocation = glGetAttribLocation(mProgram, "position");
2107 ASSERT_NE(-1, positionLocation);
2108 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2109 glEnableVertexAttribArray(positionLocation);
2110
2111 GLsizei fullDataSize = 4 * vertexCount;
2112 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2113 glBufferData(GL_ARRAY_BUFFER, fullDataSize, nullptr, GL_STATIC_DRAW);
2114 glBufferSubData(GL_ARRAY_BUFFER, 0, fullDataSize, inputData.data());
2115 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4, nullptr);
2116 glEnableVertexAttribArray(mTestAttrib);
2117
2118 glBindBuffer(GL_ARRAY_BUFFER, 0);
2119 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
2120 glEnableVertexAttribArray(mExpectedAttrib);
2121
2122 // Draw quad and verify data
2123 glClearColor(0, 0, 0, 0);
2124 glClear(GL_COLOR_BUFFER_BIT);
2125 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
2126 checkPixels();
2127
2128 // Update data with two overlapping BufferSubData calls with different set of data.
2129 size_t halfVertexCount = vertexCount / 2;
2130 size_t quadDataSize = fullDataSize / 4;
2131 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2132 // First subData is for the first 3 quarter of buffer, but only first half contains valid data.
2133 for (size_t i = 0; i < vertexCount; ++i)
2134 {
2135 if (i < halfVertexCount)
2136 {
2137 inputData[4 * i] = 3 * (i + vertexCount);
2138 inputData[4 * i + 1] = 3 * (i + vertexCount) + 1;
2139 inputData[4 * i + 2] = 3 * (i + vertexCount) + 2;
2140 }
2141 else
2142 {
2143 inputData[4 * i] = 0;
2144 inputData[4 * i + 1] = 0;
2145 inputData[4 * i + 2] = 0;
2146 }
2147
2148 expectedData[3 * i] = 3 * (i + vertexCount);
2149 expectedData[3 * i + 1] = 3 * (i + vertexCount) + 1;
2150 expectedData[3 * i + 2] = 3 * (i + vertexCount) + 2;
2151 }
2152 glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * quadDataSize, inputData.data());
2153 // Second subData call is for the last half buffer, which overlaps with previous subData range.
2154 size_t halfDataSize = fullDataSize / 2;
2155 for (size_t i = halfVertexCount; i < vertexCount; ++i)
2156 {
2157 inputData[4 * i] = 3 * (i + vertexCount);
2158 inputData[4 * i + 1] = 3 * (i + vertexCount) + 1;
2159 inputData[4 * i + 2] = 3 * (i + vertexCount) + 2;
2160 }
2161 glBufferSubData(GL_ARRAY_BUFFER, halfDataSize, fullDataSize - halfDataSize,
2162 inputData.data() + halfDataSize);
2163 glBindBuffer(GL_ARRAY_BUFFER, 0);
2164 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
2165
2166 // Draw quad and verify data
2167 glDrawArrays(GL_TRIANGLES, 0, 6);
2168 checkPixels();
2169
2170 EXPECT_GL_NO_ERROR();
2171 }
2172
2173 // Test that drawing with vertex attribute pointer with different offset. The second offset is
2174 // multiple stride after first offset.
TEST_P(VertexAttributeTest,DrawArraysWithLargerBindingOffset)2175 TEST_P(VertexAttributeTest, DrawArraysWithLargerBindingOffset)
2176 {
2177 constexpr size_t vertexCount = 6;
2178 initBasicProgram();
2179 glUseProgram(mProgram);
2180
2181 // input data is GL_BYTEx3 (3 bytes) but stride=4
2182 std::array<GLbyte, 4 * vertexCount * 2> inputData;
2183 std::array<GLfloat, 3 * vertexCount * 2> expectedData;
2184 for (size_t i = 0; i < vertexCount * 2; ++i)
2185 {
2186 inputData[4 * i] = 3 * i;
2187 inputData[4 * i + 1] = 3 * i + 1;
2188 inputData[4 * i + 2] = 3 * i + 2;
2189
2190 expectedData[3 * i] = 3 * i;
2191 expectedData[3 * i + 1] = 3 * i + 1;
2192 expectedData[3 * i + 2] = 3 * i + 2;
2193 }
2194
2195 GLBuffer quadBuffer;
2196 InitQuadVertexBuffer(&quadBuffer);
2197 GLint positionLocation = glGetAttribLocation(mProgram, "position");
2198 ASSERT_NE(-1, positionLocation);
2199 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2200 glEnableVertexAttribArray(positionLocation);
2201
2202 GLsizei fullDataSize = 4 * vertexCount * 2;
2203 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2204 glBufferData(GL_ARRAY_BUFFER, fullDataSize, nullptr, GL_STATIC_DRAW);
2205 glBufferSubData(GL_ARRAY_BUFFER, 0, fullDataSize, inputData.data());
2206 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4, /*offset*/ nullptr);
2207 glEnableVertexAttribArray(mTestAttrib);
2208
2209 glBindBuffer(GL_ARRAY_BUFFER, 0);
2210 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, /*data*/ expectedData.data());
2211 glEnableVertexAttribArray(mExpectedAttrib);
2212
2213 // Draw quad and verify data
2214 glClearColor(0, 0, 0, 0);
2215 glClear(GL_COLOR_BUFFER_BIT);
2216 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
2217 checkPixels();
2218
2219 // Now bind to a larger offset and then draw and verify
2220 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2221 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4,
2222 reinterpret_cast<const void *>(4 * vertexCount));
2223 glBindBuffer(GL_ARRAY_BUFFER, 0);
2224 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0,
2225 expectedData.data() + 3 * vertexCount);
2226 // Draw quad and verify data
2227 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
2228 checkPixels();
2229
2230 EXPECT_GL_NO_ERROR();
2231 }
2232
2233 // Test that drawing with vertex attribute pointer with different offset. The second offset is
2234 // multiple stride before first offset.
TEST_P(VertexAttributeTest,DrawArraysWithSmallerBindingOffset)2235 TEST_P(VertexAttributeTest, DrawArraysWithSmallerBindingOffset)
2236 {
2237 constexpr size_t vertexCount = 6;
2238 initBasicProgram();
2239 glUseProgram(mProgram);
2240
2241 // input data is GL_BYTEx3 (3 bytes) but stride=4
2242 std::array<GLbyte, 4 * vertexCount * 2> inputData;
2243 std::array<GLfloat, 3 * vertexCount * 2> expectedData;
2244 for (size_t i = 0; i < vertexCount * 2; ++i)
2245 {
2246 inputData[4 * i] = 3 * i;
2247 inputData[4 * i + 1] = 3 * i + 1;
2248 inputData[4 * i + 2] = 3 * i + 2;
2249
2250 expectedData[3 * i] = 3 * i;
2251 expectedData[3 * i + 1] = 3 * i + 1;
2252 expectedData[3 * i + 2] = 3 * i + 2;
2253 }
2254
2255 GLBuffer quadBuffer;
2256 InitQuadVertexBuffer(&quadBuffer);
2257 GLint positionLocation = glGetAttribLocation(mProgram, "position");
2258 ASSERT_NE(-1, positionLocation);
2259 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2260 glEnableVertexAttribArray(positionLocation);
2261
2262 GLsizei fullDataSize = 4 * vertexCount * 2;
2263 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2264 glBufferData(GL_ARRAY_BUFFER, fullDataSize, nullptr, GL_STATIC_DRAW);
2265 glBufferSubData(GL_ARRAY_BUFFER, 0, fullDataSize, inputData.data());
2266 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4,
2267 reinterpret_cast<const void *>(4 * vertexCount));
2268 glEnableVertexAttribArray(mTestAttrib);
2269
2270 glBindBuffer(GL_ARRAY_BUFFER, 0);
2271 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0,
2272 expectedData.data() + 3 * vertexCount);
2273 glEnableVertexAttribArray(mExpectedAttrib);
2274
2275 // Draw quad and verify data
2276 glClearColor(0, 0, 0, 0);
2277 glClear(GL_COLOR_BUFFER_BIT);
2278 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
2279 checkPixels();
2280
2281 // Now bind to a smaller offset and draw and verify.
2282 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2283 glVertexAttribPointer(mTestAttrib, 3, GL_BYTE, GL_FALSE, /* stride */ 4, /*offset*/ nullptr);
2284 glBindBuffer(GL_ARRAY_BUFFER, 0);
2285 glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, /*data*/ expectedData.data());
2286 // Draw quad and verify data
2287 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
2288 checkPixels();
2289
2290 EXPECT_GL_NO_ERROR();
2291 }
2292
2293 // Tests that we do not generate a SIGBUS error on arm when translating unaligned data.
2294 // GL_RG32_SNORM_ANGLEX is used when using glVertexAttribPointer with certain parameters.
TEST_P(VertexAttributeTestES3,DrawWithUnalignedData)2295 TEST_P(VertexAttributeTestES3, DrawWithUnalignedData)
2296 {
2297 constexpr char kVS[] = R"(#version 300 es
2298 precision highp float;
2299 in highp vec4 a_position;
2300 in highp vec2 a_ColorTest;
2301 out highp vec2 v_colorTest;
2302
2303 void main() {
2304 v_colorTest = a_ColorTest;
2305 gl_Position = a_position;
2306 })";
2307
2308 constexpr char kFS[] = R"(#version 300 es
2309 precision highp float;
2310 in highp vec2 v_colorTest;
2311 out vec4 fragColor;
2312
2313 void main() {
2314 // The input value is 0x01000000 / 0x7FFFFFFF
2315 if(abs(v_colorTest.x - 0.0078125) < 0.001) {
2316 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2317 } else {
2318 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2319 }
2320 })";
2321
2322 ANGLE_GL_PROGRAM(program, kVS, kFS);
2323 glBindAttribLocation(program, 0, "a_position");
2324 glBindAttribLocation(program, 1, "a_ColorTest");
2325 glLinkProgram(program);
2326 glUseProgram(program);
2327 ASSERT_GL_NO_ERROR();
2328
2329 constexpr size_t kDataSize = 12;
2330
2331 // Initialize vertex attribute data with 1u32s, but shifted right by a variable number of bytes
2332 GLubyte colorTestData[(kDataSize + 1) * sizeof(GLuint)];
2333
2334 for (size_t offset = 0; offset < sizeof(GLuint); offset++)
2335 {
2336 for (size_t dataIndex = 0; dataIndex < kDataSize * sizeof(GLuint); dataIndex++)
2337 {
2338 if (dataIndex % sizeof(GLuint) == sizeof(GLuint) - 1)
2339 {
2340 colorTestData[dataIndex + offset] = 1;
2341 }
2342 else
2343 {
2344
2345 colorTestData[dataIndex + offset] = 0;
2346 }
2347 }
2348
2349 GLubyte *offsetPtr = &colorTestData[offset];
2350 glVertexAttribPointer(1, 2, GL_INT, GL_TRUE, sizeof(GLuint), offsetPtr);
2351
2352 glBindBuffer(GL_ARRAY_BUFFER, 0);
2353 glEnableVertexAttribArray(1);
2354
2355 drawIndexedQuad(program, "a_position", 0.5f, 1.0f, false, true);
2356
2357 // Verify green was drawn.
2358 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green);
2359 ASSERT_GL_NO_ERROR();
2360 }
2361 }
2362
2363 // Tests that rendering is fine if GL_ANGLE_relaxed_vertex_attribute_type is enabled
2364 // and mismatched integer signedness between the program's attribute type and the
2365 // attribute type specified by VertexAttribIPointer are used.
TEST_P(VertexAttributeTestES3,DrawWithRelaxedVertexAttributeType)2366 TEST_P(VertexAttributeTestES3, DrawWithRelaxedVertexAttributeType)
2367 {
2368 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
2369
2370 constexpr char kVS[] = R"(#version 300 es
2371 precision highp float;
2372 in highp vec4 a_position;
2373 in highp ivec4 a_ColorTest;
2374 out highp vec4 v_colorTest;
2375
2376 void main() {
2377 v_colorTest = vec4(a_ColorTest);
2378 gl_Position = a_position;
2379 })";
2380
2381 constexpr char kFS[] = R"(#version 300 es
2382 precision highp float;
2383 in highp vec4 v_colorTest;
2384 out vec4 fragColor;
2385
2386 void main() {
2387 if(v_colorTest.x > 0.5) {
2388 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2389 } else {
2390 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2391 }
2392 })";
2393
2394 ANGLE_GL_PROGRAM(program, kVS, kFS);
2395 glBindAttribLocation(program, 0, "a_position");
2396 glBindAttribLocation(program, 1, "a_ColorTest");
2397 glLinkProgram(program);
2398 glUseProgram(program);
2399 ASSERT_GL_NO_ERROR();
2400
2401 constexpr size_t kDataSize = 48;
2402
2403 // Interleave test data with 0's.
2404 // This guards against a future code change that adjusts stride to 0
2405
2406 // clang-format off
2407 constexpr GLuint kColorTestData[kDataSize] = {
2408 // Vertex attribute data Unused data
2409 0u, 0u, 0u, 0u, /*red*/ 0u, 0u, 0u, 0u,
2410 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2411 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2412 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2413 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2414 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u
2415 };
2416 // clang-format on
2417
2418 GLBuffer buffer;
2419 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2420 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * kDataSize, kColorTestData, GL_STATIC_DRAW);
2421
2422 glVertexAttribIPointer(1, 4, GL_UNSIGNED_INT, 8 * sizeof(GLuint),
2423 reinterpret_cast<const void *>(0));
2424
2425 glBindBuffer(GL_ARRAY_BUFFER, 0);
2426 glEnableVertexAttribArray(1);
2427
2428 drawQuad(program, "a_position", 0.5f);
2429
2430 // Verify green was drawn. If the stride isn't adjusted to 0 this corner will be green. If it is
2431 // adjusted to 0, the whole image will be red
2432 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green);
2433 ASSERT_GL_NO_ERROR();
2434 }
2435
2436 // Test that ensures we do not send data for components not specified by glVertexAttribPointer when
2437 // component types and sizes are mismatched
TEST_P(VertexAttributeTestES3,DrawWithMismatchedComponentCount)2438 TEST_P(VertexAttributeTestES3, DrawWithMismatchedComponentCount)
2439 {
2440 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
2441
2442 // To ensure the test results are valid when we don't send data for every component, the
2443 // shader's values must be defined by the backend.
2444 // Vulkan Spec 22.3. Vertex Attribute Divisor in Instanced Rendering
2445 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#_vertex_attribute_divisor_in_instanced_rendering
2446 // If the format does not include G, B, or A components, then those are filled with (0,0,1) as
2447 // needed (using either 1.0f or integer 1 based on the format) for attributes that are not
2448 // 64-bit data types.
2449 ANGLE_SKIP_TEST_IF(!IsVulkan());
2450
2451 constexpr char kVS[] = R"(#version 300 es
2452 precision highp float;
2453 in highp vec4 a_position;
2454 in highp ivec2 a_ColorTest;
2455 out highp vec2 v_colorTest;
2456
2457 void main() {
2458 v_colorTest = vec2(a_ColorTest);
2459 gl_Position = a_position;
2460 })";
2461
2462 constexpr char kFS[] = R"(#version 300 es
2463 precision highp float;
2464 in highp vec2 v_colorTest;
2465 out vec4 fragColor;
2466
2467 void main() {
2468 if(v_colorTest.y < 0.5) {
2469 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2470 } else {
2471 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2472 }
2473 })";
2474
2475 ANGLE_GL_PROGRAM(program, kVS, kFS);
2476 glBindAttribLocation(program, 0, "a_position");
2477 glBindAttribLocation(program, 1, "a_ColorTest");
2478 glLinkProgram(program);
2479 glUseProgram(program);
2480 ASSERT_GL_NO_ERROR();
2481
2482 constexpr size_t kDataSize = 24;
2483
2484 // Initialize vertex attribute data with 1s.
2485 GLuint kColorTestData[kDataSize];
2486 for (size_t dataIndex = 0; dataIndex < kDataSize; dataIndex++)
2487 {
2488 kColorTestData[dataIndex] = 1u;
2489 }
2490
2491 GLBuffer buffer;
2492 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2493 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * kDataSize, kColorTestData, GL_STATIC_DRAW);
2494
2495 glVertexAttribIPointer(1, 1, GL_UNSIGNED_INT, 4 * sizeof(GLuint),
2496 reinterpret_cast<const void *>(0));
2497
2498 glBindBuffer(GL_ARRAY_BUFFER, 0);
2499 glEnableVertexAttribArray(1);
2500
2501 drawQuad(program, "a_position", 0.5f);
2502
2503 // Verify green was drawn.
2504 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
2505 ASSERT_GL_NO_ERROR();
2506 }
2507
2508 // Test that ensures we do not send data for components not specified by glVertexAttribPointer when
2509 // component types and sizes are mismatched. Also guard against out of bound errors when atttribute
2510 // locations are specified.
TEST_P(VertexAttributeTestES3,DrawWithMismatchedComponentCountLocationSpecified)2511 TEST_P(VertexAttributeTestES3, DrawWithMismatchedComponentCountLocationSpecified)
2512 {
2513 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
2514
2515 // To ensure the test results are valid when we don't send data for every component, the
2516 // shader's values must be defined by the backend.
2517 // Vulkan Spec 22.3. Vertex Attribute Divisor in Instanced Rendering
2518 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#_vertex_attribute_divisor_in_instanced_rendering
2519 // If the format does not include G, B, or A components, then those are filled with (0,0,1) as
2520 // needed (using either 1.0f or integer 1 based on the format) for attributes that are not
2521 // 64-bit data types.
2522 ANGLE_SKIP_TEST_IF(!IsVulkan());
2523
2524 constexpr char kVS[] = R"(#version 300 es
2525 precision highp float;
2526 layout(location = 2) in highp vec4 a_position;
2527 layout(location = 0) in highp ivec2 a_ColorTest;
2528 out highp vec2 v_colorTest;
2529
2530 void main() {
2531 v_colorTest = vec2(a_ColorTest);
2532 gl_Position = a_position;
2533 })";
2534
2535 constexpr char kFS[] = R"(#version 300 es
2536 precision highp float;
2537 in highp vec2 v_colorTest;
2538 out vec4 fragColor;
2539
2540 void main() {
2541 if(v_colorTest.y < 0.5) {
2542 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2543 } else {
2544 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2545 }
2546 })";
2547
2548 ANGLE_GL_PROGRAM(program, kVS, kFS);
2549 glLinkProgram(program);
2550 glUseProgram(program);
2551 ASSERT_GL_NO_ERROR();
2552
2553 constexpr size_t kDataSize = 24;
2554
2555 // Initialize vertex attribute data with 1s.
2556 GLuint kColorTestData[kDataSize];
2557 for (size_t dataIndex = 0; dataIndex < kDataSize; dataIndex++)
2558 {
2559 kColorTestData[dataIndex] = 1u;
2560 }
2561
2562 GLBuffer buffer;
2563 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2564 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * kDataSize, kColorTestData, GL_STATIC_DRAW);
2565
2566 GLint colorLocation = glGetAttribLocation(program, "a_ColorTest");
2567 ASSERT_NE(colorLocation, -1);
2568 glVertexAttribIPointer(colorLocation, 1, GL_UNSIGNED_INT, 4 * sizeof(GLuint),
2569 reinterpret_cast<const void *>(0));
2570
2571 glBindBuffer(GL_ARRAY_BUFFER, 0);
2572 glEnableVertexAttribArray(1);
2573
2574 drawQuad(program, "a_position", 0.5f);
2575
2576 // Verify green was drawn.
2577 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
2578 ASSERT_GL_NO_ERROR();
2579 }
2580
2581 class VertexAttributeTestES31 : public VertexAttributeTestES3
2582 {
2583 protected:
VertexAttributeTestES31()2584 VertexAttributeTestES31() {}
2585
initTest()2586 void initTest()
2587 {
2588 initBasicProgram();
2589 glUseProgram(mProgram);
2590
2591 glGenVertexArrays(1, &mVAO);
2592 glBindVertexArray(mVAO);
2593
2594 auto quadVertices = GetQuadVertices();
2595 GLsizeiptr quadVerticesSize =
2596 static_cast<GLsizeiptr>(quadVertices.size() * sizeof(quadVertices[0]));
2597 glGenBuffers(1, &mQuadBuffer);
2598 glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
2599 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, quadVertices.data(), GL_STATIC_DRAW);
2600
2601 GLint positionLocation = glGetAttribLocation(mProgram, "position");
2602 ASSERT_NE(-1, positionLocation);
2603 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2604 glEnableVertexAttribArray(positionLocation);
2605
2606 std::array<GLfloat, kVertexCount> expectedData;
2607 for (size_t count = 0; count < kVertexCount; ++count)
2608 {
2609 expectedData[count] = static_cast<GLfloat>(count);
2610 }
2611
2612 const GLsizei kExpectedDataSize = kVertexCount * kFloatStride;
2613 glGenBuffers(1, &mExpectedBuffer);
2614 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2615 glBufferData(GL_ARRAY_BUFFER, kExpectedDataSize, expectedData.data(), GL_STATIC_DRAW);
2616 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
2617 glEnableVertexAttribArray(mExpectedAttrib);
2618 }
2619
testTearDown()2620 void testTearDown() override
2621 {
2622 VertexAttributeTestES3::testTearDown();
2623
2624 glDeleteBuffers(1, &mQuadBuffer);
2625 glDeleteBuffers(1, &mExpectedBuffer);
2626 glDeleteVertexArrays(1, &mVAO);
2627 }
2628
drawArraysWithStrideAndRelativeOffset(GLint stride,GLuint relativeOffset)2629 void drawArraysWithStrideAndRelativeOffset(GLint stride, GLuint relativeOffset)
2630 {
2631 initTest();
2632
2633 GLint floatStride = std::max(stride / kFloatStride, 1);
2634 GLuint floatRelativeOffset = relativeOffset / kFloatStride;
2635 size_t floatCount = static_cast<size_t>(floatRelativeOffset) + kVertexCount * floatStride;
2636 GLsizeiptr inputSize = static_cast<GLsizeiptr>(floatCount) * kFloatStride;
2637
2638 std::vector<GLfloat> inputData(floatCount);
2639 for (size_t count = 0; count < kVertexCount; ++count)
2640 {
2641 inputData[floatRelativeOffset + count * floatStride] = static_cast<GLfloat>(count);
2642 }
2643
2644 // Ensure inputSize, inputStride and inputOffset are multiples of TypeStride(GL_FLOAT).
2645 GLsizei inputStride = floatStride * kFloatStride;
2646 GLsizeiptr inputRelativeOffset = floatRelativeOffset * kFloatStride;
2647 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2648 glBufferData(GL_ARRAY_BUFFER, inputSize, nullptr, GL_STATIC_DRAW);
2649 glBufferSubData(GL_ARRAY_BUFFER, 0, inputSize, inputData.data());
2650 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE,
2651 base::checked_cast<GLuint>(inputRelativeOffset));
2652 glBindVertexBuffer(mTestAttrib, mBuffer, 0, inputStride);
2653 glEnableVertexAttribArray(mTestAttrib);
2654
2655 glDrawArrays(GL_TRIANGLES, 0, 6);
2656 checkPixels();
2657
2658 EXPECT_GL_NO_ERROR();
2659 }
2660
initOnlyUpdateBindingTest(GLint bindingToUpdate)2661 void initOnlyUpdateBindingTest(GLint bindingToUpdate)
2662 {
2663 initTest();
2664
2665 constexpr GLuint kTestFloatOffset1 = kVertexCount;
2666 std::array<GLfloat, kTestFloatOffset1 + kVertexCount> inputData1 = {};
2667 for (size_t count = 0; count < kVertexCount; ++count)
2668 {
2669 GLfloat value = static_cast<GLfloat>(count);
2670 inputData1[kTestFloatOffset1 + count] = value;
2671 }
2672
2673 GLBuffer testBuffer1;
2674 glBindBuffer(GL_ARRAY_BUFFER, testBuffer1);
2675 glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
2676 GL_STATIC_DRAW);
2677
2678 ASSERT_NE(bindingToUpdate, mTestAttrib);
2679 ASSERT_NE(bindingToUpdate, mExpectedAttrib);
2680
2681 // Set mTestAttrib using the binding bindingToUpdate.
2682 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0);
2683 glBindVertexBuffer(bindingToUpdate, testBuffer1, kTestFloatOffset1 * kFloatStride,
2684 kFloatStride);
2685 glVertexAttribBinding(mTestAttrib, bindingToUpdate);
2686 glEnableVertexAttribArray(mTestAttrib);
2687
2688 // In the first draw the current VAO states are set to driver.
2689 glDrawArrays(GL_TRIANGLES, 0, 6);
2690 checkPixels();
2691 EXPECT_GL_NO_ERROR();
2692
2693 // We need the second draw to ensure all VAO dirty bits are reset.
2694 // e.g. On D3D11 back-ends, Buffer11::resize is called in the first draw, where the related
2695 // binding is set to dirty again.
2696 glDrawArrays(GL_TRIANGLES, 0, 6);
2697 checkPixels();
2698 EXPECT_GL_NO_ERROR();
2699 }
2700
2701 std::string makeMismatchingSignsTestVS(uint32_t attribCount, uint16_t signedMask);
2702 std::string makeMismatchingSignsTestFS(uint32_t attribCount);
2703 uint16_t setupVertexAttribPointersForMismatchSignsTest(uint16_t currentSignedMask,
2704 uint16_t toggleMask);
2705
2706 GLuint mVAO = 0;
2707 GLuint mExpectedBuffer = 0;
2708 GLuint mQuadBuffer = 0;
2709
2710 const GLsizei kFloatStride = TypeStride(GL_FLOAT);
2711
2712 // Set the maximum value for stride and relativeOffset in case they are too large.
2713 const GLint MAX_STRIDE_FOR_TEST = 4095;
2714 const GLint MAX_RELATIVE_OFFSET_FOR_TEST = 4095;
2715 };
2716
2717 // Verify that MAX_VERTEX_ATTRIB_STRIDE is no less than the minimum required value (2048) in ES3.1.
TEST_P(VertexAttributeTestES31,MaxVertexAttribStride)2718 TEST_P(VertexAttributeTestES31, MaxVertexAttribStride)
2719 {
2720 GLint maxStride;
2721 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
2722 ASSERT_GL_NO_ERROR();
2723
2724 EXPECT_GE(maxStride, 2048);
2725 }
2726
2727 // Verify that GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET is no less than the minimum required value
2728 // (2047) in ES3.1.
TEST_P(VertexAttributeTestES31,MaxVertexAttribRelativeOffset)2729 TEST_P(VertexAttributeTestES31, MaxVertexAttribRelativeOffset)
2730 {
2731 GLint maxRelativeOffset;
2732 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
2733 ASSERT_GL_NO_ERROR();
2734
2735 EXPECT_GE(maxRelativeOffset, 2047);
2736 }
2737
2738 // Verify using MAX_VERTEX_ATTRIB_STRIDE as stride doesn't mess up the draw.
2739 // Use default value if the value of MAX_VERTEX_ATTRIB_STRIDE is too large for this test.
TEST_P(VertexAttributeTestES31,DrawArraysWithLargeStride)2740 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride)
2741 {
2742 GLint maxStride;
2743 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
2744 ASSERT_GL_NO_ERROR();
2745
2746 GLint largeStride = std::min(maxStride, MAX_STRIDE_FOR_TEST);
2747 drawArraysWithStrideAndRelativeOffset(largeStride, 0);
2748 }
2749
2750 // Verify using MAX_VERTEX_ATTRIB_RELATIVE_OFFSET as relativeOffset doesn't mess up the draw.
2751 // Use default value if the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSSET is too large for this test.
TEST_P(VertexAttributeTestES31,DrawArraysWithLargeRelativeOffset)2752 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeRelativeOffset)
2753 {
2754 GLint maxRelativeOffset;
2755 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
2756 ASSERT_GL_NO_ERROR();
2757
2758 GLint largeRelativeOffset = std::min(maxRelativeOffset, MAX_RELATIVE_OFFSET_FOR_TEST);
2759 drawArraysWithStrideAndRelativeOffset(0, largeRelativeOffset);
2760 }
2761
2762 // Test that vertex array object works correctly when render pipeline and compute pipeline are
2763 // crossly executed.
TEST_P(VertexAttributeTestES31,MixedComputeAndRenderPipelines)2764 TEST_P(VertexAttributeTestES31, MixedComputeAndRenderPipelines)
2765 {
2766 constexpr char kComputeShader[] =
2767 R"(#version 310 es
2768 layout(local_size_x=1) in;
2769 void main()
2770 {
2771 })";
2772 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
2773
2774 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2775 glClearColor(0, 0, 0, 0);
2776
2777 constexpr char kVertexShader[] =
2778 R"(#version 310 es
2779 precision mediump float;
2780 layout(location = 0) in vec4 position;
2781 layout(location = 2) in vec2 aOffset;
2782 layout(location = 3) in vec4 aColor;
2783 out vec4 vColor;
2784 void main() {
2785 vColor = aColor;
2786 gl_Position = position + vec4(aOffset, 0.0, 0.0);
2787 })";
2788
2789 constexpr char kFragmentShader[] =
2790 R"(#version 310 es
2791 precision mediump float;
2792 in vec4 vColor;
2793 out vec4 color;
2794 void main() {
2795 color = vColor;
2796 })";
2797
2798 ANGLE_GL_PROGRAM(renderProgram, kVertexShader, kFragmentShader);
2799
2800 constexpr char kVertexShader1[] =
2801 R"(#version 310 es
2802 precision mediump float;
2803 layout(location = 1) in vec4 position;
2804 layout(location = 2) in vec2 aOffset;
2805 layout(location = 3) in vec4 aColor;
2806 out vec4 vColor;
2807 void main() {
2808 vColor = aColor;
2809 gl_Position = position + vec4(aOffset, 0.0, 0.0);
2810 })";
2811
2812 ANGLE_GL_PROGRAM(renderProgram1, kVertexShader1, kFragmentShader);
2813
2814 std::array<GLfloat, 8> offsets = {
2815 -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
2816 };
2817 GLBuffer offsetBuffer;
2818 glBindBuffer(GL_ARRAY_BUFFER, offsetBuffer);
2819 glBufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(GLfloat), offsets.data(), GL_STATIC_DRAW);
2820
2821 std::array<GLfloat, 16> colors0 = {
2822 1.0, 0.0, 0.0, 1.0, // Red
2823 0.0, 1.0, 0.0, 1.0, // Green
2824 0.0, 0.0, 1.0, 1.0, // Blue
2825 1.0, 1.0, 0.0, 1.0, // Yellow
2826 };
2827 std::array<GLfloat, 16> colors1 = {
2828 1.0, 1.0, 0.0, 1.0, // Yellow
2829 0.0, 0.0, 1.0, 1.0, // Blue
2830 0.0, 1.0, 0.0, 1.0, // Green
2831 1.0, 0.0, 0.0, 1.0, // Red
2832 };
2833 GLBuffer colorBuffers[2];
2834 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[0]);
2835 glBufferData(GL_ARRAY_BUFFER, colors0.size() * sizeof(GLfloat), colors0.data(), GL_STATIC_DRAW);
2836 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[1]);
2837 glBufferData(GL_ARRAY_BUFFER, colors1.size() * sizeof(GLfloat), colors1.data(), GL_STATIC_DRAW);
2838
2839 std::array<GLfloat, 16> positions = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
2840 1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
2841 GLBuffer positionBuffer;
2842 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
2843 glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(GLfloat), positions.data(),
2844 GL_STATIC_DRAW);
2845
2846 const int kInstanceCount = 4;
2847 GLVertexArray vao[2];
2848 for (size_t i = 0u; i < 2u; ++i)
2849 {
2850 glBindVertexArray(vao[i]);
2851
2852 glBindBuffer(GL_ARRAY_BUFFER, offsetBuffer);
2853 glEnableVertexAttribArray(2);
2854 glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0);
2855 glVertexAttribDivisor(2, 1);
2856
2857 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[i]);
2858 glEnableVertexAttribArray(3);
2859 glVertexAttribPointer(3, 4, GL_FLOAT, false, 0, 0);
2860 glVertexAttribDivisor(3, 1);
2861
2862 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
2863 glEnableVertexAttribArray(i);
2864 glVertexAttribPointer(i, 2, GL_FLOAT, false, 0, 0);
2865 }
2866
2867 glClear(GL_COLOR_BUFFER_BIT);
2868
2869 for (int i = 0; i < 3; i++)
2870 {
2871 glUseProgram(renderProgram);
2872 glBindVertexArray(vao[0]);
2873 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, kInstanceCount);
2874
2875 EXPECT_GL_NO_ERROR();
2876 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 2, GLColor::red) << i;
2877 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green) << i;
2878 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue) << i;
2879 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::yellow) << i;
2880
2881 glBindVertexArray(vao[1]);
2882 glUseProgram(computeProgram);
2883 glDispatchCompute(1, 1, 1);
2884
2885 glUseProgram(renderProgram1);
2886 glBindVertexArray(vao[1]);
2887 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, kInstanceCount);
2888
2889 EXPECT_GL_NO_ERROR();
2890 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 2, GLColor::yellow) << i;
2891 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue) << i;
2892 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green) << i;
2893 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::red) << i;
2894 }
2895 ASSERT_GL_NO_ERROR();
2896 }
2897
TEST_P(VertexAttributeTestES31,UseComputeShaderToUpdateVertexBuffer)2898 TEST_P(VertexAttributeTestES31, UseComputeShaderToUpdateVertexBuffer)
2899 {
2900 initTest();
2901 constexpr char kComputeShader[] =
2902 R"(#version 310 es
2903 layout(local_size_x=24) in;
2904 layout(std430, binding = 0) buffer buf {
2905 uint outData[24];
2906 };
2907 void main()
2908 {
2909 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
2910 })";
2911
2912 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
2913 glUseProgram(mProgram);
2914
2915 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
2916 GLuint hi = std::numeric_limits<GLuint>::max();
2917 std::array<GLuint, kVertexCount> inputData = {
2918 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
2919 std::array<GLfloat, kVertexCount> expectedData;
2920 for (size_t i = 0; i < kVertexCount; i++)
2921 {
2922 expectedData[i] = Normalize(inputData[i]);
2923 }
2924
2925 // Normalized unsigned int attribute will be classified as translated static attribute.
2926 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
2927 GLint typeSize = 4;
2928 GLsizei dataSize = kVertexCount * TypeStride(data.type);
2929 GLBuffer testBuffer;
2930 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
2931 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
2932 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
2933 reinterpret_cast<void *>(data.bufferOffset));
2934 glEnableVertexAttribArray(mTestAttrib);
2935
2936 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2937 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
2938 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
2939
2940 // Draw twice to make sure that all static attributes dirty bits are synced.
2941 glDrawArrays(GL_TRIANGLES, 0, 6);
2942 glDrawArrays(GL_TRIANGLES, 0, 6);
2943 checkPixels();
2944
2945 // Modify the testBuffer using a raw buffer
2946 glUseProgram(computeProgram);
2947 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
2948 glDispatchCompute(1, 1, 1);
2949 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
2950
2951 // Draw again to verify that testBuffer has been changed.
2952 glUseProgram(mProgram);
2953 glDrawArrays(GL_TRIANGLES, 0, 6);
2954 EXPECT_GL_NO_ERROR();
2955 checkPixelsUnEqual();
2956 }
2957
TEST_P(VertexAttributeTestES31,UsePpoComputeShaderToUpdateVertexBuffer)2958 TEST_P(VertexAttributeTestES31, UsePpoComputeShaderToUpdateVertexBuffer)
2959 {
2960 // PPOs are only supported in the Vulkan backend
2961 ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
2962
2963 initTest();
2964 constexpr char kComputeShader[] =
2965 R"(#version 310 es
2966 layout(local_size_x=24) in;
2967 layout(std430, binding = 0) buffer buf {
2968 uint outData[24];
2969 };
2970 void main()
2971 {
2972 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
2973 })";
2974
2975 glUseProgram(mProgram);
2976
2977 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
2978 GLuint hi = std::numeric_limits<GLuint>::max();
2979 std::array<GLuint, kVertexCount> inputData = {
2980 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
2981 std::array<GLfloat, kVertexCount> expectedData;
2982 for (size_t i = 0; i < kVertexCount; i++)
2983 {
2984 expectedData[i] = Normalize(inputData[i]);
2985 }
2986
2987 // Normalized unsigned int attribute will be classified as translated static attribute.
2988 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
2989 GLint typeSize = 4;
2990 GLsizei dataSize = kVertexCount * TypeStride(data.type);
2991 GLBuffer testBuffer;
2992 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
2993 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
2994 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
2995 reinterpret_cast<void *>(data.bufferOffset));
2996 glEnableVertexAttribArray(mTestAttrib);
2997
2998 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2999 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
3000 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
3001
3002 // Draw twice to make sure that all static attributes dirty bits are synced.
3003 glDrawArrays(GL_TRIANGLES, 0, 6);
3004 glDrawArrays(GL_TRIANGLES, 0, 6);
3005 checkPixels();
3006
3007 // Modify the testBuffer using a raw buffer
3008 GLProgramPipeline pipeline;
3009 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
3010 glProgramParameteri(computeProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
3011 glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, computeProgram);
3012 EXPECT_GL_NO_ERROR();
3013 glBindProgramPipeline(pipeline);
3014 EXPECT_GL_NO_ERROR();
3015 glUseProgram(0);
3016
3017 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
3018 glDispatchCompute(1, 1, 1);
3019 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
3020
3021 // Draw again to verify that testBuffer has been changed.
3022 glUseProgram(mProgram);
3023 glDrawArrays(GL_TRIANGLES, 0, 6);
3024 EXPECT_GL_NO_ERROR();
3025 checkPixelsUnEqual();
3026 }
3027
TEST_P(VertexAttributeTestES31,UseComputeShaderToUpdateVertexBufferSamePpo)3028 TEST_P(VertexAttributeTestES31, UseComputeShaderToUpdateVertexBufferSamePpo)
3029 {
3030 // PPOs are only supported in the Vulkan backend
3031 ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
3032
3033 initTest();
3034 constexpr char kComputeShader[] =
3035 R"(#version 310 es
3036 layout(local_size_x=24) in;
3037 layout(std430, binding = 0) buffer buf {
3038 uint outData[24];
3039 };
3040 void main()
3041 {
3042 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
3043 })";
3044
3045 // Mark the program separable and re-link it so it can be bound to the PPO.
3046 glProgramParameteri(mProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
3047 glLinkProgram(mProgram);
3048 mProgram = CheckLinkStatusAndReturnProgram(mProgram, true);
3049
3050 GLProgramPipeline pipeline;
3051 EXPECT_GL_NO_ERROR();
3052 glBindProgramPipeline(pipeline);
3053 glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, mProgram);
3054 EXPECT_GL_NO_ERROR();
3055 glUseProgram(0);
3056
3057 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
3058 GLuint hi = std::numeric_limits<GLuint>::max();
3059 std::array<GLuint, kVertexCount> inputData = {
3060 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
3061 std::array<GLfloat, kVertexCount> expectedData;
3062 for (size_t i = 0; i < kVertexCount; i++)
3063 {
3064 expectedData[i] = Normalize(inputData[i]);
3065 }
3066
3067 // Normalized unsigned int attribute will be classified as translated static attribute.
3068 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
3069 GLint typeSize = 4;
3070 GLsizei dataSize = kVertexCount * TypeStride(data.type);
3071 GLBuffer testBuffer;
3072 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
3073 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
3074 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
3075 reinterpret_cast<void *>(data.bufferOffset));
3076 glEnableVertexAttribArray(mTestAttrib);
3077
3078 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
3079 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
3080 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
3081
3082 // Draw twice to make sure that all static attributes dirty bits are synced.
3083 glDrawArrays(GL_TRIANGLES, 0, 6);
3084 glDrawArrays(GL_TRIANGLES, 0, 6);
3085 checkPixels();
3086
3087 // Modify the testBuffer using a raw buffer
3088 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
3089 glProgramParameteri(computeProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
3090 glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, computeProgram);
3091 EXPECT_GL_NO_ERROR();
3092
3093 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
3094 glDispatchCompute(1, 1, 1);
3095 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
3096
3097 // Draw again to verify that testBuffer has been changed.
3098 glUseProgram(mProgram);
3099 glDrawArrays(GL_TRIANGLES, 0, 6);
3100 EXPECT_GL_NO_ERROR();
3101 checkPixelsUnEqual();
3102 }
3103
3104 // Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31,ChangeAttribBindingAfterVertexAttribPointer)3105 TEST_P(VertexAttributeTestES31, ChangeAttribBindingAfterVertexAttribPointer)
3106 {
3107 initTest();
3108
3109 constexpr GLint kInputStride = 2;
3110 constexpr GLint kFloatOffset = 10;
3111 std::array<GLfloat, kVertexCount + kFloatOffset> inputData1;
3112 std::array<GLfloat, kVertexCount * kInputStride> inputData2;
3113 for (size_t count = 0; count < kVertexCount; ++count)
3114 {
3115 inputData1[kFloatOffset + count] = static_cast<GLfloat>(count);
3116 inputData2[count * kInputStride] = static_cast<GLfloat>(count);
3117 }
3118
3119 GLBuffer mBuffer1;
3120 glBindBuffer(GL_ARRAY_BUFFER, mBuffer1);
3121 glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
3122 GL_STATIC_DRAW);
3123 // Update the format indexed mTestAttrib and the binding indexed mTestAttrib by
3124 // VertexAttribPointer.
3125 const GLintptr kOffset = static_cast<GLintptr>(kFloatStride * kFloatOffset);
3126 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0,
3127 reinterpret_cast<const GLvoid *>(kOffset));
3128 glEnableVertexAttribArray(mTestAttrib);
3129
3130 constexpr GLint kTestBinding = 10;
3131 ASSERT_NE(mTestAttrib, kTestBinding);
3132
3133 GLBuffer mBuffer2;
3134 glBindBuffer(GL_ARRAY_BUFFER, mBuffer2);
3135 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
3136 GL_STATIC_DRAW);
3137 glBindVertexBuffer(kTestBinding, mBuffer2, 0, kFloatStride * kInputStride);
3138
3139 // The attribute indexed mTestAttrib is using the binding indexed kTestBinding in the first
3140 // draw.
3141 glVertexAttribBinding(mTestAttrib, kTestBinding);
3142 glDrawArrays(GL_TRIANGLES, 0, 6);
3143 checkPixels();
3144 EXPECT_GL_NO_ERROR();
3145
3146 // The attribute indexed mTestAttrib is using the binding indexed mTestAttrib which should be
3147 // set after the call VertexAttribPointer before the first draw.
3148 glVertexAttribBinding(mTestAttrib, mTestAttrib);
3149 glDrawArrays(GL_TRIANGLES, 0, 6);
3150 checkPixels();
3151 EXPECT_GL_NO_ERROR();
3152 }
3153
3154 // Verify that using VertexAttribFormat after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31,ChangeAttribFormatAfterVertexAttribPointer)3155 TEST_P(VertexAttributeTestES31, ChangeAttribFormatAfterVertexAttribPointer)
3156 {
3157 initTest();
3158
3159 constexpr GLuint kFloatOffset = 10;
3160 std::array<GLfloat, kVertexCount + kFloatOffset> inputData;
3161 for (size_t count = 0; count < kVertexCount; ++count)
3162 {
3163 inputData[kFloatOffset + count] = static_cast<GLfloat>(count);
3164 }
3165
3166 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3167 glBufferData(GL_ARRAY_BUFFER, inputData.size() * kFloatStride, inputData.data(),
3168 GL_STATIC_DRAW);
3169
3170 // Call VertexAttribPointer on mTestAttrib. Now the relativeOffset of mTestAttrib should be 0.
3171 const GLuint kOffset = static_cast<GLuint>(kFloatStride * kFloatOffset);
3172 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
3173 glEnableVertexAttribArray(mTestAttrib);
3174
3175 // Call VertexAttribFormat on mTestAttrib to modify the relativeOffset to kOffset.
3176 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, kOffset);
3177
3178 glDrawArrays(GL_TRIANGLES, 0, 6);
3179 checkPixels();
3180 EXPECT_GL_NO_ERROR();
3181 }
3182
3183 // Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31,OnlyUpdateBindingByBindVertexBuffer)3184 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByBindVertexBuffer)
3185 {
3186 // Default binding index for test
3187 constexpr GLint kTestBinding = 10;
3188 initOnlyUpdateBindingTest(kTestBinding);
3189
3190 constexpr GLuint kTestFloatOffset2 = kVertexCount * 2;
3191 std::array<GLfloat, kVertexCount> expectedData2 = {};
3192 std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
3193 for (size_t count = 0; count < kVertexCount; ++count)
3194 {
3195 GLfloat value2 = static_cast<GLfloat>(count) * 2;
3196 expectedData2[count] = value2;
3197 inputData2[count + kTestFloatOffset2] = value2;
3198 }
3199
3200 // Set another set of data for mExpectedAttrib.
3201 GLBuffer expectedBuffer2;
3202 glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
3203 glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
3204 GL_STATIC_DRAW);
3205 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3206
3207 GLBuffer testBuffer2;
3208 glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
3209 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
3210 GL_STATIC_DRAW);
3211
3212 // Only update the binding kTestBinding in the second draw by BindVertexBuffer.
3213 glBindVertexBuffer(kTestBinding, testBuffer2, kTestFloatOffset2 * kFloatStride, kFloatStride);
3214
3215 glDrawArrays(GL_TRIANGLES, 0, 6);
3216 checkPixels();
3217 EXPECT_GL_NO_ERROR();
3218 }
3219
3220 // Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31,OnlyUpdateBindingByVertexAttribPointer)3221 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByVertexAttribPointer)
3222 {
3223 // Default binding index for test
3224 constexpr GLint kTestBinding = 10;
3225 initOnlyUpdateBindingTest(kTestBinding);
3226
3227 constexpr GLuint kTestFloatOffset2 = kVertexCount * 3;
3228 std::array<GLfloat, kVertexCount> expectedData2 = {};
3229 std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
3230 for (size_t count = 0; count < kVertexCount; ++count)
3231 {
3232 GLfloat value2 = static_cast<GLfloat>(count) * 3;
3233 expectedData2[count] = value2;
3234 inputData2[count + kTestFloatOffset2] = value2;
3235 }
3236
3237 // Set another set of data for mExpectedAttrib.
3238 GLBuffer expectedBuffer2;
3239 glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
3240 glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
3241 GL_STATIC_DRAW);
3242 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3243
3244 GLBuffer testBuffer2;
3245 glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
3246 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
3247 GL_STATIC_DRAW);
3248
3249 // Only update the binding kTestBinding in the second draw by VertexAttribPointer.
3250 glVertexAttribPointer(
3251 kTestBinding, 1, GL_FLOAT, GL_FALSE, 0,
3252 reinterpret_cast<const void *>(static_cast<uintptr_t>(kTestFloatOffset2 * kFloatStride)));
3253
3254 glDrawArrays(GL_TRIANGLES, 0, 6);
3255 checkPixels();
3256 EXPECT_GL_NO_ERROR();
3257 }
3258
3259 class VertexAttributeCachingTest : public VertexAttributeTest
3260 {
3261 protected:
VertexAttributeCachingTest()3262 VertexAttributeCachingTest() {}
3263
3264 void testSetUp() override;
3265
3266 template <typename DestT>
3267 static std::vector<GLfloat> GetExpectedData(const std::vector<GLubyte> &srcData,
3268 GLenum attribType,
3269 GLboolean normalized);
3270
initDoubleAttribProgram()3271 void initDoubleAttribProgram()
3272 {
3273 constexpr char kVS[] =
3274 "attribute mediump vec4 position;\n"
3275 "attribute mediump vec4 test;\n"
3276 "attribute mediump vec4 expected;\n"
3277 "attribute mediump vec4 test2;\n"
3278 "attribute mediump vec4 expected2;\n"
3279 "varying mediump vec4 color;\n"
3280 "void main(void)\n"
3281 "{\n"
3282 " gl_Position = position;\n"
3283 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
3284 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
3285 " vec4 threshold2 = max(abs(expected2) * 0.01, 1.0 / 64.0);\n"
3286 " color += vec4(lessThanEqual(abs(test2 - expected2), threshold2));\n"
3287 "}\n";
3288
3289 constexpr char kFS[] =
3290 "varying mediump vec4 color;\n"
3291 "void main(void)\n"
3292 "{\n"
3293 " gl_FragColor = color;\n"
3294 "}\n";
3295
3296 mProgram = CompileProgram(kVS, kFS);
3297 ASSERT_NE(0u, mProgram);
3298
3299 mTestAttrib = glGetAttribLocation(mProgram, "test");
3300 ASSERT_NE(-1, mTestAttrib);
3301 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
3302 ASSERT_NE(-1, mExpectedAttrib);
3303
3304 glUseProgram(mProgram);
3305 }
3306
3307 struct AttribData
3308 {
3309 AttribData(GLenum typeIn, GLint sizeIn, GLboolean normalizedIn, GLsizei strideIn);
3310
3311 GLenum type;
3312 GLint size;
3313 GLboolean normalized;
3314 GLsizei stride;
3315 };
3316
3317 std::vector<AttribData> mTestData;
3318 std::map<GLenum, std::vector<GLfloat>> mExpectedData;
3319 std::map<GLenum, std::vector<GLfloat>> mNormExpectedData;
3320 };
3321
AttribData(GLenum typeIn,GLint sizeIn,GLboolean normalizedIn,GLsizei strideIn)3322 VertexAttributeCachingTest::AttribData::AttribData(GLenum typeIn,
3323 GLint sizeIn,
3324 GLboolean normalizedIn,
3325 GLsizei strideIn)
3326 : type(typeIn), size(sizeIn), normalized(normalizedIn), stride(strideIn)
3327 {}
3328
3329 // static
3330 template <typename DestT>
GetExpectedData(const std::vector<GLubyte> & srcData,GLenum attribType,GLboolean normalized)3331 std::vector<GLfloat> VertexAttributeCachingTest::GetExpectedData(
3332 const std::vector<GLubyte> &srcData,
3333 GLenum attribType,
3334 GLboolean normalized)
3335 {
3336 std::vector<GLfloat> expectedData;
3337
3338 const DestT *typedSrcPtr = reinterpret_cast<const DestT *>(srcData.data());
3339 size_t iterations = srcData.size() / TypeStride(attribType);
3340
3341 if (normalized)
3342 {
3343 for (size_t index = 0; index < iterations; ++index)
3344 {
3345 expectedData.push_back(Normalize(typedSrcPtr[index]));
3346 }
3347 }
3348 else
3349 {
3350 for (size_t index = 0; index < iterations; ++index)
3351 {
3352 expectedData.push_back(static_cast<GLfloat>(typedSrcPtr[index]));
3353 }
3354 }
3355
3356 return expectedData;
3357 }
3358
testSetUp()3359 void VertexAttributeCachingTest::testSetUp()
3360 {
3361 VertexAttributeTest::testSetUp();
3362
3363 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3364
3365 std::vector<GLubyte> srcData;
3366 for (size_t count = 0; count < 4; ++count)
3367 {
3368 for (GLubyte i = 0; i < std::numeric_limits<GLubyte>::max(); ++i)
3369 {
3370 srcData.push_back(i);
3371 }
3372 }
3373
3374 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
3375
3376 GLint viewportSize[4];
3377 glGetIntegerv(GL_VIEWPORT, viewportSize);
3378
3379 std::vector<GLenum> attribTypes;
3380 attribTypes.push_back(GL_BYTE);
3381 attribTypes.push_back(GL_UNSIGNED_BYTE);
3382 attribTypes.push_back(GL_SHORT);
3383 attribTypes.push_back(GL_UNSIGNED_SHORT);
3384
3385 if (getClientMajorVersion() >= 3)
3386 {
3387 attribTypes.push_back(GL_INT);
3388 attribTypes.push_back(GL_UNSIGNED_INT);
3389 }
3390
3391 constexpr GLint kMaxSize = 4;
3392 constexpr GLsizei kMaxStride = 4;
3393
3394 for (GLenum attribType : attribTypes)
3395 {
3396 for (GLint attribSize = 1; attribSize <= kMaxSize; ++attribSize)
3397 {
3398 for (GLsizei stride = 1; stride <= kMaxStride; ++stride)
3399 {
3400 mTestData.push_back(AttribData(attribType, attribSize, GL_FALSE, stride));
3401 if (attribType != GL_FLOAT)
3402 {
3403 mTestData.push_back(AttribData(attribType, attribSize, GL_TRUE, stride));
3404 }
3405 }
3406 }
3407 }
3408
3409 mExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_FALSE);
3410 mExpectedData[GL_UNSIGNED_BYTE] = GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_FALSE);
3411 mExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_FALSE);
3412 mExpectedData[GL_UNSIGNED_SHORT] =
3413 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_FALSE);
3414 mExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_FALSE);
3415 mExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_FALSE);
3416
3417 mNormExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_TRUE);
3418 mNormExpectedData[GL_UNSIGNED_BYTE] =
3419 GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_TRUE);
3420 mNormExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_TRUE);
3421 mNormExpectedData[GL_UNSIGNED_SHORT] =
3422 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_TRUE);
3423 mNormExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_TRUE);
3424 mNormExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_TRUE);
3425 }
3426
3427 // In D3D11, we must sometimes translate buffer data into static attribute caches. We also use a
3428 // cache management scheme which garbage collects old attributes after we start using too much
3429 // cache data. This test tries to make as many attribute caches from a single buffer as possible
3430 // to stress-test the caching code.
TEST_P(VertexAttributeCachingTest,BufferMulticaching)3431 TEST_P(VertexAttributeCachingTest, BufferMulticaching)
3432 {
3433 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
3434
3435 initBasicProgram();
3436
3437 glEnableVertexAttribArray(mTestAttrib);
3438 glEnableVertexAttribArray(mExpectedAttrib);
3439
3440 ASSERT_GL_NO_ERROR();
3441
3442 for (const AttribData &data : mTestData)
3443 {
3444 const auto &expected =
3445 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
3446
3447 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
3448 GLsizei stride = TypeStride(data.type) * baseStride;
3449
3450 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3451 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
3452 glBindBuffer(GL_ARRAY_BUFFER, 0);
3453 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
3454 sizeof(GLfloat) * baseStride, expected.data());
3455 drawQuad(mProgram, "position", 0.5f);
3456 ASSERT_GL_NO_ERROR();
3457 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
3458 }
3459 }
3460
3461 // With D3D11 dirty bits for VertxArray11, we can leave vertex state unchanged if there aren't any
3462 // GL calls that affect it. This test targets leaving one vertex attribute unchanged between draw
3463 // calls while changing another vertex attribute enough that it clears the static buffer cache
3464 // after enough iterations. It validates the unchanged attributes don't get deleted incidentally.
TEST_P(VertexAttributeCachingTest,BufferMulticachingWithOneUnchangedAttrib)3465 TEST_P(VertexAttributeCachingTest, BufferMulticachingWithOneUnchangedAttrib)
3466 {
3467 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
3468
3469 initDoubleAttribProgram();
3470
3471 GLint testAttrib2Location = glGetAttribLocation(mProgram, "test2");
3472 ASSERT_NE(-1, testAttrib2Location);
3473 GLint expectedAttrib2Location = glGetAttribLocation(mProgram, "expected2");
3474 ASSERT_NE(-1, expectedAttrib2Location);
3475
3476 glEnableVertexAttribArray(mTestAttrib);
3477 glEnableVertexAttribArray(mExpectedAttrib);
3478 glEnableVertexAttribArray(testAttrib2Location);
3479 glEnableVertexAttribArray(expectedAttrib2Location);
3480
3481 ASSERT_GL_NO_ERROR();
3482
3483 // Use an attribute that we know must be converted. This is a bit sensitive.
3484 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3485 glVertexAttribPointer(testAttrib2Location, 3, GL_UNSIGNED_SHORT, GL_FALSE, 6, nullptr);
3486 glBindBuffer(GL_ARRAY_BUFFER, 0);
3487 glVertexAttribPointer(expectedAttrib2Location, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3,
3488 mExpectedData[GL_UNSIGNED_SHORT].data());
3489
3490 for (const auto &data : mTestData)
3491 {
3492 const auto &expected =
3493 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
3494
3495 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
3496 GLsizei stride = TypeStride(data.type) * baseStride;
3497
3498 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3499 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
3500 glBindBuffer(GL_ARRAY_BUFFER, 0);
3501 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
3502 sizeof(GLfloat) * baseStride, expected.data());
3503 drawQuad(mProgram, "position", 0.5f);
3504
3505 ASSERT_GL_NO_ERROR();
3506 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
3507 }
3508 }
3509
3510 // Test that if there are gaps in the attribute indices, the attributes have their correct values.
TEST_P(VertexAttributeTest,UnusedVertexAttribWorks)3511 TEST_P(VertexAttributeTest, UnusedVertexAttribWorks)
3512 {
3513 constexpr char kVertexShader[] = R"(attribute vec2 position;
3514 attribute float actualValue;
3515 uniform float expectedValue;
3516 varying float result;
3517 void main()
3518 {
3519 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3520 gl_Position = vec4(position, 0, 1);
3521 })";
3522
3523 constexpr char kFragmentShader[] = R"(varying mediump float result;
3524 void main()
3525 {
3526 gl_FragColor = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3527 })";
3528
3529 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3530
3531 // Force a gap in attributes by using location 0 and 3
3532 GLint positionLocation = 0;
3533 glBindAttribLocation(program, positionLocation, "position");
3534
3535 GLint attribLoc = 3;
3536 glBindAttribLocation(program, attribLoc, "actualValue");
3537
3538 // Re-link the program to update the attribute locations
3539 glLinkProgram(program);
3540 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
3541
3542 glUseProgram(program);
3543
3544 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3545 ASSERT_NE(-1, uniLoc);
3546
3547 glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3548
3549 ASSERT_NE(-1, positionLocation);
3550 setupQuadVertexBuffer(0.5f, 1.0f);
3551 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
3552 glEnableVertexAttribArray(positionLocation);
3553
3554 std::array<GLfloat, 4> testValues = {{1, 2, 3, 4}};
3555 for (GLfloat testValue : testValues)
3556 {
3557 glUniform1f(uniLoc, testValue);
3558 glVertexAttrib1f(attribLoc, testValue);
3559 glDrawArrays(GL_TRIANGLES, 0, 6);
3560 ASSERT_GL_NO_ERROR();
3561 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3562 }
3563 }
3564
3565 // Tests that repeatedly updating a disabled vertex attribute works as expected.
3566 // This covers an ANGLE bug where dirty bits for current values were ignoring repeated updates.
TEST_P(VertexAttributeTest,DisabledAttribUpdates)3567 TEST_P(VertexAttributeTest, DisabledAttribUpdates)
3568 {
3569 constexpr char kVertexShader[] = R"(attribute vec2 position;
3570 attribute float actualValue;
3571 uniform float expectedValue;
3572 varying float result;
3573 void main()
3574 {
3575 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3576 gl_Position = vec4(position, 0, 1);
3577 })";
3578
3579 constexpr char kFragmentShader[] = R"(varying mediump float result;
3580 void main()
3581 {
3582 gl_FragColor = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3583 })";
3584
3585 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3586
3587 glUseProgram(program);
3588 GLint attribLoc = glGetAttribLocation(program, "actualValue");
3589 ASSERT_NE(-1, attribLoc);
3590
3591 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3592 ASSERT_NE(-1, uniLoc);
3593
3594 glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3595
3596 GLint positionLocation = glGetAttribLocation(program, "position");
3597 ASSERT_NE(-1, positionLocation);
3598 setupQuadVertexBuffer(0.5f, 1.0f);
3599 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
3600 glEnableVertexAttribArray(positionLocation);
3601
3602 std::array<GLfloat, 4> testValues = {{1, 2, 3, 4}};
3603 for (GLfloat testValue : testValues)
3604 {
3605 glUniform1f(uniLoc, testValue);
3606 glVertexAttrib1f(attribLoc, testValue);
3607 glDrawArrays(GL_TRIANGLES, 0, 6);
3608 ASSERT_GL_NO_ERROR();
3609 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3610 }
3611 }
3612
3613 // Test that even inactive attributes are taken into account when checking for aliasing in case the
3614 // shader version is >= 3.00. GLSL ES 3.00.6 section 12.46.
TEST_P(VertexAttributeTestES3,InactiveAttributeAliasing)3615 TEST_P(VertexAttributeTestES3, InactiveAttributeAliasing)
3616 {
3617 constexpr char vertexShader[] =
3618 R"(#version 300 es
3619 precision mediump float;
3620 in vec4 input_active;
3621 in vec4 input_unused;
3622 void main()
3623 {
3624 gl_Position = input_active;
3625 })";
3626
3627 constexpr char fragmentShader[] =
3628 R"(#version 300 es
3629 precision mediump float;
3630 out vec4 color;
3631 void main()
3632 {
3633 color = vec4(0.0);
3634 })";
3635
3636 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3637 glBindAttribLocation(program, 0, "input_active");
3638 glBindAttribLocation(program, 0, "input_unused");
3639 glLinkProgram(program);
3640 EXPECT_GL_NO_ERROR();
3641 GLint linkStatus = 0;
3642 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
3643 EXPECT_GL_FALSE(linkStatus);
3644 }
3645
3646 // Test that enabling inactive attributes doesn't cause a crash
3647 // shader version is >= 3.00
TEST_P(VertexAttributeTestES3,EnabledButInactiveAttributes)3648 TEST_P(VertexAttributeTestES3, EnabledButInactiveAttributes)
3649 {
3650 // This is similar to runtest(), and the test is disabled there
3651 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
3652
3653 constexpr char testVertexShaderSource[] =
3654 R"(#version 300 es
3655 precision mediump float;
3656 in vec4 position;
3657 layout(location = 1) in vec4 test;
3658 layout(location = 2) in vec4 unused1;
3659 layout(location = 3) in vec4 unused2;
3660 layout(location = 4) in vec4 unused3;
3661 layout(location = 5) in vec4 expected;
3662 out vec4 color;
3663 void main(void)
3664 {
3665 gl_Position = position;
3666 vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);
3667 color = vec4(lessThanEqual(abs(test - expected), threshold));
3668 })";
3669
3670 // Same as previous one, except it uses unused1/2 instead of test/expected, leaving unused3
3671 // unused
3672 constexpr char testVertexShader2Source[] =
3673 R"(#version 300 es
3674 precision mediump float;
3675 in vec4 position;
3676 layout(location = 1) in vec4 test;
3677 layout(location = 2) in vec4 unused1;
3678 layout(location = 3) in vec4 unused2;
3679 layout(location = 4) in vec4 unused3;
3680 layout(location = 5) in vec4 expected;
3681 out vec4 color;
3682 void main(void)
3683 {
3684 gl_Position = position;
3685 vec4 threshold = max(abs(unused2) * 0.01, 1.0 / 64.0);
3686 color = vec4(lessThanEqual(abs(unused1 - unused2), threshold));
3687 })";
3688
3689 constexpr char testFragmentShaderSource[] =
3690 R"(#version 300 es
3691 precision mediump float;
3692 in vec4 color;
3693 out vec4 out_color;
3694 void main()
3695 {
3696 out_color = color;
3697 })";
3698
3699 std::array<GLubyte, kVertexCount> inputData = {
3700 {0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255}};
3701 std::array<GLubyte, kVertexCount> inputData2;
3702 std::array<GLfloat, kVertexCount> expectedData;
3703 std::array<GLfloat, kVertexCount> expectedData2;
3704 for (size_t i = 0; i < kVertexCount; i++)
3705 {
3706 expectedData[i] = inputData[i];
3707 inputData2[i] = inputData[i] > 128 ? inputData[i] - 1 : inputData[i] + 1;
3708 expectedData2[i] = inputData2[i];
3709 }
3710
3711 // Setup the program
3712 mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
3713 ASSERT_NE(0u, mProgram);
3714
3715 mTestAttrib = glGetAttribLocation(mProgram, "test");
3716 ASSERT_EQ(1, mTestAttrib);
3717 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
3718 ASSERT_EQ(5, mExpectedAttrib);
3719
3720 GLint unused1Attrib = 2;
3721 GLint unused2Attrib = 3;
3722 GLint unused3Attrib = 4;
3723
3724 // Test enabling an unused attribute before glUseProgram
3725 glEnableVertexAttribArray(unused3Attrib);
3726
3727 glUseProgram(mProgram);
3728
3729 // Setup the test data
3730 TestData data(GL_UNSIGNED_BYTE, GL_FALSE, Source::IMMEDIATE, inputData.data(),
3731 expectedData.data());
3732 setupTest(data, 1);
3733
3734 // Test enabling an unused attribute after glUseProgram
3735 glVertexAttribPointer(unused1Attrib, 1, data.type, data.normalized, 0, inputData2.data());
3736 glEnableVertexAttribArray(unused1Attrib);
3737
3738 glVertexAttribPointer(unused2Attrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData2.data());
3739 glEnableVertexAttribArray(unused2Attrib);
3740
3741 // Run the test. This shouldn't use the unused attributes. Note that one of them is nullptr
3742 // which can cause a crash on certain platform-driver combination.
3743 drawQuad(mProgram, "position", 0.5f);
3744 checkPixels();
3745
3746 // Now test with the same attributes enabled, but with a program with different attributes
3747 // active
3748 mProgram = CompileProgram(testVertexShader2Source, testFragmentShaderSource);
3749 ASSERT_NE(0u, mProgram);
3750
3751 // Make sure all the attributes are in the same location
3752 ASSERT_EQ(glGetAttribLocation(mProgram, "unused1"), unused1Attrib);
3753 ASSERT_EQ(glGetAttribLocation(mProgram, "unused2"), unused2Attrib);
3754
3755 glUseProgram(mProgram);
3756
3757 // Run the test again. unused1/2 were disabled in the previous run (as they were inactive in
3758 // the shader), but should be re-enabled now.
3759 drawQuad(mProgram, "position", 0.5f);
3760 checkPixels();
3761 }
3762
3763 // Test that default integer attribute works correctly even if there is a gap in
3764 // attribute locations.
TEST_P(VertexAttributeTestES3,DefaultIntAttribWithGap)3765 TEST_P(VertexAttributeTestES3, DefaultIntAttribWithGap)
3766 {
3767 constexpr char kVertexShader[] = R"(#version 300 es
3768 layout(location = 0) in vec2 position;
3769 layout(location = 3) in int actualValue;
3770 uniform int expectedValue;
3771 out float result;
3772 void main()
3773 {
3774 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3775 gl_Position = vec4(position, 0, 1);
3776 })";
3777
3778 constexpr char kFragmentShader[] = R"(#version 300 es
3779 in mediump float result;
3780 layout(location = 0) out lowp vec4 out_color;
3781 void main()
3782 {
3783 out_color = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3784 })";
3785
3786 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3787
3788 // Re-link the program to update the attribute locations
3789 glLinkProgram(program);
3790 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
3791
3792 glUseProgram(program);
3793
3794 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3795 ASSERT_NE(-1, uniLoc);
3796
3797 glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3798
3799 setupQuadVertexBuffer(0.5f, 1.0f);
3800 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
3801 glEnableVertexAttribArray(0);
3802
3803 std::array<GLint, 4> testValues = {{1, 2, 3, 4}};
3804 for (GLfloat testValue : testValues)
3805 {
3806 glUniform1i(uniLoc, testValue);
3807 glVertexAttribI4i(3, testValue, 0, 0, 0);
3808 glDrawArrays(GL_TRIANGLES, 0, 6);
3809 ASSERT_GL_NO_ERROR();
3810 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3811 }
3812 }
3813
3814 // Test that when three vertex attribute indices are enabled, but only two attributes among them
3815 // include data via glVertexAttribPointer(), there is no crash.
TEST_P(VertexAttributeTest,VertexAttribPointerCopyBufferFromInvalidAddress)3816 TEST_P(VertexAttributeTest, VertexAttribPointerCopyBufferFromInvalidAddress)
3817 {
3818 const GLfloat vertices[] = {
3819 // position // color // texCoord
3820 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Lower left corner
3821 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, // Bottom right corner
3822 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 1.0f // Top
3823 };
3824
3825 constexpr char kVS[] = R"(
3826 attribute highp vec2 position;
3827 attribute mediump vec4 color;
3828 attribute highp vec2 texCoord;
3829 varying mediump vec4 fragColor;
3830 varying highp vec2 fragTexCoord;
3831 void main() {
3832 gl_Position = vec4(position, 0.0, 1.0);
3833 fragColor = color;
3834 fragTexCoord = texCoord;
3835 }
3836 )";
3837
3838 constexpr char kFS[] = R"(
3839 precision mediump float;
3840 varying mediump vec4 fragColor;
3841 varying highp vec2 fragTexCoord;
3842 void main() {
3843 if (fragTexCoord.x > 0.5) {
3844 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
3845 } else {
3846 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
3847 }
3848 }
3849 )";
3850
3851 mProgram = CompileProgram(kVS, kFS);
3852 ASSERT_NE(0u, mProgram);
3853 glBindAttribLocation(mProgram, 0, "position");
3854 glBindAttribLocation(mProgram, 1, "color");
3855 glBindAttribLocation(mProgram, 2, "texCoord");
3856 glUseProgram(mProgram);
3857 EXPECT_GL_NO_ERROR();
3858
3859 glGenBuffers(1, &mBuffer);
3860 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3861 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
3862 EXPECT_GL_NO_ERROR();
3863
3864 glEnableVertexAttribArray(0);
3865 glEnableVertexAttribArray(1);
3866 glEnableVertexAttribArray(2);
3867 EXPECT_GL_NO_ERROR();
3868
3869 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid *)0);
3870 // Missing VertexAttribPointer at index 1
3871 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat),
3872 (GLvoid *)(6 * sizeof(GLfloat)));
3873
3874 glDrawArrays(GL_TRIANGLES, 0, 3);
3875 EXPECT_GL_NO_ERROR();
3876
3877 glDisableVertexAttribArray(0);
3878 glDisableVertexAttribArray(1);
3879 glDisableVertexAttribArray(2);
3880 EXPECT_GL_NO_ERROR();
3881 }
3882
3883 // Test that default unsigned integer attribute works correctly even if there is a gap in
3884 // attribute locations.
TEST_P(VertexAttributeTestES3,DefaultUIntAttribWithGap)3885 TEST_P(VertexAttributeTestES3, DefaultUIntAttribWithGap)
3886 {
3887 constexpr char kVertexShader[] = R"(#version 300 es
3888 layout(location = 0) in vec2 position;
3889 layout(location = 3) in uint actualValue;
3890 uniform uint expectedValue;
3891 out float result;
3892 void main()
3893 {
3894 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3895 gl_Position = vec4(position, 0, 1);
3896 })";
3897
3898 constexpr char kFragmentShader[] = R"(#version 300 es
3899 in mediump float result;
3900 layout(location = 0) out lowp vec4 out_color;
3901 void main()
3902 {
3903 out_color = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3904 })";
3905
3906 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3907
3908 // Re-link the program to update the attribute locations
3909 glLinkProgram(program);
3910 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
3911
3912 glUseProgram(program);
3913
3914 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3915 ASSERT_NE(-1, uniLoc);
3916
3917 glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3918
3919 setupQuadVertexBuffer(0.5f, 1.0f);
3920 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
3921 glEnableVertexAttribArray(0);
3922
3923 std::array<GLuint, 4> testValues = {{1, 2, 3, 4}};
3924 for (GLfloat testValue : testValues)
3925 {
3926 glUniform1ui(uniLoc, testValue);
3927 glVertexAttribI4ui(3, testValue, 0, 0, 0);
3928 glDrawArrays(GL_TRIANGLES, 0, 6);
3929 ASSERT_GL_NO_ERROR();
3930 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3931 }
3932 }
3933
3934 // Tests that large strides that read past the end of the buffer work correctly.
3935 // Requires ES 3.1 to query MAX_VERTEX_ATTRIB_STRIDE.
TEST_P(VertexAttributeTestES31,LargeStride)3936 TEST_P(VertexAttributeTestES31, LargeStride)
3937 {
3938 struct Vertex
3939 {
3940 Vector4 position;
3941 Vector2 color;
3942 };
3943
3944 constexpr uint32_t kColorOffset = offsetof(Vertex, color);
3945
3946 // Get MAX_VERTEX_ATTRIB_STRIDE.
3947 GLint maxStride;
3948 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
3949
3950 uint32_t bufferSize = static_cast<uint32_t>(maxStride);
3951 uint32_t stride = sizeof(Vertex);
3952 uint32_t numVertices = bufferSize / stride;
3953
3954 // The last vertex fits in the buffer size. The last vertex stride extends past it.
3955 ASSERT_LT(numVertices * stride, bufferSize);
3956 ASSERT_GT(numVertices * stride + kColorOffset, bufferSize);
3957
3958 RNG rng(0);
3959
3960 std::vector<Vertex> vertexData(bufferSize, {Vector4(), Vector2()});
3961 std::vector<GLColor> expectedColors;
3962 for (uint32_t vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex)
3963 {
3964 int x = vertexIndex % getWindowWidth();
3965 int y = vertexIndex / getWindowWidth();
3966
3967 // Generate and clamp a 2 component vector.
3968 Vector4 randomVec4 = RandomVec4(rng.randomInt(), 0.0f, 1.0f);
3969 GLColor randomColor(randomVec4);
3970 randomColor[2] = 0;
3971 randomColor[3] = 255;
3972 Vector4 clampedVec = randomColor.toNormalizedVector();
3973
3974 vertexData[vertexIndex] = {Vector4(x, y, 0.0f, 1.0f),
3975 Vector2(clampedVec[0], clampedVec[1])};
3976 expectedColors.push_back(randomColor);
3977 }
3978
3979 GLBuffer buffer;
3980 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3981 glBufferData(GL_ARRAY_BUFFER, bufferSize, vertexData.data(), GL_STATIC_DRAW);
3982
3983 vertexData.resize(numVertices);
3984
3985 constexpr char kVS[] = R"(#version 310 es
3986 in vec4 pos;
3987 in vec2 color;
3988 out vec2 vcolor;
3989 void main()
3990 {
3991 vcolor = color;
3992 gl_Position = vec4(((pos.x + 0.5) / 64.0) - 1.0, ((pos.y + 0.5) / 64.0) - 1.0, 0, 1);
3993 gl_PointSize = 1.0;
3994 })";
3995
3996 constexpr char kFS[] = R"(#version 310 es
3997 precision mediump float;
3998 in vec2 vcolor;
3999 out vec4 fcolor;
4000 void main()
4001 {
4002 fcolor = vec4(vcolor, 0.0, 1.0);
4003 })";
4004
4005 ANGLE_GL_PROGRAM(program, kVS, kFS);
4006 glUseProgram(program);
4007
4008 GLint posLoc = glGetAttribLocation(program, "pos");
4009 ASSERT_NE(-1, posLoc);
4010 GLint colorLoc = glGetAttribLocation(program, "color");
4011 ASSERT_NE(-1, colorLoc);
4012
4013 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
4014 glEnableVertexAttribArray(posLoc);
4015 glVertexAttribPointer(colorLoc, 2, GL_FLOAT, GL_FALSE, stride,
4016 reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(kColorOffset)));
4017 glEnableVertexAttribArray(colorLoc);
4018
4019 glDrawArrays(GL_POINTS, 0, numVertices);
4020
4021 // Validate pixels.
4022 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
4023 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
4024 actualColors.data());
4025
4026 actualColors.resize(numVertices);
4027
4028 ASSERT_GL_NO_ERROR();
4029 EXPECT_EQ(expectedColors, actualColors);
4030 }
4031
makeMismatchingSignsTestVS(uint32_t attribCount,uint16_t signedMask)4032 std::string VertexAttributeTestES31::makeMismatchingSignsTestVS(uint32_t attribCount,
4033 uint16_t signedMask)
4034 {
4035 std::ostringstream shader;
4036
4037 shader << R"(#version 310 es
4038 precision highp float;
4039
4040 // The signedness is determined by |signedMask|.
4041 )";
4042
4043 for (uint32_t i = 0; i < attribCount; ++i)
4044 {
4045 shader << "in highp " << ((signedMask >> i & 1) == 0 ? "u" : "i") << "vec4 attrib" << i
4046 << ";\n";
4047 }
4048
4049 shader << "flat out highp uvec4 v[" << attribCount << "];\n";
4050
4051 shader << R"(
4052 void main() {
4053 )";
4054
4055 for (uint32_t i = 0; i < attribCount; ++i)
4056 {
4057 shader << "v[" << i << "] = uvec4(attrib" << i << ");\n";
4058 }
4059
4060 shader << R"(
4061 // gl_VertexID x y
4062 // 0 -1 -1
4063 // 1 1 -1
4064 // 2 -1 1
4065 // 3 1 1
4066 int bit0 = gl_VertexID & 1;
4067 int bit1 = gl_VertexID >> 1;
4068 gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, gl_VertexID % 2 == 0 ? -1 : 1, 1);
4069 })";
4070
4071 return shader.str();
4072 }
4073
makeMismatchingSignsTestFS(uint32_t attribCount)4074 std::string VertexAttributeTestES31::makeMismatchingSignsTestFS(uint32_t attribCount)
4075 {
4076 std::ostringstream shader;
4077
4078 shader << R"(#version 310 es
4079 precision highp float;
4080 )";
4081
4082 shader << "flat in highp uvec4 v[" << attribCount << "];\n";
4083
4084 shader << R"(out vec4 fragColor;
4085 uniform vec4 colorScale;
4086
4087 bool isOk(uvec4 inputVarying, uint index)
4088 {
4089 return inputVarying.x == index &&
4090 inputVarying.y == index * 2u &&
4091 inputVarying.z == index + 1u &&
4092 inputVarying.w == index + 0x12345u;
4093 }
4094
4095 void main()
4096 {
4097 bool result = true;
4098 )";
4099 shader << " for (uint index = 0u; index < " << attribCount << "u; ++index)\n";
4100 shader << R"({
4101 result = result && isOk(v[index], index);
4102 }
4103
4104 fragColor = vec4(result) * colorScale;
4105 })";
4106
4107 return shader.str();
4108 }
4109
setupVertexAttribPointersForMismatchSignsTest(uint16_t currentSignedMask,uint16_t toggleMask)4110 uint16_t VertexAttributeTestES31::setupVertexAttribPointersForMismatchSignsTest(
4111 uint16_t currentSignedMask,
4112 uint16_t toggleMask)
4113 {
4114 uint16_t newSignedMask = currentSignedMask ^ toggleMask;
4115
4116 for (uint32_t i = 0; i < 16; ++i)
4117 {
4118 if ((toggleMask >> i & 1) == 0)
4119 {
4120 continue;
4121 }
4122
4123 const GLenum type = (newSignedMask >> i & 1) == 0 ? GL_UNSIGNED_INT : GL_INT;
4124 glVertexAttribIPointer(i, 4, type, sizeof(GLuint[4]),
4125 reinterpret_cast<const void *>(sizeof(GLuint[4][4]) * i));
4126 }
4127
4128 return newSignedMask;
4129 }
4130
4131 // Test changing between matching and mismatching signedness of vertex attributes, when the
4132 // attribute changes type.
TEST_P(VertexAttributeTestES31,MismatchingSignsChangingAttributeType)4133 TEST_P(VertexAttributeTestES31, MismatchingSignsChangingAttributeType)
4134 {
4135 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
4136
4137 // GL supports a minimum of 16 vertex attributes, and gl_VertexID is counted as one.
4138 // The signedness pattern used here is:
4139 //
4140 // 0 14
4141 // iiui uuii iuui uui
4142 //
4143 // Which is chosen such that there's no clear repeating / mirror pattern.
4144 const std::string vs = makeMismatchingSignsTestVS(15, 0x49CB);
4145 const std::string fs = makeMismatchingSignsTestFS(15);
4146
4147 ANGLE_GL_PROGRAM(program, vs.c_str(), fs.c_str());
4148 for (uint32_t i = 0; i < 15; ++i)
4149 {
4150 char attribName[20];
4151 snprintf(attribName, sizeof(attribName), "attrib%u\n", i);
4152 glBindAttribLocation(program, i, attribName);
4153 }
4154 glLinkProgram(program);
4155 glUseProgram(program);
4156 ASSERT_GL_NO_ERROR();
4157
4158 GLint colorScaleLoc = glGetUniformLocation(program, "colorScale");
4159 ASSERT_NE(-1, colorScaleLoc);
4160
4161 GLuint data[15][4][4];
4162 for (GLuint i = 0; i < 15; ++i)
4163 {
4164 for (GLuint j = 0; j < 4; ++j)
4165 {
4166 // Match the expectation in the shader
4167 data[i][j][0] = i;
4168 data[i][j][1] = i * 2;
4169 data[i][j][2] = i + 1;
4170 data[i][j][3] = i + 0x12345;
4171 }
4172 }
4173
4174 GLBuffer buffer;
4175 glBindBuffer(GL_ARRAY_BUFFER, buffer);
4176 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
4177
4178 // Randomly match and mismatch the component type
4179 uint16_t signedMask = setupVertexAttribPointersForMismatchSignsTest(0x0FA5, 0x7FFF);
4180
4181 for (uint32_t i = 0; i < 15; ++i)
4182 {
4183 glEnableVertexAttribArray(i);
4184 }
4185
4186 glClearColor(0, 0, 0, 0);
4187 glClear(GL_COLOR_BUFFER_BIT);
4188
4189 glEnable(GL_BLEND);
4190 glBlendFunc(GL_ONE, GL_ONE);
4191
4192 glUniform4f(colorScaleLoc, 1, 0, 0, 0);
4193 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4194
4195 // Modify the attributes randomly and make sure tests still pass
4196
4197 signedMask = setupVertexAttribPointersForMismatchSignsTest(signedMask, 0x3572);
4198 glUniform4f(colorScaleLoc, 0, 1, 0, 0);
4199 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4200
4201 signedMask = setupVertexAttribPointersForMismatchSignsTest(signedMask, 0x4B1C);
4202 glUniform4f(colorScaleLoc, 0, 0, 1, 0);
4203 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4204
4205 signedMask = setupVertexAttribPointersForMismatchSignsTest(signedMask, 0x19D6);
4206 glUniform4f(colorScaleLoc, 0, 0, 0, 1);
4207 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4208
4209 // All channels must be 1
4210 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::white);
4211 ASSERT_GL_NO_ERROR();
4212 }
4213
4214 // Test changing between matching and mismatching signedness of vertex attributes, when the
4215 // program itself changes the type.
TEST_P(VertexAttributeTestES31,MismatchingSignsChangingProgramType)4216 TEST_P(VertexAttributeTestES31, MismatchingSignsChangingProgramType)
4217 {
4218 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
4219
4220 // GL supports a minimum of 16 vertex attributes, and gl_VertexID is counted as one.
4221 constexpr uint32_t kAttribCount[4] = {12, 9, 15, 7};
4222 constexpr uint32_t kAttribSignedMask[4] = {0x94f, 0x6A, 0x765B, 0x29};
4223
4224 GLProgram programs[4];
4225
4226 for (uint32_t progIndex = 0; progIndex < 4; ++progIndex)
4227 {
4228 const std::string vs =
4229 makeMismatchingSignsTestVS(kAttribCount[progIndex], kAttribSignedMask[progIndex]);
4230 const std::string fs = makeMismatchingSignsTestFS(kAttribCount[progIndex]);
4231
4232 programs[progIndex].makeRaster(vs.c_str(), fs.c_str());
4233 for (uint32_t i = 0; i < kAttribCount[progIndex]; ++i)
4234 {
4235 char attribName[20];
4236 snprintf(attribName, sizeof(attribName), "attrib%u\n", i);
4237 glBindAttribLocation(programs[progIndex], i, attribName);
4238 }
4239 glLinkProgram(programs[progIndex]);
4240 glUseProgram(programs[progIndex]);
4241 ASSERT_GL_NO_ERROR();
4242 }
4243
4244 GLuint data[15][4][4];
4245 for (GLuint i = 0; i < 15; ++i)
4246 {
4247 for (GLuint j = 0; j < 4; ++j)
4248 {
4249 // Match the expectation in the shader
4250 data[i][j][0] = i;
4251 data[i][j][1] = i * 2;
4252 data[i][j][2] = i + 1;
4253 data[i][j][3] = i + 0x12345;
4254 }
4255 }
4256
4257 GLBuffer buffer;
4258 glBindBuffer(GL_ARRAY_BUFFER, buffer);
4259 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
4260
4261 // Randomly match and mismatch the component type
4262 setupVertexAttribPointersForMismatchSignsTest(0x55F8, 0x7FFF);
4263
4264 for (uint32_t i = 0; i < 15; ++i)
4265 {
4266 glEnableVertexAttribArray(i);
4267 }
4268
4269 glClearColor(0, 0, 0, 0);
4270 glClear(GL_COLOR_BUFFER_BIT);
4271
4272 glEnable(GL_BLEND);
4273 glBlendFunc(GL_ONE, GL_ONE);
4274
4275 glUseProgram(programs[0]);
4276 GLint colorScaleLoc = glGetUniformLocation(programs[0], "colorScale");
4277 ASSERT_NE(-1, colorScaleLoc);
4278 glUniform4f(colorScaleLoc, 1, 0, 0, 0);
4279 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4280
4281 // Change the program, which have randomly different attribute component types and make sure
4282 // tests still pass
4283
4284 glUseProgram(programs[1]);
4285 colorScaleLoc = glGetUniformLocation(programs[1], "colorScale");
4286 ASSERT_NE(-1, colorScaleLoc);
4287 glUniform4f(colorScaleLoc, 0, 1, 0, 0);
4288 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4289
4290 glUseProgram(programs[2]);
4291 colorScaleLoc = glGetUniformLocation(programs[2], "colorScale");
4292 ASSERT_NE(-1, colorScaleLoc);
4293 glUniform4f(colorScaleLoc, 0, 0, 1, 0);
4294 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4295
4296 glUseProgram(programs[3]);
4297 colorScaleLoc = glGetUniformLocation(programs[3], "colorScale");
4298 ASSERT_NE(-1, colorScaleLoc);
4299 glUniform4f(colorScaleLoc, 0, 0, 0, 1);
4300 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4301
4302 // All channels must be 1
4303 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::white);
4304 ASSERT_GL_NO_ERROR();
4305 }
4306
4307 // Test that aliasing attribute locations work with es 100 shaders. Note that es 300 and above
4308 // don't allow vertex attribute aliasing. This test excludes matrix types.
TEST_P(VertexAttributeTest,AliasingVectorAttribLocations)4309 TEST_P(VertexAttributeTest, AliasingVectorAttribLocations)
4310 {
4311 // http://anglebug.com/42263740
4312 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
4313
4314 // http://anglebug.com/42262130
4315 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
4316
4317 // http://anglebug.com/42262131
4318 ANGLE_SKIP_TEST_IF(IsD3D());
4319
4320 // This test needs 10 total attributes. All backends support this except some old Android
4321 // devices.
4322 GLint maxVertexAttribs = 0;
4323 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
4324 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 10);
4325
4326 constexpr char kVS[] = R"(attribute vec4 position;
4327 // 4 aliasing attributes
4328 attribute float attr0f;
4329 attribute vec2 attr0v2;
4330 attribute vec3 attr0v3;
4331 attribute vec4 attr0v4;
4332 const vec4 attr0Expected = vec4(0.1, 0.2, 0.3, 0.4);
4333
4334 // 2 aliasing attributes
4335 attribute vec2 attr1v2;
4336 attribute vec3 attr1v3;
4337 const vec3 attr1Expected = vec3(0.5, 0.6, 0.7);
4338
4339 // 2 aliasing attributes
4340 attribute vec4 attr2v4;
4341 attribute float attr2f;
4342 const vec4 attr2Expected = vec4(0.8, 0.85, 0.9, 0.95);
4343
4344 // 2 aliasing attributes
4345 attribute float attr3f1;
4346 attribute float attr3f2;
4347 const float attr3Expected = 1.0;
4348
4349 uniform float attr0Select;
4350 uniform float attr1Select;
4351 uniform float attr2Select;
4352 uniform float attr3Select;
4353
4354 // Each channel controlled by success from each set of aliasing attributes. If a channel is 0, the
4355 // attribute test has failed. Otherwise it will be 0.25, 0.5, 0.75 or 1.0, depending on how many
4356 // channels there are in the compared attribute (except attr3).
4357 varying mediump vec4 color;
4358 void main()
4359 {
4360 gl_Position = position;
4361
4362 vec4 result = vec4(0);
4363
4364 if (attr0Select < 0.5)
4365 result.r = abs(attr0f - attr0Expected.x) < 0.01 ? 0.25 : 0.0;
4366 else if (attr0Select < 1.5)
4367 result.r = all(lessThan(abs(attr0v2 - attr0Expected.xy), vec2(0.01))) ? 0.5 : 0.0;
4368 else if (attr0Select < 2.5)
4369 result.r = all(lessThan(abs(attr0v3 - attr0Expected.xyz), vec3(0.01))) ? 0.75 : 0.0;
4370 else
4371 result.r = all(lessThan(abs(attr0v4 - attr0Expected), vec4(0.01 )))? 1.0 : 0.0;
4372
4373 if (attr1Select < 0.5)
4374 result.g = all(lessThan(abs(attr1v2 - attr1Expected.xy), vec2(0.01 )))? 0.5 : 0.0;
4375 else
4376 result.g = all(lessThan(abs(attr1v3 - attr1Expected), vec3(0.01 )))? 0.75 : 0.0;
4377
4378 if (attr2Select < 0.5)
4379 result.b = abs(attr2f - attr2Expected.x) < 0.01 ? 0.25 : 0.0;
4380 else
4381 result.b = all(lessThan(abs(attr2v4 - attr2Expected), vec4(0.01))) ? 1.0 : 0.0;
4382
4383 if (attr3Select < 0.5)
4384 result.a = abs(attr3f1 - attr3Expected) < 0.01 ? 0.25 : 0.0;
4385 else
4386 result.a = abs(attr3f2 - attr3Expected) < 0.01 ? 0.5 : 0.0;
4387
4388 color = result;
4389 })";
4390
4391 constexpr char kFS[] = R"(varying mediump vec4 color;
4392 void main(void)
4393 {
4394 gl_FragColor = color;
4395 })";
4396
4397 // Compile shaders.
4398 GLuint program = CompileProgram(kVS, kFS);
4399 ASSERT_NE(program, 0u);
4400
4401 // Setup bindings.
4402 glBindAttribLocation(program, 0, "attr0f");
4403 glBindAttribLocation(program, 0, "attr0v2");
4404 glBindAttribLocation(program, 0, "attr0v3");
4405 glBindAttribLocation(program, 0, "attr0v4");
4406 glBindAttribLocation(program, 1, "attr1v2");
4407 glBindAttribLocation(program, 1, "attr1v3");
4408 glBindAttribLocation(program, 2, "attr2v4");
4409 glBindAttribLocation(program, 2, "attr2f");
4410 glBindAttribLocation(program, 3, "attr3f1");
4411 glBindAttribLocation(program, 3, "attr3f2");
4412 EXPECT_GL_NO_ERROR();
4413
4414 // Link program and get uniform locations.
4415 glLinkProgram(program);
4416 glUseProgram(program);
4417 GLint attr0SelectLoc = glGetUniformLocation(program, "attr0Select");
4418 GLint attr1SelectLoc = glGetUniformLocation(program, "attr1Select");
4419 GLint attr2SelectLoc = glGetUniformLocation(program, "attr2Select");
4420 GLint attr3SelectLoc = glGetUniformLocation(program, "attr3Select");
4421 ASSERT_NE(-1, attr0SelectLoc);
4422 ASSERT_NE(-1, attr1SelectLoc);
4423 ASSERT_NE(-1, attr2SelectLoc);
4424 ASSERT_NE(-1, attr3SelectLoc);
4425 EXPECT_GL_NO_ERROR();
4426
4427 // Set values for attributes.
4428 glVertexAttrib4f(0, 0.1f, 0.2f, 0.3f, 0.4f);
4429 glVertexAttrib3f(1, 0.5f, 0.6f, 0.7f);
4430 glVertexAttrib4f(2, 0.8f, 0.85f, 0.9f, 0.95f);
4431 glVertexAttrib1f(3, 1.0f);
4432 glDisableVertexAttribArray(0);
4433 glDisableVertexAttribArray(1);
4434 glDisableVertexAttribArray(2);
4435 glDisableVertexAttribArray(3);
4436 EXPECT_GL_NO_ERROR();
4437
4438 // Go through different combination of attributes and make sure reading through every alias is
4439 // correctly handled.
4440 GLColor expected;
4441 for (uint32_t attr0Select = 0; attr0Select < 4; ++attr0Select)
4442 {
4443 glUniform1f(attr0SelectLoc, attr0Select);
4444 expected.R = attr0Select * 64 + 63;
4445
4446 for (uint32_t attr1Select = 0; attr1Select < 2; ++attr1Select)
4447 {
4448 glUniform1f(attr1SelectLoc, attr1Select);
4449 expected.G = attr1Select * 64 + 127;
4450
4451 for (uint32_t attr2Select = 0; attr2Select < 2; ++attr2Select)
4452 {
4453 glUniform1f(attr2SelectLoc, attr2Select);
4454 expected.B = attr2Select * 192 + 63;
4455
4456 for (uint32_t attr3Select = 0; attr3Select < 2; ++attr3Select)
4457 {
4458 glUniform1f(attr3SelectLoc, attr3Select);
4459 expected.A = attr3Select * 64 + 63;
4460
4461 drawQuad(program, "position", 0.5f);
4462 EXPECT_GL_NO_ERROR();
4463 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
4464 }
4465 }
4466 }
4467 }
4468 }
4469
4470 // Test that aliasing attribute locations work with es 100 shaders. Note that es 300 and above
4471 // don't allow vertex attribute aliasing. This test includes matrix types.
TEST_P(VertexAttributeTest,AliasingMatrixAttribLocations)4472 TEST_P(VertexAttributeTest, AliasingMatrixAttribLocations)
4473 {
4474 // http://anglebug.com/42263740
4475 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
4476
4477 // http://anglebug.com/42262130
4478 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
4479
4480 // http://anglebug.com/42262131
4481 ANGLE_SKIP_TEST_IF(IsD3D());
4482
4483 // This test needs 16 total attributes. All backends support this except some old Android
4484 // devices.
4485 GLint maxVertexAttribs = 0;
4486 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
4487 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 16);
4488
4489 constexpr char kVS[] = R"(attribute vec4 position;
4490 // attributes aliasing location 0 and above
4491 attribute float attr0f;
4492 attribute mat3 attr0m3;
4493 attribute mat2 attr0m2;
4494
4495 // attributes aliasing location 1 and above
4496 attribute vec4 attr1v4;
4497
4498 // attributes aliasing location 2 and above
4499 attribute mat4 attr2m4;
4500
4501 // attributes aliasing location 3 and above
4502 attribute mat2 attr3m2;
4503
4504 // attributes aliasing location 5 and above
4505 attribute vec2 attr5v2;
4506
4507 // In summary (attr prefix shortened to a):
4508 //
4509 // location 0: a0f a0m3[0] a0m2[0]
4510 // location 1: a0m3[1] a0m2[1] a1v4
4511 // location 2: a0m3[2] a2m4[0]
4512 // location 3: a2m4[1] a3m2[0]
4513 // location 4: a2m4[2] a3m2[1]
4514 // location 5: a2m4[3] a5v2
4515
4516 const vec3 loc0Expected = vec3(0.05, 0.1, 0.15);
4517 const vec4 loc1Expected = vec4(0.2, 0.25, 0.3, 0.35);
4518 const vec4 loc2Expected = vec4(0.4, 0.45, 0.5, 0.55);
4519 const vec4 loc3Expected = vec4(0.6, 0.65, 0.7, 0.75);
4520 const vec4 loc4Expected = vec4(0.8, 0.85, 0.9, 0.95);
4521 const vec4 loc5Expected = vec4(0.25, 0.5, 0.75, 1.0);
4522
4523 uniform float loc0Select;
4524 uniform float loc1Select;
4525 uniform float loc2Select;
4526 uniform float loc3Select;
4527 uniform float loc4Select;
4528 uniform float loc5Select;
4529
4530 // Each channel controlled by success from each set of aliasing locations. Locations 2 and 3
4531 // contribute to B together, while locations 4 and 5 contribute to A together. If a channel is 0,
4532 // the attribute test has failed. Otherwise it will be 1/N, 2/N, ..., 1, depending on how many
4533 // possible values there are for the controlling uniforms.
4534 varying mediump vec4 color;
4535 void main()
4536 {
4537 gl_Position = position;
4538
4539 vec4 result = vec4(0);
4540
4541 if (loc0Select < 0.5)
4542 result.r = abs(attr0f - loc0Expected.x) < 0.01 ? 0.333333 : 0.0;
4543 else if (loc0Select < 1.5)
4544 result.r = all(lessThan(abs(attr0m2[0] - loc0Expected.xy), vec2(0.01))) ? 0.666667 : 0.0;
4545 else
4546 result.r = all(lessThan(abs(attr0m3[0] - loc0Expected), vec3(0.01))) ? 1.0 : 0.0;
4547
4548 if (loc1Select < 0.5)
4549 result.g = all(lessThan(abs(attr0m3[1] - loc1Expected.xyz), vec3(0.01))) ? 0.333333 : 0.0;
4550 else if (loc1Select < 1.5)
4551 result.g = all(lessThan(abs(attr0m2[1] - loc1Expected.xy), vec2(0.01))) ? 0.666667 : 0.0;
4552 else
4553 result.g = all(lessThan(abs(attr1v4 - loc1Expected), vec4(0.01))) ? 1.0 : 0.0;
4554
4555 bool loc2Ok = false;
4556 bool loc3Ok = false;
4557
4558 if (loc2Select < 0.5)
4559 loc2Ok = all(lessThan(abs(attr0m3[2] - loc2Expected.xyz), vec3(0.01)));
4560 else
4561 loc2Ok = all(lessThan(abs(attr2m4[0] - loc2Expected), vec4(0.01)));
4562
4563 if (loc3Select < 0.5)
4564 loc3Ok = all(lessThan(abs(attr2m4[1] - loc3Expected), vec4(0.01)));
4565 else
4566 loc3Ok = all(lessThan(abs(attr3m2[0] - loc3Expected.xy), vec2(0.01)));
4567
4568 if (loc2Ok && loc3Ok)
4569 {
4570 if (loc2Select < 0.5)
4571 if (loc3Select < 0.5)
4572 result.b = 0.25;
4573 else
4574 result.b = 0.5;
4575 else
4576 if (loc3Select < 0.5)
4577 result.b = 0.75;
4578 else
4579 result.b = 1.0;
4580 }
4581
4582 bool loc4Ok = false;
4583 bool loc5Ok = false;
4584
4585 if (loc4Select < 0.5)
4586 loc4Ok = all(lessThan(abs(attr2m4[2] - loc4Expected), vec4(0.01)));
4587 else
4588 loc4Ok = all(lessThan(abs(attr3m2[1] - loc4Expected.xy), vec2(0.01)));
4589
4590 if (loc5Select < 0.5)
4591 loc5Ok = all(lessThan(abs(attr2m4[3] - loc5Expected), vec4(0.01)));
4592 else
4593 loc5Ok = all(lessThan(abs(attr5v2 - loc5Expected.xy), vec2(0.01)));
4594
4595 if (loc4Ok && loc5Ok)
4596 {
4597 if (loc4Select < 0.5)
4598 if (loc5Select < 0.5)
4599 result.a = 0.25;
4600 else
4601 result.a = 0.5;
4602 else
4603 if (loc5Select < 0.5)
4604 result.a = 0.75;
4605 else
4606 result.a = 1.0;
4607 }
4608
4609 color = result;
4610 })";
4611
4612 constexpr char kFS[] = R"(varying mediump vec4 color;
4613 void main(void)
4614 {
4615 gl_FragColor = color;
4616 })";
4617
4618 // Compile shaders.
4619 GLuint program = CompileProgram(kVS, kFS);
4620 ASSERT_NE(program, 0u);
4621
4622 // Setup bindings.
4623 glBindAttribLocation(program, 0, "attr0f");
4624 glBindAttribLocation(program, 0, "attr0m3");
4625 glBindAttribLocation(program, 0, "attr0m2");
4626 glBindAttribLocation(program, 1, "attr1v4");
4627 glBindAttribLocation(program, 2, "attr2m4");
4628 glBindAttribLocation(program, 3, "attr3m2");
4629 glBindAttribLocation(program, 5, "attr5v2");
4630 EXPECT_GL_NO_ERROR();
4631
4632 // Link program and get uniform locations.
4633 glLinkProgram(program);
4634 glUseProgram(program);
4635 EXPECT_GL_NO_ERROR();
4636
4637 GLint loc0SelectLoc = glGetUniformLocation(program, "loc0Select");
4638 GLint loc1SelectLoc = glGetUniformLocation(program, "loc1Select");
4639 GLint loc2SelectLoc = glGetUniformLocation(program, "loc2Select");
4640 GLint loc3SelectLoc = glGetUniformLocation(program, "loc3Select");
4641 GLint loc4SelectLoc = glGetUniformLocation(program, "loc4Select");
4642 GLint loc5SelectLoc = glGetUniformLocation(program, "loc5Select");
4643 ASSERT_NE(-1, loc0SelectLoc);
4644 ASSERT_NE(-1, loc1SelectLoc);
4645 ASSERT_NE(-1, loc2SelectLoc);
4646 ASSERT_NE(-1, loc3SelectLoc);
4647 ASSERT_NE(-1, loc4SelectLoc);
4648 ASSERT_NE(-1, loc5SelectLoc);
4649 EXPECT_GL_NO_ERROR();
4650
4651 // Set values for attributes.
4652 glVertexAttrib3f(0, 0.05, 0.1, 0.15);
4653 glVertexAttrib4f(1, 0.2, 0.25, 0.3, 0.35);
4654 glVertexAttrib4f(2, 0.4, 0.45, 0.5, 0.55);
4655 glVertexAttrib4f(3, 0.6, 0.65, 0.7, 0.75);
4656 glVertexAttrib4f(4, 0.8, 0.85, 0.9, 0.95);
4657 glVertexAttrib4f(5, 0.25, 0.5, 0.75, 1.0);
4658 glDisableVertexAttribArray(0);
4659 glDisableVertexAttribArray(1);
4660 glDisableVertexAttribArray(2);
4661 glDisableVertexAttribArray(3);
4662 glDisableVertexAttribArray(4);
4663 glDisableVertexAttribArray(5);
4664 EXPECT_GL_NO_ERROR();
4665
4666 // Go through different combination of attributes and make sure reading through every alias is
4667 // correctly handled.
4668 GLColor expected;
4669 for (uint32_t loc0Select = 0; loc0Select < 3; ++loc0Select)
4670 {
4671 glUniform1f(loc0SelectLoc, loc0Select);
4672 expected.R = loc0Select * 85 + 85;
4673
4674 for (uint32_t loc1Select = 0; loc1Select < 3; ++loc1Select)
4675 {
4676 glUniform1f(loc1SelectLoc, loc1Select);
4677 expected.G = loc1Select * 85 + 85;
4678
4679 for (uint32_t loc2Select = 0; loc2Select < 2; ++loc2Select)
4680 {
4681 glUniform1f(loc2SelectLoc, loc2Select);
4682
4683 for (uint32_t loc3Select = 0; loc3Select < 2; ++loc3Select)
4684 {
4685 glUniform1f(loc3SelectLoc, loc3Select);
4686 expected.B = (loc2Select << 1 | loc3Select) * 64 + 63;
4687
4688 for (uint32_t loc4Select = 0; loc4Select < 2; ++loc4Select)
4689 {
4690 glUniform1f(loc4SelectLoc, loc4Select);
4691
4692 for (uint32_t loc5Select = 0; loc5Select < 2; ++loc5Select)
4693 {
4694 glUniform1f(loc5SelectLoc, loc5Select);
4695 expected.A = (loc4Select << 1 | loc5Select) * 64 + 63;
4696
4697 drawQuad(program, "position", 0.5f);
4698 EXPECT_GL_NO_ERROR();
4699 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
4700 }
4701 }
4702 }
4703 }
4704 }
4705 }
4706 }
4707
4708 // Test that aliasing attribute locations work with differing precisions.
TEST_P(VertexAttributeTest,AliasingVectorAttribLocationsDifferingPrecisions)4709 TEST_P(VertexAttributeTest, AliasingVectorAttribLocationsDifferingPrecisions)
4710 {
4711 // http://anglebug.com/42263740
4712 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
4713
4714 // http://anglebug.com/42262130
4715 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
4716
4717 // http://anglebug.com/42262131
4718 ANGLE_SKIP_TEST_IF(IsD3D());
4719
4720 constexpr char kVS[] = R"(attribute vec4 position;
4721 // aliasing attributes.
4722 attribute mediump vec2 attr0v2;
4723 attribute highp vec3 attr0v3;
4724 const vec3 attr0Expected = vec3(0.125, 0.25, 0.375);
4725
4726 // aliasing attributes.
4727 attribute highp vec2 attr1v2;
4728 attribute mediump vec3 attr1v3;
4729 const vec3 attr1Expected = vec3(0.5, 0.625, 0.75);
4730
4731 uniform float attr0Select;
4732 uniform float attr1Select;
4733
4734 // Each channel controlled by success from each set of aliasing attributes (R and G used only). If
4735 // a channel is 0, the attribute test has failed. Otherwise it will be 0.5 or 1.0.
4736 varying mediump vec4 color;
4737 void main()
4738 {
4739 gl_Position = position;
4740
4741 vec4 result = vec4(0, 0, 0, 1);
4742
4743 if (attr0Select < 0.5)
4744 result.r = all(lessThan(abs(attr0v2 - attr0Expected.xy), vec2(0.01))) ? 0.5 : 0.0;
4745 else
4746 result.r = all(lessThan(abs(attr0v3 - attr0Expected), vec3(0.01))) ? 1.0 : 0.0;
4747
4748 if (attr1Select < 0.5)
4749 result.g = all(lessThan(abs(attr1v2 - attr1Expected.xy), vec2(0.01))) ? 0.5 : 0.0;
4750 else
4751 result.g = all(lessThan(abs(attr1v3 - attr1Expected), vec3(0.01))) ? 1.0 : 0.0;
4752
4753 color = result;
4754 })";
4755
4756 constexpr char kFS[] = R"(varying mediump vec4 color;
4757 void main(void)
4758 {
4759 gl_FragColor = color;
4760 })";
4761
4762 // Compile shaders.
4763 GLuint program = CompileProgram(kVS, kFS);
4764 ASSERT_NE(program, 0u);
4765
4766 // Setup bindings.
4767 glBindAttribLocation(program, 0, "attr0v2");
4768 glBindAttribLocation(program, 0, "attr0v3");
4769 glBindAttribLocation(program, 1, "attr1v2");
4770 glBindAttribLocation(program, 1, "attr1v3");
4771 EXPECT_GL_NO_ERROR();
4772
4773 // Link program and get uniform locations.
4774 glLinkProgram(program);
4775 glUseProgram(program);
4776 GLint attr0SelectLoc = glGetUniformLocation(program, "attr0Select");
4777 GLint attr1SelectLoc = glGetUniformLocation(program, "attr1Select");
4778 ASSERT_NE(-1, attr0SelectLoc);
4779 ASSERT_NE(-1, attr1SelectLoc);
4780 EXPECT_GL_NO_ERROR();
4781
4782 // Set values for attributes.
4783 glVertexAttrib3f(0, 0.125f, 0.25f, 0.375f);
4784 glVertexAttrib3f(1, 0.5f, 0.625f, 0.75f);
4785 glDisableVertexAttribArray(0);
4786 glDisableVertexAttribArray(1);
4787 EXPECT_GL_NO_ERROR();
4788
4789 // Go through different combination of attributes and make sure reading through every alias is
4790 // correctly handled.
4791 GLColor expected;
4792 expected.B = 0;
4793 expected.A = 255;
4794 for (uint32_t attr0Select = 0; attr0Select < 2; ++attr0Select)
4795 {
4796 glUniform1f(attr0SelectLoc, attr0Select);
4797 expected.R = attr0Select * 128 + 127;
4798
4799 for (uint32_t attr1Select = 0; attr1Select < 2; ++attr1Select)
4800 {
4801 glUniform1f(attr1SelectLoc, attr1Select);
4802 expected.G = attr1Select * 128 + 127;
4803
4804 drawQuad(program, "position", 0.5f);
4805 EXPECT_GL_NO_ERROR();
4806 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
4807 }
4808 }
4809 }
4810
4811 // Test that unsupported vertex format specified on non-existing attribute doesn't crash.
TEST_P(VertexAttributeTest,VertexFormatConversionOfNonExistingAttribute)4812 TEST_P(VertexAttributeTest, VertexFormatConversionOfNonExistingAttribute)
4813 {
4814 constexpr char kVS[] = R"(precision highp float;
4815 attribute vec3 attr1;
4816 void main(void) {
4817 gl_Position = vec4(attr1, 1.0);
4818 })";
4819
4820 constexpr char kFS[] = R"(precision highp float;
4821 void main(void) {
4822 gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
4823 })";
4824
4825 GLBuffer emptyBuffer;
4826 glBindBuffer(GL_ARRAY_BUFFER, emptyBuffer);
4827
4828 ANGLE_GL_PROGRAM(program, kVS, kFS);
4829 glBindAttribLocation(program, 0, "attr1");
4830 glLinkProgram(program);
4831 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
4832 glUseProgram(program);
4833
4834 // Use the RGB8 format for non-existing attribute 1.
4835 glEnableVertexAttribArray(1);
4836 glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, false, 1, 0);
4837
4838 glDrawArrays(GL_TRIANGLES, 0, 3);
4839 EXPECT_GL_NO_ERROR();
4840 }
4841
4842 // Covers a bug with integer formats and an element size larger than the vertex stride.
TEST_P(VertexAttributeTestES3,StrideSmallerThanIntegerElementSize)4843 TEST_P(VertexAttributeTestES3, StrideSmallerThanIntegerElementSize)
4844 {
4845 constexpr char kVS[] = R"(#version 300 es
4846 in vec4 position;
4847 in ivec2 intAttrib;
4848 in vec2 floatAttrib;
4849 out vec4 colorVarying;
4850 void main()
4851 {
4852 gl_Position = position;
4853 if (vec2(intAttrib) == floatAttrib)
4854 {
4855 colorVarying = vec4(0, 1, 0, 1);
4856 }
4857 else
4858 {
4859 colorVarying = vec4(1, 0, 0, 1);
4860 }
4861 })";
4862
4863 constexpr char kFS[] = R"(#version 300 es
4864 precision mediump float;
4865 in vec4 colorVarying;
4866 out vec4 fragColor;
4867 void main()
4868 {
4869 fragColor = colorVarying;
4870 })";
4871
4872 ANGLE_GL_PROGRAM(testProgram, kVS, kFS);
4873 glUseProgram(testProgram);
4874
4875 GLBuffer positionBuffer;
4876 {
4877 const std::array<Vector3, 6> &quadVerts = GetQuadVertices();
4878
4879 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4880 glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(),
4881 GL_STATIC_DRAW);
4882
4883 GLint posLoc = glGetAttribLocation(testProgram, "position");
4884 ASSERT_NE(posLoc, -1);
4885 glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
4886 glEnableVertexAttribArray(posLoc);
4887 }
4888
4889 GLBuffer intBuffer;
4890 {
4891 std::array<GLbyte, 12> intData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
4892
4893 glBindBuffer(GL_ARRAY_BUFFER, intBuffer);
4894 glBufferData(GL_ARRAY_BUFFER, intData.size() * sizeof(intData[0]), intData.data(),
4895 GL_STATIC_DRAW);
4896
4897 GLint intLoc = glGetAttribLocation(testProgram, "intAttrib");
4898 ASSERT_NE(intLoc, -1);
4899 glVertexAttribIPointer(intLoc, 2, GL_BYTE, 1, nullptr);
4900 glEnableVertexAttribArray(intLoc);
4901 }
4902
4903 GLBuffer floatBuffer;
4904 {
4905 std::array<GLfloat, 12> floatData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
4906
4907 glBindBuffer(GL_ARRAY_BUFFER, floatBuffer);
4908 glBufferData(GL_ARRAY_BUFFER, floatData.size() * sizeof(floatData[0]), floatData.data(),
4909 GL_STATIC_DRAW);
4910
4911 GLint floatLoc = glGetAttribLocation(testProgram, "floatAttrib");
4912 ASSERT_NE(floatLoc, -1);
4913 glVertexAttribPointer(floatLoc, 2, GL_FLOAT, GL_FALSE, 4, nullptr);
4914 glEnableVertexAttribArray(floatLoc);
4915 }
4916
4917 glDrawArrays(GL_TRIANGLES, 0, 6);
4918
4919 ASSERT_GL_NO_ERROR();
4920
4921 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
4922 }
4923
4924 // Test that pipeline is recreated properly when switching from ARRAY buffer to client buffer,
4925 // while removing client buffer. Bug observed in Dragonmania game.
TEST_P(VertexAttributeTestES31,ArrayToClientBufferStride)4926 TEST_P(VertexAttributeTestES31, ArrayToClientBufferStride)
4927 {
4928 constexpr char kVS[] = R"(#version 310 es
4929 precision highp float;
4930 in vec4 in_pos;
4931 in vec4 in_color;
4932 out vec4 color;
4933 void main(void) {
4934 gl_Position = in_pos;
4935 color = in_color;
4936 })";
4937
4938 constexpr char kFS[] = R"(#version 310 es
4939 precision highp float;
4940 in vec4 color;
4941 out vec4 frag_color;
4942 void main(void) {
4943 frag_color = color;
4944 })";
4945 swapBuffers();
4946
4947 ANGLE_GL_PROGRAM(program, kVS, kFS);
4948 glUseProgram(program);
4949 GLint posLoc = glGetAttribLocation(program, "in_pos");
4950 GLint colorLoc = glGetAttribLocation(program, "in_color");
4951 ASSERT_NE(posLoc, -1);
4952 ASSERT_NE(colorLoc, -1);
4953
4954 const std::array<Vector3, 6> &quadVerts = GetQuadVertices();
4955 // Data for packed attributes.
4956 std::array<float, ((3 + 4) * 6)> data;
4957
4958 float kYellow[4] = {1.0f, 1.0f, 0.0f, 1.0f};
4959 float kGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
4960
4961 for (int i = 0; i < 6; i++)
4962 {
4963 memcpy(&data[i * (3 + 4)], &quadVerts[i], sizeof(Vector3));
4964 memcpy(&data[i * (3 + 4) + 3], &kYellow, 4 * sizeof(float));
4965 }
4966
4967 {
4968 GLBuffer buffer;
4969 glBindBuffer(GL_ARRAY_BUFFER, buffer);
4970 glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(data[0]), data.data(), GL_STATIC_DRAW);
4971
4972 glEnableVertexAttribArray(posLoc);
4973 glEnableVertexAttribArray(colorLoc);
4974
4975 glVertexAttribPointer(posLoc, 3, GL_FLOAT, false, 28, reinterpret_cast<void *>(0));
4976 glVertexAttribPointer(colorLoc, 4, GL_FLOAT, false, 28, reinterpret_cast<void *>(12));
4977
4978 glDrawArrays(GL_TRIANGLES, 0, 6);
4979 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
4980 EXPECT_GL_NO_ERROR();
4981 // Unbind before destroy.
4982 glBindBuffer(GL_ARRAY_BUFFER, 0);
4983 }
4984
4985 // Modify color to green.
4986 for (int i = 0; i < 6; i++)
4987 {
4988 memcpy(&data[i * (3 + 4) + 3], &kGreen, 4 * sizeof(float));
4989 }
4990
4991 // Provide client pointer.
4992 glVertexAttribPointer(posLoc, 3, GL_FLOAT, false, 28, data.data());
4993 glVertexAttribPointer(colorLoc, 4, GL_FLOAT, false, 28, &data[3]);
4994
4995 glDrawArrays(GL_TRIANGLES, 0, 6);
4996 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
4997 EXPECT_GL_NO_ERROR();
4998 }
4999
5000 // Create a vertex array with an empty array buffer and attribute offsets.
5001 // This succeded in the end2end and capture/replay tests, but resulted in a trace
5002 // producing a GL error when using MEC.
5003 // Validation complained about the following:
5004 // "Client data cannot be used with a non-default vertex array object."
5005
5006 // To capture this test with MEC run:
5007 // mkdir src/tests/capture_replay_tests/empty_array_buffer_test
5008 // ANGLE_CAPTURE_ENABLED=1 ANGLE_CAPTURE_FRAME_START=2 \
5009 // ANGLE_CAPTURE_FRAME_END=2 ANGLE_CAPTURE_LABEL=empty_array_buffer_test \
5010 // ANGLE_CAPTURE_OUT_DIR=src/tests/capture_replay_tests/empty_array_buffer_test \
5011 // ./out/Debug/angle_end2end_tests \
5012 // --gtest_filter="VertexAttributeTestES3.EmptyArrayBuffer/ES3_Vulkan"
TEST_P(VertexAttributeTestES3,EmptyArrayBuffer)5013 TEST_P(VertexAttributeTestES3, EmptyArrayBuffer)
5014 {
5015 GLVertexArray vertexArray;
5016 glBindVertexArray(vertexArray);
5017
5018 GLBuffer emptyArrayBuffer;
5019 glBindBuffer(GL_ARRAY_BUFFER, emptyArrayBuffer);
5020
5021 glEnableVertexAttribArray(0);
5022 glEnableVertexAttribArray(1);
5023 glEnableVertexAttribArray(2);
5024 glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, GL_TRUE, 20, reinterpret_cast<const void *>(16));
5025 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, reinterpret_cast<const void *>(8));
5026 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 20, nullptr);
5027 EXPECT_GL_NO_ERROR();
5028
5029 glBindBuffer(GL_ARRAY_BUFFER, 0);
5030 glBindVertexArray(0);
5031
5032 EXPECT_GL_NO_ERROR();
5033
5034 // Swap a frame for MEC
5035 swapBuffers();
5036 }
5037
5038 // Set an attrib pointer and delete it's buffer after usage, while keeping the vertex array.
5039 // This will cause MEC to capture an invalid attribute pointer and also trigger
5040 // "Client data cannot be used with a non-default vertex array object."
TEST_P(VertexAttributeTestES3,InvalidAttribPointer)5041 TEST_P(VertexAttributeTestES3, InvalidAttribPointer)
5042 {
5043 GLVertexArray vertexArray;
5044 glBindVertexArray(vertexArray);
5045
5046 std::array<GLbyte, 12> vertexData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
5047
5048 {
5049 GLBuffer toBeDeletedArrayBuffer;
5050 glBindBuffer(GL_ARRAY_BUFFER, toBeDeletedArrayBuffer);
5051
5052 glBufferData(GL_ARRAY_BUFFER, vertexData.size(), vertexData.data(), GL_DYNAMIC_DRAW);
5053
5054 glEnableVertexAttribArray(0);
5055 glEnableVertexAttribArray(1);
5056
5057 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6, nullptr);
5058 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6, reinterpret_cast<const void *>(6));
5059
5060 glBindBuffer(GL_ARRAY_BUFFER, 0);
5061 glDisableVertexAttribArray(0);
5062 glDisableVertexAttribArray(1);
5063
5064 EXPECT_GL_NO_ERROR();
5065 }
5066
5067 // Set an attrib pointer that will be actually picked up by MEC, since the buffer will be kept.
5068 glEnableVertexAttribArray(0);
5069
5070 GLBuffer arrayBuffer;
5071 glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
5072
5073 glBufferData(GL_ARRAY_BUFFER, vertexData.size(), vertexData.data(), GL_DYNAMIC_DRAW);
5074
5075 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3, reinterpret_cast<const void *>(3));
5076
5077 EXPECT_GL_NO_ERROR();
5078
5079 // Swap a frame for MEC
5080 swapBuffers();
5081
5082 glBindBuffer(GL_ARRAY_BUFFER, 0);
5083 glEnableVertexAttribArray(0);
5084 }
5085
5086 // Test maxinum attribs full of Client buffers and then switch to mixed.
TEST_P(VertexAttributeTestES3,fullClientBuffersSwitchToMixed)5087 TEST_P(VertexAttributeTestES3, fullClientBuffersSwitchToMixed)
5088 {
5089 GLint maxAttribs;
5090 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
5091 ASSERT_GL_NO_ERROR();
5092
5093 // Reserve one attrib for position
5094 GLint drawAttribs = maxAttribs - 1;
5095
5096 GLuint program = compileMultiAttribProgram(drawAttribs);
5097 ASSERT_NE(0u, program);
5098
5099 const std::array<Vector2, 4> kIndexedQuadVertices = {{
5100 Vector2(-1.0f, 1.0f),
5101 Vector2(-1.0f, -1.0f),
5102 Vector2(1.0f, -1.0f),
5103 Vector2(1.0f, 1.0f),
5104 }};
5105
5106 GLsizei stride = (maxAttribs + 1) * sizeof(GLfloat);
5107
5108 constexpr std::array<GLushort, 6> kIndexedQuadIndices = {{0, 1, 2, 0, 2, 3}};
5109 GLuint indexBuffer = 0;
5110 glGenBuffers(1, &indexBuffer);
5111
5112 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
5113 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexedQuadIndices), kIndexedQuadIndices.data(),
5114 GL_STATIC_DRAW);
5115
5116 // Vertex drawAttribs color attributes plus position (x, y).
5117 GLint totalComponents = drawAttribs + 2;
5118 std::vector<GLfloat> vertexData(totalComponents * 4, 0.0f);
5119 for (GLint index = 0; index < 4; ++index)
5120 {
5121 vertexData[index * totalComponents + drawAttribs] = kIndexedQuadVertices[index].x();
5122 vertexData[index * totalComponents + drawAttribs + 1] = kIndexedQuadVertices[index].y();
5123 }
5124
5125 GLfloat attributeValue = 0.0f;
5126 GLfloat delta = 1.0f / 256.0f;
5127 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
5128 {
5129 vertexData[attribIndex] = attributeValue;
5130 vertexData[attribIndex + totalComponents] = attributeValue;
5131 vertexData[attribIndex + totalComponents * 2] = attributeValue;
5132 vertexData[attribIndex + totalComponents * 3] = attributeValue;
5133 attributeValue += delta;
5134 }
5135
5136 glUseProgram(program);
5137 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
5138 {
5139 std::stringstream attribStream;
5140 attribStream << "a" << attribIndex;
5141 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
5142 ASSERT_NE(-1, location);
5143 glVertexAttribPointer(location, 1, GL_FLOAT, GL_FALSE, stride,
5144 vertexData.data() + attribIndex);
5145 glEnableVertexAttribArray(location);
5146 }
5147 GLint posLoc = glGetAttribLocation(program, "position");
5148 ASSERT_NE(-1, posLoc);
5149 glEnableVertexAttribArray(posLoc);
5150 glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, stride, vertexData.data() + drawAttribs);
5151 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
5152
5153 // the result color should be (0 + 1 + 2 + ... + 14)/256 * 255;
5154 EXPECT_GL_NO_ERROR();
5155 EXPECT_PIXEL_NEAR(0, 0, 105, 0, 0, 255, 1);
5156
5157 // disable a few attribute use default attribute color
5158 GLint l0 = glGetAttribLocation(program, "a0");
5159 GLint l5 = glGetAttribLocation(program, "a5");
5160 GLint l13 = glGetAttribLocation(program, "a13");
5161 glDisableVertexAttribArray(l0);
5162 glVertexAttrib1f(l0, 1.0f / 16.0f);
5163 glDisableVertexAttribArray(l5);
5164 glVertexAttrib1f(l5, 1.0f / 16.0f);
5165 glDisableVertexAttribArray(l13);
5166 glVertexAttrib1f(l13, 1.0f / 16.0f);
5167
5168 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
5169
5170 EXPECT_GL_NO_ERROR();
5171 EXPECT_PIXEL_NEAR(0, 0, 134, 0, 0, 255, 1);
5172
5173 // disable all the client buffers.
5174 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
5175 {
5176 std::stringstream attribStream;
5177 attribStream << "a" << attribIndex;
5178 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
5179 ASSERT_NE(-1, location);
5180 glDisableVertexAttribArray(location);
5181 glVertexAttrib1f(location, 1.0f / 16.0f);
5182 }
5183
5184 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
5185
5186 EXPECT_GL_NO_ERROR();
5187 EXPECT_PIXEL_NEAR(0, 0, 239, 0, 0, 255, 1);
5188
5189 // enable all the client buffers.
5190 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
5191 {
5192 std::stringstream attribStream;
5193 attribStream << "a" << attribIndex;
5194 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
5195 ASSERT_NE(-1, location);
5196 glVertexAttribPointer(location, 1, GL_FLOAT, GL_FALSE, stride,
5197 vertexData.data() + attribIndex);
5198 glEnableVertexAttribArray(location);
5199 }
5200 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
5201 EXPECT_GL_NO_ERROR();
5202 EXPECT_PIXEL_NEAR(0, 0, 105, 0, 0, 255, 1);
5203 }
5204
5205 // Test bind an empty buffer for vertex attribute does not crash
TEST_P(VertexAttributeTestES3,emptyBuffer)5206 TEST_P(VertexAttributeTestES3, emptyBuffer)
5207 {
5208 constexpr char vs2[] =
5209 R"(#version 300 es
5210 in uvec4 attr0;
5211 void main()
5212 {
5213 gl_Position = vec4(attr0.x, 0.0, 0.0, 0.0);
5214 })";
5215 constexpr char fs[] =
5216 R"(#version 300 es
5217 precision highp float;
5218 out vec4 color;
5219 void main()
5220 {
5221 color = vec4(1.0, 0.0, 0.0, 1.0);
5222 })";
5223 GLuint program2 = CompileProgram(vs2, fs);
5224 GLBuffer buf;
5225 glBindBuffer(GL_ARRAY_BUFFER, buf);
5226 glEnableVertexAttribArray(0);
5227 glVertexAttribIPointer(0, 4, GL_UNSIGNED_BYTE, 0, 0);
5228 glVertexAttribDivisor(0, 2);
5229 glUseProgram(program2);
5230 glDrawArrays(GL_POINTS, 0, 1);
5231
5232 swapBuffers();
5233 }
5234
5235 // This is a test for use with ANGLE's Capture/Replay.
5236 // It emulates a situation we see in some apps, where attribs are passed in but may not be used.
5237 // In particular, that test asks for all active attributes and iterates through each one. Before any
5238 // changes to FrameCapture, this will create calls that look up attributes that are considered
5239 // unused on some platforms, making the trace non-portable. Whether they are used depends on how
5240 // well the stack optimizes the shader pipeline. In this instance, we are just passing them across
5241 // the pipeline boundary where they are dead in the fragment shader, but other cases have included
5242 // attributes passed to empty functions, or some eliminated with math. The more optimizations
5243 // applied by the driver, the higher chance of getting an unused attribute.
TEST_P(VertexAttributeTestES3,UnusedAttribsMEC)5244 TEST_P(VertexAttributeTestES3, UnusedAttribsMEC)
5245 {
5246 constexpr char vertexShader[] =
5247 R"(#version 300 es
5248 precision mediump float;
5249 in vec4 position;
5250 in vec4 input_unused;
5251 out vec4 passthrough;
5252 void main()
5253 {
5254 passthrough = input_unused;
5255 gl_Position = position;
5256 })";
5257
5258 constexpr char fragmentShader[] =
5259 R"(#version 300 es
5260 precision mediump float;
5261 in vec4 passthrough;
5262 out vec4 color;
5263 void main()
5264 {
5265 // ignore passthrough - this makes it unused with cross stage optimizations
5266 color = vec4(1.0);
5267 })";
5268
5269 GLuint program = CompileProgram(vertexShader, fragmentShader);
5270 glUseProgram(program);
5271
5272 // Set up vertex data
5273 GLBuffer positionBuffer;
5274 const std::array<Vector3, 6> &quadVerts = GetQuadVertices();
5275 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
5276 glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(),
5277 GL_STATIC_DRAW);
5278
5279 // Loop through a sequence multiple times, so MEC can capture it.
5280 // Ask about vertex attribs and set them up, regardless of whether they are used.
5281 // This matches behavior seen in some apps.
5282 for (int i = 0; i < 10; i++)
5283 {
5284 // Look up the number of attribs
5285 GLint activeAttribCount = 0;
5286 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttribCount);
5287
5288 // Look up how big they might get
5289 GLint maxActiveAttribLength = 0;
5290 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxActiveAttribLength);
5291
5292 GLsizei attribLength = 0;
5293 GLint attribSize = 0;
5294 GLenum attribType = 0;
5295 GLchar attribName[16] = {0};
5296 ASSERT(maxActiveAttribLength < 16);
5297
5298 // Look up each attribute and set them up
5299 for (int j = 0; j < activeAttribCount; j++)
5300 {
5301 glGetActiveAttrib(program, j, maxActiveAttribLength, &attribLength, &attribSize,
5302 &attribType, attribName);
5303 GLint posLoc = glGetAttribLocation(program, attribName);
5304 ASSERT_NE(posLoc, -1);
5305 glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, j, nullptr);
5306 glEnableVertexAttribArray(posLoc);
5307 }
5308
5309 // Draw and swap on each loop to trigger MEC
5310 glDrawArrays(GL_TRIANGLES, 0, 6);
5311 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
5312 swapBuffers();
5313 }
5314 }
5315
5316 // Test that a particular vertex attribute naming does not affect the functionality.
5317 // Tests the vertex attrib aliasing part. Note that aliasing works with es 100 shaders.
TEST_P(VertexAttributeTest,AliasingAttribNaming)5318 TEST_P(VertexAttributeTest, AliasingAttribNaming)
5319 {
5320 // http://anglebug.com/42263740
5321 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
5322
5323 // http://anglebug.com/42262130
5324 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
5325
5326 // http://anglebug.com/42262131
5327 ANGLE_SKIP_TEST_IF(IsD3D());
5328
5329 // This test needs 16 total attributes. All backends support this except some old Android
5330 // devices.
5331 GLint maxVertexAttribs = 0;
5332 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
5333 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 16);
5334
5335 constexpr char kVS[] = R"(attribute vec4 position;
5336 // attributes aliasing location 0 and above
5337 attribute mat3 a;
5338 attribute mat2 a_;
5339
5340 // attributes aliasing location 1 and above
5341 attribute vec4 a_1;
5342
5343 // attributes aliasing location 2 and above
5344 attribute mat4 a_0;
5345
5346 // In summary:
5347 //
5348 // location 0: a[0] a_[0]
5349 // location 1: a[1] a_[1] a_1
5350 // location 2: a[2] a_0[0]
5351 // location 3: a_0[1] (untested)
5352 // location 4: a_0[2] (untested)
5353 // location 5: a_0[3] (untested)
5354
5355 const vec3 loc0Expected = vec3(0.05, 0.1, 0.15);
5356 const vec4 loc1Expected = vec4(0.2, 0.25, 0.3, 0.35);
5357 const vec4 loc2Expected = vec4(0.4, 0.45, 0.5, 0.55);
5358
5359 uniform float loc0Select;
5360 uniform float loc1Select;
5361 uniform float loc2Select;
5362
5363 // Each channel controlled by success from each set of aliasing locations. If a channel is 0,
5364 // the attribute test has failed. Otherwise it will be 1/N, 2/N, ..., 1, depending on how many
5365 // possible values there are for the controlling uniforms.
5366 varying mediump vec4 color;
5367 void main()
5368 {
5369 gl_Position = position;
5370
5371 vec4 result = vec4(0);
5372
5373 if (loc0Select < 0.5)
5374 result.r = all(lessThan(abs(a[0] - loc0Expected.xyz), vec3(0.01))) ? 0.5 : 0.0;
5375 else
5376 result.r = all(lessThan(abs(a_[0] - loc0Expected.xy), vec2(0.01))) ? 1.0 : 0.0;
5377
5378 if (loc1Select < 0.5)
5379 result.g = all(lessThan(abs(a[1] - loc1Expected.xyz), vec3(0.01))) ? 0.333333 : 0.0;
5380 else if (loc1Select < 1.5)
5381 result.g = all(lessThan(abs(a_[1] - loc1Expected.xy), vec2(0.01))) ? 0.666667 : 0.0;
5382 else
5383 result.g = all(lessThan(abs(a_1 - loc1Expected), vec4(0.01))) ? 1.0 : 0.0;
5384
5385 if (loc2Select < 0.5)
5386 result.b = all(lessThan(abs(a[2] - loc2Expected.xyz), vec3(0.01))) ? 0.5 : 0.0;
5387 else
5388 result.b = all(lessThan(abs(a_0[0] - loc2Expected), vec4(0.01))) ? 1.0 : 0.0;
5389 result.a = 1.0;
5390 color = result;
5391 })";
5392
5393 constexpr char kFS[] = R"(varying mediump vec4 color;
5394 void main(void)
5395 {
5396 gl_FragColor = color;
5397 })";
5398
5399 // Compile shaders.
5400 GLuint program = CompileProgram(kVS, kFS);
5401 ASSERT_NE(program, 0u);
5402
5403 // Setup bindings.
5404 glBindAttribLocation(program, 0, "a");
5405 glBindAttribLocation(program, 0, "a_");
5406 glBindAttribLocation(program, 1, "a_1");
5407 glBindAttribLocation(program, 2, "a_0");
5408 EXPECT_GL_NO_ERROR();
5409
5410 // Link program and get uniform locations.
5411 glLinkProgram(program);
5412 glUseProgram(program);
5413 EXPECT_GL_NO_ERROR();
5414
5415 GLint loc0SelectLoc = glGetUniformLocation(program, "loc0Select");
5416 GLint loc1SelectLoc = glGetUniformLocation(program, "loc1Select");
5417 GLint loc2SelectLoc = glGetUniformLocation(program, "loc2Select");
5418 ASSERT_NE(-1, loc0SelectLoc);
5419 ASSERT_NE(-1, loc1SelectLoc);
5420 ASSERT_NE(-1, loc2SelectLoc);
5421 EXPECT_GL_NO_ERROR();
5422
5423 // Set values for attributes.
5424 glVertexAttrib3f(0, 0.05, 0.1, 0.15);
5425 glVertexAttrib4f(1, 0.2, 0.25, 0.3, 0.35);
5426 glVertexAttrib4f(2, 0.4, 0.45, 0.5, 0.55);
5427 glDisableVertexAttribArray(0);
5428 glDisableVertexAttribArray(1);
5429 glDisableVertexAttribArray(2);
5430 EXPECT_GL_NO_ERROR();
5431
5432 // Go through different combination of attributes and make sure reading through every alias is
5433 // correctly handled.
5434 GLColor expected;
5435 expected.A = 255;
5436 for (uint32_t loc0Select = 0; loc0Select < 2; ++loc0Select)
5437 {
5438 glUniform1f(loc0SelectLoc, loc0Select);
5439 expected.R = loc0Select * 127 + 127;
5440
5441 for (uint32_t loc1Select = 0; loc1Select < 3; ++loc1Select)
5442 {
5443 glUniform1f(loc1SelectLoc, loc1Select);
5444 expected.G = loc1Select * 85 + 85;
5445
5446 for (uint32_t loc2Select = 0; loc2Select < 2; ++loc2Select)
5447 {
5448 glUniform1f(loc2SelectLoc, loc2Select);
5449 expected.B = loc2Select * 127 + 127;
5450 drawQuad(program, "position", 0.5f);
5451 EXPECT_GL_NO_ERROR();
5452 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
5453 }
5454 }
5455 }
5456 }
5457
5458 // Test that a particular vertex attribute naming does not affect the functionality.
TEST_P(VertexAttributeTestES3,AttribNaming)5459 TEST_P(VertexAttributeTestES3, AttribNaming)
5460 {
5461 // http://anglebug.com/42263740
5462 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
5463
5464 // http://anglebug.com/42262130
5465 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
5466
5467 // http://anglebug.com/42262131
5468 ANGLE_SKIP_TEST_IF(IsD3D());
5469
5470 // This test needs roughly 16 total attributes. All backends support this except some old
5471 // Android devices.
5472 GLint maxVertexAttribs = 0;
5473 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
5474 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 16);
5475
5476 constexpr char kVS[] = R"(#version 300 es
5477 precision mediump float;
5478 in vec4 position;
5479 in mat3 a;
5480 in mat2 a_;
5481 in vec4 a_1;
5482 in vec4 a_0;
5483 const mat3 aExpected = mat3(0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8);
5484 const mat2 a_Expected = mat2(1.0, 1.1, 1.2, 1.3);
5485 const vec4 a_1Expected = vec4(2.0, 2.1, 2.2, 2.3);
5486 const vec4 a_0Expected = vec4(3.0, 3.1, 3.2, 3.3);
5487 out mediump vec4 color;
5488 void main()
5489 {
5490 gl_Position = position;
5491
5492 vec4 result = vec4(0);
5493 mat3 diff3 = a - aExpected;
5494 result.r = all(lessThan(abs(diff3[0]) + abs(diff3[1]) + abs(diff3[2]), vec3(0.01))) ? 1.0 : 0.0;
5495 mat2 diff2 = a_ - a_Expected;
5496 result.g = all(lessThan(abs(diff2[0]) + abs(diff2[1]), vec2(0.01))) ? 1.0 : 0.0;
5497 result.b = all(lessThan(abs(a_1 - a_1Expected), vec4(0.01))) ? 1.0 : 0.0;
5498 result.a = all(lessThan(abs(a_0 - a_0Expected), vec4(0.01))) ? 1.0 : 0.0;
5499 color = result;
5500 })";
5501
5502 constexpr char kFS[] = R"(#version 300 es
5503 in mediump vec4 color;
5504 out mediump vec4 fragColor;
5505 void main(void)
5506 {
5507 fragColor = color;
5508 })";
5509
5510 GLuint program = CompileProgram(kVS, kFS);
5511 ASSERT_NE(program, 0u);
5512
5513 glBindAttribLocation(program, 0, "a");
5514 glBindAttribLocation(program, 4, "a_");
5515 glBindAttribLocation(program, 6, "a_1");
5516 glBindAttribLocation(program, 7, "a_0");
5517 EXPECT_GL_NO_ERROR();
5518
5519 glLinkProgram(program);
5520 glUseProgram(program);
5521 EXPECT_GL_NO_ERROR();
5522
5523 // Set values for attributes.
5524 glVertexAttrib3f(0, 0.0, 0.1, 0.2);
5525 glVertexAttrib3f(1, 0.3, 0.4, 0.5);
5526 glVertexAttrib3f(2, 0.6, 0.7, 0.8);
5527 glVertexAttrib2f(4, 1.0, 1.1);
5528 glVertexAttrib2f(5, 1.2, 1.3);
5529 glVertexAttrib4f(6, 2.0, 2.1, 2.2, 2.3);
5530 glVertexAttrib4f(7, 3.0, 3.1, 3.2, 3.3);
5531
5532 glDisableVertexAttribArray(0);
5533 glDisableVertexAttribArray(1);
5534 glDisableVertexAttribArray(2);
5535 glDisableVertexAttribArray(3);
5536 glDisableVertexAttribArray(4);
5537 glDisableVertexAttribArray(5);
5538 glDisableVertexAttribArray(6);
5539 glDisableVertexAttribArray(7);
5540 glDisableVertexAttribArray(8);
5541 glDisableVertexAttribArray(9);
5542 EXPECT_GL_NO_ERROR();
5543
5544 // Go through different combination of attributes and make sure reading through every alias is
5545 // correctly handled.
5546 GLColor expected{255, 255, 255, 255};
5547 drawQuad(program, "position", 0.5f);
5548 EXPECT_GL_NO_ERROR();
5549 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
5550 }
5551
5552 // VAO emulation fails on Mac but is not used on Mac in the wild. http://anglebug.com/40096758
5553 #if !defined(__APPLE__)
5554 # define EMULATED_VAO_CONFIGS \
5555 ES2_OPENGL().enable(Feature::SyncAllVertexArraysToDefault), \
5556 ES2_OPENGLES().enable(Feature::SyncAllVertexArraysToDefault), \
5557 ES3_OPENGL().enable(Feature::SyncAllVertexArraysToDefault), \
5558 ES3_OPENGLES().enable(Feature::SyncAllVertexArraysToDefault),
5559 #else
5560 # define EMULATED_VAO_CONFIGS
5561 #endif
5562
5563 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
5564 VertexAttributeTest,
5565 ES2_VULKAN().enable(Feature::ForceFallbackFormat),
5566 ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5567 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5568 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5569 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5570 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass),
5571 ES2_OPENGL().enable(Feature::ForceMinimumMaxVertexAttributes),
5572 ES2_OPENGLES().enable(Feature::ForceMinimumMaxVertexAttributes),
5573 EMULATED_VAO_CONFIGS);
5574
5575 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
5576 VertexAttributeOORTest,
5577 ES2_VULKAN().enable(Feature::ForceFallbackFormat),
5578 ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5579 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5580 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5581 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5582 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass));
5583
5584 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(RobustVertexAttributeTest);
5585
5586 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexAttributeTestES3);
5587 ANGLE_INSTANTIATE_TEST_ES3_AND(
5588 VertexAttributeTestES3,
5589 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5590 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5591 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5592 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass),
5593 ES3_VULKAN()
5594 .disable(Feature::UseVertexInputBindingStrideDynamicState)
5595 .disable(Feature::SupportsGraphicsPipelineLibrary));
5596
5597 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexAttributeTestES31);
5598 ANGLE_INSTANTIATE_TEST_ES31_AND(VertexAttributeTestES31,
5599 ES31_VULKAN().enable(Feature::ForceFallbackFormat),
5600 ES31_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5601 ES31_VULKAN()
5602 .disable(Feature::UseVertexInputBindingStrideDynamicState)
5603 .disable(Feature::SupportsGraphicsPipelineLibrary));
5604
5605 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
5606 VertexAttributeCachingTest,
5607 ES2_VULKAN().enable(Feature::ForceFallbackFormat),
5608 ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5609 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5610 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5611 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5612 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass));
5613
5614 } // anonymous namespace
5615