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__anonaec9f1eb0111::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/5399
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 // Tests that we do not generate a SIGBUS error on arm when translating unaligned data.
2011 // GL_RG32_SNORM_ANGLEX is used when using glVertexAttribPointer with certain parameters.
TEST_P(VertexAttributeTestES3,DrawWithUnalignedData)2012 TEST_P(VertexAttributeTestES3, DrawWithUnalignedData)
2013 {
2014 constexpr char kVS[] = R"(#version 300 es
2015 precision highp float;
2016 in highp vec4 a_position;
2017 in highp vec2 a_ColorTest;
2018 out highp vec2 v_colorTest;
2019
2020 void main() {
2021 v_colorTest = a_ColorTest;
2022 gl_Position = a_position;
2023 })";
2024
2025 constexpr char kFS[] = R"(#version 300 es
2026 precision highp float;
2027 in highp vec2 v_colorTest;
2028 out vec4 fragColor;
2029
2030 void main() {
2031 // The input value is 0x01000000 / 0x7FFFFFFF
2032 if(abs(v_colorTest.x - 0.0078125) < 0.001) {
2033 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2034 } else {
2035 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2036 }
2037 })";
2038
2039 ANGLE_GL_PROGRAM(program, kVS, kFS);
2040 glBindAttribLocation(program, 0, "a_position");
2041 glBindAttribLocation(program, 1, "a_ColorTest");
2042 glLinkProgram(program);
2043 glUseProgram(program);
2044 ASSERT_GL_NO_ERROR();
2045
2046 constexpr size_t kDataSize = 12;
2047
2048 // Initialize vertex attribute data with 1u32s, but shifted right by a variable number of bytes
2049 GLubyte colorTestData[(kDataSize + 1) * sizeof(GLuint)];
2050
2051 for (size_t offset = 0; offset < sizeof(GLuint); offset++)
2052 {
2053 for (size_t dataIndex = 0; dataIndex < kDataSize * sizeof(GLuint); dataIndex++)
2054 {
2055 if (dataIndex % sizeof(GLuint) == sizeof(GLuint) - 1)
2056 {
2057 colorTestData[dataIndex + offset] = 1;
2058 }
2059 else
2060 {
2061
2062 colorTestData[dataIndex + offset] = 0;
2063 }
2064 }
2065
2066 GLubyte *offsetPtr = &colorTestData[offset];
2067 glVertexAttribPointer(1, 2, GL_INT, GL_TRUE, sizeof(GLuint), offsetPtr);
2068
2069 glBindBuffer(GL_ARRAY_BUFFER, 0);
2070 glEnableVertexAttribArray(1);
2071
2072 drawIndexedQuad(program, "a_position", 0.5f, 1.0f, false, true);
2073
2074 // Verify green was drawn.
2075 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green);
2076 ASSERT_GL_NO_ERROR();
2077 }
2078 }
2079
2080 // Tests that rendering is fine if GL_ANGLE_relaxed_vertex_attribute_type is enabled
2081 // and mismatched integer signedness between the program's attribute type and the
2082 // attribute type specified by VertexAttribIPointer are used.
TEST_P(VertexAttributeTestES3,DrawWithRelaxedVertexAttributeType)2083 TEST_P(VertexAttributeTestES3, DrawWithRelaxedVertexAttributeType)
2084 {
2085 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
2086
2087 constexpr char kVS[] = R"(#version 300 es
2088 precision highp float;
2089 in highp vec4 a_position;
2090 in highp ivec4 a_ColorTest;
2091 out highp vec4 v_colorTest;
2092
2093 void main() {
2094 v_colorTest = vec4(a_ColorTest);
2095 gl_Position = a_position;
2096 })";
2097
2098 constexpr char kFS[] = R"(#version 300 es
2099 precision highp float;
2100 in highp vec4 v_colorTest;
2101 out vec4 fragColor;
2102
2103 void main() {
2104 if(v_colorTest.x > 0.5) {
2105 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2106 } else {
2107 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2108 }
2109 })";
2110
2111 ANGLE_GL_PROGRAM(program, kVS, kFS);
2112 glBindAttribLocation(program, 0, "a_position");
2113 glBindAttribLocation(program, 1, "a_ColorTest");
2114 glLinkProgram(program);
2115 glUseProgram(program);
2116 ASSERT_GL_NO_ERROR();
2117
2118 constexpr size_t kDataSize = 48;
2119
2120 // Interleave test data with 0's.
2121 // This guards against a future code change that adjusts stride to 0
2122
2123 // clang-format off
2124 constexpr GLuint kColorTestData[kDataSize] = {
2125 // Vertex attribute data Unused data
2126 0u, 0u, 0u, 0u, /*red*/ 0u, 0u, 0u, 0u,
2127 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2128 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2129 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2130 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u,
2131 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u
2132 };
2133 // clang-format on
2134
2135 GLBuffer buffer;
2136 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2137 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * kDataSize, kColorTestData, GL_STATIC_DRAW);
2138
2139 glVertexAttribIPointer(1, 4, GL_UNSIGNED_INT, 8 * sizeof(GLuint),
2140 reinterpret_cast<const void *>(0));
2141
2142 glBindBuffer(GL_ARRAY_BUFFER, 0);
2143 glEnableVertexAttribArray(1);
2144
2145 drawQuad(program, "a_position", 0.5f);
2146
2147 // Verify green was drawn. If the stride isn't adjusted to 0 this corner will be green. If it is
2148 // adjusted to 0, the whole image will be red
2149 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green);
2150 ASSERT_GL_NO_ERROR();
2151 }
2152
2153 // Test that ensures we do not send data for components not specified by glVertexAttribPointer when
2154 // component types and sizes are mismatched
TEST_P(VertexAttributeTestES3,DrawWithMismatchedComponentCount)2155 TEST_P(VertexAttributeTestES3, DrawWithMismatchedComponentCount)
2156 {
2157 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
2158
2159 // To ensure the test results are valid when we don't send data for every component, the
2160 // shader's values must be defined by the backend.
2161 // Vulkan Spec 22.3. Vertex Attribute Divisor in Instanced Rendering
2162 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#_vertex_attribute_divisor_in_instanced_rendering
2163 // If the format does not include G, B, or A components, then those are filled with (0,0,1) as
2164 // needed (using either 1.0f or integer 1 based on the format) for attributes that are not
2165 // 64-bit data types.
2166 ANGLE_SKIP_TEST_IF(!IsVulkan());
2167
2168 constexpr char kVS[] = R"(#version 300 es
2169 precision highp float;
2170 in highp vec4 a_position;
2171 in highp ivec2 a_ColorTest;
2172 out highp vec2 v_colorTest;
2173
2174 void main() {
2175 v_colorTest = vec2(a_ColorTest);
2176 gl_Position = a_position;
2177 })";
2178
2179 constexpr char kFS[] = R"(#version 300 es
2180 precision highp float;
2181 in highp vec2 v_colorTest;
2182 out vec4 fragColor;
2183
2184 void main() {
2185 if(v_colorTest.y < 0.5) {
2186 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2187 } else {
2188 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2189 }
2190 })";
2191
2192 ANGLE_GL_PROGRAM(program, kVS, kFS);
2193 glBindAttribLocation(program, 0, "a_position");
2194 glBindAttribLocation(program, 1, "a_ColorTest");
2195 glLinkProgram(program);
2196 glUseProgram(program);
2197 ASSERT_GL_NO_ERROR();
2198
2199 constexpr size_t kDataSize = 24;
2200
2201 // Initialize vertex attribute data with 1s.
2202 GLuint kColorTestData[kDataSize];
2203 for (size_t dataIndex = 0; dataIndex < kDataSize; dataIndex++)
2204 {
2205 kColorTestData[dataIndex] = 1u;
2206 }
2207
2208 GLBuffer buffer;
2209 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2210 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * kDataSize, kColorTestData, GL_STATIC_DRAW);
2211
2212 glVertexAttribIPointer(1, 1, GL_UNSIGNED_INT, 4 * sizeof(GLuint),
2213 reinterpret_cast<const void *>(0));
2214
2215 glBindBuffer(GL_ARRAY_BUFFER, 0);
2216 glEnableVertexAttribArray(1);
2217
2218 drawQuad(program, "a_position", 0.5f);
2219
2220 // Verify green was drawn.
2221 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
2222 ASSERT_GL_NO_ERROR();
2223 }
2224
2225 // Test that ensures we do not send data for components not specified by glVertexAttribPointer when
2226 // component types and sizes are mismatched. Also guard against out of bound errors when atttribute
2227 // locations are specified.
TEST_P(VertexAttributeTestES3,DrawWithMismatchedComponentCountLocationSpecified)2228 TEST_P(VertexAttributeTestES3, DrawWithMismatchedComponentCountLocationSpecified)
2229 {
2230 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
2231
2232 // To ensure the test results are valid when we don't send data for every component, the
2233 // shader's values must be defined by the backend.
2234 // Vulkan Spec 22.3. Vertex Attribute Divisor in Instanced Rendering
2235 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#_vertex_attribute_divisor_in_instanced_rendering
2236 // If the format does not include G, B, or A components, then those are filled with (0,0,1) as
2237 // needed (using either 1.0f or integer 1 based on the format) for attributes that are not
2238 // 64-bit data types.
2239 ANGLE_SKIP_TEST_IF(!IsVulkan());
2240
2241 constexpr char kVS[] = R"(#version 300 es
2242 precision highp float;
2243 layout(location = 2) in highp vec4 a_position;
2244 layout(location = 0) in highp ivec2 a_ColorTest;
2245 out highp vec2 v_colorTest;
2246
2247 void main() {
2248 v_colorTest = vec2(a_ColorTest);
2249 gl_Position = a_position;
2250 })";
2251
2252 constexpr char kFS[] = R"(#version 300 es
2253 precision highp float;
2254 in highp vec2 v_colorTest;
2255 out vec4 fragColor;
2256
2257 void main() {
2258 if(v_colorTest.y < 0.5) {
2259 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
2260 } else {
2261 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
2262 }
2263 })";
2264
2265 ANGLE_GL_PROGRAM(program, kVS, kFS);
2266 glLinkProgram(program);
2267 glUseProgram(program);
2268 ASSERT_GL_NO_ERROR();
2269
2270 constexpr size_t kDataSize = 24;
2271
2272 // Initialize vertex attribute data with 1s.
2273 GLuint kColorTestData[kDataSize];
2274 for (size_t dataIndex = 0; dataIndex < kDataSize; dataIndex++)
2275 {
2276 kColorTestData[dataIndex] = 1u;
2277 }
2278
2279 GLBuffer buffer;
2280 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2281 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * kDataSize, kColorTestData, GL_STATIC_DRAW);
2282
2283 GLint colorLocation = glGetAttribLocation(program, "a_ColorTest");
2284 ASSERT_NE(colorLocation, -1);
2285 glVertexAttribIPointer(colorLocation, 1, GL_UNSIGNED_INT, 4 * sizeof(GLuint),
2286 reinterpret_cast<const void *>(0));
2287
2288 glBindBuffer(GL_ARRAY_BUFFER, 0);
2289 glEnableVertexAttribArray(1);
2290
2291 drawQuad(program, "a_position", 0.5f);
2292
2293 // Verify green was drawn.
2294 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
2295 ASSERT_GL_NO_ERROR();
2296 }
2297
2298 class VertexAttributeTestES31 : public VertexAttributeTestES3
2299 {
2300 protected:
VertexAttributeTestES31()2301 VertexAttributeTestES31() {}
2302
initTest()2303 void initTest()
2304 {
2305 initBasicProgram();
2306 glUseProgram(mProgram);
2307
2308 glGenVertexArrays(1, &mVAO);
2309 glBindVertexArray(mVAO);
2310
2311 auto quadVertices = GetQuadVertices();
2312 GLsizeiptr quadVerticesSize =
2313 static_cast<GLsizeiptr>(quadVertices.size() * sizeof(quadVertices[0]));
2314 glGenBuffers(1, &mQuadBuffer);
2315 glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
2316 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, quadVertices.data(), GL_STATIC_DRAW);
2317
2318 GLint positionLocation = glGetAttribLocation(mProgram, "position");
2319 ASSERT_NE(-1, positionLocation);
2320 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2321 glEnableVertexAttribArray(positionLocation);
2322
2323 std::array<GLfloat, kVertexCount> expectedData;
2324 for (size_t count = 0; count < kVertexCount; ++count)
2325 {
2326 expectedData[count] = static_cast<GLfloat>(count);
2327 }
2328
2329 const GLsizei kExpectedDataSize = kVertexCount * kFloatStride;
2330 glGenBuffers(1, &mExpectedBuffer);
2331 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2332 glBufferData(GL_ARRAY_BUFFER, kExpectedDataSize, expectedData.data(), GL_STATIC_DRAW);
2333 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
2334 glEnableVertexAttribArray(mExpectedAttrib);
2335 }
2336
testTearDown()2337 void testTearDown() override
2338 {
2339 VertexAttributeTestES3::testTearDown();
2340
2341 glDeleteBuffers(1, &mQuadBuffer);
2342 glDeleteBuffers(1, &mExpectedBuffer);
2343 glDeleteVertexArrays(1, &mVAO);
2344 }
2345
drawArraysWithStrideAndRelativeOffset(GLint stride,GLuint relativeOffset)2346 void drawArraysWithStrideAndRelativeOffset(GLint stride, GLuint relativeOffset)
2347 {
2348 initTest();
2349
2350 GLint floatStride = std::max(stride / kFloatStride, 1);
2351 GLuint floatRelativeOffset = relativeOffset / kFloatStride;
2352 size_t floatCount = static_cast<size_t>(floatRelativeOffset) + kVertexCount * floatStride;
2353 GLsizeiptr inputSize = static_cast<GLsizeiptr>(floatCount) * kFloatStride;
2354
2355 std::vector<GLfloat> inputData(floatCount);
2356 for (size_t count = 0; count < kVertexCount; ++count)
2357 {
2358 inputData[floatRelativeOffset + count * floatStride] = static_cast<GLfloat>(count);
2359 }
2360
2361 // Ensure inputSize, inputStride and inputOffset are multiples of TypeStride(GL_FLOAT).
2362 GLsizei inputStride = floatStride * kFloatStride;
2363 GLsizeiptr inputRelativeOffset = floatRelativeOffset * kFloatStride;
2364 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2365 glBufferData(GL_ARRAY_BUFFER, inputSize, nullptr, GL_STATIC_DRAW);
2366 glBufferSubData(GL_ARRAY_BUFFER, 0, inputSize, inputData.data());
2367 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE,
2368 base::checked_cast<GLuint>(inputRelativeOffset));
2369 glBindVertexBuffer(mTestAttrib, mBuffer, 0, inputStride);
2370 glEnableVertexAttribArray(mTestAttrib);
2371
2372 glDrawArrays(GL_TRIANGLES, 0, 6);
2373 checkPixels();
2374
2375 EXPECT_GL_NO_ERROR();
2376 }
2377
initOnlyUpdateBindingTest(GLint bindingToUpdate)2378 void initOnlyUpdateBindingTest(GLint bindingToUpdate)
2379 {
2380 initTest();
2381
2382 constexpr GLuint kTestFloatOffset1 = kVertexCount;
2383 std::array<GLfloat, kTestFloatOffset1 + kVertexCount> inputData1 = {};
2384 for (size_t count = 0; count < kVertexCount; ++count)
2385 {
2386 GLfloat value = static_cast<GLfloat>(count);
2387 inputData1[kTestFloatOffset1 + count] = value;
2388 }
2389
2390 GLBuffer testBuffer1;
2391 glBindBuffer(GL_ARRAY_BUFFER, testBuffer1);
2392 glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
2393 GL_STATIC_DRAW);
2394
2395 ASSERT_NE(bindingToUpdate, mTestAttrib);
2396 ASSERT_NE(bindingToUpdate, mExpectedAttrib);
2397
2398 // Set mTestAttrib using the binding bindingToUpdate.
2399 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0);
2400 glBindVertexBuffer(bindingToUpdate, testBuffer1, kTestFloatOffset1 * kFloatStride,
2401 kFloatStride);
2402 glVertexAttribBinding(mTestAttrib, bindingToUpdate);
2403 glEnableVertexAttribArray(mTestAttrib);
2404
2405 // In the first draw the current VAO states are set to driver.
2406 glDrawArrays(GL_TRIANGLES, 0, 6);
2407 checkPixels();
2408 EXPECT_GL_NO_ERROR();
2409
2410 // We need the second draw to ensure all VAO dirty bits are reset.
2411 // e.g. On D3D11 back-ends, Buffer11::resize is called in the first draw, where the related
2412 // binding is set to dirty again.
2413 glDrawArrays(GL_TRIANGLES, 0, 6);
2414 checkPixels();
2415 EXPECT_GL_NO_ERROR();
2416 }
2417
2418 std::string makeMismatchingSignsTestVS(uint32_t attribCount, uint16_t signedMask);
2419 std::string makeMismatchingSignsTestFS(uint32_t attribCount);
2420 uint16_t setupVertexAttribPointersForMismatchSignsTest(uint16_t currentSignedMask,
2421 uint16_t toggleMask);
2422
2423 GLuint mVAO = 0;
2424 GLuint mExpectedBuffer = 0;
2425 GLuint mQuadBuffer = 0;
2426
2427 const GLsizei kFloatStride = TypeStride(GL_FLOAT);
2428
2429 // Set the maximum value for stride and relativeOffset in case they are too large.
2430 const GLint MAX_STRIDE_FOR_TEST = 4095;
2431 const GLint MAX_RELATIVE_OFFSET_FOR_TEST = 4095;
2432 };
2433
2434 // Verify that MAX_VERTEX_ATTRIB_STRIDE is no less than the minimum required value (2048) in ES3.1.
TEST_P(VertexAttributeTestES31,MaxVertexAttribStride)2435 TEST_P(VertexAttributeTestES31, MaxVertexAttribStride)
2436 {
2437 GLint maxStride;
2438 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
2439 ASSERT_GL_NO_ERROR();
2440
2441 EXPECT_GE(maxStride, 2048);
2442 }
2443
2444 // Verify that GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET is no less than the minimum required value
2445 // (2047) in ES3.1.
TEST_P(VertexAttributeTestES31,MaxVertexAttribRelativeOffset)2446 TEST_P(VertexAttributeTestES31, MaxVertexAttribRelativeOffset)
2447 {
2448 GLint maxRelativeOffset;
2449 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
2450 ASSERT_GL_NO_ERROR();
2451
2452 EXPECT_GE(maxRelativeOffset, 2047);
2453 }
2454
2455 // Verify using MAX_VERTEX_ATTRIB_STRIDE as stride doesn't mess up the draw.
2456 // Use default value if the value of MAX_VERTEX_ATTRIB_STRIDE is too large for this test.
TEST_P(VertexAttributeTestES31,DrawArraysWithLargeStride)2457 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride)
2458 {
2459 GLint maxStride;
2460 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
2461 ASSERT_GL_NO_ERROR();
2462
2463 GLint largeStride = std::min(maxStride, MAX_STRIDE_FOR_TEST);
2464 drawArraysWithStrideAndRelativeOffset(largeStride, 0);
2465 }
2466
2467 // Verify using MAX_VERTEX_ATTRIB_RELATIVE_OFFSET as relativeOffset doesn't mess up the draw.
2468 // Use default value if the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSSET is too large for this test.
TEST_P(VertexAttributeTestES31,DrawArraysWithLargeRelativeOffset)2469 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeRelativeOffset)
2470 {
2471 GLint maxRelativeOffset;
2472 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
2473 ASSERT_GL_NO_ERROR();
2474
2475 GLint largeRelativeOffset = std::min(maxRelativeOffset, MAX_RELATIVE_OFFSET_FOR_TEST);
2476 drawArraysWithStrideAndRelativeOffset(0, largeRelativeOffset);
2477 }
2478
2479 // Test that vertex array object works correctly when render pipeline and compute pipeline are
2480 // crossly executed.
TEST_P(VertexAttributeTestES31,MixedComputeAndRenderPipelines)2481 TEST_P(VertexAttributeTestES31, MixedComputeAndRenderPipelines)
2482 {
2483 constexpr char kComputeShader[] =
2484 R"(#version 310 es
2485 layout(local_size_x=1) in;
2486 void main()
2487 {
2488 })";
2489 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
2490
2491 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2492 glClearColor(0, 0, 0, 0);
2493
2494 constexpr char kVertexShader[] =
2495 R"(#version 310 es
2496 precision mediump float;
2497 layout(location = 0) in vec4 position;
2498 layout(location = 2) in vec2 aOffset;
2499 layout(location = 3) in vec4 aColor;
2500 out vec4 vColor;
2501 void main() {
2502 vColor = aColor;
2503 gl_Position = position + vec4(aOffset, 0.0, 0.0);
2504 })";
2505
2506 constexpr char kFragmentShader[] =
2507 R"(#version 310 es
2508 precision mediump float;
2509 in vec4 vColor;
2510 out vec4 color;
2511 void main() {
2512 color = vColor;
2513 })";
2514
2515 ANGLE_GL_PROGRAM(renderProgram, kVertexShader, kFragmentShader);
2516
2517 constexpr char kVertexShader1[] =
2518 R"(#version 310 es
2519 precision mediump float;
2520 layout(location = 1) in vec4 position;
2521 layout(location = 2) in vec2 aOffset;
2522 layout(location = 3) in vec4 aColor;
2523 out vec4 vColor;
2524 void main() {
2525 vColor = aColor;
2526 gl_Position = position + vec4(aOffset, 0.0, 0.0);
2527 })";
2528
2529 ANGLE_GL_PROGRAM(renderProgram1, kVertexShader1, kFragmentShader);
2530
2531 std::array<GLfloat, 8> offsets = {
2532 -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
2533 };
2534 GLBuffer offsetBuffer;
2535 glBindBuffer(GL_ARRAY_BUFFER, offsetBuffer);
2536 glBufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(GLfloat), offsets.data(), GL_STATIC_DRAW);
2537
2538 std::array<GLfloat, 16> colors0 = {
2539 1.0, 0.0, 0.0, 1.0, // Red
2540 0.0, 1.0, 0.0, 1.0, // Green
2541 0.0, 0.0, 1.0, 1.0, // Blue
2542 1.0, 1.0, 0.0, 1.0, // Yellow
2543 };
2544 std::array<GLfloat, 16> colors1 = {
2545 1.0, 1.0, 0.0, 1.0, // Yellow
2546 0.0, 0.0, 1.0, 1.0, // Blue
2547 0.0, 1.0, 0.0, 1.0, // Green
2548 1.0, 0.0, 0.0, 1.0, // Red
2549 };
2550 GLBuffer colorBuffers[2];
2551 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[0]);
2552 glBufferData(GL_ARRAY_BUFFER, colors0.size() * sizeof(GLfloat), colors0.data(), GL_STATIC_DRAW);
2553 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[1]);
2554 glBufferData(GL_ARRAY_BUFFER, colors1.size() * sizeof(GLfloat), colors1.data(), GL_STATIC_DRAW);
2555
2556 std::array<GLfloat, 16> positions = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
2557 1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
2558 GLBuffer positionBuffer;
2559 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
2560 glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(GLfloat), positions.data(),
2561 GL_STATIC_DRAW);
2562
2563 const int kInstanceCount = 4;
2564 GLVertexArray vao[2];
2565 for (size_t i = 0u; i < 2u; ++i)
2566 {
2567 glBindVertexArray(vao[i]);
2568
2569 glBindBuffer(GL_ARRAY_BUFFER, offsetBuffer);
2570 glEnableVertexAttribArray(2);
2571 glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0);
2572 glVertexAttribDivisor(2, 1);
2573
2574 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[i]);
2575 glEnableVertexAttribArray(3);
2576 glVertexAttribPointer(3, 4, GL_FLOAT, false, 0, 0);
2577 glVertexAttribDivisor(3, 1);
2578
2579 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
2580 glEnableVertexAttribArray(i);
2581 glVertexAttribPointer(i, 2, GL_FLOAT, false, 0, 0);
2582 }
2583
2584 glClear(GL_COLOR_BUFFER_BIT);
2585
2586 for (int i = 0; i < 3; i++)
2587 {
2588 glUseProgram(renderProgram);
2589 glBindVertexArray(vao[0]);
2590 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, kInstanceCount);
2591
2592 EXPECT_GL_NO_ERROR();
2593 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 2, GLColor::red) << i;
2594 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green) << i;
2595 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue) << i;
2596 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::yellow) << i;
2597
2598 glBindVertexArray(vao[1]);
2599 glUseProgram(computeProgram);
2600 glDispatchCompute(1, 1, 1);
2601
2602 glUseProgram(renderProgram1);
2603 glBindVertexArray(vao[1]);
2604 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, kInstanceCount);
2605
2606 EXPECT_GL_NO_ERROR();
2607 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 2, GLColor::yellow) << i;
2608 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue) << i;
2609 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green) << i;
2610 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::red) << i;
2611 }
2612 ASSERT_GL_NO_ERROR();
2613 }
2614
TEST_P(VertexAttributeTestES31,UseComputeShaderToUpdateVertexBuffer)2615 TEST_P(VertexAttributeTestES31, UseComputeShaderToUpdateVertexBuffer)
2616 {
2617 initTest();
2618 constexpr char kComputeShader[] =
2619 R"(#version 310 es
2620 layout(local_size_x=24) in;
2621 layout(std430, binding = 0) buffer buf {
2622 uint outData[24];
2623 };
2624 void main()
2625 {
2626 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
2627 })";
2628
2629 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
2630 glUseProgram(mProgram);
2631
2632 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
2633 GLuint hi = std::numeric_limits<GLuint>::max();
2634 std::array<GLuint, kVertexCount> inputData = {
2635 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
2636 std::array<GLfloat, kVertexCount> expectedData;
2637 for (size_t i = 0; i < kVertexCount; i++)
2638 {
2639 expectedData[i] = Normalize(inputData[i]);
2640 }
2641
2642 // Normalized unsigned int attribute will be classified as translated static attribute.
2643 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
2644 GLint typeSize = 4;
2645 GLsizei dataSize = kVertexCount * TypeStride(data.type);
2646 GLBuffer testBuffer;
2647 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
2648 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
2649 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
2650 reinterpret_cast<void *>(data.bufferOffset));
2651 glEnableVertexAttribArray(mTestAttrib);
2652
2653 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2654 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
2655 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
2656
2657 // Draw twice to make sure that all static attributes dirty bits are synced.
2658 glDrawArrays(GL_TRIANGLES, 0, 6);
2659 glDrawArrays(GL_TRIANGLES, 0, 6);
2660 checkPixels();
2661
2662 // Modify the testBuffer using a raw buffer
2663 glUseProgram(computeProgram);
2664 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
2665 glDispatchCompute(1, 1, 1);
2666 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
2667
2668 // Draw again to verify that testBuffer has been changed.
2669 glUseProgram(mProgram);
2670 glDrawArrays(GL_TRIANGLES, 0, 6);
2671 EXPECT_GL_NO_ERROR();
2672 checkPixelsUnEqual();
2673 }
2674
TEST_P(VertexAttributeTestES31,UsePpoComputeShaderToUpdateVertexBuffer)2675 TEST_P(VertexAttributeTestES31, UsePpoComputeShaderToUpdateVertexBuffer)
2676 {
2677 // PPOs are only supported in the Vulkan backend
2678 ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
2679
2680 initTest();
2681 constexpr char kComputeShader[] =
2682 R"(#version 310 es
2683 layout(local_size_x=24) in;
2684 layout(std430, binding = 0) buffer buf {
2685 uint outData[24];
2686 };
2687 void main()
2688 {
2689 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
2690 })";
2691
2692 glUseProgram(mProgram);
2693
2694 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
2695 GLuint hi = std::numeric_limits<GLuint>::max();
2696 std::array<GLuint, kVertexCount> inputData = {
2697 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
2698 std::array<GLfloat, kVertexCount> expectedData;
2699 for (size_t i = 0; i < kVertexCount; i++)
2700 {
2701 expectedData[i] = Normalize(inputData[i]);
2702 }
2703
2704 // Normalized unsigned int attribute will be classified as translated static attribute.
2705 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
2706 GLint typeSize = 4;
2707 GLsizei dataSize = kVertexCount * TypeStride(data.type);
2708 GLBuffer testBuffer;
2709 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
2710 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
2711 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
2712 reinterpret_cast<void *>(data.bufferOffset));
2713 glEnableVertexAttribArray(mTestAttrib);
2714
2715 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2716 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
2717 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
2718
2719 // Draw twice to make sure that all static attributes dirty bits are synced.
2720 glDrawArrays(GL_TRIANGLES, 0, 6);
2721 glDrawArrays(GL_TRIANGLES, 0, 6);
2722 checkPixels();
2723
2724 // Modify the testBuffer using a raw buffer
2725 GLProgramPipeline pipeline;
2726 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
2727 glProgramParameteri(computeProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
2728 glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, computeProgram);
2729 EXPECT_GL_NO_ERROR();
2730 glBindProgramPipeline(pipeline);
2731 EXPECT_GL_NO_ERROR();
2732 glUseProgram(0);
2733
2734 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
2735 glDispatchCompute(1, 1, 1);
2736 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
2737
2738 // Draw again to verify that testBuffer has been changed.
2739 glUseProgram(mProgram);
2740 glDrawArrays(GL_TRIANGLES, 0, 6);
2741 EXPECT_GL_NO_ERROR();
2742 checkPixelsUnEqual();
2743 }
2744
TEST_P(VertexAttributeTestES31,UseComputeShaderToUpdateVertexBufferSamePpo)2745 TEST_P(VertexAttributeTestES31, UseComputeShaderToUpdateVertexBufferSamePpo)
2746 {
2747 // PPOs are only supported in the Vulkan backend
2748 ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
2749
2750 initTest();
2751 constexpr char kComputeShader[] =
2752 R"(#version 310 es
2753 layout(local_size_x=24) in;
2754 layout(std430, binding = 0) buffer buf {
2755 uint outData[24];
2756 };
2757 void main()
2758 {
2759 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
2760 })";
2761
2762 // Mark the program separable and re-link it so it can be bound to the PPO.
2763 glProgramParameteri(mProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
2764 glLinkProgram(mProgram);
2765 mProgram = CheckLinkStatusAndReturnProgram(mProgram, true);
2766
2767 GLProgramPipeline pipeline;
2768 EXPECT_GL_NO_ERROR();
2769 glBindProgramPipeline(pipeline);
2770 glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, mProgram);
2771 EXPECT_GL_NO_ERROR();
2772 glUseProgram(0);
2773
2774 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
2775 GLuint hi = std::numeric_limits<GLuint>::max();
2776 std::array<GLuint, kVertexCount> inputData = {
2777 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
2778 std::array<GLfloat, kVertexCount> expectedData;
2779 for (size_t i = 0; i < kVertexCount; i++)
2780 {
2781 expectedData[i] = Normalize(inputData[i]);
2782 }
2783
2784 // Normalized unsigned int attribute will be classified as translated static attribute.
2785 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
2786 GLint typeSize = 4;
2787 GLsizei dataSize = kVertexCount * TypeStride(data.type);
2788 GLBuffer testBuffer;
2789 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
2790 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
2791 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
2792 reinterpret_cast<void *>(data.bufferOffset));
2793 glEnableVertexAttribArray(mTestAttrib);
2794
2795 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
2796 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
2797 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
2798
2799 // Draw twice to make sure that all static attributes dirty bits are synced.
2800 glDrawArrays(GL_TRIANGLES, 0, 6);
2801 glDrawArrays(GL_TRIANGLES, 0, 6);
2802 checkPixels();
2803
2804 // Modify the testBuffer using a raw buffer
2805 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
2806 glProgramParameteri(computeProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
2807 glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, computeProgram);
2808 EXPECT_GL_NO_ERROR();
2809
2810 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
2811 glDispatchCompute(1, 1, 1);
2812 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
2813
2814 // Draw again to verify that testBuffer has been changed.
2815 glUseProgram(mProgram);
2816 glDrawArrays(GL_TRIANGLES, 0, 6);
2817 EXPECT_GL_NO_ERROR();
2818 checkPixelsUnEqual();
2819 }
2820
2821 // Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31,ChangeAttribBindingAfterVertexAttribPointer)2822 TEST_P(VertexAttributeTestES31, ChangeAttribBindingAfterVertexAttribPointer)
2823 {
2824 initTest();
2825
2826 constexpr GLint kInputStride = 2;
2827 constexpr GLint kFloatOffset = 10;
2828 std::array<GLfloat, kVertexCount + kFloatOffset> inputData1;
2829 std::array<GLfloat, kVertexCount * kInputStride> inputData2;
2830 for (size_t count = 0; count < kVertexCount; ++count)
2831 {
2832 inputData1[kFloatOffset + count] = static_cast<GLfloat>(count);
2833 inputData2[count * kInputStride] = static_cast<GLfloat>(count);
2834 }
2835
2836 GLBuffer mBuffer1;
2837 glBindBuffer(GL_ARRAY_BUFFER, mBuffer1);
2838 glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
2839 GL_STATIC_DRAW);
2840 // Update the format indexed mTestAttrib and the binding indexed mTestAttrib by
2841 // VertexAttribPointer.
2842 const GLintptr kOffset = static_cast<GLintptr>(kFloatStride * kFloatOffset);
2843 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0,
2844 reinterpret_cast<const GLvoid *>(kOffset));
2845 glEnableVertexAttribArray(mTestAttrib);
2846
2847 constexpr GLint kTestBinding = 10;
2848 ASSERT_NE(mTestAttrib, kTestBinding);
2849
2850 GLBuffer mBuffer2;
2851 glBindBuffer(GL_ARRAY_BUFFER, mBuffer2);
2852 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
2853 GL_STATIC_DRAW);
2854 glBindVertexBuffer(kTestBinding, mBuffer2, 0, kFloatStride * kInputStride);
2855
2856 // The attribute indexed mTestAttrib is using the binding indexed kTestBinding in the first
2857 // draw.
2858 glVertexAttribBinding(mTestAttrib, kTestBinding);
2859 glDrawArrays(GL_TRIANGLES, 0, 6);
2860 checkPixels();
2861 EXPECT_GL_NO_ERROR();
2862
2863 // The attribute indexed mTestAttrib is using the binding indexed mTestAttrib which should be
2864 // set after the call VertexAttribPointer before the first draw.
2865 glVertexAttribBinding(mTestAttrib, mTestAttrib);
2866 glDrawArrays(GL_TRIANGLES, 0, 6);
2867 checkPixels();
2868 EXPECT_GL_NO_ERROR();
2869 }
2870
2871 // Verify that using VertexAttribFormat after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31,ChangeAttribFormatAfterVertexAttribPointer)2872 TEST_P(VertexAttributeTestES31, ChangeAttribFormatAfterVertexAttribPointer)
2873 {
2874 initTest();
2875
2876 constexpr GLuint kFloatOffset = 10;
2877 std::array<GLfloat, kVertexCount + kFloatOffset> inputData;
2878 for (size_t count = 0; count < kVertexCount; ++count)
2879 {
2880 inputData[kFloatOffset + count] = static_cast<GLfloat>(count);
2881 }
2882
2883 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2884 glBufferData(GL_ARRAY_BUFFER, inputData.size() * kFloatStride, inputData.data(),
2885 GL_STATIC_DRAW);
2886
2887 // Call VertexAttribPointer on mTestAttrib. Now the relativeOffset of mTestAttrib should be 0.
2888 const GLuint kOffset = static_cast<GLuint>(kFloatStride * kFloatOffset);
2889 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
2890 glEnableVertexAttribArray(mTestAttrib);
2891
2892 // Call VertexAttribFormat on mTestAttrib to modify the relativeOffset to kOffset.
2893 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, kOffset);
2894
2895 glDrawArrays(GL_TRIANGLES, 0, 6);
2896 checkPixels();
2897 EXPECT_GL_NO_ERROR();
2898 }
2899
2900 // Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31,OnlyUpdateBindingByBindVertexBuffer)2901 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByBindVertexBuffer)
2902 {
2903 // Default binding index for test
2904 constexpr GLint kTestBinding = 10;
2905 initOnlyUpdateBindingTest(kTestBinding);
2906
2907 constexpr GLuint kTestFloatOffset2 = kVertexCount * 2;
2908 std::array<GLfloat, kVertexCount> expectedData2 = {};
2909 std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
2910 for (size_t count = 0; count < kVertexCount; ++count)
2911 {
2912 GLfloat value2 = static_cast<GLfloat>(count) * 2;
2913 expectedData2[count] = value2;
2914 inputData2[count + kTestFloatOffset2] = value2;
2915 }
2916
2917 // Set another set of data for mExpectedAttrib.
2918 GLBuffer expectedBuffer2;
2919 glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
2920 glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
2921 GL_STATIC_DRAW);
2922 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
2923
2924 GLBuffer testBuffer2;
2925 glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
2926 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
2927 GL_STATIC_DRAW);
2928
2929 // Only update the binding kTestBinding in the second draw by BindVertexBuffer.
2930 glBindVertexBuffer(kTestBinding, testBuffer2, kTestFloatOffset2 * kFloatStride, kFloatStride);
2931
2932 glDrawArrays(GL_TRIANGLES, 0, 6);
2933 checkPixels();
2934 EXPECT_GL_NO_ERROR();
2935 }
2936
2937 // Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31,OnlyUpdateBindingByVertexAttribPointer)2938 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByVertexAttribPointer)
2939 {
2940 // Default binding index for test
2941 constexpr GLint kTestBinding = 10;
2942 initOnlyUpdateBindingTest(kTestBinding);
2943
2944 constexpr GLuint kTestFloatOffset2 = kVertexCount * 3;
2945 std::array<GLfloat, kVertexCount> expectedData2 = {};
2946 std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
2947 for (size_t count = 0; count < kVertexCount; ++count)
2948 {
2949 GLfloat value2 = static_cast<GLfloat>(count) * 3;
2950 expectedData2[count] = value2;
2951 inputData2[count + kTestFloatOffset2] = value2;
2952 }
2953
2954 // Set another set of data for mExpectedAttrib.
2955 GLBuffer expectedBuffer2;
2956 glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
2957 glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
2958 GL_STATIC_DRAW);
2959 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
2960
2961 GLBuffer testBuffer2;
2962 glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
2963 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
2964 GL_STATIC_DRAW);
2965
2966 // Only update the binding kTestBinding in the second draw by VertexAttribPointer.
2967 glVertexAttribPointer(
2968 kTestBinding, 1, GL_FLOAT, GL_FALSE, 0,
2969 reinterpret_cast<const void *>(static_cast<uintptr_t>(kTestFloatOffset2 * kFloatStride)));
2970
2971 glDrawArrays(GL_TRIANGLES, 0, 6);
2972 checkPixels();
2973 EXPECT_GL_NO_ERROR();
2974 }
2975
2976 class VertexAttributeCachingTest : public VertexAttributeTest
2977 {
2978 protected:
VertexAttributeCachingTest()2979 VertexAttributeCachingTest() {}
2980
2981 void testSetUp() override;
2982
2983 template <typename DestT>
2984 static std::vector<GLfloat> GetExpectedData(const std::vector<GLubyte> &srcData,
2985 GLenum attribType,
2986 GLboolean normalized);
2987
initDoubleAttribProgram()2988 void initDoubleAttribProgram()
2989 {
2990 constexpr char kVS[] =
2991 "attribute mediump vec4 position;\n"
2992 "attribute mediump vec4 test;\n"
2993 "attribute mediump vec4 expected;\n"
2994 "attribute mediump vec4 test2;\n"
2995 "attribute mediump vec4 expected2;\n"
2996 "varying mediump vec4 color;\n"
2997 "void main(void)\n"
2998 "{\n"
2999 " gl_Position = position;\n"
3000 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
3001 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
3002 " vec4 threshold2 = max(abs(expected2) * 0.01, 1.0 / 64.0);\n"
3003 " color += vec4(lessThanEqual(abs(test2 - expected2), threshold2));\n"
3004 "}\n";
3005
3006 constexpr char kFS[] =
3007 "varying mediump vec4 color;\n"
3008 "void main(void)\n"
3009 "{\n"
3010 " gl_FragColor = color;\n"
3011 "}\n";
3012
3013 mProgram = CompileProgram(kVS, kFS);
3014 ASSERT_NE(0u, mProgram);
3015
3016 mTestAttrib = glGetAttribLocation(mProgram, "test");
3017 ASSERT_NE(-1, mTestAttrib);
3018 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
3019 ASSERT_NE(-1, mExpectedAttrib);
3020
3021 glUseProgram(mProgram);
3022 }
3023
3024 struct AttribData
3025 {
3026 AttribData(GLenum typeIn, GLint sizeIn, GLboolean normalizedIn, GLsizei strideIn);
3027
3028 GLenum type;
3029 GLint size;
3030 GLboolean normalized;
3031 GLsizei stride;
3032 };
3033
3034 std::vector<AttribData> mTestData;
3035 std::map<GLenum, std::vector<GLfloat>> mExpectedData;
3036 std::map<GLenum, std::vector<GLfloat>> mNormExpectedData;
3037 };
3038
AttribData(GLenum typeIn,GLint sizeIn,GLboolean normalizedIn,GLsizei strideIn)3039 VertexAttributeCachingTest::AttribData::AttribData(GLenum typeIn,
3040 GLint sizeIn,
3041 GLboolean normalizedIn,
3042 GLsizei strideIn)
3043 : type(typeIn), size(sizeIn), normalized(normalizedIn), stride(strideIn)
3044 {}
3045
3046 // static
3047 template <typename DestT>
GetExpectedData(const std::vector<GLubyte> & srcData,GLenum attribType,GLboolean normalized)3048 std::vector<GLfloat> VertexAttributeCachingTest::GetExpectedData(
3049 const std::vector<GLubyte> &srcData,
3050 GLenum attribType,
3051 GLboolean normalized)
3052 {
3053 std::vector<GLfloat> expectedData;
3054
3055 const DestT *typedSrcPtr = reinterpret_cast<const DestT *>(srcData.data());
3056 size_t iterations = srcData.size() / TypeStride(attribType);
3057
3058 if (normalized)
3059 {
3060 for (size_t index = 0; index < iterations; ++index)
3061 {
3062 expectedData.push_back(Normalize(typedSrcPtr[index]));
3063 }
3064 }
3065 else
3066 {
3067 for (size_t index = 0; index < iterations; ++index)
3068 {
3069 expectedData.push_back(static_cast<GLfloat>(typedSrcPtr[index]));
3070 }
3071 }
3072
3073 return expectedData;
3074 }
3075
testSetUp()3076 void VertexAttributeCachingTest::testSetUp()
3077 {
3078 VertexAttributeTest::testSetUp();
3079
3080 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3081
3082 std::vector<GLubyte> srcData;
3083 for (size_t count = 0; count < 4; ++count)
3084 {
3085 for (GLubyte i = 0; i < std::numeric_limits<GLubyte>::max(); ++i)
3086 {
3087 srcData.push_back(i);
3088 }
3089 }
3090
3091 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
3092
3093 GLint viewportSize[4];
3094 glGetIntegerv(GL_VIEWPORT, viewportSize);
3095
3096 std::vector<GLenum> attribTypes;
3097 attribTypes.push_back(GL_BYTE);
3098 attribTypes.push_back(GL_UNSIGNED_BYTE);
3099 attribTypes.push_back(GL_SHORT);
3100 attribTypes.push_back(GL_UNSIGNED_SHORT);
3101
3102 if (getClientMajorVersion() >= 3)
3103 {
3104 attribTypes.push_back(GL_INT);
3105 attribTypes.push_back(GL_UNSIGNED_INT);
3106 }
3107
3108 constexpr GLint kMaxSize = 4;
3109 constexpr GLsizei kMaxStride = 4;
3110
3111 for (GLenum attribType : attribTypes)
3112 {
3113 for (GLint attribSize = 1; attribSize <= kMaxSize; ++attribSize)
3114 {
3115 for (GLsizei stride = 1; stride <= kMaxStride; ++stride)
3116 {
3117 mTestData.push_back(AttribData(attribType, attribSize, GL_FALSE, stride));
3118 if (attribType != GL_FLOAT)
3119 {
3120 mTestData.push_back(AttribData(attribType, attribSize, GL_TRUE, stride));
3121 }
3122 }
3123 }
3124 }
3125
3126 mExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_FALSE);
3127 mExpectedData[GL_UNSIGNED_BYTE] = GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_FALSE);
3128 mExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_FALSE);
3129 mExpectedData[GL_UNSIGNED_SHORT] =
3130 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_FALSE);
3131 mExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_FALSE);
3132 mExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_FALSE);
3133
3134 mNormExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_TRUE);
3135 mNormExpectedData[GL_UNSIGNED_BYTE] =
3136 GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_TRUE);
3137 mNormExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_TRUE);
3138 mNormExpectedData[GL_UNSIGNED_SHORT] =
3139 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_TRUE);
3140 mNormExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_TRUE);
3141 mNormExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_TRUE);
3142 }
3143
3144 // In D3D11, we must sometimes translate buffer data into static attribute caches. We also use a
3145 // cache management scheme which garbage collects old attributes after we start using too much
3146 // cache data. This test tries to make as many attribute caches from a single buffer as possible
3147 // to stress-test the caching code.
TEST_P(VertexAttributeCachingTest,BufferMulticaching)3148 TEST_P(VertexAttributeCachingTest, BufferMulticaching)
3149 {
3150 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
3151
3152 initBasicProgram();
3153
3154 glEnableVertexAttribArray(mTestAttrib);
3155 glEnableVertexAttribArray(mExpectedAttrib);
3156
3157 ASSERT_GL_NO_ERROR();
3158
3159 for (const AttribData &data : mTestData)
3160 {
3161 const auto &expected =
3162 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
3163
3164 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
3165 GLsizei stride = TypeStride(data.type) * baseStride;
3166
3167 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3168 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
3169 glBindBuffer(GL_ARRAY_BUFFER, 0);
3170 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
3171 sizeof(GLfloat) * baseStride, expected.data());
3172 drawQuad(mProgram, "position", 0.5f);
3173 ASSERT_GL_NO_ERROR();
3174 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
3175 }
3176 }
3177
3178 // With D3D11 dirty bits for VertxArray11, we can leave vertex state unchanged if there aren't any
3179 // GL calls that affect it. This test targets leaving one vertex attribute unchanged between draw
3180 // calls while changing another vertex attribute enough that it clears the static buffer cache
3181 // after enough iterations. It validates the unchanged attributes don't get deleted incidentally.
TEST_P(VertexAttributeCachingTest,BufferMulticachingWithOneUnchangedAttrib)3182 TEST_P(VertexAttributeCachingTest, BufferMulticachingWithOneUnchangedAttrib)
3183 {
3184 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
3185
3186 initDoubleAttribProgram();
3187
3188 GLint testAttrib2Location = glGetAttribLocation(mProgram, "test2");
3189 ASSERT_NE(-1, testAttrib2Location);
3190 GLint expectedAttrib2Location = glGetAttribLocation(mProgram, "expected2");
3191 ASSERT_NE(-1, expectedAttrib2Location);
3192
3193 glEnableVertexAttribArray(mTestAttrib);
3194 glEnableVertexAttribArray(mExpectedAttrib);
3195 glEnableVertexAttribArray(testAttrib2Location);
3196 glEnableVertexAttribArray(expectedAttrib2Location);
3197
3198 ASSERT_GL_NO_ERROR();
3199
3200 // Use an attribute that we know must be converted. This is a bit sensitive.
3201 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3202 glVertexAttribPointer(testAttrib2Location, 3, GL_UNSIGNED_SHORT, GL_FALSE, 6, nullptr);
3203 glBindBuffer(GL_ARRAY_BUFFER, 0);
3204 glVertexAttribPointer(expectedAttrib2Location, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3,
3205 mExpectedData[GL_UNSIGNED_SHORT].data());
3206
3207 for (const auto &data : mTestData)
3208 {
3209 const auto &expected =
3210 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
3211
3212 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
3213 GLsizei stride = TypeStride(data.type) * baseStride;
3214
3215 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
3216 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
3217 glBindBuffer(GL_ARRAY_BUFFER, 0);
3218 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
3219 sizeof(GLfloat) * baseStride, expected.data());
3220 drawQuad(mProgram, "position", 0.5f);
3221
3222 ASSERT_GL_NO_ERROR();
3223 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
3224 }
3225 }
3226
3227 // Test that if there are gaps in the attribute indices, the attributes have their correct values.
TEST_P(VertexAttributeTest,UnusedVertexAttribWorks)3228 TEST_P(VertexAttributeTest, UnusedVertexAttribWorks)
3229 {
3230 constexpr char kVertexShader[] = R"(attribute vec2 position;
3231 attribute float actualValue;
3232 uniform float expectedValue;
3233 varying float result;
3234 void main()
3235 {
3236 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3237 gl_Position = vec4(position, 0, 1);
3238 })";
3239
3240 constexpr char kFragmentShader[] = R"(varying mediump float result;
3241 void main()
3242 {
3243 gl_FragColor = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3244 })";
3245
3246 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3247
3248 // Force a gap in attributes by using location 0 and 3
3249 GLint positionLocation = 0;
3250 glBindAttribLocation(program, positionLocation, "position");
3251
3252 GLint attribLoc = 3;
3253 glBindAttribLocation(program, attribLoc, "actualValue");
3254
3255 // Re-link the program to update the attribute locations
3256 glLinkProgram(program);
3257 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
3258
3259 glUseProgram(program);
3260
3261 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3262 ASSERT_NE(-1, uniLoc);
3263
3264 glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3265
3266 ASSERT_NE(-1, positionLocation);
3267 setupQuadVertexBuffer(0.5f, 1.0f);
3268 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
3269 glEnableVertexAttribArray(positionLocation);
3270
3271 std::array<GLfloat, 4> testValues = {{1, 2, 3, 4}};
3272 for (GLfloat testValue : testValues)
3273 {
3274 glUniform1f(uniLoc, testValue);
3275 glVertexAttrib1f(attribLoc, testValue);
3276 glDrawArrays(GL_TRIANGLES, 0, 6);
3277 ASSERT_GL_NO_ERROR();
3278 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3279 }
3280 }
3281
3282 // Tests that repeatedly updating a disabled vertex attribute works as expected.
3283 // This covers an ANGLE bug where dirty bits for current values were ignoring repeated updates.
TEST_P(VertexAttributeTest,DisabledAttribUpdates)3284 TEST_P(VertexAttributeTest, DisabledAttribUpdates)
3285 {
3286 constexpr char kVertexShader[] = R"(attribute vec2 position;
3287 attribute float actualValue;
3288 uniform float expectedValue;
3289 varying float result;
3290 void main()
3291 {
3292 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3293 gl_Position = vec4(position, 0, 1);
3294 })";
3295
3296 constexpr char kFragmentShader[] = R"(varying mediump float result;
3297 void main()
3298 {
3299 gl_FragColor = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3300 })";
3301
3302 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3303
3304 glUseProgram(program);
3305 GLint attribLoc = glGetAttribLocation(program, "actualValue");
3306 ASSERT_NE(-1, attribLoc);
3307
3308 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3309 ASSERT_NE(-1, uniLoc);
3310
3311 glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3312
3313 GLint positionLocation = glGetAttribLocation(program, "position");
3314 ASSERT_NE(-1, positionLocation);
3315 setupQuadVertexBuffer(0.5f, 1.0f);
3316 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
3317 glEnableVertexAttribArray(positionLocation);
3318
3319 std::array<GLfloat, 4> testValues = {{1, 2, 3, 4}};
3320 for (GLfloat testValue : testValues)
3321 {
3322 glUniform1f(uniLoc, testValue);
3323 glVertexAttrib1f(attribLoc, testValue);
3324 glDrawArrays(GL_TRIANGLES, 0, 6);
3325 ASSERT_GL_NO_ERROR();
3326 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3327 }
3328 }
3329
3330 // Test that even inactive attributes are taken into account when checking for aliasing in case the
3331 // shader version is >= 3.00. GLSL ES 3.00.6 section 12.46.
TEST_P(VertexAttributeTestES3,InactiveAttributeAliasing)3332 TEST_P(VertexAttributeTestES3, InactiveAttributeAliasing)
3333 {
3334 constexpr char vertexShader[] =
3335 R"(#version 300 es
3336 precision mediump float;
3337 in vec4 input_active;
3338 in vec4 input_unused;
3339 void main()
3340 {
3341 gl_Position = input_active;
3342 })";
3343
3344 constexpr char fragmentShader[] =
3345 R"(#version 300 es
3346 precision mediump float;
3347 out vec4 color;
3348 void main()
3349 {
3350 color = vec4(0.0);
3351 })";
3352
3353 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3354 glBindAttribLocation(program, 0, "input_active");
3355 glBindAttribLocation(program, 0, "input_unused");
3356 glLinkProgram(program);
3357 EXPECT_GL_NO_ERROR();
3358 GLint linkStatus = 0;
3359 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
3360 EXPECT_GL_FALSE(linkStatus);
3361 }
3362
3363 // Test that enabling inactive attributes doesn't cause a crash
3364 // shader version is >= 3.00
TEST_P(VertexAttributeTestES3,EnabledButInactiveAttributes)3365 TEST_P(VertexAttributeTestES3, EnabledButInactiveAttributes)
3366 {
3367 // This is similar to runtest(), and the test is disabled there
3368 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
3369
3370 constexpr char testVertexShaderSource[] =
3371 R"(#version 300 es
3372 precision mediump float;
3373 in vec4 position;
3374 layout(location = 1) in vec4 test;
3375 layout(location = 2) in vec4 unused1;
3376 layout(location = 3) in vec4 unused2;
3377 layout(location = 4) in vec4 unused3;
3378 layout(location = 5) in vec4 expected;
3379 out vec4 color;
3380 void main(void)
3381 {
3382 gl_Position = position;
3383 vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);
3384 color = vec4(lessThanEqual(abs(test - expected), threshold));
3385 })";
3386
3387 // Same as previous one, except it uses unused1/2 instead of test/expected, leaving unused3
3388 // unused
3389 constexpr char testVertexShader2Source[] =
3390 R"(#version 300 es
3391 precision mediump float;
3392 in vec4 position;
3393 layout(location = 1) in vec4 test;
3394 layout(location = 2) in vec4 unused1;
3395 layout(location = 3) in vec4 unused2;
3396 layout(location = 4) in vec4 unused3;
3397 layout(location = 5) in vec4 expected;
3398 out vec4 color;
3399 void main(void)
3400 {
3401 gl_Position = position;
3402 vec4 threshold = max(abs(unused2) * 0.01, 1.0 / 64.0);
3403 color = vec4(lessThanEqual(abs(unused1 - unused2), threshold));
3404 })";
3405
3406 constexpr char testFragmentShaderSource[] =
3407 R"(#version 300 es
3408 precision mediump float;
3409 in vec4 color;
3410 out vec4 out_color;
3411 void main()
3412 {
3413 out_color = color;
3414 })";
3415
3416 std::array<GLubyte, kVertexCount> inputData = {
3417 {0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255}};
3418 std::array<GLubyte, kVertexCount> inputData2;
3419 std::array<GLfloat, kVertexCount> expectedData;
3420 std::array<GLfloat, kVertexCount> expectedData2;
3421 for (size_t i = 0; i < kVertexCount; i++)
3422 {
3423 expectedData[i] = inputData[i];
3424 inputData2[i] = inputData[i] > 128 ? inputData[i] - 1 : inputData[i] + 1;
3425 expectedData2[i] = inputData2[i];
3426 }
3427
3428 // Setup the program
3429 mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
3430 ASSERT_NE(0u, mProgram);
3431
3432 mTestAttrib = glGetAttribLocation(mProgram, "test");
3433 ASSERT_EQ(1, mTestAttrib);
3434 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
3435 ASSERT_EQ(5, mExpectedAttrib);
3436
3437 GLint unused1Attrib = 2;
3438 GLint unused2Attrib = 3;
3439 GLint unused3Attrib = 4;
3440
3441 // Test enabling an unused attribute before glUseProgram
3442 glEnableVertexAttribArray(unused3Attrib);
3443
3444 glUseProgram(mProgram);
3445
3446 // Setup the test data
3447 TestData data(GL_UNSIGNED_BYTE, GL_FALSE, Source::IMMEDIATE, inputData.data(),
3448 expectedData.data());
3449 setupTest(data, 1);
3450
3451 // Test enabling an unused attribute after glUseProgram
3452 glVertexAttribPointer(unused1Attrib, 1, data.type, data.normalized, 0, inputData2.data());
3453 glEnableVertexAttribArray(unused1Attrib);
3454
3455 glVertexAttribPointer(unused2Attrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData2.data());
3456 glEnableVertexAttribArray(unused2Attrib);
3457
3458 // Run the test. This shouldn't use the unused attributes. Note that one of them is nullptr
3459 // which can cause a crash on certain platform-driver combination.
3460 drawQuad(mProgram, "position", 0.5f);
3461 checkPixels();
3462
3463 // Now test with the same attributes enabled, but with a program with different attributes
3464 // active
3465 mProgram = CompileProgram(testVertexShader2Source, testFragmentShaderSource);
3466 ASSERT_NE(0u, mProgram);
3467
3468 // Make sure all the attributes are in the same location
3469 ASSERT_EQ(glGetAttribLocation(mProgram, "unused1"), unused1Attrib);
3470 ASSERT_EQ(glGetAttribLocation(mProgram, "unused2"), unused2Attrib);
3471
3472 glUseProgram(mProgram);
3473
3474 // Run the test again. unused1/2 were disabled in the previous run (as they were inactive in
3475 // the shader), but should be re-enabled now.
3476 drawQuad(mProgram, "position", 0.5f);
3477 checkPixels();
3478 }
3479
3480 // Test that default integer attribute works correctly even if there is a gap in
3481 // attribute locations.
TEST_P(VertexAttributeTestES3,DefaultIntAttribWithGap)3482 TEST_P(VertexAttributeTestES3, DefaultIntAttribWithGap)
3483 {
3484 constexpr char kVertexShader[] = R"(#version 300 es
3485 layout(location = 0) in vec2 position;
3486 layout(location = 3) in int actualValue;
3487 uniform int expectedValue;
3488 out float result;
3489 void main()
3490 {
3491 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3492 gl_Position = vec4(position, 0, 1);
3493 })";
3494
3495 constexpr char kFragmentShader[] = R"(#version 300 es
3496 in mediump float result;
3497 layout(location = 0) out lowp vec4 out_color;
3498 void main()
3499 {
3500 out_color = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3501 })";
3502
3503 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3504
3505 // Re-link the program to update the attribute locations
3506 glLinkProgram(program);
3507 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
3508
3509 glUseProgram(program);
3510
3511 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3512 ASSERT_NE(-1, uniLoc);
3513
3514 glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3515
3516 setupQuadVertexBuffer(0.5f, 1.0f);
3517 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
3518 glEnableVertexAttribArray(0);
3519
3520 std::array<GLint, 4> testValues = {{1, 2, 3, 4}};
3521 for (GLfloat testValue : testValues)
3522 {
3523 glUniform1i(uniLoc, testValue);
3524 glVertexAttribI4i(3, testValue, 0, 0, 0);
3525 glDrawArrays(GL_TRIANGLES, 0, 6);
3526 ASSERT_GL_NO_ERROR();
3527 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3528 }
3529 }
3530
3531 // Test that default unsigned integer attribute works correctly even if there is a gap in
3532 // attribute locations.
TEST_P(VertexAttributeTestES3,DefaultUIntAttribWithGap)3533 TEST_P(VertexAttributeTestES3, DefaultUIntAttribWithGap)
3534 {
3535 constexpr char kVertexShader[] = R"(#version 300 es
3536 layout(location = 0) in vec2 position;
3537 layout(location = 3) in uint actualValue;
3538 uniform uint expectedValue;
3539 out float result;
3540 void main()
3541 {
3542 result = (actualValue == expectedValue) ? 1.0 : 0.0;
3543 gl_Position = vec4(position, 0, 1);
3544 })";
3545
3546 constexpr char kFragmentShader[] = R"(#version 300 es
3547 in mediump float result;
3548 layout(location = 0) out lowp vec4 out_color;
3549 void main()
3550 {
3551 out_color = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
3552 })";
3553
3554 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
3555
3556 // Re-link the program to update the attribute locations
3557 glLinkProgram(program);
3558 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
3559
3560 glUseProgram(program);
3561
3562 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
3563 ASSERT_NE(-1, uniLoc);
3564
3565 glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
3566
3567 setupQuadVertexBuffer(0.5f, 1.0f);
3568 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
3569 glEnableVertexAttribArray(0);
3570
3571 std::array<GLuint, 4> testValues = {{1, 2, 3, 4}};
3572 for (GLfloat testValue : testValues)
3573 {
3574 glUniform1ui(uniLoc, testValue);
3575 glVertexAttribI4ui(3, testValue, 0, 0, 0);
3576 glDrawArrays(GL_TRIANGLES, 0, 6);
3577 ASSERT_GL_NO_ERROR();
3578 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3579 }
3580 }
3581
3582 // Tests that large strides that read past the end of the buffer work correctly.
3583 // Requires ES 3.1 to query MAX_VERTEX_ATTRIB_STRIDE.
TEST_P(VertexAttributeTestES31,LargeStride)3584 TEST_P(VertexAttributeTestES31, LargeStride)
3585 {
3586 struct Vertex
3587 {
3588 Vector4 position;
3589 Vector2 color;
3590 };
3591
3592 constexpr uint32_t kColorOffset = offsetof(Vertex, color);
3593
3594 // Get MAX_VERTEX_ATTRIB_STRIDE.
3595 GLint maxStride;
3596 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
3597
3598 uint32_t bufferSize = static_cast<uint32_t>(maxStride);
3599 uint32_t stride = sizeof(Vertex);
3600 uint32_t numVertices = bufferSize / stride;
3601
3602 // The last vertex fits in the buffer size. The last vertex stride extends past it.
3603 ASSERT_LT(numVertices * stride, bufferSize);
3604 ASSERT_GT(numVertices * stride + kColorOffset, bufferSize);
3605
3606 RNG rng(0);
3607
3608 std::vector<Vertex> vertexData(bufferSize, {Vector4(), Vector2()});
3609 std::vector<GLColor> expectedColors;
3610 for (uint32_t vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex)
3611 {
3612 int x = vertexIndex % getWindowWidth();
3613 int y = vertexIndex / getWindowWidth();
3614
3615 // Generate and clamp a 2 component vector.
3616 Vector4 randomVec4 = RandomVec4(rng.randomInt(), 0.0f, 1.0f);
3617 GLColor randomColor(randomVec4);
3618 randomColor[2] = 0;
3619 randomColor[3] = 255;
3620 Vector4 clampedVec = randomColor.toNormalizedVector();
3621
3622 vertexData[vertexIndex] = {Vector4(x, y, 0.0f, 1.0f),
3623 Vector2(clampedVec[0], clampedVec[1])};
3624 expectedColors.push_back(randomColor);
3625 }
3626
3627 GLBuffer buffer;
3628 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3629 glBufferData(GL_ARRAY_BUFFER, bufferSize, vertexData.data(), GL_STATIC_DRAW);
3630
3631 vertexData.resize(numVertices);
3632
3633 constexpr char kVS[] = R"(#version 310 es
3634 in vec4 pos;
3635 in vec2 color;
3636 out vec2 vcolor;
3637 void main()
3638 {
3639 vcolor = color;
3640 gl_Position = vec4(((pos.x + 0.5) / 64.0) - 1.0, ((pos.y + 0.5) / 64.0) - 1.0, 0, 1);
3641 gl_PointSize = 1.0;
3642 })";
3643
3644 constexpr char kFS[] = R"(#version 310 es
3645 precision mediump float;
3646 in vec2 vcolor;
3647 out vec4 fcolor;
3648 void main()
3649 {
3650 fcolor = vec4(vcolor, 0.0, 1.0);
3651 })";
3652
3653 ANGLE_GL_PROGRAM(program, kVS, kFS);
3654 glUseProgram(program);
3655
3656 GLint posLoc = glGetAttribLocation(program, "pos");
3657 ASSERT_NE(-1, posLoc);
3658 GLint colorLoc = glGetAttribLocation(program, "color");
3659 ASSERT_NE(-1, colorLoc);
3660
3661 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
3662 glEnableVertexAttribArray(posLoc);
3663 glVertexAttribPointer(colorLoc, 2, GL_FLOAT, GL_FALSE, stride,
3664 reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(kColorOffset)));
3665 glEnableVertexAttribArray(colorLoc);
3666
3667 glDrawArrays(GL_POINTS, 0, numVertices);
3668
3669 // Validate pixels.
3670 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
3671 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
3672 actualColors.data());
3673
3674 actualColors.resize(numVertices);
3675
3676 ASSERT_GL_NO_ERROR();
3677 EXPECT_EQ(expectedColors, actualColors);
3678 }
3679
makeMismatchingSignsTestVS(uint32_t attribCount,uint16_t signedMask)3680 std::string VertexAttributeTestES31::makeMismatchingSignsTestVS(uint32_t attribCount,
3681 uint16_t signedMask)
3682 {
3683 std::ostringstream shader;
3684
3685 shader << R"(#version 310 es
3686 precision highp float;
3687
3688 // The signedness is determined by |signedMask|.
3689 )";
3690
3691 for (uint32_t i = 0; i < attribCount; ++i)
3692 {
3693 shader << "in highp " << ((signedMask >> i & 1) == 0 ? "u" : "i") << "vec4 attrib" << i
3694 << ";\n";
3695 }
3696
3697 shader << "flat out highp uvec4 v[" << attribCount << "];\n";
3698
3699 shader << R"(
3700 void main() {
3701 )";
3702
3703 for (uint32_t i = 0; i < attribCount; ++i)
3704 {
3705 shader << "v[" << i << "] = uvec4(attrib" << i << ");\n";
3706 }
3707
3708 shader << R"(
3709 // gl_VertexID x y
3710 // 0 -1 -1
3711 // 1 1 -1
3712 // 2 -1 1
3713 // 3 1 1
3714 int bit0 = gl_VertexID & 1;
3715 int bit1 = gl_VertexID >> 1;
3716 gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, gl_VertexID % 2 == 0 ? -1 : 1, 1);
3717 })";
3718
3719 return shader.str();
3720 }
3721
makeMismatchingSignsTestFS(uint32_t attribCount)3722 std::string VertexAttributeTestES31::makeMismatchingSignsTestFS(uint32_t attribCount)
3723 {
3724 std::ostringstream shader;
3725
3726 shader << R"(#version 310 es
3727 precision highp float;
3728 )";
3729
3730 shader << "flat in highp uvec4 v[" << attribCount << "];\n";
3731
3732 shader << R"(out vec4 fragColor;
3733 uniform vec4 colorScale;
3734
3735 bool isOk(uvec4 inputVarying, uint index)
3736 {
3737 return inputVarying.x == index &&
3738 inputVarying.y == index * 2u &&
3739 inputVarying.z == index + 1u &&
3740 inputVarying.w == index + 0x12345u;
3741 }
3742
3743 void main()
3744 {
3745 bool result = true;
3746 )";
3747 shader << " for (uint index = 0u; index < " << attribCount << "u; ++index)\n";
3748 shader << R"({
3749 result = result && isOk(v[index], index);
3750 }
3751
3752 fragColor = vec4(result) * colorScale;
3753 })";
3754
3755 return shader.str();
3756 }
3757
setupVertexAttribPointersForMismatchSignsTest(uint16_t currentSignedMask,uint16_t toggleMask)3758 uint16_t VertexAttributeTestES31::setupVertexAttribPointersForMismatchSignsTest(
3759 uint16_t currentSignedMask,
3760 uint16_t toggleMask)
3761 {
3762 uint16_t newSignedMask = currentSignedMask ^ toggleMask;
3763
3764 for (uint32_t i = 0; i < 16; ++i)
3765 {
3766 if ((toggleMask >> i & 1) == 0)
3767 {
3768 continue;
3769 }
3770
3771 const GLenum type = (newSignedMask >> i & 1) == 0 ? GL_UNSIGNED_INT : GL_INT;
3772 glVertexAttribIPointer(i, 4, type, sizeof(GLuint[4]),
3773 reinterpret_cast<const void *>(sizeof(GLuint[4][4]) * i));
3774 }
3775
3776 return newSignedMask;
3777 }
3778
3779 // Test changing between matching and mismatching signedness of vertex attributes, when the
3780 // attribute changes type.
TEST_P(VertexAttributeTestES31,MismatchingSignsChangingAttributeType)3781 TEST_P(VertexAttributeTestES31, MismatchingSignsChangingAttributeType)
3782 {
3783 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
3784
3785 // GL supports a minimum of 16 vertex attributes, and gl_VertexID is counted as one.
3786 // The signedness pattern used here is:
3787 //
3788 // 0 14
3789 // iiui uuii iuui uui
3790 //
3791 // Which is chosen such that there's no clear repeating / mirror pattern.
3792 const std::string vs = makeMismatchingSignsTestVS(15, 0x49CB);
3793 const std::string fs = makeMismatchingSignsTestFS(15);
3794
3795 ANGLE_GL_PROGRAM(program, vs.c_str(), fs.c_str());
3796 for (uint32_t i = 0; i < 15; ++i)
3797 {
3798 char attribName[20];
3799 snprintf(attribName, sizeof(attribName), "attrib%u\n", i);
3800 glBindAttribLocation(program, i, attribName);
3801 }
3802 glLinkProgram(program);
3803 glUseProgram(program);
3804 ASSERT_GL_NO_ERROR();
3805
3806 GLint colorScaleLoc = glGetUniformLocation(program, "colorScale");
3807 ASSERT_NE(-1, colorScaleLoc);
3808
3809 GLuint data[15][4][4];
3810 for (GLuint i = 0; i < 15; ++i)
3811 {
3812 for (GLuint j = 0; j < 4; ++j)
3813 {
3814 // Match the expectation in the shader
3815 data[i][j][0] = i;
3816 data[i][j][1] = i * 2;
3817 data[i][j][2] = i + 1;
3818 data[i][j][3] = i + 0x12345;
3819 }
3820 }
3821
3822 GLBuffer buffer;
3823 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3824 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
3825
3826 // Randomly match and mismatch the component type
3827 uint16_t signedMask = setupVertexAttribPointersForMismatchSignsTest(0x0FA5, 0x7FFF);
3828
3829 for (uint32_t i = 0; i < 15; ++i)
3830 {
3831 glEnableVertexAttribArray(i);
3832 }
3833
3834 glClearColor(0, 0, 0, 0);
3835 glClear(GL_COLOR_BUFFER_BIT);
3836
3837 glEnable(GL_BLEND);
3838 glBlendFunc(GL_ONE, GL_ONE);
3839
3840 glUniform4f(colorScaleLoc, 1, 0, 0, 0);
3841 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3842
3843 // Modify the attributes randomly and make sure tests still pass
3844
3845 signedMask = setupVertexAttribPointersForMismatchSignsTest(signedMask, 0x3572);
3846 glUniform4f(colorScaleLoc, 0, 1, 0, 0);
3847 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3848
3849 signedMask = setupVertexAttribPointersForMismatchSignsTest(signedMask, 0x4B1C);
3850 glUniform4f(colorScaleLoc, 0, 0, 1, 0);
3851 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3852
3853 signedMask = setupVertexAttribPointersForMismatchSignsTest(signedMask, 0x19D6);
3854 glUniform4f(colorScaleLoc, 0, 0, 0, 1);
3855 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3856
3857 // All channels must be 1
3858 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::white);
3859 ASSERT_GL_NO_ERROR();
3860 }
3861
3862 // Test changing between matching and mismatching signedness of vertex attributes, when the
3863 // program itself changes the type.
TEST_P(VertexAttributeTestES31,MismatchingSignsChangingProgramType)3864 TEST_P(VertexAttributeTestES31, MismatchingSignsChangingProgramType)
3865 {
3866 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_relaxed_vertex_attribute_type"));
3867
3868 // GL supports a minimum of 16 vertex attributes, and gl_VertexID is counted as one.
3869 constexpr uint32_t kAttribCount[4] = {12, 9, 15, 7};
3870 constexpr uint32_t kAttribSignedMask[4] = {0x94f, 0x6A, 0x765B, 0x29};
3871
3872 GLProgram programs[4];
3873
3874 for (uint32_t progIndex = 0; progIndex < 4; ++progIndex)
3875 {
3876 const std::string vs =
3877 makeMismatchingSignsTestVS(kAttribCount[progIndex], kAttribSignedMask[progIndex]);
3878 const std::string fs = makeMismatchingSignsTestFS(kAttribCount[progIndex]);
3879
3880 programs[progIndex].makeRaster(vs.c_str(), fs.c_str());
3881 for (uint32_t i = 0; i < kAttribCount[progIndex]; ++i)
3882 {
3883 char attribName[20];
3884 snprintf(attribName, sizeof(attribName), "attrib%u\n", i);
3885 glBindAttribLocation(programs[progIndex], i, attribName);
3886 }
3887 glLinkProgram(programs[progIndex]);
3888 glUseProgram(programs[progIndex]);
3889 ASSERT_GL_NO_ERROR();
3890 }
3891
3892 GLuint data[15][4][4];
3893 for (GLuint i = 0; i < 15; ++i)
3894 {
3895 for (GLuint j = 0; j < 4; ++j)
3896 {
3897 // Match the expectation in the shader
3898 data[i][j][0] = i;
3899 data[i][j][1] = i * 2;
3900 data[i][j][2] = i + 1;
3901 data[i][j][3] = i + 0x12345;
3902 }
3903 }
3904
3905 GLBuffer buffer;
3906 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3907 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
3908
3909 // Randomly match and mismatch the component type
3910 setupVertexAttribPointersForMismatchSignsTest(0x55F8, 0x7FFF);
3911
3912 for (uint32_t i = 0; i < 15; ++i)
3913 {
3914 glEnableVertexAttribArray(i);
3915 }
3916
3917 glClearColor(0, 0, 0, 0);
3918 glClear(GL_COLOR_BUFFER_BIT);
3919
3920 glEnable(GL_BLEND);
3921 glBlendFunc(GL_ONE, GL_ONE);
3922
3923 glUseProgram(programs[0]);
3924 GLint colorScaleLoc = glGetUniformLocation(programs[0], "colorScale");
3925 ASSERT_NE(-1, colorScaleLoc);
3926 glUniform4f(colorScaleLoc, 1, 0, 0, 0);
3927 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3928
3929 // Change the program, which have randomly different attribute component types and make sure
3930 // tests still pass
3931
3932 glUseProgram(programs[1]);
3933 colorScaleLoc = glGetUniformLocation(programs[1], "colorScale");
3934 ASSERT_NE(-1, colorScaleLoc);
3935 glUniform4f(colorScaleLoc, 0, 1, 0, 0);
3936 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3937
3938 glUseProgram(programs[2]);
3939 colorScaleLoc = glGetUniformLocation(programs[2], "colorScale");
3940 ASSERT_NE(-1, colorScaleLoc);
3941 glUniform4f(colorScaleLoc, 0, 0, 1, 0);
3942 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3943
3944 glUseProgram(programs[3]);
3945 colorScaleLoc = glGetUniformLocation(programs[3], "colorScale");
3946 ASSERT_NE(-1, colorScaleLoc);
3947 glUniform4f(colorScaleLoc, 0, 0, 0, 1);
3948 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3949
3950 // All channels must be 1
3951 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::white);
3952 ASSERT_GL_NO_ERROR();
3953 }
3954
3955 // Test that aliasing attribute locations work with es 100 shaders. Note that es 300 and above
3956 // don't allow vertex attribute aliasing. This test excludes matrix types.
TEST_P(VertexAttributeTest,AliasingVectorAttribLocations)3957 TEST_P(VertexAttributeTest, AliasingVectorAttribLocations)
3958 {
3959 // http://anglebug.com/5180
3960 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
3961
3962 // http://anglebug.com/3466
3963 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
3964
3965 // http://anglebug.com/3467
3966 ANGLE_SKIP_TEST_IF(IsD3D());
3967
3968 // TODO(anglebug.com/5491): iOS GLSL compiler rejects attribute aliasing.
3969 ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
3970
3971 // This test needs 10 total attributes. All backends support this except some old Android
3972 // devices.
3973 GLint maxVertexAttribs = 0;
3974 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
3975 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 10);
3976
3977 constexpr char kVS[] = R"(attribute vec4 position;
3978 // 4 aliasing attributes
3979 attribute float attr0f;
3980 attribute vec2 attr0v2;
3981 attribute vec3 attr0v3;
3982 attribute vec4 attr0v4;
3983 const vec4 attr0Expected = vec4(0.1, 0.2, 0.3, 0.4);
3984
3985 // 2 aliasing attributes
3986 attribute vec2 attr1v2;
3987 attribute vec3 attr1v3;
3988 const vec3 attr1Expected = vec3(0.5, 0.6, 0.7);
3989
3990 // 2 aliasing attributes
3991 attribute vec4 attr2v4;
3992 attribute float attr2f;
3993 const vec4 attr2Expected = vec4(0.8, 0.85, 0.9, 0.95);
3994
3995 // 2 aliasing attributes
3996 attribute float attr3f1;
3997 attribute float attr3f2;
3998 const float attr3Expected = 1.0;
3999
4000 uniform float attr0Select;
4001 uniform float attr1Select;
4002 uniform float attr2Select;
4003 uniform float attr3Select;
4004
4005 // Each channel controlled by success from each set of aliasing attributes. If a channel is 0, the
4006 // attribute test has failed. Otherwise it will be 0.25, 0.5, 0.75 or 1.0, depending on how many
4007 // channels there are in the compared attribute (except attr3).
4008 varying mediump vec4 color;
4009 void main()
4010 {
4011 gl_Position = position;
4012
4013 vec4 result = vec4(0);
4014
4015 if (attr0Select < 0.5)
4016 result.r = abs(attr0f - attr0Expected.x) < 0.01 ? 0.25 : 0.0;
4017 else if (attr0Select < 1.5)
4018 result.r = all(lessThan(abs(attr0v2 - attr0Expected.xy), vec2(0.01))) ? 0.5 : 0.0;
4019 else if (attr0Select < 2.5)
4020 result.r = all(lessThan(abs(attr0v3 - attr0Expected.xyz), vec3(0.01))) ? 0.75 : 0.0;
4021 else
4022 result.r = all(lessThan(abs(attr0v4 - attr0Expected), vec4(0.01 )))? 1.0 : 0.0;
4023
4024 if (attr1Select < 0.5)
4025 result.g = all(lessThan(abs(attr1v2 - attr1Expected.xy), vec2(0.01 )))? 0.5 : 0.0;
4026 else
4027 result.g = all(lessThan(abs(attr1v3 - attr1Expected), vec3(0.01 )))? 0.75 : 0.0;
4028
4029 if (attr2Select < 0.5)
4030 result.b = abs(attr2f - attr2Expected.x) < 0.01 ? 0.25 : 0.0;
4031 else
4032 result.b = all(lessThan(abs(attr2v4 - attr2Expected), vec4(0.01))) ? 1.0 : 0.0;
4033
4034 if (attr3Select < 0.5)
4035 result.a = abs(attr3f1 - attr3Expected) < 0.01 ? 0.25 : 0.0;
4036 else
4037 result.a = abs(attr3f2 - attr3Expected) < 0.01 ? 0.5 : 0.0;
4038
4039 color = result;
4040 })";
4041
4042 constexpr char kFS[] = R"(varying mediump vec4 color;
4043 void main(void)
4044 {
4045 gl_FragColor = color;
4046 })";
4047
4048 // Compile shaders.
4049 GLuint program = CompileProgram(kVS, kFS);
4050 ASSERT_NE(program, 0u);
4051
4052 // Setup bindings.
4053 glBindAttribLocation(program, 0, "attr0f");
4054 glBindAttribLocation(program, 0, "attr0v2");
4055 glBindAttribLocation(program, 0, "attr0v3");
4056 glBindAttribLocation(program, 0, "attr0v4");
4057 glBindAttribLocation(program, 1, "attr1v2");
4058 glBindAttribLocation(program, 1, "attr1v3");
4059 glBindAttribLocation(program, 2, "attr2v4");
4060 glBindAttribLocation(program, 2, "attr2f");
4061 glBindAttribLocation(program, 3, "attr3f1");
4062 glBindAttribLocation(program, 3, "attr3f2");
4063 EXPECT_GL_NO_ERROR();
4064
4065 // Link program and get uniform locations.
4066 glLinkProgram(program);
4067 glUseProgram(program);
4068 GLint attr0SelectLoc = glGetUniformLocation(program, "attr0Select");
4069 GLint attr1SelectLoc = glGetUniformLocation(program, "attr1Select");
4070 GLint attr2SelectLoc = glGetUniformLocation(program, "attr2Select");
4071 GLint attr3SelectLoc = glGetUniformLocation(program, "attr3Select");
4072 ASSERT_NE(-1, attr0SelectLoc);
4073 ASSERT_NE(-1, attr1SelectLoc);
4074 ASSERT_NE(-1, attr2SelectLoc);
4075 ASSERT_NE(-1, attr3SelectLoc);
4076 EXPECT_GL_NO_ERROR();
4077
4078 // Set values for attributes.
4079 glVertexAttrib4f(0, 0.1f, 0.2f, 0.3f, 0.4f);
4080 glVertexAttrib3f(1, 0.5f, 0.6f, 0.7f);
4081 glVertexAttrib4f(2, 0.8f, 0.85f, 0.9f, 0.95f);
4082 glVertexAttrib1f(3, 1.0f);
4083 glDisableVertexAttribArray(0);
4084 glDisableVertexAttribArray(1);
4085 glDisableVertexAttribArray(2);
4086 glDisableVertexAttribArray(3);
4087 EXPECT_GL_NO_ERROR();
4088
4089 // Go through different combination of attributes and make sure reading through every alias is
4090 // correctly handled.
4091 GLColor expected;
4092 for (uint32_t attr0Select = 0; attr0Select < 4; ++attr0Select)
4093 {
4094 glUniform1f(attr0SelectLoc, attr0Select);
4095 expected.R = attr0Select * 64 + 63;
4096
4097 for (uint32_t attr1Select = 0; attr1Select < 2; ++attr1Select)
4098 {
4099 glUniform1f(attr1SelectLoc, attr1Select);
4100 expected.G = attr1Select * 64 + 127;
4101
4102 for (uint32_t attr2Select = 0; attr2Select < 2; ++attr2Select)
4103 {
4104 glUniform1f(attr2SelectLoc, attr2Select);
4105 expected.B = attr2Select * 192 + 63;
4106
4107 for (uint32_t attr3Select = 0; attr3Select < 2; ++attr3Select)
4108 {
4109 glUniform1f(attr3SelectLoc, attr3Select);
4110 expected.A = attr3Select * 64 + 63;
4111
4112 drawQuad(program, "position", 0.5f);
4113 EXPECT_GL_NO_ERROR();
4114 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
4115 }
4116 }
4117 }
4118 }
4119 }
4120
4121 // Test that aliasing attribute locations work with es 100 shaders. Note that es 300 and above
4122 // don't allow vertex attribute aliasing. This test includes matrix types.
TEST_P(VertexAttributeTest,AliasingMatrixAttribLocations)4123 TEST_P(VertexAttributeTest, AliasingMatrixAttribLocations)
4124 {
4125 // http://anglebug.com/5180
4126 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
4127
4128 // http://anglebug.com/3466
4129 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
4130
4131 // http://anglebug.com/3467
4132 ANGLE_SKIP_TEST_IF(IsD3D());
4133
4134 // TODO(anglebug.com/5491): iOS GLSL compiler rejects attribute aliasing.
4135 ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
4136
4137 // This test needs 16 total attributes. All backends support this except some old Android
4138 // devices.
4139 GLint maxVertexAttribs = 0;
4140 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
4141 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 16);
4142
4143 constexpr char kVS[] = R"(attribute vec4 position;
4144 // attributes aliasing location 0 and above
4145 attribute float attr0f;
4146 attribute mat3 attr0m3;
4147 attribute mat2 attr0m2;
4148
4149 // attributes aliasing location 1 and above
4150 attribute vec4 attr1v4;
4151
4152 // attributes aliasing location 2 and above
4153 attribute mat4 attr2m4;
4154
4155 // attributes aliasing location 3 and above
4156 attribute mat2 attr3m2;
4157
4158 // attributes aliasing location 5 and above
4159 attribute vec2 attr5v2;
4160
4161 // In summary (attr prefix shortened to a):
4162 //
4163 // location 0: a0f a0m3[0] a0m2[0]
4164 // location 1: a0m3[1] a0m2[1] a1v4
4165 // location 2: a0m3[2] a2m4[0]
4166 // location 3: a2m4[1] a3m2[0]
4167 // location 4: a2m4[2] a3m2[1]
4168 // location 5: a2m4[3] a5v2
4169
4170 const vec3 loc0Expected = vec3(0.05, 0.1, 0.15);
4171 const vec4 loc1Expected = vec4(0.2, 0.25, 0.3, 0.35);
4172 const vec4 loc2Expected = vec4(0.4, 0.45, 0.5, 0.55);
4173 const vec4 loc3Expected = vec4(0.6, 0.65, 0.7, 0.75);
4174 const vec4 loc4Expected = vec4(0.8, 0.85, 0.9, 0.95);
4175 const vec4 loc5Expected = vec4(0.25, 0.5, 0.75, 1.0);
4176
4177 uniform float loc0Select;
4178 uniform float loc1Select;
4179 uniform float loc2Select;
4180 uniform float loc3Select;
4181 uniform float loc4Select;
4182 uniform float loc5Select;
4183
4184 // Each channel controlled by success from each set of aliasing locations. Locations 2 and 3
4185 // contribute to B together, while locations 4 and 5 contribute to A together. If a channel is 0,
4186 // the attribute test has failed. Otherwise it will be 1/N, 2/N, ..., 1, depending on how many
4187 // possible values there are for the controlling uniforms.
4188 varying mediump vec4 color;
4189 void main()
4190 {
4191 gl_Position = position;
4192
4193 vec4 result = vec4(0);
4194
4195 if (loc0Select < 0.5)
4196 result.r = abs(attr0f - loc0Expected.x) < 0.01 ? 0.333333 : 0.0;
4197 else if (loc0Select < 1.5)
4198 result.r = all(lessThan(abs(attr0m2[0] - loc0Expected.xy), vec2(0.01))) ? 0.666667 : 0.0;
4199 else
4200 result.r = all(lessThan(abs(attr0m3[0] - loc0Expected), vec3(0.01))) ? 1.0 : 0.0;
4201
4202 if (loc1Select < 0.5)
4203 result.g = all(lessThan(abs(attr0m3[1] - loc1Expected.xyz), vec3(0.01))) ? 0.333333 : 0.0;
4204 else if (loc1Select < 1.5)
4205 result.g = all(lessThan(abs(attr0m2[1] - loc1Expected.xy), vec2(0.01))) ? 0.666667 : 0.0;
4206 else
4207 result.g = all(lessThan(abs(attr1v4 - loc1Expected), vec4(0.01))) ? 1.0 : 0.0;
4208
4209 bool loc2Ok = false;
4210 bool loc3Ok = false;
4211
4212 if (loc2Select < 0.5)
4213 loc2Ok = all(lessThan(abs(attr0m3[2] - loc2Expected.xyz), vec3(0.01)));
4214 else
4215 loc2Ok = all(lessThan(abs(attr2m4[0] - loc2Expected), vec4(0.01)));
4216
4217 if (loc3Select < 0.5)
4218 loc3Ok = all(lessThan(abs(attr2m4[1] - loc3Expected), vec4(0.01)));
4219 else
4220 loc3Ok = all(lessThan(abs(attr3m2[0] - loc3Expected.xy), vec2(0.01)));
4221
4222 if (loc2Ok && loc3Ok)
4223 {
4224 if (loc2Select < 0.5)
4225 if (loc3Select < 0.5)
4226 result.b = 0.25;
4227 else
4228 result.b = 0.5;
4229 else
4230 if (loc3Select < 0.5)
4231 result.b = 0.75;
4232 else
4233 result.b = 1.0;
4234 }
4235
4236 bool loc4Ok = false;
4237 bool loc5Ok = false;
4238
4239 if (loc4Select < 0.5)
4240 loc4Ok = all(lessThan(abs(attr2m4[2] - loc4Expected), vec4(0.01)));
4241 else
4242 loc4Ok = all(lessThan(abs(attr3m2[1] - loc4Expected.xy), vec2(0.01)));
4243
4244 if (loc5Select < 0.5)
4245 loc5Ok = all(lessThan(abs(attr2m4[3] - loc5Expected), vec4(0.01)));
4246 else
4247 loc5Ok = all(lessThan(abs(attr5v2 - loc5Expected.xy), vec2(0.01)));
4248
4249 if (loc4Ok && loc5Ok)
4250 {
4251 if (loc4Select < 0.5)
4252 if (loc5Select < 0.5)
4253 result.a = 0.25;
4254 else
4255 result.a = 0.5;
4256 else
4257 if (loc5Select < 0.5)
4258 result.a = 0.75;
4259 else
4260 result.a = 1.0;
4261 }
4262
4263 color = result;
4264 })";
4265
4266 constexpr char kFS[] = R"(varying mediump vec4 color;
4267 void main(void)
4268 {
4269 gl_FragColor = color;
4270 })";
4271
4272 // Compile shaders.
4273 GLuint program = CompileProgram(kVS, kFS);
4274 ASSERT_NE(program, 0u);
4275
4276 // Setup bindings.
4277 glBindAttribLocation(program, 0, "attr0f");
4278 glBindAttribLocation(program, 0, "attr0m3");
4279 glBindAttribLocation(program, 0, "attr0m2");
4280 glBindAttribLocation(program, 1, "attr1v4");
4281 glBindAttribLocation(program, 2, "attr2m4");
4282 glBindAttribLocation(program, 3, "attr3m2");
4283 glBindAttribLocation(program, 5, "attr5v2");
4284 EXPECT_GL_NO_ERROR();
4285
4286 // Link program and get uniform locations.
4287 glLinkProgram(program);
4288 glUseProgram(program);
4289 EXPECT_GL_NO_ERROR();
4290
4291 GLint loc0SelectLoc = glGetUniformLocation(program, "loc0Select");
4292 GLint loc1SelectLoc = glGetUniformLocation(program, "loc1Select");
4293 GLint loc2SelectLoc = glGetUniformLocation(program, "loc2Select");
4294 GLint loc3SelectLoc = glGetUniformLocation(program, "loc3Select");
4295 GLint loc4SelectLoc = glGetUniformLocation(program, "loc4Select");
4296 GLint loc5SelectLoc = glGetUniformLocation(program, "loc5Select");
4297 ASSERT_NE(-1, loc0SelectLoc);
4298 ASSERT_NE(-1, loc1SelectLoc);
4299 ASSERT_NE(-1, loc2SelectLoc);
4300 ASSERT_NE(-1, loc3SelectLoc);
4301 ASSERT_NE(-1, loc4SelectLoc);
4302 ASSERT_NE(-1, loc5SelectLoc);
4303 EXPECT_GL_NO_ERROR();
4304
4305 // Set values for attributes.
4306 glVertexAttrib3f(0, 0.05, 0.1, 0.15);
4307 glVertexAttrib4f(1, 0.2, 0.25, 0.3, 0.35);
4308 glVertexAttrib4f(2, 0.4, 0.45, 0.5, 0.55);
4309 glVertexAttrib4f(3, 0.6, 0.65, 0.7, 0.75);
4310 glVertexAttrib4f(4, 0.8, 0.85, 0.9, 0.95);
4311 glVertexAttrib4f(5, 0.25, 0.5, 0.75, 1.0);
4312 glDisableVertexAttribArray(0);
4313 glDisableVertexAttribArray(1);
4314 glDisableVertexAttribArray(2);
4315 glDisableVertexAttribArray(3);
4316 glDisableVertexAttribArray(4);
4317 glDisableVertexAttribArray(5);
4318 EXPECT_GL_NO_ERROR();
4319
4320 // Go through different combination of attributes and make sure reading through every alias is
4321 // correctly handled.
4322 GLColor expected;
4323 for (uint32_t loc0Select = 0; loc0Select < 3; ++loc0Select)
4324 {
4325 glUniform1f(loc0SelectLoc, loc0Select);
4326 expected.R = loc0Select * 85 + 85;
4327
4328 for (uint32_t loc1Select = 0; loc1Select < 3; ++loc1Select)
4329 {
4330 glUniform1f(loc1SelectLoc, loc1Select);
4331 expected.G = loc1Select * 85 + 85;
4332
4333 for (uint32_t loc2Select = 0; loc2Select < 2; ++loc2Select)
4334 {
4335 glUniform1f(loc2SelectLoc, loc2Select);
4336
4337 for (uint32_t loc3Select = 0; loc3Select < 2; ++loc3Select)
4338 {
4339 glUniform1f(loc3SelectLoc, loc3Select);
4340 expected.B = (loc2Select << 1 | loc3Select) * 64 + 63;
4341
4342 for (uint32_t loc4Select = 0; loc4Select < 2; ++loc4Select)
4343 {
4344 glUniform1f(loc4SelectLoc, loc4Select);
4345
4346 for (uint32_t loc5Select = 0; loc5Select < 2; ++loc5Select)
4347 {
4348 glUniform1f(loc5SelectLoc, loc5Select);
4349 expected.A = (loc4Select << 1 | loc5Select) * 64 + 63;
4350
4351 drawQuad(program, "position", 0.5f);
4352 EXPECT_GL_NO_ERROR();
4353 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
4354 }
4355 }
4356 }
4357 }
4358 }
4359 }
4360 }
4361
4362 // Test that aliasing attribute locations work with differing precisions.
TEST_P(VertexAttributeTest,AliasingVectorAttribLocationsDifferingPrecisions)4363 TEST_P(VertexAttributeTest, AliasingVectorAttribLocationsDifferingPrecisions)
4364 {
4365 // http://anglebug.com/5180
4366 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
4367
4368 // http://anglebug.com/3466
4369 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
4370
4371 // http://anglebug.com/3467
4372 ANGLE_SKIP_TEST_IF(IsD3D());
4373
4374 // TODO(anglebug.com/5491): iOS GLSL compiler rejects attribute aliasing.
4375 ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
4376
4377 constexpr char kVS[] = R"(attribute vec4 position;
4378 // aliasing attributes.
4379 attribute mediump vec2 attr0v2;
4380 attribute highp vec3 attr0v3;
4381 const vec3 attr0Expected = vec3(0.125, 0.25, 0.375);
4382
4383 // aliasing attributes.
4384 attribute highp vec2 attr1v2;
4385 attribute mediump vec3 attr1v3;
4386 const vec3 attr1Expected = vec3(0.5, 0.625, 0.75);
4387
4388 uniform float attr0Select;
4389 uniform float attr1Select;
4390
4391 // Each channel controlled by success from each set of aliasing attributes (R and G used only). If
4392 // a channel is 0, the attribute test has failed. Otherwise it will be 0.5 or 1.0.
4393 varying mediump vec4 color;
4394 void main()
4395 {
4396 gl_Position = position;
4397
4398 vec4 result = vec4(0, 0, 0, 1);
4399
4400 if (attr0Select < 0.5)
4401 result.r = all(lessThan(abs(attr0v2 - attr0Expected.xy), vec2(0.01))) ? 0.5 : 0.0;
4402 else
4403 result.r = all(lessThan(abs(attr0v3 - attr0Expected), vec3(0.01))) ? 1.0 : 0.0;
4404
4405 if (attr1Select < 0.5)
4406 result.g = all(lessThan(abs(attr1v2 - attr1Expected.xy), vec2(0.01))) ? 0.5 : 0.0;
4407 else
4408 result.g = all(lessThan(abs(attr1v3 - attr1Expected), vec3(0.01))) ? 1.0 : 0.0;
4409
4410 color = result;
4411 })";
4412
4413 constexpr char kFS[] = R"(varying mediump vec4 color;
4414 void main(void)
4415 {
4416 gl_FragColor = color;
4417 })";
4418
4419 // Compile shaders.
4420 GLuint program = CompileProgram(kVS, kFS);
4421 ASSERT_NE(program, 0u);
4422
4423 // Setup bindings.
4424 glBindAttribLocation(program, 0, "attr0v2");
4425 glBindAttribLocation(program, 0, "attr0v3");
4426 glBindAttribLocation(program, 1, "attr1v2");
4427 glBindAttribLocation(program, 1, "attr1v3");
4428 EXPECT_GL_NO_ERROR();
4429
4430 // Link program and get uniform locations.
4431 glLinkProgram(program);
4432 glUseProgram(program);
4433 GLint attr0SelectLoc = glGetUniformLocation(program, "attr0Select");
4434 GLint attr1SelectLoc = glGetUniformLocation(program, "attr1Select");
4435 ASSERT_NE(-1, attr0SelectLoc);
4436 ASSERT_NE(-1, attr1SelectLoc);
4437 EXPECT_GL_NO_ERROR();
4438
4439 // Set values for attributes.
4440 glVertexAttrib3f(0, 0.125f, 0.25f, 0.375f);
4441 glVertexAttrib3f(1, 0.5f, 0.625f, 0.75f);
4442 glDisableVertexAttribArray(0);
4443 glDisableVertexAttribArray(1);
4444 EXPECT_GL_NO_ERROR();
4445
4446 // Go through different combination of attributes and make sure reading through every alias is
4447 // correctly handled.
4448 GLColor expected;
4449 expected.B = 0;
4450 expected.A = 255;
4451 for (uint32_t attr0Select = 0; attr0Select < 2; ++attr0Select)
4452 {
4453 glUniform1f(attr0SelectLoc, attr0Select);
4454 expected.R = attr0Select * 128 + 127;
4455
4456 for (uint32_t attr1Select = 0; attr1Select < 2; ++attr1Select)
4457 {
4458 glUniform1f(attr1SelectLoc, attr1Select);
4459 expected.G = attr1Select * 128 + 127;
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 // Test that unsupported vertex format specified on non-existing attribute doesn't crash.
TEST_P(VertexAttributeTest,VertexFormatConversionOfNonExistingAttribute)4469 TEST_P(VertexAttributeTest, VertexFormatConversionOfNonExistingAttribute)
4470 {
4471 constexpr char kVS[] = R"(precision highp float;
4472 attribute vec3 attr1;
4473 void main(void) {
4474 gl_Position = vec4(attr1, 1.0);
4475 })";
4476
4477 constexpr char kFS[] = R"(precision highp float;
4478 void main(void) {
4479 gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
4480 })";
4481
4482 GLBuffer emptyBuffer;
4483 glBindBuffer(GL_ARRAY_BUFFER, emptyBuffer);
4484
4485 ANGLE_GL_PROGRAM(program, kVS, kFS);
4486 glBindAttribLocation(program, 0, "attr1");
4487 glLinkProgram(program);
4488 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
4489 glUseProgram(program);
4490
4491 // Use the RGB8 format for non-existing attribute 1.
4492 glEnableVertexAttribArray(1);
4493 glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, false, 1, 0);
4494
4495 glDrawArrays(GL_TRIANGLES, 0, 3);
4496 EXPECT_GL_NO_ERROR();
4497 }
4498
4499 // Covers a bug with integer formats and an element size larger than the vertex stride.
TEST_P(VertexAttributeTestES3,StrideSmallerThanIntegerElementSize)4500 TEST_P(VertexAttributeTestES3, StrideSmallerThanIntegerElementSize)
4501 {
4502 constexpr char kVS[] = R"(#version 300 es
4503 in vec4 position;
4504 in ivec2 intAttrib;
4505 in vec2 floatAttrib;
4506 out vec4 colorVarying;
4507 void main()
4508 {
4509 gl_Position = position;
4510 if (vec2(intAttrib) == floatAttrib)
4511 {
4512 colorVarying = vec4(0, 1, 0, 1);
4513 }
4514 else
4515 {
4516 colorVarying = vec4(1, 0, 0, 1);
4517 }
4518 })";
4519
4520 constexpr char kFS[] = R"(#version 300 es
4521 precision mediump float;
4522 in vec4 colorVarying;
4523 out vec4 fragColor;
4524 void main()
4525 {
4526 fragColor = colorVarying;
4527 })";
4528
4529 ANGLE_GL_PROGRAM(testProgram, kVS, kFS);
4530 glUseProgram(testProgram);
4531
4532 GLBuffer positionBuffer;
4533 {
4534 const std::array<Vector3, 6> &quadVerts = GetQuadVertices();
4535
4536 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4537 glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(),
4538 GL_STATIC_DRAW);
4539
4540 GLint posLoc = glGetAttribLocation(testProgram, "position");
4541 ASSERT_NE(posLoc, -1);
4542 glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
4543 glEnableVertexAttribArray(posLoc);
4544 }
4545
4546 GLBuffer intBuffer;
4547 {
4548 std::array<GLbyte, 12> intData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
4549
4550 glBindBuffer(GL_ARRAY_BUFFER, intBuffer);
4551 glBufferData(GL_ARRAY_BUFFER, intData.size() * sizeof(intData[0]), intData.data(),
4552 GL_STATIC_DRAW);
4553
4554 GLint intLoc = glGetAttribLocation(testProgram, "intAttrib");
4555 ASSERT_NE(intLoc, -1);
4556 glVertexAttribIPointer(intLoc, 2, GL_BYTE, 1, nullptr);
4557 glEnableVertexAttribArray(intLoc);
4558 }
4559
4560 GLBuffer floatBuffer;
4561 {
4562 std::array<GLfloat, 12> floatData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
4563
4564 glBindBuffer(GL_ARRAY_BUFFER, floatBuffer);
4565 glBufferData(GL_ARRAY_BUFFER, floatData.size() * sizeof(floatData[0]), floatData.data(),
4566 GL_STATIC_DRAW);
4567
4568 GLint floatLoc = glGetAttribLocation(testProgram, "floatAttrib");
4569 ASSERT_NE(floatLoc, -1);
4570 glVertexAttribPointer(floatLoc, 2, GL_FLOAT, GL_FALSE, 4, nullptr);
4571 glEnableVertexAttribArray(floatLoc);
4572 }
4573
4574 glDrawArrays(GL_TRIANGLES, 0, 6);
4575
4576 ASSERT_GL_NO_ERROR();
4577
4578 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
4579 }
4580
4581 // Test that pipeline is recreated properly when switching from ARRAY buffer to client buffer,
4582 // while removing client buffer. Bug observed in Dragonmania game.
TEST_P(VertexAttributeTestES31,ArrayToClientBufferStride)4583 TEST_P(VertexAttributeTestES31, ArrayToClientBufferStride)
4584 {
4585 constexpr char kVS[] = R"(#version 310 es
4586 precision highp float;
4587 in vec4 in_pos;
4588 in vec4 in_color;
4589 out vec4 color;
4590 void main(void) {
4591 gl_Position = in_pos;
4592 color = in_color;
4593 })";
4594
4595 constexpr char kFS[] = R"(#version 310 es
4596 precision highp float;
4597 in vec4 color;
4598 out vec4 frag_color;
4599 void main(void) {
4600 frag_color = color;
4601 })";
4602 swapBuffers();
4603
4604 ANGLE_GL_PROGRAM(program, kVS, kFS);
4605 glUseProgram(program);
4606 GLint posLoc = glGetAttribLocation(program, "in_pos");
4607 GLint colorLoc = glGetAttribLocation(program, "in_color");
4608 ASSERT_NE(posLoc, -1);
4609 ASSERT_NE(colorLoc, -1);
4610
4611 const std::array<Vector3, 6> &quadVerts = GetQuadVertices();
4612 // Data for packed attributes.
4613 std::array<float, ((3 + 4) * 6)> data;
4614
4615 float kYellow[4] = {1.0f, 1.0f, 0.0f, 1.0f};
4616 float kGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
4617
4618 for (int i = 0; i < 6; i++)
4619 {
4620 memcpy(&data[i * (3 + 4)], &quadVerts[i], sizeof(Vector3));
4621 memcpy(&data[i * (3 + 4) + 3], &kYellow, 4 * sizeof(float));
4622 }
4623
4624 {
4625 GLBuffer buffer;
4626 glBindBuffer(GL_ARRAY_BUFFER, buffer);
4627 glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(data[0]), data.data(), GL_STATIC_DRAW);
4628
4629 glEnableVertexAttribArray(posLoc);
4630 glEnableVertexAttribArray(colorLoc);
4631
4632 glVertexAttribPointer(posLoc, 3, GL_FLOAT, false, 28, reinterpret_cast<void *>(0));
4633 glVertexAttribPointer(colorLoc, 4, GL_FLOAT, false, 28, reinterpret_cast<void *>(12));
4634
4635 glDrawArrays(GL_TRIANGLES, 0, 6);
4636 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
4637 EXPECT_GL_NO_ERROR();
4638 // Unbind before destroy.
4639 glBindBuffer(GL_ARRAY_BUFFER, 0);
4640 }
4641
4642 // Modify color to green.
4643 for (int i = 0; i < 6; i++)
4644 {
4645 memcpy(&data[i * (3 + 4) + 3], &kGreen, 4 * sizeof(float));
4646 }
4647
4648 // Provide client pointer.
4649 glVertexAttribPointer(posLoc, 3, GL_FLOAT, false, 28, data.data());
4650 glVertexAttribPointer(colorLoc, 4, GL_FLOAT, false, 28, &data[3]);
4651
4652 glDrawArrays(GL_TRIANGLES, 0, 6);
4653 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
4654 EXPECT_GL_NO_ERROR();
4655 }
4656
4657 // Create a vertex array with an empty array buffer and attribute offsets.
4658 // This succeded in the end2end and capture/replay tests, but resulted in a trace
4659 // producing a GL error when using MEC.
4660 // Validation complained about the following:
4661 // "Client data cannot be used with a non-default vertex array object."
4662
4663 // To capture this test with MEC run:
4664 // mkdir src/tests/capture_replay_tests/empty_array_buffer_test
4665 // ANGLE_CAPTURE_ENABLED=1 ANGLE_CAPTURE_FRAME_START=2 \
4666 // ANGLE_CAPTURE_FRAME_END=2 ANGLE_CAPTURE_LABEL=empty_array_buffer_test \
4667 // ANGLE_CAPTURE_OUT_DIR=src/tests/capture_replay_tests/empty_array_buffer_test \
4668 // ./out/Debug/angle_end2end_tests \
4669 // --gtest_filter="VertexAttributeTestES3.EmptyArrayBuffer/ES3_Vulkan"
TEST_P(VertexAttributeTestES3,EmptyArrayBuffer)4670 TEST_P(VertexAttributeTestES3, EmptyArrayBuffer)
4671 {
4672 GLVertexArray vertexArray;
4673 glBindVertexArray(vertexArray);
4674
4675 GLBuffer emptyArrayBuffer;
4676 glBindBuffer(GL_ARRAY_BUFFER, emptyArrayBuffer);
4677
4678 glEnableVertexAttribArray(0);
4679 glEnableVertexAttribArray(1);
4680 glEnableVertexAttribArray(2);
4681 glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, GL_TRUE, 20, reinterpret_cast<const void *>(16));
4682 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, reinterpret_cast<const void *>(8));
4683 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 20, nullptr);
4684 EXPECT_GL_NO_ERROR();
4685
4686 glBindBuffer(GL_ARRAY_BUFFER, 0);
4687 glBindVertexArray(0);
4688
4689 EXPECT_GL_NO_ERROR();
4690
4691 // Swap a frame for MEC
4692 swapBuffers();
4693 }
4694
4695 // Set an attrib pointer and delete it's buffer after usage, while keeping the vertex array.
4696 // This will cause MEC to capture an invalid attribute pointer and also trigger
4697 // "Client data cannot be used with a non-default vertex array object."
TEST_P(VertexAttributeTestES3,InvalidAttribPointer)4698 TEST_P(VertexAttributeTestES3, InvalidAttribPointer)
4699 {
4700 GLVertexArray vertexArray;
4701 glBindVertexArray(vertexArray);
4702
4703 std::array<GLbyte, 12> vertexData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
4704
4705 {
4706 GLBuffer toBeDeletedArrayBuffer;
4707 glBindBuffer(GL_ARRAY_BUFFER, toBeDeletedArrayBuffer);
4708
4709 glBufferData(GL_ARRAY_BUFFER, vertexData.size(), vertexData.data(), GL_DYNAMIC_DRAW);
4710
4711 glEnableVertexAttribArray(0);
4712 glEnableVertexAttribArray(1);
4713
4714 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6, nullptr);
4715 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6, reinterpret_cast<const void *>(6));
4716
4717 glBindBuffer(GL_ARRAY_BUFFER, 0);
4718 glDisableVertexAttribArray(0);
4719 glDisableVertexAttribArray(1);
4720
4721 EXPECT_GL_NO_ERROR();
4722 }
4723
4724 // Set an attrib pointer that will be actually picked up by MEC, since the buffer will be kept.
4725 glEnableVertexAttribArray(0);
4726
4727 GLBuffer arrayBuffer;
4728 glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
4729
4730 glBufferData(GL_ARRAY_BUFFER, vertexData.size(), vertexData.data(), GL_DYNAMIC_DRAW);
4731
4732 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3, reinterpret_cast<const void *>(3));
4733
4734 EXPECT_GL_NO_ERROR();
4735
4736 // Swap a frame for MEC
4737 swapBuffers();
4738
4739 glBindBuffer(GL_ARRAY_BUFFER, 0);
4740 glEnableVertexAttribArray(0);
4741 }
4742
4743 // Test maxinum attribs full of Client buffers and then switch to mixed.
TEST_P(VertexAttributeTestES3,fullClientBuffersSwitchToMixed)4744 TEST_P(VertexAttributeTestES3, fullClientBuffersSwitchToMixed)
4745 {
4746 GLint maxAttribs;
4747 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
4748 ASSERT_GL_NO_ERROR();
4749
4750 // Reserve one attrib for position
4751 GLint drawAttribs = maxAttribs - 1;
4752
4753 GLuint program = compileMultiAttribProgram(drawAttribs);
4754 ASSERT_NE(0u, program);
4755
4756 const std::array<Vector2, 4> kIndexedQuadVertices = {{
4757 Vector2(-1.0f, 1.0f),
4758 Vector2(-1.0f, -1.0f),
4759 Vector2(1.0f, -1.0f),
4760 Vector2(1.0f, 1.0f),
4761 }};
4762
4763 GLsizei stride = (maxAttribs + 1) * sizeof(GLfloat);
4764
4765 constexpr std::array<GLushort, 6> kIndexedQuadIndices = {{0, 1, 2, 0, 2, 3}};
4766 GLuint indexBuffer = 0;
4767 glGenBuffers(1, &indexBuffer);
4768
4769 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
4770 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexedQuadIndices), kIndexedQuadIndices.data(),
4771 GL_STATIC_DRAW);
4772
4773 // Vertex drawAttribs color attributes plus position (x, y).
4774 GLint totalComponents = drawAttribs + 2;
4775 std::vector<GLfloat> vertexData(totalComponents * 4, 0.0f);
4776 for (GLint index = 0; index < 4; ++index)
4777 {
4778 vertexData[index * totalComponents + drawAttribs] = kIndexedQuadVertices[index].x();
4779 vertexData[index * totalComponents + drawAttribs + 1] = kIndexedQuadVertices[index].y();
4780 }
4781
4782 GLfloat attributeValue = 0.0f;
4783 GLfloat delta = 1.0f / 256.0f;
4784 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
4785 {
4786 vertexData[attribIndex] = attributeValue;
4787 vertexData[attribIndex + totalComponents] = attributeValue;
4788 vertexData[attribIndex + totalComponents * 2] = attributeValue;
4789 vertexData[attribIndex + totalComponents * 3] = attributeValue;
4790 attributeValue += delta;
4791 }
4792
4793 glUseProgram(program);
4794 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
4795 {
4796 std::stringstream attribStream;
4797 attribStream << "a" << attribIndex;
4798 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
4799 ASSERT_NE(-1, location);
4800 glVertexAttribPointer(location, 1, GL_FLOAT, GL_FALSE, stride,
4801 vertexData.data() + attribIndex);
4802 glEnableVertexAttribArray(location);
4803 }
4804 GLint posLoc = glGetAttribLocation(program, "position");
4805 ASSERT_NE(-1, posLoc);
4806 glEnableVertexAttribArray(posLoc);
4807 glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, stride, vertexData.data() + drawAttribs);
4808 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
4809
4810 // the result color should be (0 + 1 + 2 + ... + 14)/256 * 255;
4811 EXPECT_GL_NO_ERROR();
4812 EXPECT_PIXEL_NEAR(0, 0, 105, 0, 0, 255, 1);
4813
4814 // disable a few attribute use default attribute color
4815 GLint l0 = glGetAttribLocation(program, "a0");
4816 GLint l5 = glGetAttribLocation(program, "a5");
4817 GLint l13 = glGetAttribLocation(program, "a13");
4818 glDisableVertexAttribArray(l0);
4819 glVertexAttrib1f(l0, 1.0f / 16.0f);
4820 glDisableVertexAttribArray(l5);
4821 glVertexAttrib1f(l5, 1.0f / 16.0f);
4822 glDisableVertexAttribArray(l13);
4823 glVertexAttrib1f(l13, 1.0f / 16.0f);
4824
4825 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
4826
4827 EXPECT_GL_NO_ERROR();
4828 EXPECT_PIXEL_NEAR(0, 0, 134, 0, 0, 255, 1);
4829
4830 // disable all the client buffers.
4831 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
4832 {
4833 std::stringstream attribStream;
4834 attribStream << "a" << attribIndex;
4835 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
4836 ASSERT_NE(-1, location);
4837 glDisableVertexAttribArray(location);
4838 glVertexAttrib1f(location, 1.0f / 16.0f);
4839 }
4840
4841 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
4842
4843 EXPECT_GL_NO_ERROR();
4844 EXPECT_PIXEL_NEAR(0, 0, 239, 0, 0, 255, 1);
4845
4846 // enable all the client buffers.
4847 for (GLint attribIndex = 0; attribIndex < drawAttribs; ++attribIndex)
4848 {
4849 std::stringstream attribStream;
4850 attribStream << "a" << attribIndex;
4851 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
4852 ASSERT_NE(-1, location);
4853 glVertexAttribPointer(location, 1, GL_FLOAT, GL_FALSE, stride,
4854 vertexData.data() + attribIndex);
4855 glEnableVertexAttribArray(location);
4856 }
4857 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
4858 EXPECT_GL_NO_ERROR();
4859 EXPECT_PIXEL_NEAR(0, 0, 105, 0, 0, 255, 1);
4860 }
4861
4862 // Test bind an empty buffer for vertex attribute does not crash
TEST_P(VertexAttributeTestES3,emptyBuffer)4863 TEST_P(VertexAttributeTestES3, emptyBuffer)
4864 {
4865 constexpr char vs2[] =
4866 R"(#version 300 es
4867 in uvec4 attr0;
4868 void main()
4869 {
4870 gl_Position = vec4(attr0.x, 0.0, 0.0, 0.0);
4871 })";
4872 constexpr char fs[] =
4873 R"(#version 300 es
4874 precision highp float;
4875 out vec4 color;
4876 void main()
4877 {
4878 color = vec4(1.0, 0.0, 0.0, 1.0);
4879 })";
4880 GLuint program2 = CompileProgram(vs2, fs);
4881 GLBuffer buf;
4882 glBindBuffer(GL_ARRAY_BUFFER, buf);
4883 glEnableVertexAttribArray(0);
4884 glVertexAttribIPointer(0, 4, GL_UNSIGNED_BYTE, 0, 0);
4885 glVertexAttribDivisor(0, 2);
4886 glUseProgram(program2);
4887 glDrawArrays(GL_POINTS, 0, 1);
4888
4889 swapBuffers();
4890 }
4891
4892 // This is a test for use with ANGLE's Capture/Replay.
4893 // It emulates a situation we see in some apps, where attribs are passed in but may not be used.
4894 // In particular, that test asks for all active attributes and iterates through each one. Before any
4895 // changes to FrameCapture, this will create calls that look up attributes that are considered
4896 // unused on some platforms, making the trace non-portable. Whether they are used depends on how
4897 // well the stack optimizes the shader pipeline. In this instance, we are just passing them across
4898 // the pipeline boundary where they are dead in the fragment shader, but other cases have included
4899 // attributes passed to empty functions, or some eliminated with math. The more optimizations
4900 // applied by the driver, the higher chance of getting an unused attribute.
TEST_P(VertexAttributeTestES3,UnusedAttribsMEC)4901 TEST_P(VertexAttributeTestES3, UnusedAttribsMEC)
4902 {
4903 constexpr char vertexShader[] =
4904 R"(#version 300 es
4905 precision mediump float;
4906 in vec4 position;
4907 in vec4 input_unused;
4908 out vec4 passthrough;
4909 void main()
4910 {
4911 passthrough = input_unused;
4912 gl_Position = position;
4913 })";
4914
4915 constexpr char fragmentShader[] =
4916 R"(#version 300 es
4917 precision mediump float;
4918 in vec4 passthrough;
4919 out vec4 color;
4920 void main()
4921 {
4922 // ignore passthrough - this makes it unused with cross stage optimizations
4923 color = vec4(1.0);
4924 })";
4925
4926 GLuint program = CompileProgram(vertexShader, fragmentShader);
4927 glUseProgram(program);
4928
4929 // Set up vertex data
4930 GLBuffer positionBuffer;
4931 const std::array<Vector3, 6> &quadVerts = GetQuadVertices();
4932 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4933 glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(),
4934 GL_STATIC_DRAW);
4935
4936 // Loop through a sequence multiple times, so MEC can capture it.
4937 // Ask about vertex attribs and set them up, regardless of whether they are used.
4938 // This matches behavior seen in some apps.
4939 for (int i = 0; i < 10; i++)
4940 {
4941 // Look up the number of attribs
4942 GLint activeAttribCount = 0;
4943 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttribCount);
4944
4945 // Look up how big they might get
4946 GLint maxActiveAttribLength = 0;
4947 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxActiveAttribLength);
4948
4949 GLsizei attribLength = 0;
4950 GLint attribSize = 0;
4951 GLenum attribType = 0;
4952 GLchar attribName[16] = {0};
4953 ASSERT(maxActiveAttribLength < 16);
4954
4955 // Look up each attribute and set them up
4956 for (int j = 0; j < activeAttribCount; j++)
4957 {
4958 glGetActiveAttrib(program, j, maxActiveAttribLength, &attribLength, &attribSize,
4959 &attribType, attribName);
4960 GLint posLoc = glGetAttribLocation(program, attribName);
4961 ASSERT_NE(posLoc, -1);
4962 glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, j, nullptr);
4963 glEnableVertexAttribArray(posLoc);
4964 }
4965
4966 // Draw and swap on each loop to trigger MEC
4967 glDrawArrays(GL_TRIANGLES, 0, 6);
4968 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
4969 swapBuffers();
4970 }
4971 }
4972
4973 // Test that a particular vertex attribute naming does not affect the functionality.
4974 // Tests the vertex attrib aliasing part. Note that aliasing works with es 100 shaders.
TEST_P(VertexAttributeTest,AliasingAttribNaming)4975 TEST_P(VertexAttributeTest, AliasingAttribNaming)
4976 {
4977 // http://anglebug.com/5180
4978 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
4979
4980 // http://anglebug.com/3466
4981 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
4982
4983 // http://anglebug.com/3467
4984 ANGLE_SKIP_TEST_IF(IsD3D());
4985
4986 // TODO(anglebug.com/5491): iOS GLSL compiler rejects attribute aliasing.
4987 ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
4988
4989 // This test needs 16 total attributes. All backends support this except some old Android
4990 // devices.
4991 GLint maxVertexAttribs = 0;
4992 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
4993 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 16);
4994
4995 constexpr char kVS[] = R"(attribute vec4 position;
4996 // attributes aliasing location 0 and above
4997 attribute mat3 a;
4998 attribute mat2 a_;
4999
5000 // attributes aliasing location 1 and above
5001 attribute vec4 a_1;
5002
5003 // attributes aliasing location 2 and above
5004 attribute mat4 a_0;
5005
5006 // In summary:
5007 //
5008 // location 0: a[0] a_[0]
5009 // location 1: a[1] a_[1] a_1
5010 // location 2: a[2] a_0[0]
5011 // location 3: a_0[1] (untested)
5012 // location 4: a_0[2] (untested)
5013 // location 5: a_0[3] (untested)
5014
5015 const vec3 loc0Expected = vec3(0.05, 0.1, 0.15);
5016 const vec4 loc1Expected = vec4(0.2, 0.25, 0.3, 0.35);
5017 const vec4 loc2Expected = vec4(0.4, 0.45, 0.5, 0.55);
5018
5019 uniform float loc0Select;
5020 uniform float loc1Select;
5021 uniform float loc2Select;
5022
5023 // Each channel controlled by success from each set of aliasing locations. If a channel is 0,
5024 // the attribute test has failed. Otherwise it will be 1/N, 2/N, ..., 1, depending on how many
5025 // possible values there are for the controlling uniforms.
5026 varying mediump vec4 color;
5027 void main()
5028 {
5029 gl_Position = position;
5030
5031 vec4 result = vec4(0);
5032
5033 if (loc0Select < 0.5)
5034 result.r = all(lessThan(abs(a[0] - loc0Expected.xyz), vec3(0.01))) ? 0.5 : 0.0;
5035 else
5036 result.r = all(lessThan(abs(a_[0] - loc0Expected.xy), vec2(0.01))) ? 1.0 : 0.0;
5037
5038 if (loc1Select < 0.5)
5039 result.g = all(lessThan(abs(a[1] - loc1Expected.xyz), vec3(0.01))) ? 0.333333 : 0.0;
5040 else if (loc1Select < 1.5)
5041 result.g = all(lessThan(abs(a_[1] - loc1Expected.xy), vec2(0.01))) ? 0.666667 : 0.0;
5042 else
5043 result.g = all(lessThan(abs(a_1 - loc1Expected), vec4(0.01))) ? 1.0 : 0.0;
5044
5045 if (loc2Select < 0.5)
5046 result.b = all(lessThan(abs(a[2] - loc2Expected.xyz), vec3(0.01))) ? 0.5 : 0.0;
5047 else
5048 result.b = all(lessThan(abs(a_0[0] - loc2Expected), vec4(0.01))) ? 1.0 : 0.0;
5049 result.a = 1.0;
5050 color = result;
5051 })";
5052
5053 constexpr char kFS[] = R"(varying mediump vec4 color;
5054 void main(void)
5055 {
5056 gl_FragColor = color;
5057 })";
5058
5059 // Compile shaders.
5060 GLuint program = CompileProgram(kVS, kFS);
5061 ASSERT_NE(program, 0u);
5062
5063 // Setup bindings.
5064 glBindAttribLocation(program, 0, "a");
5065 glBindAttribLocation(program, 0, "a_");
5066 glBindAttribLocation(program, 1, "a_1");
5067 glBindAttribLocation(program, 2, "a_0");
5068 EXPECT_GL_NO_ERROR();
5069
5070 // Link program and get uniform locations.
5071 glLinkProgram(program);
5072 glUseProgram(program);
5073 EXPECT_GL_NO_ERROR();
5074
5075 GLint loc0SelectLoc = glGetUniformLocation(program, "loc0Select");
5076 GLint loc1SelectLoc = glGetUniformLocation(program, "loc1Select");
5077 GLint loc2SelectLoc = glGetUniformLocation(program, "loc2Select");
5078 ASSERT_NE(-1, loc0SelectLoc);
5079 ASSERT_NE(-1, loc1SelectLoc);
5080 ASSERT_NE(-1, loc2SelectLoc);
5081 EXPECT_GL_NO_ERROR();
5082
5083 // Set values for attributes.
5084 glVertexAttrib3f(0, 0.05, 0.1, 0.15);
5085 glVertexAttrib4f(1, 0.2, 0.25, 0.3, 0.35);
5086 glVertexAttrib4f(2, 0.4, 0.45, 0.5, 0.55);
5087 glDisableVertexAttribArray(0);
5088 glDisableVertexAttribArray(1);
5089 glDisableVertexAttribArray(2);
5090 EXPECT_GL_NO_ERROR();
5091
5092 // Go through different combination of attributes and make sure reading through every alias is
5093 // correctly handled.
5094 GLColor expected;
5095 expected.A = 255;
5096 for (uint32_t loc0Select = 0; loc0Select < 2; ++loc0Select)
5097 {
5098 glUniform1f(loc0SelectLoc, loc0Select);
5099 expected.R = loc0Select * 127 + 127;
5100
5101 for (uint32_t loc1Select = 0; loc1Select < 3; ++loc1Select)
5102 {
5103 glUniform1f(loc1SelectLoc, loc1Select);
5104 expected.G = loc1Select * 85 + 85;
5105
5106 for (uint32_t loc2Select = 0; loc2Select < 2; ++loc2Select)
5107 {
5108 glUniform1f(loc2SelectLoc, loc2Select);
5109 expected.B = loc2Select * 127 + 127;
5110 drawQuad(program, "position", 0.5f);
5111 EXPECT_GL_NO_ERROR();
5112 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
5113 }
5114 }
5115 }
5116 }
5117
5118 // Test that a particular vertex attribute naming does not affect the functionality.
TEST_P(VertexAttributeTestES3,AttribNaming)5119 TEST_P(VertexAttributeTestES3, AttribNaming)
5120 {
5121 // http://anglebug.com/5180
5122 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
5123
5124 // http://anglebug.com/3466
5125 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
5126
5127 // http://anglebug.com/3467
5128 ANGLE_SKIP_TEST_IF(IsD3D());
5129
5130 // TODO(anglebug.com/5491): iOS GLSL compiler rejects attribute aliasing.
5131 ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
5132
5133 // This test needs roughly 16 total attributes. All backends support this except some old
5134 // Android devices.
5135 GLint maxVertexAttribs = 0;
5136 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
5137 ANGLE_SKIP_TEST_IF(maxVertexAttribs < 16);
5138
5139 constexpr char kVS[] = R"(#version 300 es
5140 precision mediump float;
5141 in vec4 position;
5142 in mat3 a;
5143 in mat2 a_;
5144 in vec4 a_1;
5145 in vec4 a_0;
5146 const mat3 aExpected = mat3(0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8);
5147 const mat2 a_Expected = mat2(1.0, 1.1, 1.2, 1.3);
5148 const vec4 a_1Expected = vec4(2.0, 2.1, 2.2, 2.3);
5149 const vec4 a_0Expected = vec4(3.0, 3.1, 3.2, 3.3);
5150 out mediump vec4 color;
5151 void main()
5152 {
5153 gl_Position = position;
5154
5155 vec4 result = vec4(0);
5156 mat3 diff3 = a - aExpected;
5157 result.r = all(lessThan(abs(diff3[0]) + abs(diff3[1]) + abs(diff3[2]), vec3(0.01))) ? 1.0 : 0.0;
5158 mat2 diff2 = a_ - a_Expected;
5159 result.g = all(lessThan(abs(diff2[0]) + abs(diff2[1]), vec2(0.01))) ? 1.0 : 0.0;
5160 result.b = all(lessThan(abs(a_1 - a_1Expected), vec4(0.01))) ? 1.0 : 0.0;
5161 result.a = all(lessThan(abs(a_0 - a_0Expected), vec4(0.01))) ? 1.0 : 0.0;
5162 color = result;
5163 })";
5164
5165 constexpr char kFS[] = R"(#version 300 es
5166 in mediump vec4 color;
5167 out mediump vec4 fragColor;
5168 void main(void)
5169 {
5170 fragColor = color;
5171 })";
5172
5173 GLuint program = CompileProgram(kVS, kFS);
5174 ASSERT_NE(program, 0u);
5175
5176 glBindAttribLocation(program, 0, "a");
5177 glBindAttribLocation(program, 4, "a_");
5178 glBindAttribLocation(program, 6, "a_1");
5179 glBindAttribLocation(program, 7, "a_0");
5180 EXPECT_GL_NO_ERROR();
5181
5182 glLinkProgram(program);
5183 glUseProgram(program);
5184 EXPECT_GL_NO_ERROR();
5185
5186 // Set values for attributes.
5187 glVertexAttrib3f(0, 0.0, 0.1, 0.2);
5188 glVertexAttrib3f(1, 0.3, 0.4, 0.5);
5189 glVertexAttrib3f(2, 0.6, 0.7, 0.8);
5190 glVertexAttrib2f(4, 1.0, 1.1);
5191 glVertexAttrib2f(5, 1.2, 1.3);
5192 glVertexAttrib4f(6, 2.0, 2.1, 2.2, 2.3);
5193 glVertexAttrib4f(7, 3.0, 3.1, 3.2, 3.3);
5194
5195 glDisableVertexAttribArray(0);
5196 glDisableVertexAttribArray(1);
5197 glDisableVertexAttribArray(2);
5198 glDisableVertexAttribArray(3);
5199 glDisableVertexAttribArray(4);
5200 glDisableVertexAttribArray(5);
5201 glDisableVertexAttribArray(6);
5202 glDisableVertexAttribArray(7);
5203 glDisableVertexAttribArray(8);
5204 glDisableVertexAttribArray(9);
5205 EXPECT_GL_NO_ERROR();
5206
5207 // Go through different combination of attributes and make sure reading through every alias is
5208 // correctly handled.
5209 GLColor expected{255, 255, 255, 255};
5210 drawQuad(program, "position", 0.5f);
5211 EXPECT_GL_NO_ERROR();
5212 EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1);
5213 }
5214
5215 // VAO emulation fails on Mac but is not used on Mac in the wild. http://anglebug.com/5577
5216 #if !defined(__APPLE__)
5217 # define EMULATED_VAO_CONFIGS \
5218 ES2_OPENGL().enable(Feature::SyncVertexArraysToDefault), \
5219 ES2_OPENGLES().enable(Feature::SyncVertexArraysToDefault), \
5220 ES3_OPENGL().enable(Feature::SyncVertexArraysToDefault), \
5221 ES3_OPENGLES().enable(Feature::SyncVertexArraysToDefault),
5222 #else
5223 # define EMULATED_VAO_CONFIGS
5224 #endif
5225
5226 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
5227 VertexAttributeTest,
5228 ES2_VULKAN().enable(Feature::ForceFallbackFormat),
5229 ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5230 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5231 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5232 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5233 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass),
5234 ES2_OPENGL().enable(Feature::ForceMinimumMaxVertexAttributes),
5235 ES2_OPENGLES().enable(Feature::ForceMinimumMaxVertexAttributes),
5236 EMULATED_VAO_CONFIGS);
5237
5238 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
5239 VertexAttributeOORTest,
5240 ES2_VULKAN().enable(Feature::ForceFallbackFormat),
5241 ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5242 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5243 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5244 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5245 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass));
5246
5247 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(RobustVertexAttributeTest);
5248
5249 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexAttributeTestES3);
5250 ANGLE_INSTANTIATE_TEST_ES3_AND(
5251 VertexAttributeTestES3,
5252 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5253 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5254 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5255 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass),
5256 ES3_VULKAN()
5257 .disable(Feature::UseVertexInputBindingStrideDynamicState)
5258 .disable(Feature::SupportsGraphicsPipelineLibrary));
5259
5260 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexAttributeTestES31);
5261 ANGLE_INSTANTIATE_TEST_ES31_AND(VertexAttributeTestES31,
5262 ES31_VULKAN().enable(Feature::ForceFallbackFormat),
5263 ES31_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5264 ES31_VULKAN()
5265 .disable(Feature::UseVertexInputBindingStrideDynamicState)
5266 .disable(Feature::SupportsGraphicsPipelineLibrary));
5267
5268 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
5269 VertexAttributeCachingTest,
5270 ES2_VULKAN().enable(Feature::ForceFallbackFormat),
5271 ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5272 ES3_VULKAN().enable(Feature::ForceFallbackFormat),
5273 ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat),
5274 ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
5275 ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass));
5276
5277 } // anonymous namespace
5278