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 "platform/FeaturesVk.h"
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 #include "util/random_utils.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
TypeStride(GLenum attribType)18 GLsizei TypeStride(GLenum attribType)
19 {
20 switch (attribType)
21 {
22 case GL_UNSIGNED_BYTE:
23 case GL_BYTE:
24 return 1;
25 case GL_UNSIGNED_SHORT:
26 case GL_SHORT:
27 case GL_HALF_FLOAT:
28 case GL_HALF_FLOAT_OES:
29 return 2;
30 case GL_UNSIGNED_INT:
31 case GL_INT:
32 case GL_FLOAT:
33 case GL_UNSIGNED_INT_10_10_10_2_OES:
34 case GL_INT_10_10_10_2_OES:
35 return 4;
36 default:
37 EXPECT_TRUE(false);
38 return 0;
39 }
40 }
41
42 template <typename T>
Normalize(T value)43 GLfloat Normalize(T value)
44 {
45 static_assert(std::is_integral<T>::value, "Integer required.");
46 if (std::is_signed<T>::value)
47 {
48 typedef typename std::make_unsigned<T>::type unsigned_type;
49 return (2.0f * static_cast<GLfloat>(value) + 1.0f) /
50 static_cast<GLfloat>(std::numeric_limits<unsigned_type>::max());
51 }
52 else
53 {
54 return static_cast<GLfloat>(value) / static_cast<GLfloat>(std::numeric_limits<T>::max());
55 }
56 }
57
58 // Normalization for each channel of signed/unsigned 10_10_10_2 types
59 template <typename T>
Normalize10(T value)60 GLfloat Normalize10(T value)
61 {
62 static_assert(std::is_integral<T>::value, "Integer required.");
63 GLfloat floatOutput;
64 if (std::is_signed<T>::value)
65 {
66 const uint32_t signMask = 0x200; // 1 set at the 9th bit
67 const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1
68
69 if (value & signMask)
70 {
71 int negativeNumber = value | negativeMask;
72 floatOutput = static_cast<GLfloat>(negativeNumber);
73 }
74 else
75 {
76 floatOutput = static_cast<GLfloat>(value);
77 }
78
79 const int32_t maxValue = 0x1FF; // 1 set in bits 0 through 8
80 const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue
81
82 // A 10-bit two's complement number has the possibility of being minValue - 1 but
83 // OpenGL's normalization rules dictate that it should be clamped to minValue in
84 // this case.
85 if (floatOutput < minValue)
86 floatOutput = minValue;
87
88 const int32_t halfRange = (maxValue - minValue) >> 1;
89 floatOutput = ((floatOutput - minValue) / halfRange) - 1.0f;
90 }
91 else
92 {
93 const GLfloat maxValue = 1023.0f; // 1 set in bits 0 through 9
94 floatOutput = static_cast<GLfloat>(value) / maxValue;
95 }
96 return floatOutput;
97 }
98
99 template <typename T>
Normalize2(T value)100 GLfloat Normalize2(T value)
101 {
102 static_assert(std::is_integral<T>::value, "Integer required.");
103 if (std::is_signed<T>::value)
104 {
105 GLfloat outputValue = static_cast<float>(value) / 1.0f;
106 outputValue = (outputValue >= -1.0f) ? (outputValue) : (-1.0f);
107 return outputValue;
108 }
109 else
110 {
111 return static_cast<float>(value) / 3.0f;
112 }
113 }
114
115 template <typename DestT, typename SrcT>
Pack1010102(std::array<SrcT,4> input)116 DestT Pack1010102(std::array<SrcT, 4> input)
117 {
118 static_assert(std::is_integral<SrcT>::value, "Integer required.");
119 static_assert(std::is_integral<DestT>::value, "Integer required.");
120 static_assert(std::is_unsigned<SrcT>::value == std::is_unsigned<DestT>::value,
121 "Signedness should be equal.");
122 DestT rOut, gOut, bOut, aOut;
123 rOut = static_cast<DestT>(input[0]);
124 gOut = static_cast<DestT>(input[1]);
125 bOut = static_cast<DestT>(input[2]);
126 aOut = static_cast<DestT>(input[3]);
127
128 if (std::is_unsigned<SrcT>::value)
129 {
130 return rOut << 22 | gOut << 12 | bOut << 2 | aOut;
131 }
132 else
133 {
134 // Need to apply bit mask to account for sign extension
135 return (0xFFC00000u & rOut << 22) | (0x003FF000u & gOut << 12) | (0x00000FFCu & bOut << 2) |
136 (0x00000003u & aOut);
137 }
138 }
139
140 class VertexAttributeTest : public ANGLETest
141 {
142 protected:
VertexAttributeTest()143 VertexAttributeTest()
144 : mProgram(0), mTestAttrib(-1), mExpectedAttrib(-1), mBuffer(0), mQuadBuffer(0)
145 {
146 setWindowWidth(128);
147 setWindowHeight(128);
148 setConfigRedBits(8);
149 setConfigGreenBits(8);
150 setConfigBlueBits(8);
151 setConfigAlphaBits(8);
152 setConfigDepthBits(24);
153 }
154
155 enum class Source
156 {
157 BUFFER,
158 IMMEDIATE,
159 };
160
161 struct TestData final : private angle::NonCopyable
162 {
TestData__anonb060ee770111::VertexAttributeTest::TestData163 TestData(GLenum typeIn,
164 GLboolean normalizedIn,
165 Source sourceIn,
166 const void *inputDataIn,
167 const GLfloat *expectedDataIn)
168 : type(typeIn),
169 normalized(normalizedIn),
170 bufferOffset(0),
171 source(sourceIn),
172 inputData(inputDataIn),
173 expectedData(expectedDataIn)
174 {}
175
176 GLenum type;
177 GLboolean normalized;
178 size_t bufferOffset;
179 Source source;
180
181 const void *inputData;
182 const GLfloat *expectedData;
183 };
184
setupTest(const TestData & test,GLint typeSize)185 void setupTest(const TestData &test, GLint typeSize)
186 {
187 if (mProgram == 0)
188 {
189 initBasicProgram();
190 }
191
192 if (test.source == Source::BUFFER)
193 {
194 GLsizei dataSize = kVertexCount * TypeStride(test.type);
195 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
196 glBufferData(GL_ARRAY_BUFFER, dataSize, test.inputData, GL_STATIC_DRAW);
197 glVertexAttribPointer(mTestAttrib, typeSize, test.type, test.normalized, 0,
198 reinterpret_cast<void *>(test.bufferOffset));
199 glBindBuffer(GL_ARRAY_BUFFER, 0);
200 }
201 else
202 {
203 ASSERT_EQ(Source::IMMEDIATE, test.source);
204 glBindBuffer(GL_ARRAY_BUFFER, 0);
205 glVertexAttribPointer(mTestAttrib, typeSize, test.type, test.normalized, 0,
206 test.inputData);
207 }
208
209 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, test.expectedData);
210
211 glEnableVertexAttribArray(mTestAttrib);
212 glEnableVertexAttribArray(mExpectedAttrib);
213 }
214
checkPixels()215 void checkPixels() { checkRGBPixels(true); }
216
checkRGBPixels(bool checkAlpha)217 void checkRGBPixels(bool checkAlpha)
218 {
219 GLint viewportSize[4];
220 glGetIntegerv(GL_VIEWPORT, viewportSize);
221
222 GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
223 GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
224
225 // We need to offset our checks from triangle edges to ensure we don't fall on a single tri
226 // Avoid making assumptions of drawQuad with four checks to check the four possible tri
227 // regions
228 if (checkAlpha)
229 {
230 EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
231 EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
232 EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
233 EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
234 }
235 else
236 {
237 EXPECT_PIXEL_RGB_EQUAL((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255);
238 EXPECT_PIXEL_RGB_EQUAL((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255);
239 EXPECT_PIXEL_RGB_EQUAL(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255);
240 EXPECT_PIXEL_RGB_EQUAL(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255);
241 }
242 }
243
checkPixelsUnEqual()244 void checkPixelsUnEqual()
245 {
246 GLint viewportSize[4];
247 glGetIntegerv(GL_VIEWPORT, viewportSize);
248
249 GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
250 GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
251
252 // We need to offset our checks from triangle edges to ensure we don't fall on a single tri
253 // Avoid making assumptions of drawQuad with four checks to check the four possible tri
254 // regions
255 EXPECT_PIXEL_NE((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
256 EXPECT_PIXEL_NE((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
257 EXPECT_PIXEL_NE(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
258 EXPECT_PIXEL_NE(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
259 }
260
runTest(const TestData & test)261 void runTest(const TestData &test) { runTest(test, true); }
262
runTest(const TestData & test,bool checkPixelEqual)263 void runTest(const TestData &test, bool checkPixelEqual)
264 {
265 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
266 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
267
268 for (GLint i = 0; i < 4; i++)
269 {
270 GLint typeSize = i + 1;
271 setupTest(test, typeSize);
272
273 drawQuad(mProgram, "position", 0.5f);
274
275 glDisableVertexAttribArray(mTestAttrib);
276 glDisableVertexAttribArray(mExpectedAttrib);
277
278 if (checkPixelEqual)
279 {
280 if ((test.type == GL_HALF_FLOAT || test.type == GL_HALF_FLOAT_OES) && IsVulkan() &&
281 typeSize == 3)
282 { // We need a special case for RGB16F format on a Vulkan backend due to the fact
283 // that in such a usecase, we need to ignore the alpha channel.
284 checkRGBPixels(false);
285 }
286 else
287 {
288 checkPixels();
289 }
290 }
291 else
292 {
293 checkPixelsUnEqual();
294 }
295 }
296 }
297
testSetUp()298 void testSetUp() override
299 {
300 glClearColor(0, 0, 0, 0);
301 glClearDepthf(0.0);
302 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
303
304 glDisable(GL_DEPTH_TEST);
305
306 glGenBuffers(1, &mBuffer);
307 }
308
testTearDown()309 void testTearDown() override
310 {
311 glDeleteProgram(mProgram);
312 glDeleteBuffers(1, &mBuffer);
313 glDeleteBuffers(1, &mQuadBuffer);
314 }
315
316 // Override a feature to force emulation of attribute formats.
overrideFeaturesVk(FeaturesVk * featuresVk)317 void overrideFeaturesVk(FeaturesVk *featuresVk) override
318 {
319 featuresVk->overrideFeatures({"force_fallback_format"}, true);
320 }
321
compileMultiAttribProgram(GLint attribCount)322 GLuint compileMultiAttribProgram(GLint attribCount)
323 {
324 std::stringstream shaderStream;
325
326 shaderStream << "attribute mediump vec4 position;" << std::endl;
327 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
328 {
329 shaderStream << "attribute float a" << attribIndex << ";" << std::endl;
330 }
331 shaderStream << "varying mediump float color;" << std::endl
332 << "void main() {" << std::endl
333 << " gl_Position = position;" << std::endl
334 << " color = 0.0;" << std::endl;
335 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
336 {
337 shaderStream << " color += a" << attribIndex << ";" << std::endl;
338 }
339 shaderStream << "}" << std::endl;
340
341 constexpr char kFS[] =
342 "varying mediump float color;\n"
343 "void main(void)\n"
344 "{\n"
345 " gl_FragColor = vec4(color, 0.0, 0.0, 1.0);\n"
346 "}\n";
347
348 return CompileProgram(shaderStream.str().c_str(), kFS);
349 }
350
setupMultiAttribs(GLuint program,GLint attribCount,GLfloat value)351 void setupMultiAttribs(GLuint program, GLint attribCount, GLfloat value)
352 {
353 glUseProgram(program);
354 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
355 {
356 std::stringstream attribStream;
357 attribStream << "a" << attribIndex;
358 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
359 ASSERT_NE(-1, location);
360 glVertexAttrib1f(location, value);
361 glDisableVertexAttribArray(location);
362 }
363 }
364
initBasicProgram()365 void initBasicProgram()
366 {
367 constexpr char kVS[] =
368 "attribute mediump vec4 position;\n"
369 "attribute mediump vec4 test;\n"
370 "attribute mediump vec4 expected;\n"
371 "varying mediump vec4 color;\n"
372 "void main(void)\n"
373 "{\n"
374 " gl_Position = position;\n"
375 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
376 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
377 "}\n";
378
379 constexpr char kFS[] =
380 "varying mediump vec4 color;\n"
381 "void main(void)\n"
382 "{\n"
383 " gl_FragColor = color;\n"
384 "}\n";
385
386 mProgram = CompileProgram(kVS, kFS);
387 ASSERT_NE(0u, mProgram);
388
389 mTestAttrib = glGetAttribLocation(mProgram, "test");
390 ASSERT_NE(-1, mTestAttrib);
391 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
392 ASSERT_NE(-1, mExpectedAttrib);
393
394 glUseProgram(mProgram);
395 }
396
397 static constexpr size_t kVertexCount = 24;
398
InitTestData(std::array<GLfloat,kVertexCount> & inputData,std::array<GLfloat,kVertexCount> & expectedData)399 static void InitTestData(std::array<GLfloat, kVertexCount> &inputData,
400 std::array<GLfloat, kVertexCount> &expectedData)
401 {
402 for (size_t count = 0; count < kVertexCount; ++count)
403 {
404 inputData[count] = static_cast<GLfloat>(count);
405 expectedData[count] = inputData[count];
406 }
407 }
408
409 GLuint mProgram;
410 GLint mTestAttrib;
411 GLint mExpectedAttrib;
412 GLuint mBuffer;
413 GLuint mQuadBuffer;
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 class VertexAttributeTestES3 : public VertexAttributeTest
932 {
933 protected:
VertexAttributeTestES3()934 VertexAttributeTestES3() {}
935 };
936
TEST_P(VertexAttributeTestES3,IntUnnormalized)937 TEST_P(VertexAttributeTestES3, IntUnnormalized)
938 {
939 GLint lo = std::numeric_limits<GLint>::min();
940 GLint hi = std::numeric_limits<GLint>::max();
941 std::array<GLint, kVertexCount> inputData = {
942 {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1}};
943 std::array<GLfloat, kVertexCount> expectedData;
944 for (size_t i = 0; i < kVertexCount; i++)
945 {
946 expectedData[i] = static_cast<GLfloat>(inputData[i]);
947 }
948
949 TestData data(GL_INT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
950 runTest(data);
951 }
952
TEST_P(VertexAttributeTestES3,IntNormalized)953 TEST_P(VertexAttributeTestES3, IntNormalized)
954 {
955 GLint lo = std::numeric_limits<GLint>::min();
956 GLint hi = std::numeric_limits<GLint>::max();
957 std::array<GLint, kVertexCount> inputData = {
958 {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1}};
959 std::array<GLfloat, kVertexCount> expectedData;
960 for (size_t i = 0; i < kVertexCount; i++)
961 {
962 expectedData[i] = Normalize(inputData[i]);
963 }
964
965 TestData data(GL_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
966 runTest(data);
967 }
968
TEST_P(VertexAttributeTestES3,UnsignedIntUnnormalized)969 TEST_P(VertexAttributeTestES3, UnsignedIntUnnormalized)
970 {
971 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
972 GLuint hi = std::numeric_limits<GLuint>::max();
973 std::array<GLuint, kVertexCount> inputData = {
974 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
975 std::array<GLfloat, kVertexCount> expectedData;
976 for (size_t i = 0; i < kVertexCount; i++)
977 {
978 expectedData[i] = static_cast<GLfloat>(inputData[i]);
979 }
980
981 TestData data(GL_UNSIGNED_INT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
982 runTest(data);
983 }
984
TEST_P(VertexAttributeTestES3,UnsignedIntNormalized)985 TEST_P(VertexAttributeTestES3, UnsignedIntNormalized)
986 {
987 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
988 GLuint hi = std::numeric_limits<GLuint>::max();
989 std::array<GLuint, kVertexCount> inputData = {
990 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
991 std::array<GLfloat, kVertexCount> expectedData;
992 for (size_t i = 0; i < kVertexCount; i++)
993 {
994 expectedData[i] = Normalize(inputData[i]);
995 }
996
997 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
998 runTest(data);
999 }
1000
SetupColorsForUnitQuad(GLint location,const GLColor32F & color,GLenum usage,GLBuffer * vbo)1001 void SetupColorsForUnitQuad(GLint location, const GLColor32F &color, GLenum usage, GLBuffer *vbo)
1002 {
1003 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
1004 std::vector<GLColor32F> vertices(6, color);
1005 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLColor32F), vertices.data(), usage);
1006 glEnableVertexAttribArray(location);
1007 glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, 0);
1008 }
1009
1010 // Tests that rendering works as expected with VAOs.
TEST_P(VertexAttributeTestES3,VertexArrayObjectRendering)1011 TEST_P(VertexAttributeTestES3, VertexArrayObjectRendering)
1012 {
1013 constexpr char kVertexShader[] =
1014 "attribute vec4 a_position;\n"
1015 "attribute vec4 a_color;\n"
1016 "varying vec4 v_color;\n"
1017 "void main()\n"
1018 "{\n"
1019 " gl_Position = a_position;\n"
1020 " v_color = a_color;\n"
1021 "}";
1022
1023 constexpr char kFragmentShader[] =
1024 "precision mediump float;\n"
1025 "varying vec4 v_color;\n"
1026 "void main()\n"
1027 "{\n"
1028 " gl_FragColor = v_color;\n"
1029 "}";
1030
1031 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
1032
1033 GLint positionLoc = glGetAttribLocation(program, "a_position");
1034 ASSERT_NE(-1, positionLoc);
1035 GLint colorLoc = glGetAttribLocation(program, "a_color");
1036 ASSERT_NE(-1, colorLoc);
1037
1038 GLVertexArray vaos[2];
1039 GLBuffer positionBuffer;
1040 GLBuffer colorBuffers[2];
1041
1042 const auto &quadVertices = GetQuadVertices();
1043
1044 glBindVertexArray(vaos[0]);
1045 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
1046 glBufferData(GL_ARRAY_BUFFER, quadVertices.size() * sizeof(Vector3), quadVertices.data(),
1047 GL_STATIC_DRAW);
1048 glEnableVertexAttribArray(positionLoc);
1049 glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1050 SetupColorsForUnitQuad(colorLoc, kFloatRed, GL_STREAM_DRAW, &colorBuffers[0]);
1051
1052 glBindVertexArray(vaos[1]);
1053 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
1054 glEnableVertexAttribArray(positionLoc);
1055 glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1056 SetupColorsForUnitQuad(colorLoc, kFloatGreen, GL_STATIC_DRAW, &colorBuffers[1]);
1057
1058 glUseProgram(program);
1059 ASSERT_GL_NO_ERROR();
1060
1061 for (int ii = 0; ii < 2; ++ii)
1062 {
1063 glBindVertexArray(vaos[0]);
1064 glDrawArrays(GL_TRIANGLES, 0, 6);
1065 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1066
1067 glBindVertexArray(vaos[1]);
1068 glDrawArrays(GL_TRIANGLES, 0, 6);
1069 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1070 }
1071
1072 ASSERT_GL_NO_ERROR();
1073 }
1074
1075 // Validate that we can support GL_MAX_ATTRIBS attribs
TEST_P(VertexAttributeTest,MaxAttribs)1076 TEST_P(VertexAttributeTest, MaxAttribs)
1077 {
1078 // TODO(jmadill): Figure out why we get this error on AMD/OpenGL.
1079 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
1080
1081 // TODO: Support this test on Vulkan. http://anglebug.com/2797
1082 ANGLE_SKIP_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
1083
1084 GLint maxAttribs;
1085 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
1086 ASSERT_GL_NO_ERROR();
1087
1088 // Reserve one attrib for position
1089 GLint drawAttribs = maxAttribs - 1;
1090
1091 GLuint program = compileMultiAttribProgram(drawAttribs);
1092 ASSERT_NE(0u, program);
1093
1094 setupMultiAttribs(program, drawAttribs, 0.5f / static_cast<float>(drawAttribs));
1095 drawQuad(program, "position", 0.5f);
1096
1097 EXPECT_GL_NO_ERROR();
1098 EXPECT_PIXEL_NEAR(0, 0, 128, 0, 0, 255, 1);
1099 }
1100
1101 // Validate that we cannot support GL_MAX_ATTRIBS+1 attribs
TEST_P(VertexAttributeTest,MaxAttribsPlusOne)1102 TEST_P(VertexAttributeTest, MaxAttribsPlusOne)
1103 {
1104 // TODO(jmadill): Figure out why we get this error on AMD/ES2/OpenGL
1105 ANGLE_SKIP_TEST_IF(IsAMD() && GetParam() == ES2_OPENGL());
1106
1107 GLint maxAttribs;
1108 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
1109 ASSERT_GL_NO_ERROR();
1110
1111 // Exceed attrib count by one (counting position)
1112 GLint drawAttribs = maxAttribs;
1113
1114 GLuint program = compileMultiAttribProgram(drawAttribs);
1115 ASSERT_EQ(0u, program);
1116 }
1117
1118 // Simple test for when we use glBindAttribLocation
TEST_P(VertexAttributeTest,SimpleBindAttribLocation)1119 TEST_P(VertexAttributeTest, SimpleBindAttribLocation)
1120 {
1121 // Re-use the multi-attrib program, binding attribute 0
1122 GLuint program = compileMultiAttribProgram(1);
1123 glBindAttribLocation(program, 2, "position");
1124 glBindAttribLocation(program, 3, "a0");
1125 glLinkProgram(program);
1126
1127 // Setup and draw the quad
1128 setupMultiAttribs(program, 1, 0.5f);
1129 drawQuad(program, "position", 0.5f);
1130 EXPECT_GL_NO_ERROR();
1131 EXPECT_PIXEL_NEAR(0, 0, 128, 0, 0, 255, 1);
1132 }
1133
1134 class VertexAttributeOORTest : public VertexAttributeTest
1135 {
1136 public:
VertexAttributeOORTest()1137 VertexAttributeOORTest()
1138 {
1139 setWebGLCompatibilityEnabled(true);
1140 setRobustAccess(false);
1141 }
1142 };
1143
1144 // Verify that drawing with a large out-of-range offset generates INVALID_OPERATION.
1145 // Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest,ANGLEDrawArraysBufferTooSmall)1146 TEST_P(VertexAttributeOORTest, ANGLEDrawArraysBufferTooSmall)
1147 {
1148 // Test skipped due to supporting GL_KHR_robust_buffer_access_behavior
1149 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior"));
1150
1151 std::array<GLfloat, kVertexCount> inputData;
1152 std::array<GLfloat, kVertexCount> expectedData;
1153 InitTestData(inputData, expectedData);
1154
1155 TestData data(GL_FLOAT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1156 data.bufferOffset = kVertexCount * TypeStride(GL_FLOAT);
1157
1158 setupTest(data, 1);
1159 drawQuad(mProgram, "position", 0.5f);
1160 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1161 }
1162
1163 // Verify that index draw with an out-of-range offset generates INVALID_OPERATION.
1164 // Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest,ANGLEDrawElementsBufferTooSmall)1165 TEST_P(VertexAttributeOORTest, ANGLEDrawElementsBufferTooSmall)
1166 {
1167 // Test skipped due to supporting GL_KHR_robust_buffer_access_behavior
1168 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior"));
1169
1170 std::array<GLfloat, kVertexCount> inputData;
1171 std::array<GLfloat, kVertexCount> expectedData;
1172 InitTestData(inputData, expectedData);
1173
1174 TestData data(GL_FLOAT, GL_FALSE, Source::BUFFER, inputData.data(), expectedData.data());
1175 data.bufferOffset = (kVertexCount - 3) * TypeStride(GL_FLOAT);
1176
1177 setupTest(data, 1);
1178 drawIndexedQuad(mProgram, "position", 0.5f);
1179 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1180 }
1181
1182 // Verify that DrawArarys with an out-of-range offset generates INVALID_OPERATION.
1183 // Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest,ANGLEDrawArraysOutOfBoundsCases)1184 TEST_P(VertexAttributeOORTest, ANGLEDrawArraysOutOfBoundsCases)
1185 {
1186 // Test skipped due to supporting GL_KHR_robust_buffer_access_behavior
1187 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior"));
1188
1189 initBasicProgram();
1190
1191 GLfloat singleFloat = 1.0f;
1192 GLsizei dataSize = TypeStride(GL_FLOAT);
1193
1194 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1195 glBufferData(GL_ARRAY_BUFFER, dataSize, &singleFloat, GL_STATIC_DRAW);
1196 glVertexAttribPointer(mTestAttrib, 2, GL_FLOAT, GL_FALSE, 8, 0);
1197 glEnableVertexAttribArray(mTestAttrib);
1198 glBindBuffer(GL_ARRAY_BUFFER, 0);
1199
1200 drawIndexedQuad(mProgram, "position", 0.5f);
1201 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1202 }
1203
1204 // Verify that using a different start vertex doesn't mess up the draw.
TEST_P(VertexAttributeTest,DrawArraysWithBufferOffset)1205 TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
1206 {
1207 // anglebug.com/4258
1208 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && IsOSX());
1209
1210 // anglebug.com/4163
1211 ANGLE_SKIP_TEST_IF(IsD3D11() && IsNVIDIA() && IsWindows7());
1212
1213 // TODO(jmadill): Diagnose this failure.
1214 ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
1215
1216 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
1217 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
1218
1219 // TODO(cnorthrop): Test this again on more recent drivers. http://anglebug.com/3951
1220 ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
1221
1222 // TODO(https://anglebug.com/4269): Test is flaky on OpenGL and Metal on Mac NVIDIA.
1223 ANGLE_SKIP_TEST_IF(IsOSX() && IsNVIDIA());
1224
1225 initBasicProgram();
1226 glUseProgram(mProgram);
1227
1228 std::array<GLfloat, kVertexCount> inputData;
1229 std::array<GLfloat, kVertexCount> expectedData;
1230 InitTestData(inputData, expectedData);
1231
1232 auto quadVertices = GetQuadVertices();
1233 GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
1234
1235 glGenBuffers(1, &mQuadBuffer);
1236 glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
1237 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
1238 glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
1239
1240 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1241 ASSERT_NE(-1, positionLocation);
1242 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1243 glEnableVertexAttribArray(positionLocation);
1244
1245 GLsizei dataSize = kVertexCount * TypeStride(GL_FLOAT);
1246 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1247 glBufferData(GL_ARRAY_BUFFER, dataSize + TypeStride(GL_FLOAT), nullptr, GL_STATIC_DRAW);
1248 glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, inputData.data());
1249 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1250 glEnableVertexAttribArray(mTestAttrib);
1251
1252 glBindBuffer(GL_ARRAY_BUFFER, 0);
1253 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1254 glEnableVertexAttribArray(mExpectedAttrib);
1255
1256 // Vertex draw with no start vertex offset (second argument is zero).
1257 glDrawArrays(GL_TRIANGLES, 0, 6);
1258 checkPixels();
1259
1260 // Draw offset by one vertex.
1261 glDrawArrays(GL_TRIANGLES, 1, 6);
1262 checkPixels();
1263
1264 EXPECT_GL_NO_ERROR();
1265 }
1266
1267 // Verify that when we pass a client memory pointer to a disabled attribute the draw is still
1268 // correct.
TEST_P(VertexAttributeTest,DrawArraysWithDisabledAttribute)1269 TEST_P(VertexAttributeTest, DrawArraysWithDisabledAttribute)
1270 {
1271 initBasicProgram();
1272
1273 std::array<GLfloat, kVertexCount> inputData;
1274 std::array<GLfloat, kVertexCount> expectedData;
1275 InitTestData(inputData, expectedData);
1276
1277 auto quadVertices = GetQuadVertices();
1278 GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
1279
1280 glGenBuffers(1, &mQuadBuffer);
1281 glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
1282 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, quadVertices.data(), GL_STATIC_DRAW);
1283
1284 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1285 ASSERT_NE(-1, positionLocation);
1286 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1287 glEnableVertexAttribArray(positionLocation);
1288
1289 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1290 glBufferData(GL_ARRAY_BUFFER, sizeof(inputData), inputData.data(), GL_STATIC_DRAW);
1291 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1292 glEnableVertexAttribArray(mTestAttrib);
1293
1294 glBindBuffer(GL_ARRAY_BUFFER, 0);
1295 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1296 glEnableVertexAttribArray(mExpectedAttrib);
1297
1298 // mProgram2 adds an attribute 'disabled' on the basis of mProgram.
1299 constexpr char testVertexShaderSource2[] =
1300 "attribute mediump vec4 position;\n"
1301 "attribute mediump vec4 test;\n"
1302 "attribute mediump vec4 expected;\n"
1303 "attribute mediump vec4 disabled;\n"
1304 "varying mediump vec4 color;\n"
1305 "void main(void)\n"
1306 "{\n"
1307 " gl_Position = position;\n"
1308 " vec4 threshold = max(abs(expected + disabled) * 0.005, 1.0 / 64.0);\n"
1309 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
1310 "}\n";
1311
1312 constexpr char testFragmentShaderSource[] =
1313 "varying mediump vec4 color;\n"
1314 "void main(void)\n"
1315 "{\n"
1316 " gl_FragColor = color;\n"
1317 "}\n";
1318
1319 ANGLE_GL_PROGRAM(program, testVertexShaderSource2, testFragmentShaderSource);
1320 GLuint mProgram2 = program.get();
1321
1322 ASSERT_EQ(positionLocation, glGetAttribLocation(mProgram2, "position"));
1323 ASSERT_EQ(mTestAttrib, glGetAttribLocation(mProgram2, "test"));
1324 ASSERT_EQ(mExpectedAttrib, glGetAttribLocation(mProgram2, "expected"));
1325
1326 // Pass a client memory pointer to disabledAttribute and disable it.
1327 GLint disabledAttribute = glGetAttribLocation(mProgram2, "disabled");
1328 ASSERT_EQ(-1, glGetAttribLocation(mProgram, "disabled"));
1329 glVertexAttribPointer(disabledAttribute, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1330 glDisableVertexAttribArray(disabledAttribute);
1331
1332 glUseProgram(mProgram);
1333 glDrawArrays(GL_TRIANGLES, 0, 6);
1334 checkPixels();
1335
1336 // Now enable disabledAttribute which should be used in mProgram2.
1337 glEnableVertexAttribArray(disabledAttribute);
1338 glUseProgram(mProgram2);
1339 glDrawArrays(GL_TRIANGLES, 0, 6);
1340 checkPixels();
1341
1342 EXPECT_GL_NO_ERROR();
1343 }
1344
1345 // Test based on WebGL Test attribs/gl-disabled-vertex-attrib.html
TEST_P(VertexAttributeTest,DisabledAttribArrays)1346 TEST_P(VertexAttributeTest, DisabledAttribArrays)
1347 {
1348 // Known failure on Retina MBP: http://crbug.com/635081
1349 ANGLE_SKIP_TEST_IF(IsOSX() && IsNVIDIA());
1350
1351 // TODO: Support this test on Vulkan. http://anglebug.com/2797
1352 ANGLE_SKIP_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
1353
1354 constexpr char kVS[] =
1355 "attribute vec4 a_position;\n"
1356 "attribute vec4 a_color;\n"
1357 "varying vec4 v_color;\n"
1358 "bool isCorrectColor(vec4 v) {\n"
1359 " return v.x == 0.0 && v.y == 0.0 && v.z == 0.0 && v.w == 1.0;\n"
1360 "}"
1361 "void main() {\n"
1362 " gl_Position = a_position;\n"
1363 " v_color = isCorrectColor(a_color) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
1364 "}";
1365
1366 constexpr char kFS[] =
1367 "varying mediump vec4 v_color;\n"
1368 "void main() {\n"
1369 " gl_FragColor = v_color;\n"
1370 "}";
1371
1372 GLint maxVertexAttribs = 0;
1373 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
1374
1375 for (GLint colorIndex = 0; colorIndex < maxVertexAttribs; ++colorIndex)
1376 {
1377 GLuint program = CompileProgram(kVS, kFS, [&](GLuint program) {
1378 glBindAttribLocation(program, colorIndex, "a_color");
1379 });
1380 ASSERT_NE(0u, program);
1381
1382 drawQuad(program, "a_position", 0.5f);
1383 ASSERT_GL_NO_ERROR();
1384
1385 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1386
1387 glDeleteProgram(program);
1388 }
1389 }
1390
1391 // Test that draw with offset larger than vertex attribute's stride can work
TEST_P(VertexAttributeTest,DrawWithLargeBufferOffset)1392 TEST_P(VertexAttributeTest, DrawWithLargeBufferOffset)
1393 {
1394 constexpr size_t kBufferOffset = 10000;
1395 constexpr size_t kQuadVertexCount = 4;
1396
1397 std::array<GLbyte, kQuadVertexCount> validInputData = {{0, 1, 2, 3}};
1398
1399 // 4 components
1400 std::array<GLbyte, 4 *kQuadVertexCount + kBufferOffset> inputData = {};
1401
1402 std::array<GLfloat, 4 * kQuadVertexCount> expectedData;
1403 for (size_t i = 0; i < kQuadVertexCount; i++)
1404 {
1405 for (int j = 0; j < 4; ++j)
1406 {
1407 inputData[kBufferOffset + 4 * i + j] = validInputData[i];
1408 expectedData[4 * i + j] = validInputData[i];
1409 }
1410 }
1411
1412 initBasicProgram();
1413
1414 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1415 glBufferData(GL_ARRAY_BUFFER, inputData.size(), inputData.data(), GL_STATIC_DRAW);
1416 glVertexAttribPointer(mTestAttrib, 4, GL_BYTE, GL_FALSE, 0,
1417 reinterpret_cast<const void *>(kBufferOffset));
1418 glEnableVertexAttribArray(mTestAttrib);
1419 glBindBuffer(GL_ARRAY_BUFFER, 0);
1420
1421 glVertexAttribPointer(mExpectedAttrib, 4, GL_FLOAT, GL_FALSE, 0, expectedData.data());
1422 glEnableVertexAttribArray(mExpectedAttrib);
1423
1424 drawIndexedQuad(mProgram, "position", 0.5f);
1425
1426 checkPixels();
1427 }
1428
1429 // Test that drawing with large vertex attribute pointer offset and less components than
1430 // shader expects is OK
TEST_P(VertexAttributeTest,DrawWithLargeBufferOffsetAndLessComponents)1431 TEST_P(VertexAttributeTest, DrawWithLargeBufferOffsetAndLessComponents)
1432 {
1433 // Shader expects vec4 but glVertexAttribPointer only provides 2 components
1434 constexpr char kVS[] = R"(attribute vec4 a_position;
1435 attribute vec4 a_attrib;
1436 varying vec4 v_attrib;
1437 void main()
1438 {
1439 v_attrib = a_attrib;
1440 gl_Position = a_position;
1441 })";
1442
1443 constexpr char kFS[] = R"(precision mediump float;
1444 varying vec4 v_attrib;
1445 void main()
1446 {
1447 gl_FragColor = v_attrib;
1448 })";
1449
1450 ANGLE_GL_PROGRAM(program, kVS, kFS);
1451 glBindAttribLocation(program, 0, "a_position");
1452 glBindAttribLocation(program, 1, "a_attrib");
1453 glLinkProgram(program);
1454 glUseProgram(program);
1455 ASSERT_GL_NO_ERROR();
1456
1457 constexpr size_t kBufferOffset = 4998;
1458
1459 // Set up color data so yellow is drawn (only R, G components are provided)
1460 std::vector<GLushort> data(kBufferOffset + 12);
1461 for (int i = 0; i < 12; ++i)
1462 {
1463 data[kBufferOffset + i] = 0xffff;
1464 }
1465
1466 GLBuffer buffer;
1467 glBindBuffer(GL_ARRAY_BUFFER, buffer);
1468 glBufferData(GL_ARRAY_BUFFER, sizeof(GLushort) * data.size(), data.data(), GL_STATIC_DRAW);
1469 // Provide only 2 components for the vec4 in the shader
1470 glVertexAttribPointer(1, 2, GL_UNSIGNED_SHORT, GL_TRUE, 0,
1471 reinterpret_cast<const void *>(sizeof(GLushort) * kBufferOffset));
1472 glBindBuffer(GL_ARRAY_BUFFER, 0);
1473 glEnableVertexAttribArray(1);
1474
1475 drawQuad(program, "a_position", 0.5f);
1476 // Verify yellow was drawn
1477 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1478 }
1479
1480 class VertexAttributeTestES31 : public VertexAttributeTestES3
1481 {
1482 protected:
VertexAttributeTestES31()1483 VertexAttributeTestES31() {}
1484
initTest()1485 void initTest()
1486 {
1487 initBasicProgram();
1488 glUseProgram(mProgram);
1489
1490 glGenVertexArrays(1, &mVAO);
1491 glBindVertexArray(mVAO);
1492
1493 auto quadVertices = GetQuadVertices();
1494 GLsizeiptr quadVerticesSize =
1495 static_cast<GLsizeiptr>(quadVertices.size() * sizeof(quadVertices[0]));
1496 glGenBuffers(1, &mQuadBuffer);
1497 glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
1498 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, quadVertices.data(), GL_STATIC_DRAW);
1499
1500 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1501 ASSERT_NE(-1, positionLocation);
1502 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1503 glEnableVertexAttribArray(positionLocation);
1504
1505 std::array<GLfloat, kVertexCount> expectedData;
1506 for (size_t count = 0; count < kVertexCount; ++count)
1507 {
1508 expectedData[count] = static_cast<GLfloat>(count);
1509 }
1510
1511 const GLsizei kExpectedDataSize = kVertexCount * kFloatStride;
1512 glGenBuffers(1, &mExpectedBuffer);
1513 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
1514 glBufferData(GL_ARRAY_BUFFER, kExpectedDataSize, expectedData.data(), GL_STATIC_DRAW);
1515 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1516 glEnableVertexAttribArray(mExpectedAttrib);
1517 }
1518
testTearDown()1519 void testTearDown() override
1520 {
1521 VertexAttributeTestES3::testTearDown();
1522
1523 glDeleteBuffers(1, &mExpectedBuffer);
1524 glDeleteVertexArrays(1, &mVAO);
1525 }
1526
drawArraysWithStrideAndRelativeOffset(GLint stride,GLuint relativeOffset)1527 void drawArraysWithStrideAndRelativeOffset(GLint stride, GLuint relativeOffset)
1528 {
1529 initTest();
1530
1531 GLint floatStride = std::max(stride / kFloatStride, 1);
1532 GLuint floatRelativeOffset = relativeOffset / kFloatStride;
1533 size_t floatCount = static_cast<size_t>(floatRelativeOffset) + kVertexCount * floatStride;
1534 GLsizeiptr inputSize = static_cast<GLsizeiptr>(floatCount) * kFloatStride;
1535
1536 std::vector<GLfloat> inputData(floatCount);
1537 for (size_t count = 0; count < kVertexCount; ++count)
1538 {
1539 inputData[floatRelativeOffset + count * floatStride] = static_cast<GLfloat>(count);
1540 }
1541
1542 // Ensure inputSize, inputStride and inputOffset are multiples of TypeStride(GL_FLOAT).
1543 GLsizei inputStride = floatStride * kFloatStride;
1544 GLsizeiptr inputRelativeOffset = floatRelativeOffset * kFloatStride;
1545 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1546 glBufferData(GL_ARRAY_BUFFER, inputSize, nullptr, GL_STATIC_DRAW);
1547 glBufferSubData(GL_ARRAY_BUFFER, 0, inputSize, inputData.data());
1548 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE,
1549 base::checked_cast<GLuint>(inputRelativeOffset));
1550 glBindVertexBuffer(mTestAttrib, mBuffer, 0, inputStride);
1551 glEnableVertexAttribArray(mTestAttrib);
1552
1553 glDrawArrays(GL_TRIANGLES, 0, 6);
1554 checkPixels();
1555
1556 EXPECT_GL_NO_ERROR();
1557 }
1558
initOnlyUpdateBindingTest(GLint bindingToUpdate)1559 void initOnlyUpdateBindingTest(GLint bindingToUpdate)
1560 {
1561 initTest();
1562
1563 constexpr GLuint kTestFloatOffset1 = kVertexCount;
1564 std::array<GLfloat, kTestFloatOffset1 + kVertexCount> inputData1 = {};
1565 for (size_t count = 0; count < kVertexCount; ++count)
1566 {
1567 GLfloat value = static_cast<GLfloat>(count);
1568 inputData1[kTestFloatOffset1 + count] = value;
1569 }
1570
1571 GLBuffer testBuffer1;
1572 glBindBuffer(GL_ARRAY_BUFFER, testBuffer1);
1573 glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
1574 GL_STATIC_DRAW);
1575
1576 ASSERT_NE(bindingToUpdate, mTestAttrib);
1577 ASSERT_NE(bindingToUpdate, mExpectedAttrib);
1578
1579 // Set mTestAttrib using the binding bindingToUpdate.
1580 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0);
1581 glBindVertexBuffer(bindingToUpdate, testBuffer1, kTestFloatOffset1 * kFloatStride,
1582 kFloatStride);
1583 glVertexAttribBinding(mTestAttrib, bindingToUpdate);
1584 glEnableVertexAttribArray(mTestAttrib);
1585
1586 // In the first draw the current VAO states are set to driver.
1587 glDrawArrays(GL_TRIANGLES, 0, 6);
1588 checkPixels();
1589 EXPECT_GL_NO_ERROR();
1590
1591 // We need the second draw to ensure all VAO dirty bits are reset.
1592 // e.g. On D3D11 back-ends, Buffer11::resize is called in the first draw, where the related
1593 // binding is set to dirty again.
1594 glDrawArrays(GL_TRIANGLES, 0, 6);
1595 checkPixels();
1596 EXPECT_GL_NO_ERROR();
1597 }
1598
1599 GLuint mVAO;
1600 GLuint mExpectedBuffer;
1601
1602 const GLsizei kFloatStride = TypeStride(GL_FLOAT);
1603
1604 // Set the maximum value for stride and relativeOffset in case they are too large.
1605 const GLint MAX_STRIDE_FOR_TEST = 4095;
1606 const GLint MAX_RELATIVE_OFFSET_FOR_TEST = 4095;
1607 };
1608
1609 // Verify that MAX_VERTEX_ATTRIB_STRIDE is no less than the minimum required value (2048) in ES3.1.
TEST_P(VertexAttributeTestES31,MaxVertexAttribStride)1610 TEST_P(VertexAttributeTestES31, MaxVertexAttribStride)
1611 {
1612 GLint maxStride;
1613 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
1614 ASSERT_GL_NO_ERROR();
1615
1616 EXPECT_GE(maxStride, 2048);
1617 }
1618
1619 // Verify that GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET is no less than the minimum required value
1620 // (2047) in ES3.1.
TEST_P(VertexAttributeTestES31,MaxVertexAttribRelativeOffset)1621 TEST_P(VertexAttributeTestES31, MaxVertexAttribRelativeOffset)
1622 {
1623 GLint maxRelativeOffset;
1624 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
1625 ASSERT_GL_NO_ERROR();
1626
1627 EXPECT_GE(maxRelativeOffset, 2047);
1628 }
1629
1630 // Verify using MAX_VERTEX_ATTRIB_STRIDE as stride doesn't mess up the draw.
1631 // Use default value if the value of MAX_VERTEX_ATTRIB_STRIDE is too large for this test.
TEST_P(VertexAttributeTestES31,DrawArraysWithLargeStride)1632 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride)
1633 {
1634 GLint maxStride;
1635 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
1636 ASSERT_GL_NO_ERROR();
1637
1638 GLint largeStride = std::min(maxStride, MAX_STRIDE_FOR_TEST);
1639 drawArraysWithStrideAndRelativeOffset(largeStride, 0);
1640 }
1641
1642 // Verify using MAX_VERTEX_ATTRIB_RELATIVE_OFFSET as relativeOffset doesn't mess up the draw.
1643 // Use default value if the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSSET is too large for this test.
TEST_P(VertexAttributeTestES31,DrawArraysWithLargeRelativeOffset)1644 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeRelativeOffset)
1645 {
1646 GLint maxRelativeOffset;
1647 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
1648 ASSERT_GL_NO_ERROR();
1649
1650 GLint largeRelativeOffset = std::min(maxRelativeOffset, MAX_RELATIVE_OFFSET_FOR_TEST);
1651 drawArraysWithStrideAndRelativeOffset(0, largeRelativeOffset);
1652 }
1653
1654 // Test that vertex array object works correctly when render pipeline and compute pipeline are
1655 // crossly executed.
TEST_P(VertexAttributeTestES31,MixedComputeAndRenderPipelines)1656 TEST_P(VertexAttributeTestES31, MixedComputeAndRenderPipelines)
1657 {
1658 constexpr char kComputeShader[] =
1659 R"(#version 310 es
1660 layout(local_size_x=1) in;
1661 void main()
1662 {
1663 })";
1664 ANGLE_GL_COMPUTE_PROGRAM(computePogram, kComputeShader);
1665
1666 glViewport(0, 0, getWindowWidth(), getWindowHeight());
1667 glClearColor(0, 0, 0, 0);
1668
1669 constexpr char kVertexShader[] =
1670 R"(#version 310 es
1671 precision mediump float;
1672 layout(location = 0) in vec4 position;
1673 layout(location = 2) in vec2 aOffset;
1674 layout(location = 3) in vec4 aColor;
1675 out vec4 vColor;
1676 void main() {
1677 vColor = aColor;
1678 gl_Position = position + vec4(aOffset, 0.0, 0.0);
1679 })";
1680
1681 constexpr char kFragmentShader[] =
1682 R"(#version 310 es
1683 precision mediump float;
1684 in vec4 vColor;
1685 out vec4 color;
1686 void main() {
1687 color = vColor;
1688 })";
1689
1690 ANGLE_GL_PROGRAM(renderProgram, kVertexShader, kFragmentShader);
1691
1692 constexpr char kVertexShader1[] =
1693 R"(#version 310 es
1694 precision mediump float;
1695 layout(location = 1) in vec4 position;
1696 layout(location = 2) in vec2 aOffset;
1697 layout(location = 3) in vec4 aColor;
1698 out vec4 vColor;
1699 void main() {
1700 vColor = aColor;
1701 gl_Position = position + vec4(aOffset, 0.0, 0.0);
1702 })";
1703
1704 ANGLE_GL_PROGRAM(renderProgram1, kVertexShader1, kFragmentShader);
1705
1706 std::array<GLfloat, 8> offsets = {
1707 -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
1708 };
1709 GLBuffer offsetBuffer;
1710 glBindBuffer(GL_ARRAY_BUFFER, offsetBuffer);
1711 glBufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(GLfloat), offsets.data(), GL_STATIC_DRAW);
1712
1713 std::array<GLfloat, 16> colors0 = {
1714 1.0, 0.0, 0.0, 1.0, // Red
1715 0.0, 1.0, 0.0, 1.0, // Green
1716 0.0, 0.0, 1.0, 1.0, // Blue
1717 1.0, 1.0, 0.0, 1.0, // Yellow
1718 };
1719 std::array<GLfloat, 16> colors1 = {
1720 1.0, 1.0, 0.0, 1.0, // Yellow
1721 0.0, 0.0, 1.0, 1.0, // Blue
1722 0.0, 1.0, 0.0, 1.0, // Green
1723 1.0, 0.0, 0.0, 1.0, // Red
1724 };
1725 GLBuffer colorBuffers[2];
1726 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[0]);
1727 glBufferData(GL_ARRAY_BUFFER, colors0.size() * sizeof(GLfloat), colors0.data(), GL_STATIC_DRAW);
1728 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[1]);
1729 glBufferData(GL_ARRAY_BUFFER, colors1.size() * sizeof(GLfloat), colors1.data(), GL_STATIC_DRAW);
1730
1731 std::array<GLfloat, 16> positions = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
1732 1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
1733 GLBuffer positionBuffer;
1734 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
1735 glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(GLfloat), positions.data(),
1736 GL_STATIC_DRAW);
1737
1738 const int kInstanceCount = 4;
1739 GLVertexArray vao[2];
1740 for (size_t i = 0u; i < 2u; ++i)
1741 {
1742 glBindVertexArray(vao[i]);
1743
1744 glBindBuffer(GL_ARRAY_BUFFER, offsetBuffer);
1745 glEnableVertexAttribArray(2);
1746 glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0);
1747 glVertexAttribDivisor(2, 1);
1748
1749 glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[i]);
1750 glEnableVertexAttribArray(3);
1751 glVertexAttribPointer(3, 4, GL_FLOAT, false, 0, 0);
1752 glVertexAttribDivisor(3, 1);
1753
1754 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
1755 glEnableVertexAttribArray(i);
1756 glVertexAttribPointer(i, 2, GL_FLOAT, false, 0, 0);
1757 }
1758
1759 glClear(GL_COLOR_BUFFER_BIT);
1760
1761 for (int i = 0; i < 3; i++)
1762 {
1763 glUseProgram(renderProgram.get());
1764 glBindVertexArray(vao[0]);
1765 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, kInstanceCount);
1766
1767 EXPECT_GL_NO_ERROR();
1768 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 2, GLColor::red);
1769 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
1770 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1771 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::yellow);
1772
1773 glBindVertexArray(vao[1]);
1774 glUseProgram(computePogram.get());
1775 glDispatchCompute(1, 1, 1);
1776
1777 glUseProgram(renderProgram1.get());
1778 glBindVertexArray(vao[1]);
1779 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, kInstanceCount);
1780
1781 EXPECT_GL_NO_ERROR();
1782 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 2, GLColor::yellow);
1783 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1784 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1785 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::red);
1786 }
1787 }
1788
TEST_P(VertexAttributeTestES31,UseComputeShaderToUpdateVertexBuffer)1789 TEST_P(VertexAttributeTestES31, UseComputeShaderToUpdateVertexBuffer)
1790 {
1791 initTest();
1792 constexpr char kComputeShader[] =
1793 R"(#version 310 es
1794 layout(local_size_x=24) in;
1795 layout(std430, binding = 0) buffer buf {
1796 uint outData[24];
1797 };
1798 void main()
1799 {
1800 outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
1801 })";
1802
1803 ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
1804 glUseProgram(mProgram);
1805
1806 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
1807 GLuint hi = std::numeric_limits<GLuint>::max();
1808 std::array<GLuint, kVertexCount> inputData = {
1809 {0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
1810 std::array<GLfloat, kVertexCount> expectedData;
1811 for (size_t i = 0; i < kVertexCount; i++)
1812 {
1813 expectedData[i] = Normalize(inputData[i]);
1814 }
1815
1816 // Normalized unsigned int attribute will be classified as translated static attribute.
1817 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
1818 GLint typeSize = 4;
1819 GLsizei dataSize = kVertexCount * TypeStride(data.type);
1820 GLBuffer testBuffer;
1821 glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
1822 glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
1823 glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
1824 reinterpret_cast<void *>(data.bufferOffset));
1825 glEnableVertexAttribArray(mTestAttrib);
1826
1827 glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
1828 glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
1829 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
1830
1831 // Draw twice to make sure that all static attributes dirty bits are synced.
1832 glDrawArrays(GL_TRIANGLES, 0, 6);
1833 glDrawArrays(GL_TRIANGLES, 0, 6);
1834 checkPixels();
1835
1836 // Modify the testBuffer using a raw buffer
1837 glUseProgram(computeProgram);
1838 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
1839 glDispatchCompute(1, 1, 1);
1840 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
1841
1842 // Draw again to verify that testBuffer has been changed.
1843 glUseProgram(mProgram);
1844 glDrawArrays(GL_TRIANGLES, 0, 6);
1845 EXPECT_GL_NO_ERROR();
1846 checkPixelsUnEqual();
1847 }
1848
1849 // Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31,ChangeAttribBindingAfterVertexAttribPointer)1850 TEST_P(VertexAttributeTestES31, ChangeAttribBindingAfterVertexAttribPointer)
1851 {
1852 initTest();
1853
1854 constexpr GLint kInputStride = 2;
1855 constexpr GLint kFloatOffset = 10;
1856 std::array<GLfloat, kVertexCount + kFloatOffset> inputData1;
1857 std::array<GLfloat, kVertexCount * kInputStride> inputData2;
1858 for (size_t count = 0; count < kVertexCount; ++count)
1859 {
1860 inputData1[kFloatOffset + count] = static_cast<GLfloat>(count);
1861 inputData2[count * kInputStride] = static_cast<GLfloat>(count);
1862 }
1863
1864 GLBuffer mBuffer1;
1865 glBindBuffer(GL_ARRAY_BUFFER, mBuffer1);
1866 glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
1867 GL_STATIC_DRAW);
1868 // Update the format indexed mTestAttrib and the binding indexed mTestAttrib by
1869 // VertexAttribPointer.
1870 const GLintptr kOffset = static_cast<GLintptr>(kFloatStride * kFloatOffset);
1871 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0,
1872 reinterpret_cast<const GLvoid *>(kOffset));
1873 glEnableVertexAttribArray(mTestAttrib);
1874
1875 constexpr GLint kTestBinding = 10;
1876 ASSERT_NE(mTestAttrib, kTestBinding);
1877
1878 GLBuffer mBuffer2;
1879 glBindBuffer(GL_ARRAY_BUFFER, mBuffer2);
1880 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
1881 GL_STATIC_DRAW);
1882 glBindVertexBuffer(kTestBinding, mBuffer2, 0, kFloatStride * kInputStride);
1883
1884 // The attribute indexed mTestAttrib is using the binding indexed kTestBinding in the first
1885 // draw.
1886 glVertexAttribBinding(mTestAttrib, kTestBinding);
1887 glDrawArrays(GL_TRIANGLES, 0, 6);
1888 checkPixels();
1889 EXPECT_GL_NO_ERROR();
1890
1891 // The attribute indexed mTestAttrib is using the binding indexed mTestAttrib which should be
1892 // set after the call VertexAttribPointer before the first draw.
1893 glVertexAttribBinding(mTestAttrib, mTestAttrib);
1894 glDrawArrays(GL_TRIANGLES, 0, 6);
1895 checkPixels();
1896 EXPECT_GL_NO_ERROR();
1897 }
1898
1899 // Verify that using VertexAttribFormat after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31,ChangeAttribFormatAfterVertexAttribPointer)1900 TEST_P(VertexAttributeTestES31, ChangeAttribFormatAfterVertexAttribPointer)
1901 {
1902 initTest();
1903
1904 constexpr GLuint kFloatOffset = 10;
1905 std::array<GLfloat, kVertexCount + kFloatOffset> inputData;
1906 for (size_t count = 0; count < kVertexCount; ++count)
1907 {
1908 inputData[kFloatOffset + count] = static_cast<GLfloat>(count);
1909 }
1910
1911 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
1912 glBufferData(GL_ARRAY_BUFFER, inputData.size() * kFloatStride, inputData.data(),
1913 GL_STATIC_DRAW);
1914
1915 // Call VertexAttribPointer on mTestAttrib. Now the relativeOffset of mTestAttrib should be 0.
1916 const GLuint kOffset = static_cast<GLuint>(kFloatStride * kFloatOffset);
1917 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
1918 glEnableVertexAttribArray(mTestAttrib);
1919
1920 // Call VertexAttribFormat on mTestAttrib to modify the relativeOffset to kOffset.
1921 glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, kOffset);
1922
1923 glDrawArrays(GL_TRIANGLES, 0, 6);
1924 checkPixels();
1925 EXPECT_GL_NO_ERROR();
1926 }
1927
1928 // Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31,OnlyUpdateBindingByBindVertexBuffer)1929 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByBindVertexBuffer)
1930 {
1931 // Default binding index for test
1932 constexpr GLint kTestBinding = 10;
1933 initOnlyUpdateBindingTest(kTestBinding);
1934
1935 constexpr GLuint kTestFloatOffset2 = kVertexCount * 2;
1936 std::array<GLfloat, kVertexCount> expectedData2 = {};
1937 std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
1938 for (size_t count = 0; count < kVertexCount; ++count)
1939 {
1940 GLfloat value2 = static_cast<GLfloat>(count) * 2;
1941 expectedData2[count] = value2;
1942 inputData2[count + kTestFloatOffset2] = value2;
1943 }
1944
1945 // Set another set of data for mExpectedAttrib.
1946 GLBuffer expectedBuffer2;
1947 glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
1948 glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
1949 GL_STATIC_DRAW);
1950 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1951
1952 GLBuffer testBuffer2;
1953 glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
1954 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
1955 GL_STATIC_DRAW);
1956
1957 // Only update the binding kTestBinding in the second draw by BindVertexBuffer.
1958 glBindVertexBuffer(kTestBinding, testBuffer2, kTestFloatOffset2 * kFloatStride, kFloatStride);
1959
1960 glDrawArrays(GL_TRIANGLES, 0, 6);
1961 checkPixels();
1962 EXPECT_GL_NO_ERROR();
1963 }
1964
1965 // Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31,OnlyUpdateBindingByVertexAttribPointer)1966 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByVertexAttribPointer)
1967 {
1968 // Default binding index for test
1969 constexpr GLint kTestBinding = 10;
1970 initOnlyUpdateBindingTest(kTestBinding);
1971
1972 constexpr GLuint kTestFloatOffset2 = kVertexCount * 3;
1973 std::array<GLfloat, kVertexCount> expectedData2 = {};
1974 std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
1975 for (size_t count = 0; count < kVertexCount; ++count)
1976 {
1977 GLfloat value2 = static_cast<GLfloat>(count) * 3;
1978 expectedData2[count] = value2;
1979 inputData2[count + kTestFloatOffset2] = value2;
1980 }
1981
1982 // Set another set of data for mExpectedAttrib.
1983 GLBuffer expectedBuffer2;
1984 glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
1985 glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
1986 GL_STATIC_DRAW);
1987 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1988
1989 GLBuffer testBuffer2;
1990 glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
1991 glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
1992 GL_STATIC_DRAW);
1993
1994 // Only update the binding kTestBinding in the second draw by VertexAttribPointer.
1995 glVertexAttribPointer(kTestBinding, 1, GL_FLOAT, GL_FALSE, 0,
1996 reinterpret_cast<const void *>(kTestFloatOffset2 * kFloatStride));
1997
1998 glDrawArrays(GL_TRIANGLES, 0, 6);
1999 checkPixels();
2000 EXPECT_GL_NO_ERROR();
2001 }
2002
2003 class VertexAttributeCachingTest : public VertexAttributeTest
2004 {
2005 protected:
VertexAttributeCachingTest()2006 VertexAttributeCachingTest() {}
2007
2008 void testSetUp() override;
2009
2010 template <typename DestT>
2011 static std::vector<GLfloat> GetExpectedData(const std::vector<GLubyte> &srcData,
2012 GLenum attribType,
2013 GLboolean normalized);
2014
initDoubleAttribProgram()2015 void initDoubleAttribProgram()
2016 {
2017 constexpr char kVS[] =
2018 "attribute mediump vec4 position;\n"
2019 "attribute mediump vec4 test;\n"
2020 "attribute mediump vec4 expected;\n"
2021 "attribute mediump vec4 test2;\n"
2022 "attribute mediump vec4 expected2;\n"
2023 "varying mediump vec4 color;\n"
2024 "void main(void)\n"
2025 "{\n"
2026 " gl_Position = position;\n"
2027 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
2028 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
2029 " vec4 threshold2 = max(abs(expected2) * 0.01, 1.0 / 64.0);\n"
2030 " color += vec4(lessThanEqual(abs(test2 - expected2), threshold2));\n"
2031 "}\n";
2032
2033 constexpr char kFS[] =
2034 "varying mediump vec4 color;\n"
2035 "void main(void)\n"
2036 "{\n"
2037 " gl_FragColor = color;\n"
2038 "}\n";
2039
2040 mProgram = CompileProgram(kVS, kFS);
2041 ASSERT_NE(0u, mProgram);
2042
2043 mTestAttrib = glGetAttribLocation(mProgram, "test");
2044 ASSERT_NE(-1, mTestAttrib);
2045 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
2046 ASSERT_NE(-1, mExpectedAttrib);
2047
2048 glUseProgram(mProgram);
2049 }
2050
2051 struct AttribData
2052 {
2053 AttribData(GLenum typeIn, GLint sizeIn, GLboolean normalizedIn, GLsizei strideIn);
2054
2055 GLenum type;
2056 GLint size;
2057 GLboolean normalized;
2058 GLsizei stride;
2059 };
2060
2061 std::vector<AttribData> mTestData;
2062 std::map<GLenum, std::vector<GLfloat>> mExpectedData;
2063 std::map<GLenum, std::vector<GLfloat>> mNormExpectedData;
2064 };
2065
AttribData(GLenum typeIn,GLint sizeIn,GLboolean normalizedIn,GLsizei strideIn)2066 VertexAttributeCachingTest::AttribData::AttribData(GLenum typeIn,
2067 GLint sizeIn,
2068 GLboolean normalizedIn,
2069 GLsizei strideIn)
2070 : type(typeIn), size(sizeIn), normalized(normalizedIn), stride(strideIn)
2071 {}
2072
2073 // static
2074 template <typename DestT>
GetExpectedData(const std::vector<GLubyte> & srcData,GLenum attribType,GLboolean normalized)2075 std::vector<GLfloat> VertexAttributeCachingTest::GetExpectedData(
2076 const std::vector<GLubyte> &srcData,
2077 GLenum attribType,
2078 GLboolean normalized)
2079 {
2080 std::vector<GLfloat> expectedData;
2081
2082 const DestT *typedSrcPtr = reinterpret_cast<const DestT *>(srcData.data());
2083 size_t iterations = srcData.size() / TypeStride(attribType);
2084
2085 if (normalized)
2086 {
2087 for (size_t index = 0; index < iterations; ++index)
2088 {
2089 expectedData.push_back(Normalize(typedSrcPtr[index]));
2090 }
2091 }
2092 else
2093 {
2094 for (size_t index = 0; index < iterations; ++index)
2095 {
2096 expectedData.push_back(static_cast<GLfloat>(typedSrcPtr[index]));
2097 }
2098 }
2099
2100 return expectedData;
2101 }
2102
testSetUp()2103 void VertexAttributeCachingTest::testSetUp()
2104 {
2105 VertexAttributeTest::testSetUp();
2106
2107 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2108
2109 std::vector<GLubyte> srcData;
2110 for (size_t count = 0; count < 4; ++count)
2111 {
2112 for (GLubyte i = 0; i < std::numeric_limits<GLubyte>::max(); ++i)
2113 {
2114 srcData.push_back(i);
2115 }
2116 }
2117
2118 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
2119
2120 GLint viewportSize[4];
2121 glGetIntegerv(GL_VIEWPORT, viewportSize);
2122
2123 std::vector<GLenum> attribTypes;
2124 attribTypes.push_back(GL_BYTE);
2125 attribTypes.push_back(GL_UNSIGNED_BYTE);
2126 attribTypes.push_back(GL_SHORT);
2127 attribTypes.push_back(GL_UNSIGNED_SHORT);
2128
2129 if (getClientMajorVersion() >= 3)
2130 {
2131 attribTypes.push_back(GL_INT);
2132 attribTypes.push_back(GL_UNSIGNED_INT);
2133 }
2134
2135 constexpr GLint kMaxSize = 4;
2136 constexpr GLsizei kMaxStride = 4;
2137
2138 for (GLenum attribType : attribTypes)
2139 {
2140 for (GLint attribSize = 1; attribSize <= kMaxSize; ++attribSize)
2141 {
2142 for (GLsizei stride = 1; stride <= kMaxStride; ++stride)
2143 {
2144 mTestData.push_back(AttribData(attribType, attribSize, GL_FALSE, stride));
2145 if (attribType != GL_FLOAT)
2146 {
2147 mTestData.push_back(AttribData(attribType, attribSize, GL_TRUE, stride));
2148 }
2149 }
2150 }
2151 }
2152
2153 mExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_FALSE);
2154 mExpectedData[GL_UNSIGNED_BYTE] = GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_FALSE);
2155 mExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_FALSE);
2156 mExpectedData[GL_UNSIGNED_SHORT] =
2157 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_FALSE);
2158 mExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_FALSE);
2159 mExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_FALSE);
2160
2161 mNormExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_TRUE);
2162 mNormExpectedData[GL_UNSIGNED_BYTE] =
2163 GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_TRUE);
2164 mNormExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_TRUE);
2165 mNormExpectedData[GL_UNSIGNED_SHORT] =
2166 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_TRUE);
2167 mNormExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_TRUE);
2168 mNormExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_TRUE);
2169 }
2170
2171 // In D3D11, we must sometimes translate buffer data into static attribute caches. We also use a
2172 // cache management scheme which garbage collects old attributes after we start using too much
2173 // cache data. This test tries to make as many attribute caches from a single buffer as possible
2174 // to stress-test the caching code.
TEST_P(VertexAttributeCachingTest,BufferMulticaching)2175 TEST_P(VertexAttributeCachingTest, BufferMulticaching)
2176 {
2177 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
2178
2179 initBasicProgram();
2180
2181 glEnableVertexAttribArray(mTestAttrib);
2182 glEnableVertexAttribArray(mExpectedAttrib);
2183
2184 ASSERT_GL_NO_ERROR();
2185
2186 for (const AttribData &data : mTestData)
2187 {
2188 const auto &expected =
2189 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
2190
2191 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
2192 GLsizei stride = TypeStride(data.type) * baseStride;
2193
2194 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2195 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
2196 glBindBuffer(GL_ARRAY_BUFFER, 0);
2197 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
2198 sizeof(GLfloat) * baseStride, expected.data());
2199 drawQuad(mProgram, "position", 0.5f);
2200 ASSERT_GL_NO_ERROR();
2201 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
2202 }
2203 }
2204
2205 // With D3D11 dirty bits for VertxArray11, we can leave vertex state unchanged if there aren't any
2206 // GL calls that affect it. This test targets leaving one vertex attribute unchanged between draw
2207 // calls while changing another vertex attribute enough that it clears the static buffer cache
2208 // after enough iterations. It validates the unchanged attributes don't get deleted incidentally.
TEST_P(VertexAttributeCachingTest,BufferMulticachingWithOneUnchangedAttrib)2209 TEST_P(VertexAttributeCachingTest, BufferMulticachingWithOneUnchangedAttrib)
2210 {
2211 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
2212
2213 initDoubleAttribProgram();
2214
2215 GLint testAttrib2Location = glGetAttribLocation(mProgram, "test2");
2216 ASSERT_NE(-1, testAttrib2Location);
2217 GLint expectedAttrib2Location = glGetAttribLocation(mProgram, "expected2");
2218 ASSERT_NE(-1, expectedAttrib2Location);
2219
2220 glEnableVertexAttribArray(mTestAttrib);
2221 glEnableVertexAttribArray(mExpectedAttrib);
2222 glEnableVertexAttribArray(testAttrib2Location);
2223 glEnableVertexAttribArray(expectedAttrib2Location);
2224
2225 ASSERT_GL_NO_ERROR();
2226
2227 // Use an attribute that we know must be converted. This is a bit sensitive.
2228 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2229 glVertexAttribPointer(testAttrib2Location, 3, GL_UNSIGNED_SHORT, GL_FALSE, 6, nullptr);
2230 glBindBuffer(GL_ARRAY_BUFFER, 0);
2231 glVertexAttribPointer(expectedAttrib2Location, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3,
2232 mExpectedData[GL_UNSIGNED_SHORT].data());
2233
2234 for (const auto &data : mTestData)
2235 {
2236 const auto &expected =
2237 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
2238
2239 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
2240 GLsizei stride = TypeStride(data.type) * baseStride;
2241
2242 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
2243 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
2244 glBindBuffer(GL_ARRAY_BUFFER, 0);
2245 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
2246 sizeof(GLfloat) * baseStride, expected.data());
2247 drawQuad(mProgram, "position", 0.5f);
2248
2249 ASSERT_GL_NO_ERROR();
2250 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
2251 }
2252 }
2253
2254 // Test that if there are gaps in the attribute indices, the attributes have their correct values.
TEST_P(VertexAttributeTest,UnusedVertexAttribWorks)2255 TEST_P(VertexAttributeTest, UnusedVertexAttribWorks)
2256 {
2257 constexpr char kVertexShader[] = R"(attribute vec2 position;
2258 attribute float actualValue;
2259 uniform float expectedValue;
2260 varying float result;
2261 void main()
2262 {
2263 result = (actualValue == expectedValue) ? 1.0 : 0.0;
2264 gl_Position = vec4(position, 0, 1);
2265 })";
2266
2267 constexpr char kFragmentShader[] = R"(varying mediump float result;
2268 void main()
2269 {
2270 gl_FragColor = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
2271 })";
2272
2273 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
2274
2275 // Force a gap in attributes by using location 0 and 3
2276 GLint positionLocation = 0;
2277 glBindAttribLocation(program, positionLocation, "position");
2278
2279 GLint attribLoc = 3;
2280 glBindAttribLocation(program, attribLoc, "actualValue");
2281
2282 // Re-link the program to update the attribute locations
2283 glLinkProgram(program);
2284 ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
2285
2286 glUseProgram(program);
2287
2288 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
2289 ASSERT_NE(-1, uniLoc);
2290
2291 glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
2292
2293 ASSERT_NE(-1, positionLocation);
2294 setupQuadVertexBuffer(0.5f, 1.0f);
2295 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2296 glEnableVertexAttribArray(positionLocation);
2297
2298 std::array<GLfloat, 4> testValues = {{1, 2, 3, 4}};
2299 for (GLfloat testValue : testValues)
2300 {
2301 glUniform1f(uniLoc, testValue);
2302 glVertexAttrib1f(attribLoc, testValue);
2303 glDrawArrays(GL_TRIANGLES, 0, 6);
2304 ASSERT_GL_NO_ERROR();
2305 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
2306 }
2307 }
2308
2309 // Tests that repeatedly updating a disabled vertex attribute works as expected.
2310 // This covers an ANGLE bug where dirty bits for current values were ignoring repeated updates.
TEST_P(VertexAttributeTest,DisabledAttribUpdates)2311 TEST_P(VertexAttributeTest, DisabledAttribUpdates)
2312 {
2313 constexpr char kVertexShader[] = R"(attribute vec2 position;
2314 attribute float actualValue;
2315 uniform float expectedValue;
2316 varying float result;
2317 void main()
2318 {
2319 result = (actualValue == expectedValue) ? 1.0 : 0.0;
2320 gl_Position = vec4(position, 0, 1);
2321 })";
2322
2323 constexpr char kFragmentShader[] = R"(varying mediump float result;
2324 void main()
2325 {
2326 gl_FragColor = result > 0.0 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
2327 })";
2328
2329 ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
2330
2331 glUseProgram(program);
2332 GLint attribLoc = glGetAttribLocation(program, "actualValue");
2333 ASSERT_NE(-1, attribLoc);
2334
2335 GLint uniLoc = glGetUniformLocation(program, "expectedValue");
2336 ASSERT_NE(-1, uniLoc);
2337
2338 glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
2339
2340 GLint positionLocation = glGetAttribLocation(program, "position");
2341 ASSERT_NE(-1, positionLocation);
2342 setupQuadVertexBuffer(0.5f, 1.0f);
2343 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2344 glEnableVertexAttribArray(positionLocation);
2345
2346 std::array<GLfloat, 4> testValues = {{1, 2, 3, 4}};
2347 for (GLfloat testValue : testValues)
2348 {
2349 glUniform1f(uniLoc, testValue);
2350 glVertexAttrib1f(attribLoc, testValue);
2351 glDrawArrays(GL_TRIANGLES, 0, 6);
2352 ASSERT_GL_NO_ERROR();
2353 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
2354 }
2355 }
2356
2357 // Test that even inactive attributes are taken into account when checking for aliasing in case the
2358 // shader version is >= 3.00. GLSL ES 3.00.6 section 12.46.
TEST_P(VertexAttributeTestES3,InactiveAttributeAliasing)2359 TEST_P(VertexAttributeTestES3, InactiveAttributeAliasing)
2360 {
2361 constexpr char vertexShader[] =
2362 R"(#version 300 es
2363 precision mediump float;
2364 in vec4 input_active;
2365 in vec4 input_unused;
2366 void main()
2367 {
2368 gl_Position = input_active;
2369 })";
2370
2371 constexpr char fragmentShader[] =
2372 R"(#version 300 es
2373 precision mediump float;
2374 out vec4 color;
2375 void main()
2376 {
2377 color = vec4(0.0);
2378 })";
2379
2380 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2381 glBindAttribLocation(program, 0, "input_active");
2382 glBindAttribLocation(program, 0, "input_unused");
2383 glLinkProgram(program);
2384 EXPECT_GL_NO_ERROR();
2385 GLint linkStatus = 0;
2386 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
2387 EXPECT_GL_FALSE(linkStatus);
2388 }
2389
2390 // Test that enabling inactive attributes doesn't cause a crash
2391 // shader version is >= 3.00
TEST_P(VertexAttributeTestES3,EnabledButInactiveAttributes)2392 TEST_P(VertexAttributeTestES3, EnabledButInactiveAttributes)
2393 {
2394 // This is similar to runtest(), and the test is disabled there
2395 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
2396
2397 constexpr char testVertexShaderSource[] =
2398 R"(#version 300 es
2399 precision mediump float;
2400 in vec4 position;
2401 layout(location = 1) in vec4 test;
2402 layout(location = 2) in vec4 unused1;
2403 layout(location = 3) in vec4 unused2;
2404 layout(location = 4) in vec4 unused3;
2405 layout(location = 5) in vec4 expected;
2406 out vec4 color;
2407 void main(void)
2408 {
2409 gl_Position = position;
2410 vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);
2411 color = vec4(lessThanEqual(abs(test - expected), threshold));
2412 })";
2413
2414 // Same as previous one, except it uses unused1/2 instead of test/expected, leaving unused3
2415 // unused
2416 constexpr char testVertexShader2Source[] =
2417 R"(#version 300 es
2418 precision mediump float;
2419 in vec4 position;
2420 layout(location = 1) in vec4 test;
2421 layout(location = 2) in vec4 unused1;
2422 layout(location = 3) in vec4 unused2;
2423 layout(location = 4) in vec4 unused3;
2424 layout(location = 5) in vec4 expected;
2425 out vec4 color;
2426 void main(void)
2427 {
2428 gl_Position = position;
2429 vec4 threshold = max(abs(unused2) * 0.01, 1.0 / 64.0);
2430 color = vec4(lessThanEqual(abs(unused1 - unused2), threshold));
2431 })";
2432
2433 constexpr char testFragmentShaderSource[] =
2434 R"(#version 300 es
2435 precision mediump float;
2436 in vec4 color;
2437 out vec4 out_color;
2438 void main()
2439 {
2440 out_color = color;
2441 })";
2442
2443 std::array<GLubyte, kVertexCount> inputData = {
2444 {0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255}};
2445 std::array<GLubyte, kVertexCount> inputData2;
2446 std::array<GLfloat, kVertexCount> expectedData;
2447 std::array<GLfloat, kVertexCount> expectedData2;
2448 for (size_t i = 0; i < kVertexCount; i++)
2449 {
2450 expectedData[i] = inputData[i];
2451 inputData2[i] = inputData[i] > 128 ? inputData[i] - 1 : inputData[i] + 1;
2452 expectedData2[i] = inputData2[i];
2453 }
2454
2455 // Setup the program
2456 mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
2457 ASSERT_NE(0u, mProgram);
2458
2459 mTestAttrib = glGetAttribLocation(mProgram, "test");
2460 ASSERT_EQ(1, mTestAttrib);
2461 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
2462 ASSERT_EQ(5, mExpectedAttrib);
2463
2464 GLint unused1Attrib = 2;
2465 GLint unused2Attrib = 3;
2466 GLint unused3Attrib = 4;
2467
2468 // Test enabling an unused attribute before glUseProgram
2469 glEnableVertexAttribArray(unused3Attrib);
2470
2471 glUseProgram(mProgram);
2472
2473 // Setup the test data
2474 TestData data(GL_UNSIGNED_BYTE, GL_FALSE, Source::IMMEDIATE, inputData.data(),
2475 expectedData.data());
2476 setupTest(data, 1);
2477
2478 // Test enabling an unused attribute after glUseProgram
2479 glVertexAttribPointer(unused1Attrib, 1, data.type, data.normalized, 0, inputData2.data());
2480 glEnableVertexAttribArray(unused1Attrib);
2481
2482 glVertexAttribPointer(unused2Attrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData2.data());
2483 glEnableVertexAttribArray(unused2Attrib);
2484
2485 // Run the test. This shouldn't use the unused attributes. Note that one of them is nullptr
2486 // which can cause a crash on certain platform-driver combination.
2487 drawQuad(mProgram, "position", 0.5f);
2488 checkPixels();
2489
2490 // Now test with the same attributes enabled, but with a program with different attributes
2491 // active
2492 mProgram = CompileProgram(testVertexShader2Source, testFragmentShaderSource);
2493 ASSERT_NE(0u, mProgram);
2494
2495 // Make sure all the attributes are in the same location
2496 ASSERT_EQ(glGetAttribLocation(mProgram, "unused1"), unused1Attrib);
2497 ASSERT_EQ(glGetAttribLocation(mProgram, "unused2"), unused2Attrib);
2498
2499 glUseProgram(mProgram);
2500
2501 // Run the test again. unused1/2 were disabled in the previous run (as they were inactive in
2502 // the shader), but should be re-enabled now.
2503 drawQuad(mProgram, "position", 0.5f);
2504 checkPixels();
2505 }
2506
2507 // Tests that large strides that read past the end of the buffer work correctly.
2508 // Requires ES 3.1 to query MAX_VERTEX_ATTRIB_STRIDE.
TEST_P(VertexAttributeTestES31,LargeStride)2509 TEST_P(VertexAttributeTestES31, LargeStride)
2510 {
2511 struct Vertex
2512 {
2513 Vector4 position;
2514 Vector2 color;
2515 };
2516
2517 constexpr uint32_t kColorOffset = offsetof(Vertex, color);
2518
2519 // Get MAX_VERTEX_ATTRIB_STRIDE.
2520 GLint maxStride;
2521 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
2522
2523 uint32_t bufferSize = static_cast<uint32_t>(maxStride);
2524 uint32_t stride = sizeof(Vertex);
2525 uint32_t numVertices = bufferSize / stride;
2526
2527 // The last vertex fits in the buffer size. The last vertex stride extends past it.
2528 ASSERT_LT(numVertices * stride, bufferSize);
2529 ASSERT_GT(numVertices * stride + kColorOffset, bufferSize);
2530
2531 RNG rng(0);
2532
2533 std::vector<Vertex> vertexData(bufferSize, {Vector4(), Vector2()});
2534 std::vector<GLColor> expectedColors;
2535 for (uint32_t vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex)
2536 {
2537 int x = vertexIndex % getWindowWidth();
2538 int y = vertexIndex / getWindowWidth();
2539
2540 // Generate and clamp a 2 component vector.
2541 Vector4 randomVec4 = RandomVec4(rng.randomInt(), 0.0f, 1.0f);
2542 GLColor randomColor(randomVec4);
2543 randomColor[2] = 0;
2544 randomColor[3] = 255;
2545 Vector4 clampedVec = randomColor.toNormalizedVector();
2546
2547 vertexData[vertexIndex] = {Vector4(x, y, 0.0f, 1.0f),
2548 Vector2(clampedVec[0], clampedVec[1])};
2549 expectedColors.push_back(randomColor);
2550 }
2551
2552 GLBuffer buffer;
2553 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2554 glBufferData(GL_ARRAY_BUFFER, bufferSize, vertexData.data(), GL_STATIC_DRAW);
2555
2556 vertexData.resize(numVertices);
2557
2558 constexpr char kVS[] = R"(#version 310 es
2559 in vec4 pos;
2560 in vec2 color;
2561 out vec2 vcolor;
2562 void main()
2563 {
2564 vcolor = color;
2565 gl_Position = vec4(((pos.x + 0.5) / 64.0) - 1.0, ((pos.y + 0.5) / 64.0) - 1.0, 0, 1);
2566 gl_PointSize = 1.0;
2567 })";
2568
2569 constexpr char kFS[] = R"(#version 310 es
2570 precision mediump float;
2571 in vec2 vcolor;
2572 out vec4 fcolor;
2573 void main()
2574 {
2575 fcolor = vec4(vcolor, 0.0, 1.0);
2576 })";
2577
2578 ANGLE_GL_PROGRAM(program, kVS, kFS);
2579 glUseProgram(program);
2580
2581 GLint posLoc = glGetAttribLocation(program, "pos");
2582 ASSERT_NE(-1, posLoc);
2583 GLint colorLoc = glGetAttribLocation(program, "color");
2584 ASSERT_NE(-1, colorLoc);
2585
2586 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
2587 glEnableVertexAttribArray(posLoc);
2588 glVertexAttribPointer(colorLoc, 2, GL_FLOAT, GL_FALSE, stride,
2589 reinterpret_cast<GLvoid *>(kColorOffset));
2590 glEnableVertexAttribArray(colorLoc);
2591
2592 glDrawArrays(GL_POINTS, 0, numVertices);
2593
2594 // Validate pixels.
2595 std::vector<GLColor> actualColors(getWindowWidth() * getWindowHeight());
2596 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
2597 actualColors.data());
2598
2599 actualColors.resize(numVertices);
2600
2601 ASSERT_GL_NO_ERROR();
2602 EXPECT_EQ(expectedColors, actualColors);
2603 }
2604
2605 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
2606 // tests should be run against.
2607 // D3D11 Feature Level 9_3 uses different D3D formats for vertex attribs compared to Feature Levels
2608 // 10_0+, so we should test them separately.
2609 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VertexAttributeTest);
2610
2611 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VertexAttributeOORTest);
2612
2613 ANGLE_INSTANTIATE_TEST_ES3(VertexAttributeTestES3);
2614
2615 ANGLE_INSTANTIATE_TEST_ES31(VertexAttributeTestES31);
2616
2617 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VertexAttributeCachingTest);
2618
2619 } // anonymous namespace
2620