1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9
10 #include "util/random_utils.h"
11
12 #include <stdint.h>
13
14 using namespace angle;
15
16 class BufferDataTest : public ANGLETest
17 {
18 protected:
BufferDataTest()19 BufferDataTest()
20 {
21 setWindowWidth(16);
22 setWindowHeight(16);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27 setConfigDepthBits(24);
28
29 mBuffer = 0;
30 mProgram = 0;
31 mAttribLocation = -1;
32 }
33
testSetUp()34 void testSetUp() override
35 {
36 constexpr char kVS[] = R"(attribute vec4 position;
37 attribute float in_attrib;
38 varying float v_attrib;
39 void main()
40 {
41 v_attrib = in_attrib;
42 gl_Position = position;
43 })";
44
45 constexpr char kFS[] = R"(precision mediump float;
46 varying float v_attrib;
47 void main()
48 {
49 gl_FragColor = vec4(v_attrib, 0, 0, 1);
50 })";
51
52 glGenBuffers(1, &mBuffer);
53 ASSERT_NE(mBuffer, 0U);
54
55 mProgram = CompileProgram(kVS, kFS);
56 ASSERT_NE(mProgram, 0U);
57
58 mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");
59 ASSERT_NE(mAttribLocation, -1);
60
61 glClearColor(0, 0, 0, 0);
62 glClearDepthf(0.0);
63 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
64
65 glDisable(GL_DEPTH_TEST);
66
67 ASSERT_GL_NO_ERROR();
68 }
69
testTearDown()70 void testTearDown() override
71 {
72 glDeleteBuffers(1, &mBuffer);
73 glDeleteProgram(mProgram);
74 }
75
76 GLuint mBuffer;
77 GLuint mProgram;
78 GLint mAttribLocation;
79 };
80
81 // Disabled in debug because it's way too slow.
82 #if !defined(NDEBUG)
83 # define MAYBE_NULLData DISABLED_NULLData
84 #else
85 # define MAYBE_NULLData NULLData
86 #endif // !defined(NDEBUG)
87
TEST_P(BufferDataTest,MAYBE_NULLData)88 TEST_P(BufferDataTest, MAYBE_NULLData)
89 {
90 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
91 EXPECT_GL_NO_ERROR();
92
93 const int numIterations = 128;
94 for (int i = 0; i < numIterations; ++i)
95 {
96 GLsizei bufferSize = sizeof(GLfloat) * (i + 1);
97 glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW);
98 EXPECT_GL_NO_ERROR();
99
100 for (int j = 0; j < bufferSize; j++)
101 {
102 for (int k = 0; k < bufferSize - j; k++)
103 {
104 glBufferSubData(GL_ARRAY_BUFFER, k, j, nullptr);
105 ASSERT_GL_NO_ERROR();
106 }
107 }
108 }
109 }
110
TEST_P(BufferDataTest,ZeroNonNULLData)111 TEST_P(BufferDataTest, ZeroNonNULLData)
112 {
113 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
114 EXPECT_GL_NO_ERROR();
115
116 char *zeroData = new char[0];
117 glBufferData(GL_ARRAY_BUFFER, 0, zeroData, GL_STATIC_DRAW);
118 EXPECT_GL_NO_ERROR();
119
120 glBufferSubData(GL_ARRAY_BUFFER, 0, 0, zeroData);
121 EXPECT_GL_NO_ERROR();
122
123 delete[] zeroData;
124 }
125
TEST_P(BufferDataTest,NULLResolvedData)126 TEST_P(BufferDataTest, NULLResolvedData)
127 {
128 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
129 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_DYNAMIC_DRAW);
130
131 glUseProgram(mProgram);
132 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
133 glEnableVertexAttribArray(mAttribLocation);
134 glBindBuffer(GL_ARRAY_BUFFER, 0);
135
136 drawQuad(mProgram, "position", 0.5f);
137 }
138
139 // Internally in D3D, we promote dynamic data to static after many draw loops. This code tests
140 // path.
TEST_P(BufferDataTest,RepeatedDrawWithDynamic)141 TEST_P(BufferDataTest, RepeatedDrawWithDynamic)
142 {
143 std::vector<GLfloat> data;
144 for (int i = 0; i < 16; ++i)
145 {
146 data.push_back(static_cast<GLfloat>(i));
147 }
148
149 glUseProgram(mProgram);
150 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
151 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
152 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
153 glBindBuffer(GL_ARRAY_BUFFER, 0);
154 glEnableVertexAttribArray(mAttribLocation);
155
156 for (int drawCount = 0; drawCount < 40; ++drawCount)
157 {
158 drawQuad(mProgram, "position", 0.5f);
159 }
160
161 EXPECT_GL_NO_ERROR();
162 }
163
164 // Tests for a bug where vertex attribute translation was not being invalidated when switching to
165 // DYNAMIC
TEST_P(BufferDataTest,RepeatedDrawDynamicBug)166 TEST_P(BufferDataTest, RepeatedDrawDynamicBug)
167 {
168 // http://anglebug.com/2843: Seems to be an Intel driver bug.
169 ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsWindows());
170
171 glUseProgram(mProgram);
172
173 GLint positionLocation = glGetAttribLocation(mProgram, "position");
174 ASSERT_NE(-1, positionLocation);
175
176 auto quadVertices = GetQuadVertices();
177 for (angle::Vector3 &vertex : quadVertices)
178 {
179 vertex.x() *= 1.0f;
180 vertex.y() *= 1.0f;
181 vertex.z() = 0.0f;
182 }
183
184 // Set up quad vertices with DYNAMIC data
185 GLBuffer positionBuffer;
186 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
187 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * quadVertices.size() * 3, quadVertices.data(),
188 GL_DYNAMIC_DRAW);
189 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
190 glEnableVertexAttribArray(positionLocation);
191 glBindBuffer(GL_ARRAY_BUFFER, 0);
192 EXPECT_GL_NO_ERROR();
193
194 // Set up color data so red is drawn
195 std::vector<GLfloat> data(6, 1.0f);
196
197 // Set data to DYNAMIC
198 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
199 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
200 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
201 glEnableVertexAttribArray(mAttribLocation);
202 EXPECT_GL_NO_ERROR();
203
204 // Draw enough times to promote data to DIRECT mode
205 for (int i = 0; i < 20; i++)
206 {
207 glDrawArrays(GL_TRIANGLES, 0, 6);
208 }
209
210 // Verify red was drawn
211 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
212
213 // Set up color value so black is drawn
214 std::fill(data.begin(), data.end(), 0.0f);
215
216 // Update the data, changing back to DYNAMIC mode.
217 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
218
219 // This draw should produce a black quad
220 glDrawArrays(GL_TRIANGLES, 0, 6);
221 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
222 EXPECT_GL_NO_ERROR();
223 }
224
225 class IndexedBufferCopyTest : public ANGLETest
226 {
227 protected:
IndexedBufferCopyTest()228 IndexedBufferCopyTest()
229 {
230 setWindowWidth(16);
231 setWindowHeight(16);
232 setConfigRedBits(8);
233 setConfigGreenBits(8);
234 setConfigBlueBits(8);
235 setConfigAlphaBits(8);
236 setConfigDepthBits(24);
237 }
238
testSetUp()239 void testSetUp() override
240 {
241 constexpr char kVS[] = R"(attribute vec3 in_attrib;
242 varying vec3 v_attrib;
243 void main()
244 {
245 v_attrib = in_attrib;
246 gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
247 gl_PointSize = 100.0;
248 })";
249
250 constexpr char kFS[] = R"(precision mediump float;
251 varying vec3 v_attrib;
252 void main()
253 {
254 gl_FragColor = vec4(v_attrib, 1);
255 })";
256
257 glGenBuffers(2, mBuffers);
258 ASSERT_NE(mBuffers[0], 0U);
259 ASSERT_NE(mBuffers[1], 0U);
260
261 glGenBuffers(1, &mElementBuffer);
262 ASSERT_NE(mElementBuffer, 0U);
263
264 mProgram = CompileProgram(kVS, kFS);
265 ASSERT_NE(mProgram, 0U);
266
267 mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");
268 ASSERT_NE(mAttribLocation, -1);
269
270 glClearColor(0, 0, 0, 0);
271 glDisable(GL_DEPTH_TEST);
272 glClear(GL_COLOR_BUFFER_BIT);
273
274 ASSERT_GL_NO_ERROR();
275 }
276
testTearDown()277 void testTearDown() override
278 {
279 glDeleteBuffers(2, mBuffers);
280 glDeleteBuffers(1, &mElementBuffer);
281 glDeleteProgram(mProgram);
282 }
283
284 GLuint mBuffers[2];
285 GLuint mElementBuffer;
286 GLuint mProgram;
287 GLint mAttribLocation;
288 };
289
290 // The following test covers an ANGLE bug where our index ranges
291 // weren't updated from CopyBufferSubData calls
292 // https://code.google.com/p/angleproject/issues/detail?id=709
TEST_P(IndexedBufferCopyTest,IndexRangeBug)293 TEST_P(IndexedBufferCopyTest, IndexRangeBug)
294 {
295 // http://anglebug.com/4092
296 ANGLE_SKIP_TEST_IF(isSwiftshader());
297 // TODO(geofflang): Figure out why this fails on AMD OpenGL (http://anglebug.com/1291)
298 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
299
300 unsigned char vertexData[] = {255, 0, 0, 0, 0, 0};
301 unsigned int indexData[] = {0, 1};
302
303 glBindBuffer(GL_ARRAY_BUFFER, mBuffers[0]);
304 glBufferData(GL_ARRAY_BUFFER, sizeof(char) * 6, vertexData, GL_STATIC_DRAW);
305
306 glUseProgram(mProgram);
307 glVertexAttribPointer(mAttribLocation, 3, GL_UNSIGNED_BYTE, GL_TRUE, 3, nullptr);
308 glEnableVertexAttribArray(mAttribLocation);
309
310 ASSERT_GL_NO_ERROR();
311
312 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
313 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 1, indexData, GL_STATIC_DRAW);
314
315 glUseProgram(mProgram);
316
317 ASSERT_GL_NO_ERROR();
318
319 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
320
321 EXPECT_GL_NO_ERROR();
322 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
323
324 glBindBuffer(GL_COPY_READ_BUFFER, mBuffers[1]);
325 glBufferData(GL_COPY_READ_BUFFER, 4, &indexData[1], GL_STATIC_DRAW);
326
327 glBindBuffer(GL_COPY_WRITE_BUFFER, mElementBuffer);
328
329 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(int));
330
331 ASSERT_GL_NO_ERROR();
332
333 glClear(GL_COLOR_BUFFER_BIT);
334 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
335
336 unsigned char newData[] = {0, 255, 0};
337 glBufferSubData(GL_ARRAY_BUFFER, 3, 3, newData);
338
339 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
340
341 EXPECT_GL_NO_ERROR();
342 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
343 }
344
345 class BufferDataTestES3 : public BufferDataTest
346 {};
347
348 // The following test covers an ANGLE bug where the buffer storage
349 // is not resized by Buffer11::getLatestBufferStorage when needed.
350 // https://code.google.com/p/angleproject/issues/detail?id=897
TEST_P(BufferDataTestES3,BufferResizing)351 TEST_P(BufferDataTestES3, BufferResizing)
352 {
353 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
354 ASSERT_GL_NO_ERROR();
355
356 // Allocate a buffer with one byte
357 uint8_t singleByte[] = {0xaa};
358 glBufferData(GL_ARRAY_BUFFER, 1, singleByte, GL_STATIC_DRAW);
359
360 // Resize the buffer
361 // To trigger the bug, the buffer need to be big enough because some hardware copy buffers
362 // by chunks of pages instead of the minimum number of bytes needed.
363 const size_t numBytes = 4096 * 4;
364 glBufferData(GL_ARRAY_BUFFER, numBytes, nullptr, GL_STATIC_DRAW);
365
366 // Copy the original data to the buffer
367 uint8_t srcBytes[numBytes];
368 for (size_t i = 0; i < numBytes; ++i)
369 {
370 srcBytes[i] = static_cast<uint8_t>(i);
371 }
372
373 void *dest = glMapBufferRange(GL_ARRAY_BUFFER, 0, numBytes,
374 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
375
376 ASSERT_GL_NO_ERROR();
377
378 memcpy(dest, srcBytes, numBytes);
379 glUnmapBuffer(GL_ARRAY_BUFFER);
380
381 EXPECT_GL_NO_ERROR();
382
383 // Create a new buffer and copy the data to it
384 GLuint readBuffer;
385 glGenBuffers(1, &readBuffer);
386 glBindBuffer(GL_COPY_WRITE_BUFFER, readBuffer);
387 uint8_t zeros[numBytes];
388 for (size_t i = 0; i < numBytes; ++i)
389 {
390 zeros[i] = 0;
391 }
392 glBufferData(GL_COPY_WRITE_BUFFER, numBytes, zeros, GL_STATIC_DRAW);
393 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numBytes);
394
395 ASSERT_GL_NO_ERROR();
396
397 // Read back the data and compare it to the original
398 uint8_t *data = reinterpret_cast<uint8_t *>(
399 glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numBytes, GL_MAP_READ_BIT));
400
401 ASSERT_GL_NO_ERROR();
402
403 for (size_t i = 0; i < numBytes; ++i)
404 {
405 EXPECT_EQ(srcBytes[i], data[i]);
406 }
407 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
408
409 glDeleteBuffers(1, &readBuffer);
410
411 EXPECT_GL_NO_ERROR();
412 }
413
414 // Test to verify mapping a buffer after copying to it contains flushed/updated data
TEST_P(BufferDataTestES3,CopyBufferSubDataMapReadTest)415 TEST_P(BufferDataTestES3, CopyBufferSubDataMapReadTest)
416 {
417 const char simpleVertex[] = R"(attribute vec2 position;
418 attribute vec4 color;
419 varying vec4 vColor;
420 void main()
421 {
422 gl_Position = vec4(position, 0, 1);
423 vColor = color;
424 }
425 )";
426 const char simpleFragment[] = R"(precision mediump float;
427 varying vec4 vColor;
428 void main()
429 {
430 gl_FragColor = vColor;
431 }
432 )";
433
434 const uint32_t numComponents = 3;
435 const uint32_t width = 4;
436 const uint32_t height = 4;
437 const size_t numElements = width * height * numComponents;
438 std::vector<uint8_t> srcData(numElements);
439 std::vector<uint8_t> dstData(numElements);
440
441 for (uint8_t i = 0; i < srcData.size(); i++)
442 {
443 srcData[i] = 128;
444 }
445 for (uint8_t i = 0; i < dstData.size(); i++)
446 {
447 dstData[i] = 0;
448 }
449
450 GLBuffer srcBuffer;
451 GLBuffer dstBuffer;
452
453 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
454 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
455 ASSERT_GL_NO_ERROR();
456
457 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dstBuffer);
458 glBufferData(GL_PIXEL_UNPACK_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);
459 ASSERT_GL_NO_ERROR();
460
461 ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);
462 glUseProgram(program);
463
464 GLint colorLoc = glGetAttribLocation(program, "color");
465 ASSERT_NE(-1, colorLoc);
466
467 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
468 glVertexAttribPointer(colorLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
469 glEnableVertexAttribArray(colorLoc);
470
471 drawQuad(program, "position", 0.5f, 1.0f, true);
472 ASSERT_GL_NO_ERROR();
473
474 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, 0, numElements);
475
476 // With GL_MAP_READ_BIT, we expect the data to be flushed and updated to match srcData
477 uint8_t *data = reinterpret_cast<uint8_t *>(
478 glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_READ_BIT));
479 EXPECT_GL_NO_ERROR();
480 for (size_t i = 0; i < numElements; ++i)
481 {
482 EXPECT_EQ(srcData[i], data[i]);
483 }
484 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
485 EXPECT_GL_NO_ERROR();
486 }
487
488 // Test to verify mapping a buffer after copying to it contains expected data
489 // with GL_MAP_UNSYNCHRONIZED_BIT
TEST_P(BufferDataTestES3,MapBufferUnsynchronizedReadTest)490 TEST_P(BufferDataTestES3, MapBufferUnsynchronizedReadTest)
491 {
492 const char simpleVertex[] = R"(attribute vec2 position;
493 attribute vec4 color;
494 varying vec4 vColor;
495 void main()
496 {
497 gl_Position = vec4(position, 0, 1);
498 vColor = color;
499 }
500 )";
501 const char simpleFragment[] = R"(precision mediump float;
502 varying vec4 vColor;
503 void main()
504 {
505 gl_FragColor = vColor;
506 }
507 )";
508
509 const uint32_t numComponents = 3;
510 const uint32_t width = 4;
511 const uint32_t height = 4;
512 const size_t numElements = width * height * numComponents;
513 std::vector<uint8_t> srcData(numElements);
514 std::vector<uint8_t> dstData(numElements);
515
516 for (uint8_t i = 0; i < srcData.size(); i++)
517 {
518 srcData[i] = 128;
519 }
520 for (uint8_t i = 0; i < dstData.size(); i++)
521 {
522 dstData[i] = 0;
523 }
524
525 GLBuffer srcBuffer;
526 GLBuffer dstBuffer;
527
528 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
529 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
530 ASSERT_GL_NO_ERROR();
531
532 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dstBuffer);
533 glBufferData(GL_PIXEL_UNPACK_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);
534 ASSERT_GL_NO_ERROR();
535
536 ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);
537 glUseProgram(program);
538
539 GLint colorLoc = glGetAttribLocation(program, "color");
540 ASSERT_NE(-1, colorLoc);
541
542 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
543 glVertexAttribPointer(colorLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
544 glEnableVertexAttribArray(colorLoc);
545
546 drawQuad(program, "position", 0.5f, 1.0f, true);
547 ASSERT_GL_NO_ERROR();
548
549 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, 0, numElements);
550
551 // Synchronize.
552 glFinish();
553
554 // Map with GL_MAP_UNSYNCHRONIZED_BIT and overwrite buffers data with srcData
555 uint8_t *data = reinterpret_cast<uint8_t *>(glMapBufferRange(
556 GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
557 EXPECT_GL_NO_ERROR();
558 memcpy(data, srcData.data(), srcData.size());
559 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
560 EXPECT_GL_NO_ERROR();
561
562 // Map without GL_MAP_UNSYNCHRONIZED_BIT and read data. We expect it to be srcData
563 data = reinterpret_cast<uint8_t *>(
564 glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_READ_BIT));
565 EXPECT_GL_NO_ERROR();
566 for (size_t i = 0; i < numElements; ++i)
567 {
568 EXPECT_EQ(srcData[i], data[i]);
569 }
570 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
571 EXPECT_GL_NO_ERROR();
572 }
573
574 // Verify the functionality of glMapBufferRange()'s GL_MAP_UNSYNCHRONIZED_BIT
575 // NOTE: On Vulkan, if we ever use memory that's not `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`, then
576 // this could incorrectly pass.
TEST_P(BufferDataTestES3,MapBufferRangeUnsynchronizedBit)577 TEST_P(BufferDataTestES3, MapBufferRangeUnsynchronizedBit)
578 {
579 // We can currently only control the behavior of the Vulkan backend's synchronizing operation's
580 ANGLE_SKIP_TEST_IF(!IsVulkan());
581
582 const size_t numElements = 10;
583 std::vector<uint8_t> srcData(numElements);
584 std::vector<uint8_t> dstData(numElements);
585
586 for (uint8_t i = 0; i < srcData.size(); i++)
587 {
588 srcData[i] = i;
589 }
590 for (uint8_t i = 0; i < dstData.size(); i++)
591 {
592 dstData[i] = static_cast<uint8_t>(i + dstData.size());
593 }
594
595 GLBuffer srcBuffer;
596 GLBuffer dstBuffer;
597
598 glBindBuffer(GL_COPY_READ_BUFFER, srcBuffer);
599 ASSERT_GL_NO_ERROR();
600 glBindBuffer(GL_COPY_WRITE_BUFFER, dstBuffer);
601 ASSERT_GL_NO_ERROR();
602
603 glBufferData(GL_COPY_READ_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
604 ASSERT_GL_NO_ERROR();
605 glBufferData(GL_COPY_WRITE_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);
606 ASSERT_GL_NO_ERROR();
607
608 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numElements);
609
610 // With GL_MAP_UNSYNCHRONIZED_BIT, we expect the data to be stale and match dstData
611 // NOTE: We are specifying GL_MAP_WRITE_BIT so we can use GL_MAP_UNSYNCHRONIZED_BIT. This is
612 // venturing into undefined behavior, since we are actually planning on reading from this
613 // pointer.
614 auto *data = reinterpret_cast<uint8_t *>(glMapBufferRange(
615 GL_COPY_WRITE_BUFFER, 0, numElements, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
616 EXPECT_GL_NO_ERROR();
617 for (size_t i = 0; i < numElements; ++i)
618 {
619 EXPECT_EQ(dstData[i], data[i]);
620 }
621 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
622 EXPECT_GL_NO_ERROR();
623
624 // Without GL_MAP_UNSYNCHRONIZED_BIT, we expect the data to be copied and match srcData
625 data = reinterpret_cast<uint8_t *>(
626 glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numElements, GL_MAP_READ_BIT));
627 EXPECT_GL_NO_ERROR();
628 for (size_t i = 0; i < numElements; ++i)
629 {
630 EXPECT_EQ(srcData[i], data[i]);
631 }
632 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
633 EXPECT_GL_NO_ERROR();
634 }
635
636 // Verify OES_mapbuffer is present if EXT_map_buffer_range is.
TEST_P(BufferDataTest,ExtensionDependency)637 TEST_P(BufferDataTest, ExtensionDependency)
638 {
639 if (IsGLExtensionEnabled("GL_EXT_map_buffer_range"))
640 {
641 ASSERT_TRUE(IsGLExtensionEnabled("GL_OES_mapbuffer"));
642 }
643 }
644
645 // Test mapping with the OES extension.
TEST_P(BufferDataTest,MapBufferOES)646 TEST_P(BufferDataTest, MapBufferOES)
647 {
648 if (!IsGLExtensionEnabled("GL_EXT_map_buffer_range"))
649 {
650 // Needed for test validation.
651 return;
652 }
653
654 std::vector<uint8_t> data(1024);
655 FillVectorWithRandomUBytes(&data);
656
657 GLBuffer buffer;
658 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
659 glBufferData(GL_ARRAY_BUFFER, data.size(), nullptr, GL_STATIC_DRAW);
660
661 // Validate that other map flags don't work.
662 void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);
663 EXPECT_EQ(nullptr, badMapPtr);
664 EXPECT_GL_ERROR(GL_INVALID_ENUM);
665
666 // Map and write.
667 void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
668 ASSERT_NE(nullptr, mapPtr);
669 ASSERT_GL_NO_ERROR();
670 memcpy(mapPtr, data.data(), data.size());
671 glUnmapBufferOES(GL_ARRAY_BUFFER);
672
673 // Validate data with EXT_map_buffer_range
674 void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);
675 ASSERT_NE(nullptr, readMapPtr);
676 ASSERT_GL_NO_ERROR();
677 std::vector<uint8_t> actualData(data.size());
678 memcpy(actualData.data(), readMapPtr, data.size());
679 glUnmapBufferOES(GL_ARRAY_BUFFER);
680
681 EXPECT_EQ(data, actualData);
682 }
683
684 // Tests a bug where copying buffer data immediately after creation hit a nullptr in D3D11.
TEST_P(BufferDataTestES3,NoBufferInitDataCopyBug)685 TEST_P(BufferDataTestES3, NoBufferInitDataCopyBug)
686 {
687 constexpr GLsizei size = 64;
688
689 GLBuffer sourceBuffer;
690 glBindBuffer(GL_COPY_READ_BUFFER, sourceBuffer);
691 glBufferData(GL_COPY_READ_BUFFER, size, nullptr, GL_STATIC_DRAW);
692
693 GLBuffer destBuffer;
694 glBindBuffer(GL_ARRAY_BUFFER, destBuffer);
695 glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW);
696
697 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, 0, size);
698 ASSERT_GL_NO_ERROR();
699 }
700
701 // Ensures that calling glBufferData on a mapped buffer results in an unmapped buffer
TEST_P(BufferDataTestES3,BufferDataUnmap)702 TEST_P(BufferDataTestES3, BufferDataUnmap)
703 {
704 // Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to
705 // BufferData happens on a mapped buffer:
706 //
707 // If any portion of the buffer object is mapped in the current context or
708 // any context current to another thread, it is as though UnmapBuffer
709 // (see section 2.10.3) is executed in each such context prior to deleting
710 // the existing data store.
711 //
712
713 std::vector<uint8_t> data1(16);
714 std::vector<uint8_t> data2(16);
715
716 GLBuffer dataBuffer;
717 glBindBuffer(GL_ARRAY_BUFFER, dataBuffer);
718 glBufferData(GL_ARRAY_BUFFER, data1.size(), data1.data(), GL_STATIC_DRAW);
719
720 // Map the buffer once
721 void *mappedBuffer =
722 glMapBufferRange(GL_ARRAY_BUFFER, 0, data1.size(),
723 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT |
724 GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
725
726 // Then repopulate the buffer. This should cause the buffer to become unmapped.
727 glBufferData(GL_ARRAY_BUFFER, data2.size(), data2.data(), GL_STATIC_DRAW);
728 ASSERT_GL_NO_ERROR();
729
730 // Try to unmap the buffer, this should fail
731 bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
732 ASSERT_EQ(result, false);
733 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
734
735 // Try to map the buffer again, which should succeed
736 mappedBuffer = glMapBufferRange(GL_ARRAY_BUFFER, 0, data2.size(),
737 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT |
738 GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
739 ASSERT_GL_NO_ERROR();
740 }
741
742 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
743 // tests should be run against.
744 ANGLE_INSTANTIATE_TEST_ES2(BufferDataTest);
745 ANGLE_INSTANTIATE_TEST_ES3(BufferDataTestES3);
746 ANGLE_INSTANTIATE_TEST_ES3(IndexedBufferCopyTest);
747
748 #ifdef _WIN64
749
750 // Test a bug where an integer overflow bug could trigger a crash in D3D.
751 // The test uses 8 buffers with a size just under 0x2000000 to overflow max uint
752 // (with the internal D3D rounding to 16-byte values) and trigger the bug.
753 // Only handle this bug on 64-bit Windows for now. Harder to repro on 32-bit.
754 class BufferDataOverflowTest : public ANGLETest
755 {
756 protected:
BufferDataOverflowTest()757 BufferDataOverflowTest() {}
758 };
759
760 // See description above.
TEST_P(BufferDataOverflowTest,VertexBufferIntegerOverflow)761 TEST_P(BufferDataOverflowTest, VertexBufferIntegerOverflow)
762 {
763 // http://anglebug.com/3786: flaky timeout on Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)
764 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsD3D11());
765 // http://anglebug.com/4092
766 ANGLE_SKIP_TEST_IF(IsWindows() && (IsVulkan() || IsOpenGL()));
767
768 // These values are special, to trigger the rounding bug.
769 unsigned int numItems = 0x7FFFFFE;
770 constexpr GLsizei bufferCnt = 8;
771
772 std::vector<GLBuffer> buffers(bufferCnt);
773
774 std::stringstream vertexShaderStr;
775
776 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
777 {
778 vertexShaderStr << "attribute float attrib" << bufferIndex << ";\n";
779 }
780
781 vertexShaderStr << "attribute vec2 position;\n"
782 "varying float v_attrib;\n"
783 "void main() {\n"
784 " gl_Position = vec4(position, 0, 1);\n"
785 " v_attrib = 0.0;\n";
786
787 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
788 {
789 vertexShaderStr << "v_attrib += attrib" << bufferIndex << ";\n";
790 }
791
792 vertexShaderStr << "}";
793
794 constexpr char kFS[] =
795 "varying highp float v_attrib;\n"
796 "void main() {\n"
797 " gl_FragColor = vec4(v_attrib, 0, 0, 1);\n"
798 "}";
799
800 ANGLE_GL_PROGRAM(program, vertexShaderStr.str().c_str(), kFS);
801 glUseProgram(program.get());
802
803 std::vector<GLfloat> data(numItems, 1.0f);
804
805 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
806 {
807 glBindBuffer(GL_ARRAY_BUFFER, buffers[bufferIndex].get());
808 glBufferData(GL_ARRAY_BUFFER, numItems * sizeof(float), &data[0], GL_DYNAMIC_DRAW);
809
810 std::stringstream attribNameStr;
811 attribNameStr << "attrib" << bufferIndex;
812
813 GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());
814 ASSERT_NE(-1, attribLocation);
815
816 glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
817 glEnableVertexAttribArray(attribLocation);
818 }
819
820 GLint positionLocation = glGetAttribLocation(program.get(), "position");
821 ASSERT_NE(-1, positionLocation);
822 glDisableVertexAttribArray(positionLocation);
823 glVertexAttrib2f(positionLocation, 1.0f, 1.0f);
824
825 EXPECT_GL_NO_ERROR();
826 glDrawArrays(GL_TRIANGLES, 0, numItems);
827 EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);
828
829 // Test that a small draw still works.
830 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
831 {
832 std::stringstream attribNameStr;
833 attribNameStr << "attrib" << bufferIndex;
834 GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());
835 ASSERT_NE(-1, attribLocation);
836 glDisableVertexAttribArray(attribLocation);
837 }
838
839 glDrawArrays(GL_TRIANGLES, 0, 3);
840 EXPECT_GL_ERROR(GL_NO_ERROR);
841 }
842
843 // Tests a security bug in our CopyBufferSubData validation (integer overflow).
TEST_P(BufferDataOverflowTest,CopySubDataValidation)844 TEST_P(BufferDataOverflowTest, CopySubDataValidation)
845 {
846 GLBuffer readBuffer, writeBuffer;
847
848 glBindBuffer(GL_COPY_READ_BUFFER, readBuffer.get());
849 glBindBuffer(GL_COPY_WRITE_BUFFER, writeBuffer.get());
850
851 constexpr int bufSize = 100;
852
853 glBufferData(GL_COPY_READ_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);
854 glBufferData(GL_COPY_WRITE_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);
855
856 GLintptr big = std::numeric_limits<GLintptr>::max() - bufSize + 90;
857
858 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, big, 0, 50);
859 EXPECT_GL_ERROR(GL_INVALID_VALUE);
860
861 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, big, 50);
862 EXPECT_GL_ERROR(GL_INVALID_VALUE);
863 }
864
865 ANGLE_INSTANTIATE_TEST_ES3(BufferDataOverflowTest);
866
867 #endif // _WIN64
868