1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "test_utils/ANGLETest.h"
8
9 using namespace angle;
10
11 namespace
12 {
13
TypeStride(GLenum attribType)14 GLsizei TypeStride(GLenum attribType)
15 {
16 switch (attribType)
17 {
18 case GL_UNSIGNED_BYTE:
19 case GL_BYTE:
20 return 1;
21 case GL_UNSIGNED_SHORT:
22 case GL_SHORT:
23 return 2;
24 case GL_UNSIGNED_INT:
25 case GL_INT:
26 case GL_FLOAT:
27 return 4;
28 default:
29 UNREACHABLE();
30 return 0;
31 }
32 }
33
34 template <typename T>
Normalize(T value)35 GLfloat Normalize(T value)
36 {
37 static_assert(std::is_integral<T>::value, "Integer required.");
38 if (std::is_signed<T>::value)
39 {
40 typedef typename std::make_unsigned<T>::type unsigned_type;
41 return (2.0f * static_cast<GLfloat>(value) + 1.0f) /
42 static_cast<GLfloat>(std::numeric_limits<unsigned_type>::max());
43 }
44 else
45 {
46 return static_cast<GLfloat>(value) / static_cast<GLfloat>(std::numeric_limits<T>::max());
47 }
48 }
49
50 class VertexAttributeTest : public ANGLETest
51 {
52 protected:
VertexAttributeTest()53 VertexAttributeTest()
54 : mProgram(0), mTestAttrib(-1), mExpectedAttrib(-1), mBuffer(0), mQuadBuffer(0)
55 {
56 setWindowWidth(128);
57 setWindowHeight(128);
58 setConfigRedBits(8);
59 setConfigGreenBits(8);
60 setConfigBlueBits(8);
61 setConfigAlphaBits(8);
62 setConfigDepthBits(24);
63 }
64
65 enum class Source
66 {
67 BUFFER,
68 IMMEDIATE,
69 };
70
71 struct TestData final : angle::NonCopyable
72 {
TestData__anon93bce5600111::VertexAttributeTest::TestData73 TestData(GLenum typeIn,
74 GLboolean normalizedIn,
75 Source sourceIn,
76 const void *inputDataIn,
77 const GLfloat *expectedDataIn)
78 : type(typeIn),
79 normalized(normalizedIn),
80 bufferOffset(0),
81 source(sourceIn),
82 inputData(inputDataIn),
83 expectedData(expectedDataIn)
84 {
85 }
86
87 GLenum type;
88 GLboolean normalized;
89 size_t bufferOffset;
90 Source source;
91
92 const void *inputData;
93 const GLfloat *expectedData;
94 };
95
setupTest(const TestData & test,GLint typeSize)96 void setupTest(const TestData &test, GLint typeSize)
97 {
98 if (mProgram == 0)
99 {
100 initBasicProgram();
101 }
102
103 if (test.source == Source::BUFFER)
104 {
105 GLsizei dataSize = mVertexCount * TypeStride(test.type);
106 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
107 glBufferData(GL_ARRAY_BUFFER, dataSize, test.inputData, GL_STATIC_DRAW);
108 glVertexAttribPointer(mTestAttrib, typeSize, test.type, test.normalized, 0,
109 reinterpret_cast<GLvoid *>(test.bufferOffset));
110 glBindBuffer(GL_ARRAY_BUFFER, 0);
111 }
112 else
113 {
114 ASSERT_EQ(Source::IMMEDIATE, test.source);
115 glBindBuffer(GL_ARRAY_BUFFER, 0);
116 glVertexAttribPointer(mTestAttrib, typeSize, test.type, test.normalized, 0,
117 test.inputData);
118 }
119
120 glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, test.expectedData);
121
122 glEnableVertexAttribArray(mTestAttrib);
123 glEnableVertexAttribArray(mExpectedAttrib);
124 }
125
checkPixels()126 void checkPixels()
127 {
128 GLint viewportSize[4];
129 glGetIntegerv(GL_VIEWPORT, viewportSize);
130
131 GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
132 GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
133
134 // We need to offset our checks from triangle edges to ensure we don't fall on a single tri
135 // Avoid making assumptions of drawQuad with four checks to check the four possible tri
136 // regions
137 EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
138 EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
139 EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
140 EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
141 }
142
runTest(const TestData & test)143 void runTest(const TestData &test)
144 {
145 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
146 if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
147 {
148 std::cout << "Test skipped on AMD OpenGL." << std::endl;
149 return;
150 }
151
152 for (GLint i = 0; i < 4; i++)
153 {
154 GLint typeSize = i + 1;
155 setupTest(test, typeSize);
156
157 drawQuad(mProgram, "position", 0.5f);
158
159 glDisableVertexAttribArray(mTestAttrib);
160 glDisableVertexAttribArray(mExpectedAttrib);
161
162 checkPixels();
163 }
164 }
165
SetUp()166 void SetUp() override
167 {
168 ANGLETest::SetUp();
169
170 glClearColor(0, 0, 0, 0);
171 glClearDepthf(0.0);
172 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
173
174 glDisable(GL_DEPTH_TEST);
175
176 glGenBuffers(1, &mBuffer);
177 }
178
TearDown()179 void TearDown() override
180 {
181 glDeleteProgram(mProgram);
182 glDeleteBuffers(1, &mBuffer);
183 glDeleteBuffers(1, &mQuadBuffer);
184
185 ANGLETest::TearDown();
186 }
187
compileMultiAttribProgram(GLint attribCount)188 GLuint compileMultiAttribProgram(GLint attribCount)
189 {
190 std::stringstream shaderStream;
191
192 shaderStream << "attribute mediump vec4 position;" << std::endl;
193 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
194 {
195 shaderStream << "attribute float a" << attribIndex << ";" << std::endl;
196 }
197 shaderStream << "varying mediump float color;" << std::endl
198 << "void main() {" << std::endl
199 << " gl_Position = position;" << std::endl
200 << " color = 0.0;" << std::endl;
201 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
202 {
203 shaderStream << " color += a" << attribIndex << ";" << std::endl;
204 }
205 shaderStream << "}" << std::endl;
206
207 const std::string testFragmentShaderSource =
208 SHADER_SOURCE(varying mediump float color; void main(void)
209 {
210 gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
211 });
212
213 return CompileProgram(shaderStream.str(), testFragmentShaderSource);
214 }
215
setupMultiAttribs(GLuint program,GLint attribCount,GLfloat value)216 void setupMultiAttribs(GLuint program, GLint attribCount, GLfloat value)
217 {
218 glUseProgram(program);
219 for (GLint attribIndex = 0; attribIndex < attribCount; ++attribIndex)
220 {
221 std::stringstream attribStream;
222 attribStream << "a" << attribIndex;
223 GLint location = glGetAttribLocation(program, attribStream.str().c_str());
224 ASSERT_NE(-1, location);
225 glVertexAttrib1f(location, value);
226 glDisableVertexAttribArray(location);
227 }
228 }
229
initBasicProgram()230 void initBasicProgram()
231 {
232 const std::string testVertexShaderSource =
233 "attribute mediump vec4 position;\n"
234 "attribute mediump vec4 test;\n"
235 "attribute mediump vec4 expected;\n"
236 "varying mediump vec4 color;\n"
237 "void main(void)\n"
238 "{\n"
239 " gl_Position = position;\n"
240 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
241 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
242 "}\n";
243
244 const std::string testFragmentShaderSource =
245 "varying mediump vec4 color;\n"
246 "void main(void)\n"
247 "{\n"
248 " gl_FragColor = color;\n"
249 "}\n";
250
251 mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
252 ASSERT_NE(0u, mProgram);
253
254 mTestAttrib = glGetAttribLocation(mProgram, "test");
255 ASSERT_NE(-1, mTestAttrib);
256 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
257 ASSERT_NE(-1, mExpectedAttrib);
258
259 glUseProgram(mProgram);
260 }
261
262 static const size_t mVertexCount = 24;
263
264 GLuint mProgram;
265 GLint mTestAttrib;
266 GLint mExpectedAttrib;
267 GLuint mBuffer;
268 GLuint mQuadBuffer;
269 };
270
TEST_P(VertexAttributeTest,UnsignedByteUnnormalized)271 TEST_P(VertexAttributeTest, UnsignedByteUnnormalized)
272 {
273 GLubyte inputData[mVertexCount] = { 0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255 };
274 GLfloat expectedData[mVertexCount];
275 for (size_t i = 0; i < mVertexCount; i++)
276 {
277 expectedData[i] = inputData[i];
278 }
279
280 TestData data(GL_UNSIGNED_BYTE, GL_FALSE, Source::IMMEDIATE, inputData, expectedData);
281 runTest(data);
282 }
283
TEST_P(VertexAttributeTest,UnsignedByteNormalized)284 TEST_P(VertexAttributeTest, UnsignedByteNormalized)
285 {
286 GLubyte inputData[mVertexCount] = { 0, 1, 2, 3, 4, 5, 6, 7, 125, 126, 127, 128, 129, 250, 251, 252, 253, 254, 255 };
287 GLfloat expectedData[mVertexCount];
288 for (size_t i = 0; i < mVertexCount; i++)
289 {
290 expectedData[i] = Normalize(inputData[i]);
291 }
292
293 TestData data(GL_UNSIGNED_BYTE, GL_TRUE, Source::IMMEDIATE, inputData, expectedData);
294 runTest(data);
295 }
296
TEST_P(VertexAttributeTest,ByteUnnormalized)297 TEST_P(VertexAttributeTest, ByteUnnormalized)
298 {
299 GLbyte inputData[mVertexCount] = { 0, 1, 2, 3, 4, -1, -2, -3, -4, 125, 126, 127, -128, -127, -126 };
300 GLfloat expectedData[mVertexCount];
301 for (size_t i = 0; i < mVertexCount; i++)
302 {
303 expectedData[i] = inputData[i];
304 }
305
306 TestData data(GL_BYTE, GL_FALSE, Source::IMMEDIATE, inputData, expectedData);
307 runTest(data);
308 }
309
TEST_P(VertexAttributeTest,ByteNormalized)310 TEST_P(VertexAttributeTest, ByteNormalized)
311 {
312 GLbyte inputData[mVertexCount] = { 0, 1, 2, 3, 4, -1, -2, -3, -4, 125, 126, 127, -128, -127, -126 };
313 GLfloat expectedData[mVertexCount];
314 for (size_t i = 0; i < mVertexCount; i++)
315 {
316 expectedData[i] = Normalize(inputData[i]);
317 }
318
319 TestData data(GL_BYTE, GL_TRUE, Source::IMMEDIATE, inputData, expectedData);
320 runTest(data);
321 }
322
TEST_P(VertexAttributeTest,UnsignedShortUnnormalized)323 TEST_P(VertexAttributeTest, UnsignedShortUnnormalized)
324 {
325 GLushort inputData[mVertexCount] = { 0, 1, 2, 3, 254, 255, 256, 32766, 32767, 32768, 65533, 65534, 65535 };
326 GLfloat expectedData[mVertexCount];
327 for (size_t i = 0; i < mVertexCount; i++)
328 {
329 expectedData[i] = inputData[i];
330 }
331
332 TestData data(GL_UNSIGNED_SHORT, GL_FALSE, Source::IMMEDIATE, inputData, expectedData);
333 runTest(data);
334 }
335
TEST_P(VertexAttributeTest,UnsignedShortNormalized)336 TEST_P(VertexAttributeTest, UnsignedShortNormalized)
337 {
338 GLushort inputData[mVertexCount] = { 0, 1, 2, 3, 254, 255, 256, 32766, 32767, 32768, 65533, 65534, 65535 };
339 GLfloat expectedData[mVertexCount];
340 for (size_t i = 0; i < mVertexCount; i++)
341 {
342 expectedData[i] = Normalize(inputData[i]);
343 }
344
345 TestData data(GL_UNSIGNED_SHORT, GL_TRUE, Source::IMMEDIATE, inputData, expectedData);
346 runTest(data);
347 }
348
TEST_P(VertexAttributeTest,ShortUnnormalized)349 TEST_P(VertexAttributeTest, ShortUnnormalized)
350 {
351 GLshort inputData[mVertexCount] = { 0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766 };
352 GLfloat expectedData[mVertexCount];
353 for (size_t i = 0; i < mVertexCount; i++)
354 {
355 expectedData[i] = inputData[i];
356 }
357
358 TestData data(GL_SHORT, GL_FALSE, Source::IMMEDIATE, inputData, expectedData);
359 runTest(data);
360 }
361
TEST_P(VertexAttributeTest,ShortNormalized)362 TEST_P(VertexAttributeTest, ShortNormalized)
363 {
364 GLshort inputData[mVertexCount] = { 0, 1, 2, 3, -1, -2, -3, -4, 32766, 32767, -32768, -32767, -32766 };
365 GLfloat expectedData[mVertexCount];
366 for (size_t i = 0; i < mVertexCount; i++)
367 {
368 expectedData[i] = Normalize(inputData[i]);
369 }
370
371 TestData data(GL_SHORT, GL_TRUE, Source::IMMEDIATE, inputData, expectedData);
372 runTest(data);
373 }
374
375 class VertexAttributeTestES3 : public VertexAttributeTest
376 {
377 protected:
VertexAttributeTestES3()378 VertexAttributeTestES3() {}
379 };
380
TEST_P(VertexAttributeTestES3,IntUnnormalized)381 TEST_P(VertexAttributeTestES3, IntUnnormalized)
382 {
383 GLint lo = std::numeric_limits<GLint>::min();
384 GLint hi = std::numeric_limits<GLint>::max();
385 GLint inputData[mVertexCount] = {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1};
386 GLfloat expectedData[mVertexCount];
387 for (size_t i = 0; i < mVertexCount; i++)
388 {
389 expectedData[i] = static_cast<GLfloat>(inputData[i]);
390 }
391
392 TestData data(GL_INT, GL_FALSE, Source::BUFFER, inputData, expectedData);
393 runTest(data);
394 }
395
TEST_P(VertexAttributeTestES3,IntNormalized)396 TEST_P(VertexAttributeTestES3, IntNormalized)
397 {
398 GLint lo = std::numeric_limits<GLint>::min();
399 GLint hi = std::numeric_limits<GLint>::max();
400 GLint inputData[mVertexCount] = {0, 1, 2, 3, -1, -2, -3, -4, -1, hi, hi - 1, lo, lo + 1};
401 GLfloat expectedData[mVertexCount];
402 for (size_t i = 0; i < mVertexCount; i++)
403 {
404 expectedData[i] = Normalize(inputData[i]);
405 }
406
407 TestData data(GL_INT, GL_TRUE, Source::BUFFER, inputData, expectedData);
408 runTest(data);
409 }
410
TEST_P(VertexAttributeTestES3,UnsignedIntUnnormalized)411 TEST_P(VertexAttributeTestES3, UnsignedIntUnnormalized)
412 {
413 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
414 GLuint hi = std::numeric_limits<GLuint>::max();
415 GLuint inputData[mVertexCount] = {0, 1, 2, 3, 254, 255, 256,
416 mid - 1, mid, mid + 1, hi - 2, hi - 1, hi};
417 GLfloat expectedData[mVertexCount];
418 for (size_t i = 0; i < mVertexCount; i++)
419 {
420 expectedData[i] = static_cast<GLfloat>(inputData[i]);
421 }
422
423 TestData data(GL_UNSIGNED_INT, GL_FALSE, Source::BUFFER, inputData, expectedData);
424 runTest(data);
425 }
426
TEST_P(VertexAttributeTestES3,UnsignedIntNormalized)427 TEST_P(VertexAttributeTestES3, UnsignedIntNormalized)
428 {
429 GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
430 GLuint hi = std::numeric_limits<GLuint>::max();
431 GLuint inputData[mVertexCount] = {0, 1, 2, 3, 254, 255, 256,
432 mid - 1, mid, mid + 1, hi - 2, hi - 1, hi};
433 GLfloat expectedData[mVertexCount];
434 for (size_t i = 0; i < mVertexCount; i++)
435 {
436 expectedData[i] = Normalize(inputData[i]);
437 }
438
439 TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData, expectedData);
440 runTest(data);
441 }
442
443 // Validate that we can support GL_MAX_ATTRIBS attribs
TEST_P(VertexAttributeTest,MaxAttribs)444 TEST_P(VertexAttributeTest, MaxAttribs)
445 {
446 // TODO(jmadill): Figure out why we get this error on AMD/OpenGL and Intel.
447 if ((IsIntel() || IsAMD()) && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
448 {
449 std::cout << "Test skipped on Intel and AMD." << std::endl;
450 return;
451 }
452
453 GLint maxAttribs;
454 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
455 ASSERT_GL_NO_ERROR();
456
457 // Reserve one attrib for position
458 GLint drawAttribs = maxAttribs - 1;
459
460 GLuint program = compileMultiAttribProgram(drawAttribs);
461 ASSERT_NE(0u, program);
462
463 setupMultiAttribs(program, drawAttribs, 0.5f / static_cast<float>(drawAttribs));
464 drawQuad(program, "position", 0.5f);
465
466 EXPECT_GL_NO_ERROR();
467 EXPECT_PIXEL_NEAR(0, 0, 128, 0, 0, 255, 1);
468 }
469
470 // Validate that we cannot support GL_MAX_ATTRIBS+1 attribs
TEST_P(VertexAttributeTest,MaxAttribsPlusOne)471 TEST_P(VertexAttributeTest, MaxAttribsPlusOne)
472 {
473 // TODO(jmadill): Figure out why we get this error on AMD/ES2/OpenGL
474 if (IsAMD() && GetParam() == ES2_OPENGL())
475 {
476 std::cout << "Test disabled on AMD/ES2/OpenGL" << std::endl;
477 return;
478 }
479
480 GLint maxAttribs;
481 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
482 ASSERT_GL_NO_ERROR();
483
484 // Exceed attrib count by one (counting position)
485 GLint drawAttribs = maxAttribs;
486
487 GLuint program = compileMultiAttribProgram(drawAttribs);
488 ASSERT_EQ(0u, program);
489 }
490
491 // Simple test for when we use glBindAttribLocation
TEST_P(VertexAttributeTest,SimpleBindAttribLocation)492 TEST_P(VertexAttributeTest, SimpleBindAttribLocation)
493 {
494 // TODO(jmadill): Figure out why this fails on Intel.
495 if (IsIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
496 {
497 std::cout << "Test skipped on Intel." << std::endl;
498 return;
499 }
500
501 // Re-use the multi-attrib program, binding attribute 0
502 GLuint program = compileMultiAttribProgram(1);
503 glBindAttribLocation(program, 2, "position");
504 glBindAttribLocation(program, 3, "a0");
505 glLinkProgram(program);
506
507 // Setup and draw the quad
508 setupMultiAttribs(program, 1, 0.5f);
509 drawQuad(program, "position", 0.5f);
510 EXPECT_GL_NO_ERROR();
511 EXPECT_PIXEL_NEAR(0, 0, 128, 0, 0, 255, 1);
512 }
513
514 // Verify that drawing with a large out-of-range offset generates INVALID_OPERATION.
TEST_P(VertexAttributeTest,DrawArraysBufferTooSmall)515 TEST_P(VertexAttributeTest, DrawArraysBufferTooSmall)
516 {
517 GLfloat inputData[mVertexCount];
518 GLfloat expectedData[mVertexCount];
519 for (size_t count = 0; count < mVertexCount; ++count)
520 {
521 inputData[count] = static_cast<GLfloat>(count);
522 expectedData[count] = inputData[count];
523 }
524
525 TestData data(GL_FLOAT, GL_FALSE, Source::BUFFER, inputData, expectedData);
526 data.bufferOffset = mVertexCount * TypeStride(GL_FLOAT);
527
528 setupTest(data, 1);
529 drawQuad(mProgram, "position", 0.5f);
530 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
531 }
532
533 // Verify that index draw with an out-of-range offset generates INVALID_OPERATION.
TEST_P(VertexAttributeTest,DrawElementsBufferTooSmall)534 TEST_P(VertexAttributeTest, DrawElementsBufferTooSmall)
535 {
536 GLfloat inputData[mVertexCount];
537 GLfloat expectedData[mVertexCount];
538 for (size_t count = 0; count < mVertexCount; ++count)
539 {
540 inputData[count] = static_cast<GLfloat>(count);
541 expectedData[count] = inputData[count];
542 }
543
544 TestData data(GL_FLOAT, GL_FALSE, Source::BUFFER, inputData, expectedData);
545 data.bufferOffset = (mVertexCount - 3) * TypeStride(GL_FLOAT);
546
547 setupTest(data, 1);
548 drawIndexedQuad(mProgram, "position", 0.5f);
549 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
550 }
551
552 // Verify that using a different start vertex doesn't mess up the draw.
TEST_P(VertexAttributeTest,DrawArraysWithBufferOffset)553 TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
554 {
555 // TODO(jmadill): Diagnose this failure.
556 if (IsD3D11_FL93())
557 {
558 std::cout << "Test disabled on D3D11 FL 9_3" << std::endl;
559 return;
560 }
561
562 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
563 if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
564 {
565 std::cout << "Test skipped on AMD OpenGL." << std::endl;
566 return;
567 }
568
569 initBasicProgram();
570 glUseProgram(mProgram);
571
572 GLfloat inputData[mVertexCount];
573 GLfloat expectedData[mVertexCount];
574 for (size_t count = 0; count < mVertexCount; ++count)
575 {
576 inputData[count] = static_cast<GLfloat>(count);
577 expectedData[count] = inputData[count];
578 }
579
580 auto quadVertices = GetQuadVertices();
581 GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
582
583 glGenBuffers(1, &mQuadBuffer);
584 glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
585 glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
586 glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
587
588 GLint positionLocation = glGetAttribLocation(mProgram, "position");
589 ASSERT_NE(-1, positionLocation);
590 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
591 glEnableVertexAttribArray(positionLocation);
592
593 GLsizei dataSize = mVertexCount * TypeStride(GL_FLOAT);
594 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
595 glBufferData(GL_ARRAY_BUFFER, dataSize + TypeStride(GL_FLOAT), nullptr, GL_STATIC_DRAW);
596 glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, inputData);
597 glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
598 glEnableVertexAttribArray(mTestAttrib);
599
600 glBindBuffer(GL_ARRAY_BUFFER, 0);
601 glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData);
602 glEnableVertexAttribArray(mExpectedAttrib);
603
604 // Vertex draw with no start vertex offset (second argument is zero).
605 glDrawArrays(GL_TRIANGLES, 0, 6);
606 checkPixels();
607
608 // Draw offset by one vertex.
609 glDrawArrays(GL_TRIANGLES, 1, 6);
610 checkPixels();
611
612 EXPECT_GL_NO_ERROR();
613 }
614
615 class VertexAttributeCachingTest : public VertexAttributeTest
616 {
617 protected:
VertexAttributeCachingTest()618 VertexAttributeCachingTest() {}
619
620 void SetUp() override;
621
622 template <typename DestT>
623 static std::vector<GLfloat> GetExpectedData(const std::vector<GLubyte> &srcData,
624 GLenum attribType,
625 GLboolean normalized);
626
initDoubleAttribProgram()627 void initDoubleAttribProgram()
628 {
629 const std::string testVertexShaderSource =
630 "attribute mediump vec4 position;\n"
631 "attribute mediump vec4 test;\n"
632 "attribute mediump vec4 expected;\n"
633 "attribute mediump vec4 test2;\n"
634 "attribute mediump vec4 expected2;\n"
635 "varying mediump vec4 color;\n"
636 "void main(void)\n"
637 "{\n"
638 " gl_Position = position;\n"
639 " vec4 threshold = max(abs(expected) * 0.01, 1.0 / 64.0);\n"
640 " color = vec4(lessThanEqual(abs(test - expected), threshold));\n"
641 " vec4 threshold2 = max(abs(expected2) * 0.01, 1.0 / 64.0);\n"
642 " color += vec4(lessThanEqual(abs(test2 - expected2), threshold2));\n"
643 "}\n";
644
645 const std::string testFragmentShaderSource =
646 "varying mediump vec4 color;\n"
647 "void main(void)\n"
648 "{\n"
649 " gl_FragColor = color;\n"
650 "}\n";
651
652 mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
653 ASSERT_NE(0u, mProgram);
654
655 mTestAttrib = glGetAttribLocation(mProgram, "test");
656 ASSERT_NE(-1, mTestAttrib);
657 mExpectedAttrib = glGetAttribLocation(mProgram, "expected");
658 ASSERT_NE(-1, mExpectedAttrib);
659
660 glUseProgram(mProgram);
661 }
662
663 struct AttribData
664 {
665 AttribData(GLenum typeIn, GLint sizeIn, GLboolean normalizedIn, GLsizei strideIn);
666
667 GLenum type;
668 GLint size;
669 GLboolean normalized;
670 GLsizei stride;
671 };
672
673 std::vector<AttribData> mTestData;
674 std::map<GLenum, std::vector<GLfloat>> mExpectedData;
675 std::map<GLenum, std::vector<GLfloat>> mNormExpectedData;
676 };
677
AttribData(GLenum typeIn,GLint sizeIn,GLboolean normalizedIn,GLsizei strideIn)678 VertexAttributeCachingTest::AttribData::AttribData(GLenum typeIn,
679 GLint sizeIn,
680 GLboolean normalizedIn,
681 GLsizei strideIn)
682 : type(typeIn), size(sizeIn), normalized(normalizedIn), stride(strideIn)
683 {
684 }
685
686 // static
687 template <typename DestT>
GetExpectedData(const std::vector<GLubyte> & srcData,GLenum attribType,GLboolean normalized)688 std::vector<GLfloat> VertexAttributeCachingTest::GetExpectedData(
689 const std::vector<GLubyte> &srcData,
690 GLenum attribType,
691 GLboolean normalized)
692 {
693 std::vector<GLfloat> expectedData;
694
695 const DestT *typedSrcPtr = reinterpret_cast<const DestT *>(srcData.data());
696 size_t iterations = srcData.size() / TypeStride(attribType);
697
698 if (normalized)
699 {
700 for (size_t index = 0; index < iterations; ++index)
701 {
702 expectedData.push_back(Normalize(typedSrcPtr[index]));
703 }
704 }
705 else
706 {
707 for (size_t index = 0; index < iterations; ++index)
708 {
709 expectedData.push_back(static_cast<GLfloat>(typedSrcPtr[index]));
710 }
711 }
712
713 return expectedData;
714 }
715
SetUp()716 void VertexAttributeCachingTest::SetUp()
717 {
718 VertexAttributeTest::SetUp();
719
720 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
721
722 std::vector<GLubyte> srcData;
723 for (size_t count = 0; count < 4; ++count)
724 {
725 for (GLubyte i = 0; i < std::numeric_limits<GLubyte>::max(); ++i)
726 {
727 srcData.push_back(i);
728 }
729 }
730
731 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
732
733 GLint viewportSize[4];
734 glGetIntegerv(GL_VIEWPORT, viewportSize);
735
736 std::vector<GLenum> attribTypes;
737 attribTypes.push_back(GL_BYTE);
738 attribTypes.push_back(GL_UNSIGNED_BYTE);
739 attribTypes.push_back(GL_SHORT);
740 attribTypes.push_back(GL_UNSIGNED_SHORT);
741
742 if (getClientMajorVersion() >= 3)
743 {
744 attribTypes.push_back(GL_INT);
745 attribTypes.push_back(GL_UNSIGNED_INT);
746 }
747
748 const GLint maxSize = 4;
749 const GLsizei maxStride = 4;
750
751 for (GLenum attribType : attribTypes)
752 {
753 for (GLint attribSize = 1; attribSize <= maxSize; ++attribSize)
754 {
755 for (GLsizei stride = 1; stride <= maxStride; ++stride)
756 {
757 mTestData.push_back(AttribData(attribType, attribSize, GL_FALSE, stride));
758 if (attribType != GL_FLOAT)
759 {
760 mTestData.push_back(AttribData(attribType, attribSize, GL_TRUE, stride));
761 }
762 }
763 }
764 }
765
766 mExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_FALSE);
767 mExpectedData[GL_UNSIGNED_BYTE] = GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_FALSE);
768 mExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_FALSE);
769 mExpectedData[GL_UNSIGNED_SHORT] =
770 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_FALSE);
771 mExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_FALSE);
772 mExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_FALSE);
773
774 mNormExpectedData[GL_BYTE] = GetExpectedData<GLbyte>(srcData, GL_BYTE, GL_TRUE);
775 mNormExpectedData[GL_UNSIGNED_BYTE] =
776 GetExpectedData<GLubyte>(srcData, GL_UNSIGNED_BYTE, GL_TRUE);
777 mNormExpectedData[GL_SHORT] = GetExpectedData<GLshort>(srcData, GL_SHORT, GL_TRUE);
778 mNormExpectedData[GL_UNSIGNED_SHORT] =
779 GetExpectedData<GLushort>(srcData, GL_UNSIGNED_SHORT, GL_TRUE);
780 mNormExpectedData[GL_INT] = GetExpectedData<GLint>(srcData, GL_INT, GL_TRUE);
781 mNormExpectedData[GL_UNSIGNED_INT] = GetExpectedData<GLuint>(srcData, GL_UNSIGNED_INT, GL_TRUE);
782 }
783
784 // In D3D11, we must sometimes translate buffer data into static attribute caches. We also use a
785 // cache management scheme which garbage collects old attributes after we start using too much
786 // cache data. This test tries to make as many attribute caches from a single buffer as possible
787 // to stress-test the caching code.
TEST_P(VertexAttributeCachingTest,BufferMulticaching)788 TEST_P(VertexAttributeCachingTest, BufferMulticaching)
789 {
790 if (IsAMD() && IsDesktopOpenGL())
791 {
792 std::cout << "Test skipped on AMD OpenGL." << std::endl;
793 return;
794 }
795
796 initBasicProgram();
797
798 glEnableVertexAttribArray(mTestAttrib);
799 glEnableVertexAttribArray(mExpectedAttrib);
800
801 ASSERT_GL_NO_ERROR();
802
803 for (const auto &data : mTestData)
804 {
805 const auto &expected =
806 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
807
808 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
809 GLsizei stride = TypeStride(data.type) * baseStride;
810
811 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
812 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
813 glBindBuffer(GL_ARRAY_BUFFER, 0);
814 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
815 sizeof(GLfloat) * baseStride, expected.data());
816 drawQuad(mProgram, "position", 0.5f);
817 ASSERT_GL_NO_ERROR();
818 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
819 }
820 }
821
822 // With D3D11 dirty bits for VertxArray11, we can leave vertex state unchanged if there aren't any
823 // GL calls that affect it. This test targets leaving one vertex attribute unchanged between draw
824 // calls while changing another vertex attribute enough that it clears the static buffer cache
825 // after enough iterations. It validates the unchanged attributes don't get deleted incidentally.
TEST_P(VertexAttributeCachingTest,BufferMulticachingWithOneUnchangedAttrib)826 TEST_P(VertexAttributeCachingTest, BufferMulticachingWithOneUnchangedAttrib)
827 {
828 if (IsAMD() && IsDesktopOpenGL())
829 {
830 std::cout << "Test skipped on AMD OpenGL." << std::endl;
831 return;
832 }
833
834 initDoubleAttribProgram();
835
836 GLint testAttrib2Location = glGetAttribLocation(mProgram, "test2");
837 ASSERT_NE(-1, testAttrib2Location);
838 GLint expectedAttrib2Location = glGetAttribLocation(mProgram, "expected2");
839 ASSERT_NE(-1, expectedAttrib2Location);
840
841 glEnableVertexAttribArray(mTestAttrib);
842 glEnableVertexAttribArray(mExpectedAttrib);
843 glEnableVertexAttribArray(testAttrib2Location);
844 glEnableVertexAttribArray(expectedAttrib2Location);
845
846 ASSERT_GL_NO_ERROR();
847
848 // Use an attribute that we know must be converted. This is a bit sensitive.
849 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
850 glVertexAttribPointer(testAttrib2Location, 3, GL_UNSIGNED_SHORT, GL_FALSE, 6, nullptr);
851 glBindBuffer(GL_ARRAY_BUFFER, 0);
852 glVertexAttribPointer(expectedAttrib2Location, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3,
853 mExpectedData[GL_UNSIGNED_SHORT].data());
854
855 for (const auto &data : mTestData)
856 {
857 const auto &expected =
858 (data.normalized) ? mNormExpectedData[data.type] : mExpectedData[data.type];
859
860 GLsizei baseStride = static_cast<GLsizei>(data.size) * data.stride;
861 GLsizei stride = TypeStride(data.type) * baseStride;
862
863 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
864 glVertexAttribPointer(mTestAttrib, data.size, data.type, data.normalized, stride, nullptr);
865 glBindBuffer(GL_ARRAY_BUFFER, 0);
866 glVertexAttribPointer(mExpectedAttrib, data.size, GL_FLOAT, GL_FALSE,
867 sizeof(GLfloat) * baseStride, expected.data());
868 drawQuad(mProgram, "position", 0.5f);
869
870 ASSERT_GL_NO_ERROR();
871 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
872 }
873 }
874
875 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
876 // D3D11 Feature Level 9_3 uses different D3D formats for vertex attribs compared to Feature Levels 10_0+, so we should test them separately.
877 ANGLE_INSTANTIATE_TEST(VertexAttributeTest,
878 ES2_D3D9(),
879 ES2_D3D11(),
880 ES2_D3D11_FL9_3(),
881 ES2_OPENGL(),
882 ES3_OPENGL(),
883 ES2_OPENGLES(),
884 ES3_OPENGLES());
885
886 ANGLE_INSTANTIATE_TEST(VertexAttributeTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
887
888 ANGLE_INSTANTIATE_TEST(VertexAttributeCachingTest,
889 ES2_D3D9(),
890 ES2_D3D11(),
891 ES3_D3D11(),
892 ES3_OPENGL());
893
894 } // anonymous namespace
895