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 // If glBufferData was not called yet the capturing must not try to
82 // read the data. http://anglebug.com/6093
TEST_P(BufferDataTest,Uninitialized)83 TEST_P(BufferDataTest, Uninitialized)
84 {
85 // Trigger frame capture to try capturing the
86 // generated but uninitialized buffer
87 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
88 swapBuffers();
89 }
90
TEST_P(BufferDataTest,ZeroNonNULLData)91 TEST_P(BufferDataTest, ZeroNonNULLData)
92 {
93 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
94 EXPECT_GL_NO_ERROR();
95
96 char *zeroData = new char[0];
97 glBufferData(GL_ARRAY_BUFFER, 0, zeroData, GL_STATIC_DRAW);
98 EXPECT_GL_NO_ERROR();
99
100 glBufferSubData(GL_ARRAY_BUFFER, 0, 0, zeroData);
101 EXPECT_GL_NO_ERROR();
102
103 delete[] zeroData;
104 }
105
TEST_P(BufferDataTest,NULLResolvedData)106 TEST_P(BufferDataTest, NULLResolvedData)
107 {
108 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
109 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_DYNAMIC_DRAW);
110
111 glUseProgram(mProgram);
112 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
113 glEnableVertexAttribArray(mAttribLocation);
114 glBindBuffer(GL_ARRAY_BUFFER, 0);
115
116 drawQuad(mProgram, "position", 0.5f);
117 }
118
119 // Internally in D3D, we promote dynamic data to static after many draw loops. This code tests
120 // path.
TEST_P(BufferDataTest,RepeatedDrawWithDynamic)121 TEST_P(BufferDataTest, RepeatedDrawWithDynamic)
122 {
123 std::vector<GLfloat> data;
124 for (int i = 0; i < 16; ++i)
125 {
126 data.push_back(static_cast<GLfloat>(i));
127 }
128
129 glUseProgram(mProgram);
130 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
131 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
132 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
133 glBindBuffer(GL_ARRAY_BUFFER, 0);
134 glEnableVertexAttribArray(mAttribLocation);
135
136 for (int drawCount = 0; drawCount < 40; ++drawCount)
137 {
138 drawQuad(mProgram, "position", 0.5f);
139 }
140
141 EXPECT_GL_NO_ERROR();
142 }
143
144 // Tests for a bug where vertex attribute translation was not being invalidated when switching to
145 // DYNAMIC
TEST_P(BufferDataTest,RepeatedDrawDynamicBug)146 TEST_P(BufferDataTest, RepeatedDrawDynamicBug)
147 {
148 // http://anglebug.com/2843: Seems to be an Intel driver bug.
149 ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsWindows());
150
151 glUseProgram(mProgram);
152
153 GLint positionLocation = glGetAttribLocation(mProgram, "position");
154 ASSERT_NE(-1, positionLocation);
155
156 auto quadVertices = GetQuadVertices();
157 for (angle::Vector3 &vertex : quadVertices)
158 {
159 vertex.x() *= 1.0f;
160 vertex.y() *= 1.0f;
161 vertex.z() = 0.0f;
162 }
163
164 // Set up quad vertices with DYNAMIC data
165 GLBuffer positionBuffer;
166 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
167 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * quadVertices.size() * 3, quadVertices.data(),
168 GL_DYNAMIC_DRAW);
169 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
170 glEnableVertexAttribArray(positionLocation);
171 glBindBuffer(GL_ARRAY_BUFFER, 0);
172 EXPECT_GL_NO_ERROR();
173
174 // Set up color data so red is drawn
175 std::vector<GLfloat> data(6, 1.0f);
176
177 // Set data to DYNAMIC
178 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
179 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
180 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
181 glEnableVertexAttribArray(mAttribLocation);
182 EXPECT_GL_NO_ERROR();
183
184 // Draw enough times to promote data to DIRECT mode
185 for (int i = 0; i < 20; i++)
186 {
187 glDrawArrays(GL_TRIANGLES, 0, 6);
188 }
189
190 // Verify red was drawn
191 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
192
193 // Set up color value so black is drawn
194 std::fill(data.begin(), data.end(), 0.0f);
195
196 // Update the data, changing back to DYNAMIC mode.
197 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
198
199 // This draw should produce a black quad
200 glDrawArrays(GL_TRIANGLES, 0, 6);
201 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
202 EXPECT_GL_NO_ERROR();
203 }
204
205 class IndexedBufferCopyTest : public ANGLETest
206 {
207 protected:
IndexedBufferCopyTest()208 IndexedBufferCopyTest()
209 {
210 setWindowWidth(16);
211 setWindowHeight(16);
212 setConfigRedBits(8);
213 setConfigGreenBits(8);
214 setConfigBlueBits(8);
215 setConfigAlphaBits(8);
216 setConfigDepthBits(24);
217 }
218
testSetUp()219 void testSetUp() override
220 {
221 constexpr char kVS[] = R"(attribute vec3 in_attrib;
222 varying vec3 v_attrib;
223 void main()
224 {
225 v_attrib = in_attrib;
226 gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
227 gl_PointSize = 100.0;
228 })";
229
230 constexpr char kFS[] = R"(precision mediump float;
231 varying vec3 v_attrib;
232 void main()
233 {
234 gl_FragColor = vec4(v_attrib, 1);
235 })";
236
237 glGenBuffers(2, mBuffers);
238 ASSERT_NE(mBuffers[0], 0U);
239 ASSERT_NE(mBuffers[1], 0U);
240
241 glGenBuffers(1, &mElementBuffer);
242 ASSERT_NE(mElementBuffer, 0U);
243
244 mProgram = CompileProgram(kVS, kFS);
245 ASSERT_NE(mProgram, 0U);
246
247 mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");
248 ASSERT_NE(mAttribLocation, -1);
249
250 glClearColor(0, 0, 0, 0);
251 glDisable(GL_DEPTH_TEST);
252 glClear(GL_COLOR_BUFFER_BIT);
253
254 ASSERT_GL_NO_ERROR();
255 }
256
testTearDown()257 void testTearDown() override
258 {
259 glDeleteBuffers(2, mBuffers);
260 glDeleteBuffers(1, &mElementBuffer);
261 glDeleteProgram(mProgram);
262 }
263
264 GLuint mBuffers[2];
265 GLuint mElementBuffer;
266 GLuint mProgram;
267 GLint mAttribLocation;
268 };
269
270 // The following test covers an ANGLE bug where our index ranges
271 // weren't updated from CopyBufferSubData calls
272 // https://code.google.com/p/angleproject/issues/detail?id=709
TEST_P(IndexedBufferCopyTest,IndexRangeBug)273 TEST_P(IndexedBufferCopyTest, IndexRangeBug)
274 {
275 // http://anglebug.com/4092
276 ANGLE_SKIP_TEST_IF(isSwiftshader());
277 // TODO(geofflang): Figure out why this fails on AMD OpenGL (http://anglebug.com/1291)
278 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
279
280 unsigned char vertexData[] = {255, 0, 0, 0, 0, 0};
281 unsigned int indexData[] = {0, 1};
282
283 glBindBuffer(GL_ARRAY_BUFFER, mBuffers[0]);
284 glBufferData(GL_ARRAY_BUFFER, sizeof(char) * 6, vertexData, GL_STATIC_DRAW);
285
286 glUseProgram(mProgram);
287 glVertexAttribPointer(mAttribLocation, 3, GL_UNSIGNED_BYTE, GL_TRUE, 3, nullptr);
288 glEnableVertexAttribArray(mAttribLocation);
289
290 ASSERT_GL_NO_ERROR();
291
292 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
293 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 1, indexData, GL_STATIC_DRAW);
294
295 glUseProgram(mProgram);
296
297 ASSERT_GL_NO_ERROR();
298
299 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
300
301 EXPECT_GL_NO_ERROR();
302 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
303
304 glBindBuffer(GL_COPY_READ_BUFFER, mBuffers[1]);
305 glBufferData(GL_COPY_READ_BUFFER, 4, &indexData[1], GL_STATIC_DRAW);
306
307 glBindBuffer(GL_COPY_WRITE_BUFFER, mElementBuffer);
308
309 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(int));
310
311 ASSERT_GL_NO_ERROR();
312
313 glClear(GL_COLOR_BUFFER_BIT);
314 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
315
316 unsigned char newData[] = {0, 255, 0};
317 glBufferSubData(GL_ARRAY_BUFFER, 3, 3, newData);
318
319 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
320
321 EXPECT_GL_NO_ERROR();
322 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
323 }
324
325 class BufferDataTestES3 : public BufferDataTest
326 {};
327
328 // The following test covers an ANGLE bug where the buffer storage
329 // is not resized by Buffer11::getLatestBufferStorage when needed.
330 // https://code.google.com/p/angleproject/issues/detail?id=897
TEST_P(BufferDataTestES3,BufferResizing)331 TEST_P(BufferDataTestES3, BufferResizing)
332 {
333 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
334 ASSERT_GL_NO_ERROR();
335
336 // Allocate a buffer with one byte
337 uint8_t singleByte[] = {0xaa};
338 glBufferData(GL_ARRAY_BUFFER, 1, singleByte, GL_STATIC_DRAW);
339
340 // Resize the buffer
341 // To trigger the bug, the buffer need to be big enough because some hardware copy buffers
342 // by chunks of pages instead of the minimum number of bytes needed.
343 const size_t numBytes = 4096 * 4;
344 glBufferData(GL_ARRAY_BUFFER, numBytes, nullptr, GL_STATIC_DRAW);
345
346 // Copy the original data to the buffer
347 uint8_t srcBytes[numBytes];
348 for (size_t i = 0; i < numBytes; ++i)
349 {
350 srcBytes[i] = static_cast<uint8_t>(i);
351 }
352
353 void *dest = glMapBufferRange(GL_ARRAY_BUFFER, 0, numBytes,
354 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
355
356 ASSERT_GL_NO_ERROR();
357
358 memcpy(dest, srcBytes, numBytes);
359 glUnmapBuffer(GL_ARRAY_BUFFER);
360
361 EXPECT_GL_NO_ERROR();
362
363 // Create a new buffer and copy the data to it
364 GLuint readBuffer;
365 glGenBuffers(1, &readBuffer);
366 glBindBuffer(GL_COPY_WRITE_BUFFER, readBuffer);
367 uint8_t zeros[numBytes];
368 for (size_t i = 0; i < numBytes; ++i)
369 {
370 zeros[i] = 0;
371 }
372 glBufferData(GL_COPY_WRITE_BUFFER, numBytes, zeros, GL_STATIC_DRAW);
373 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numBytes);
374
375 ASSERT_GL_NO_ERROR();
376
377 // Read back the data and compare it to the original
378 uint8_t *data = reinterpret_cast<uint8_t *>(
379 glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numBytes, GL_MAP_READ_BIT));
380
381 ASSERT_GL_NO_ERROR();
382
383 for (size_t i = 0; i < numBytes; ++i)
384 {
385 EXPECT_EQ(srcBytes[i], data[i]);
386 }
387 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
388
389 glDeleteBuffers(1, &readBuffer);
390
391 EXPECT_GL_NO_ERROR();
392 }
393
394 // Test to verify mapping a buffer after copying to it contains flushed/updated data
TEST_P(BufferDataTestES3,CopyBufferSubDataMapReadTest)395 TEST_P(BufferDataTestES3, CopyBufferSubDataMapReadTest)
396 {
397 const char simpleVertex[] = R"(attribute vec2 position;
398 attribute vec4 color;
399 varying vec4 vColor;
400 void main()
401 {
402 gl_Position = vec4(position, 0, 1);
403 vColor = color;
404 }
405 )";
406 const char simpleFragment[] = R"(precision mediump float;
407 varying vec4 vColor;
408 void main()
409 {
410 gl_FragColor = vColor;
411 }
412 )";
413
414 const uint32_t numComponents = 3;
415 const uint32_t width = 4;
416 const uint32_t height = 4;
417 const size_t numElements = width * height * numComponents;
418 std::vector<uint8_t> srcData(numElements);
419 std::vector<uint8_t> dstData(numElements);
420
421 for (uint8_t i = 0; i < srcData.size(); i++)
422 {
423 srcData[i] = 128;
424 }
425 for (uint8_t i = 0; i < dstData.size(); i++)
426 {
427 dstData[i] = 0;
428 }
429
430 GLBuffer srcBuffer;
431 GLBuffer dstBuffer;
432
433 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
434 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
435 ASSERT_GL_NO_ERROR();
436
437 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dstBuffer);
438 glBufferData(GL_PIXEL_UNPACK_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);
439 ASSERT_GL_NO_ERROR();
440
441 ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);
442 glUseProgram(program);
443
444 GLint colorLoc = glGetAttribLocation(program, "color");
445 ASSERT_NE(-1, colorLoc);
446
447 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
448 glVertexAttribPointer(colorLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
449 glEnableVertexAttribArray(colorLoc);
450
451 drawQuad(program, "position", 0.5f, 1.0f, true);
452 ASSERT_GL_NO_ERROR();
453
454 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, 0, numElements);
455
456 // With GL_MAP_READ_BIT, we expect the data to be flushed and updated to match srcData
457 uint8_t *data = reinterpret_cast<uint8_t *>(
458 glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_READ_BIT));
459 EXPECT_GL_NO_ERROR();
460 for (size_t i = 0; i < numElements; ++i)
461 {
462 EXPECT_EQ(srcData[i], data[i]);
463 }
464 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
465 EXPECT_GL_NO_ERROR();
466 }
467
468 // Test to verify mapping a buffer after copying to it contains expected data
469 // with GL_MAP_UNSYNCHRONIZED_BIT
TEST_P(BufferDataTestES3,MapBufferUnsynchronizedReadTest)470 TEST_P(BufferDataTestES3, MapBufferUnsynchronizedReadTest)
471 {
472 const char simpleVertex[] = R"(attribute vec2 position;
473 attribute vec4 color;
474 varying vec4 vColor;
475 void main()
476 {
477 gl_Position = vec4(position, 0, 1);
478 vColor = color;
479 }
480 )";
481 const char simpleFragment[] = R"(precision mediump float;
482 varying vec4 vColor;
483 void main()
484 {
485 gl_FragColor = vColor;
486 }
487 )";
488
489 const uint32_t numComponents = 3;
490 const uint32_t width = 4;
491 const uint32_t height = 4;
492 const size_t numElements = width * height * numComponents;
493 std::vector<uint8_t> srcData(numElements);
494 std::vector<uint8_t> dstData(numElements);
495
496 for (uint8_t i = 0; i < srcData.size(); i++)
497 {
498 srcData[i] = 128;
499 }
500 for (uint8_t i = 0; i < dstData.size(); i++)
501 {
502 dstData[i] = 0;
503 }
504
505 GLBuffer srcBuffer;
506 GLBuffer dstBuffer;
507
508 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
509 glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
510 ASSERT_GL_NO_ERROR();
511
512 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dstBuffer);
513 glBufferData(GL_PIXEL_UNPACK_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);
514 ASSERT_GL_NO_ERROR();
515
516 ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);
517 glUseProgram(program);
518
519 GLint colorLoc = glGetAttribLocation(program, "color");
520 ASSERT_NE(-1, colorLoc);
521
522 glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);
523 glVertexAttribPointer(colorLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
524 glEnableVertexAttribArray(colorLoc);
525
526 drawQuad(program, "position", 0.5f, 1.0f, true);
527 ASSERT_GL_NO_ERROR();
528
529 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, 0, numElements);
530
531 // Synchronize.
532 glFinish();
533
534 // Map with GL_MAP_UNSYNCHRONIZED_BIT and overwrite buffers data with srcData
535 uint8_t *data = reinterpret_cast<uint8_t *>(glMapBufferRange(
536 GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
537 EXPECT_GL_NO_ERROR();
538 memcpy(data, srcData.data(), srcData.size());
539 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
540 EXPECT_GL_NO_ERROR();
541
542 // Map without GL_MAP_UNSYNCHRONIZED_BIT and read data. We expect it to be srcData
543 data = reinterpret_cast<uint8_t *>(
544 glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_READ_BIT));
545 EXPECT_GL_NO_ERROR();
546 for (size_t i = 0; i < numElements; ++i)
547 {
548 EXPECT_EQ(srcData[i], data[i]);
549 }
550 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
551 EXPECT_GL_NO_ERROR();
552 }
553
554 // Verify the functionality of glMapBufferRange()'s GL_MAP_UNSYNCHRONIZED_BIT
555 // NOTE: On Vulkan, if we ever use memory that's not `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`, then
556 // this could incorrectly pass.
TEST_P(BufferDataTestES3,MapBufferRangeUnsynchronizedBit)557 TEST_P(BufferDataTestES3, MapBufferRangeUnsynchronizedBit)
558 {
559 // We can currently only control the behavior of the Vulkan backend's synchronizing operation's
560 ANGLE_SKIP_TEST_IF(!IsVulkan());
561
562 const size_t numElements = 10;
563 std::vector<uint8_t> srcData(numElements);
564 std::vector<uint8_t> dstData(numElements);
565
566 for (uint8_t i = 0; i < srcData.size(); i++)
567 {
568 srcData[i] = i;
569 }
570 for (uint8_t i = 0; i < dstData.size(); i++)
571 {
572 dstData[i] = static_cast<uint8_t>(i + dstData.size());
573 }
574
575 GLBuffer srcBuffer;
576 GLBuffer dstBuffer;
577
578 glBindBuffer(GL_COPY_READ_BUFFER, srcBuffer);
579 ASSERT_GL_NO_ERROR();
580 glBindBuffer(GL_COPY_WRITE_BUFFER, dstBuffer);
581 ASSERT_GL_NO_ERROR();
582
583 glBufferData(GL_COPY_READ_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);
584 ASSERT_GL_NO_ERROR();
585 glBufferData(GL_COPY_WRITE_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);
586 ASSERT_GL_NO_ERROR();
587
588 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numElements);
589
590 // With GL_MAP_UNSYNCHRONIZED_BIT, we expect the data to be stale and match dstData
591 // NOTE: We are specifying GL_MAP_WRITE_BIT so we can use GL_MAP_UNSYNCHRONIZED_BIT. This is
592 // venturing into undefined behavior, since we are actually planning on reading from this
593 // pointer.
594 auto *data = reinterpret_cast<uint8_t *>(glMapBufferRange(
595 GL_COPY_WRITE_BUFFER, 0, numElements, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
596 EXPECT_GL_NO_ERROR();
597 for (size_t i = 0; i < numElements; ++i)
598 {
599 // Allow for the possibility that data matches either "dstData" or "srcData"
600 if (dstData[i] != data[i])
601 {
602 EXPECT_EQ(srcData[i], data[i]);
603 }
604 }
605 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
606 EXPECT_GL_NO_ERROR();
607
608 // Without GL_MAP_UNSYNCHRONIZED_BIT, we expect the data to be copied and match srcData
609 data = reinterpret_cast<uint8_t *>(
610 glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numElements, GL_MAP_READ_BIT));
611 EXPECT_GL_NO_ERROR();
612 for (size_t i = 0; i < numElements; ++i)
613 {
614 EXPECT_EQ(srcData[i], data[i]);
615 }
616 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
617 EXPECT_GL_NO_ERROR();
618 }
619
620 // Verify OES_mapbuffer is present if EXT_map_buffer_range is.
TEST_P(BufferDataTest,ExtensionDependency)621 TEST_P(BufferDataTest, ExtensionDependency)
622 {
623 if (IsGLExtensionEnabled("GL_EXT_map_buffer_range"))
624 {
625 ASSERT_TRUE(IsGLExtensionEnabled("GL_OES_mapbuffer"));
626 }
627 }
628
629 // Test mapping with the OES extension.
TEST_P(BufferDataTest,MapBufferOES)630 TEST_P(BufferDataTest, MapBufferOES)
631 {
632 if (!IsGLExtensionEnabled("GL_EXT_map_buffer_range"))
633 {
634 // Needed for test validation.
635 return;
636 }
637
638 std::vector<uint8_t> data(1024);
639 FillVectorWithRandomUBytes(&data);
640
641 GLBuffer buffer;
642 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
643 glBufferData(GL_ARRAY_BUFFER, data.size(), nullptr, GL_STATIC_DRAW);
644
645 // Validate that other map flags don't work.
646 void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);
647 EXPECT_EQ(nullptr, badMapPtr);
648 EXPECT_GL_ERROR(GL_INVALID_ENUM);
649
650 // Map and write.
651 void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
652 ASSERT_NE(nullptr, mapPtr);
653 ASSERT_GL_NO_ERROR();
654 memcpy(mapPtr, data.data(), data.size());
655 glUnmapBufferOES(GL_ARRAY_BUFFER);
656
657 // Validate data with EXT_map_buffer_range
658 void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);
659 ASSERT_NE(nullptr, readMapPtr);
660 ASSERT_GL_NO_ERROR();
661 std::vector<uint8_t> actualData(data.size());
662 memcpy(actualData.data(), readMapPtr, data.size());
663 glUnmapBufferOES(GL_ARRAY_BUFFER);
664
665 EXPECT_EQ(data, actualData);
666 }
667
668 // Test to verify mapping a dynamic buffer with GL_MAP_UNSYNCHRONIZED_BIT to modify a portion
669 // won't affect draw calls using other portions.
TEST_P(BufferDataTest,MapDynamicBufferUnsynchronizedEXTTest)670 TEST_P(BufferDataTest, MapDynamicBufferUnsynchronizedEXTTest)
671 {
672 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_map_buffer_range"));
673
674 const char simpleVertex[] = R"(attribute vec2 position;
675 attribute vec4 color;
676 varying vec4 vColor;
677 void main()
678 {
679 gl_Position = vec4(position, 0, 1);
680 vColor = color;
681 }
682 )";
683 const char simpleFragment[] = R"(precision mediump float;
684 varying vec4 vColor;
685 void main()
686 {
687 gl_FragColor = vColor;
688 }
689 )";
690
691 constexpr int kNumVertices = 6;
692
693 std::vector<GLubyte> color(8 * kNumVertices);
694 for (int i = 0; i < kNumVertices; ++i)
695 {
696 color[4 * i] = 255;
697 color[4 * i + 3] = 255;
698 }
699 GLBuffer buffer;
700 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
701 glBufferData(GL_ARRAY_BUFFER, color.size(), color.data(), GL_DYNAMIC_DRAW);
702
703 ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);
704 glUseProgram(program);
705
706 GLint colorLoc = glGetAttribLocation(program, "color");
707 ASSERT_NE(-1, colorLoc);
708
709 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
710 glEnableVertexAttribArray(colorLoc);
711
712 glViewport(0, 0, 2, 2);
713 drawQuad(program, "position", 0.5f, 1.0f, true);
714 ASSERT_GL_NO_ERROR();
715
716 // Map with GL_MAP_UNSYNCHRONIZED_BIT and overwrite buffers data at offset 24
717 uint8_t *data = reinterpret_cast<uint8_t *>(
718 glMapBufferRangeEXT(GL_ARRAY_BUFFER, 4 * kNumVertices, 4 * kNumVertices,
719 GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
720 EXPECT_GL_NO_ERROR();
721 for (int i = 0; i < kNumVertices; ++i)
722 {
723 data[4 * i] = 0;
724 data[4 * i + 1] = 255;
725 data[4 * i + 2] = 0;
726 data[4 * i + 3] = 255;
727 }
728 glUnmapBufferOES(GL_ARRAY_BUFFER);
729 EXPECT_GL_NO_ERROR();
730
731 // Re-draw using offset = 0 but to different viewport
732 glViewport(0, 2, 2, 2);
733 drawQuad(program, "position", 0.5f, 1.0f, true);
734 ASSERT_GL_NO_ERROR();
735
736 // Change vertex attribute to use buffer starting from offset 24
737 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0,
738 reinterpret_cast<void *>(4 * kNumVertices));
739
740 glViewport(2, 2, 2, 2);
741 drawQuad(program, "position", 0.5f, 1.0f, true);
742 ASSERT_GL_NO_ERROR();
743
744 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
745 EXPECT_PIXEL_COLOR_EQ(1, 3, GLColor::red);
746 EXPECT_PIXEL_COLOR_EQ(3, 3, GLColor::green);
747 }
748
749 // Tests a bug where copying buffer data immediately after creation hit a nullptr in D3D11.
TEST_P(BufferDataTestES3,NoBufferInitDataCopyBug)750 TEST_P(BufferDataTestES3, NoBufferInitDataCopyBug)
751 {
752 constexpr GLsizei size = 64;
753
754 GLBuffer sourceBuffer;
755 glBindBuffer(GL_COPY_READ_BUFFER, sourceBuffer);
756 glBufferData(GL_COPY_READ_BUFFER, size, nullptr, GL_STATIC_DRAW);
757
758 GLBuffer destBuffer;
759 glBindBuffer(GL_ARRAY_BUFFER, destBuffer);
760 glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW);
761
762 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, 0, size);
763 ASSERT_GL_NO_ERROR();
764 }
765
766 // Ensures that calling glBufferData on a mapped buffer results in an unmapped buffer
TEST_P(BufferDataTestES3,BufferDataUnmap)767 TEST_P(BufferDataTestES3, BufferDataUnmap)
768 {
769 // Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to
770 // BufferData happens on a mapped buffer:
771 //
772 // If any portion of the buffer object is mapped in the current context or
773 // any context current to another thread, it is as though UnmapBuffer
774 // (see section 2.10.3) is executed in each such context prior to deleting
775 // the existing data store.
776 //
777
778 std::vector<uint8_t> data1(16);
779 std::vector<uint8_t> data2(16);
780
781 GLBuffer dataBuffer;
782 glBindBuffer(GL_ARRAY_BUFFER, dataBuffer);
783 glBufferData(GL_ARRAY_BUFFER, data1.size(), data1.data(), GL_STATIC_DRAW);
784
785 // Map the buffer once
786 void *mappedBuffer =
787 glMapBufferRange(GL_ARRAY_BUFFER, 0, data1.size(),
788 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT |
789 GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
790
791 // Then repopulate the buffer. This should cause the buffer to become unmapped.
792 glBufferData(GL_ARRAY_BUFFER, data2.size(), data2.data(), GL_STATIC_DRAW);
793 ASSERT_GL_NO_ERROR();
794
795 // Try to unmap the buffer, this should fail
796 bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
797 ASSERT_EQ(result, false);
798 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
799
800 // Try to map the buffer again, which should succeed
801 mappedBuffer = glMapBufferRange(GL_ARRAY_BUFFER, 0, data2.size(),
802 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT |
803 GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
804 ASSERT_GL_NO_ERROR();
805 }
806
807 // Ensures that mapping buffer with GL_MAP_INVALIDATE_BUFFER_BIT followed by glBufferSubData calls
808 // works. Regression test for the Vulkan backend where that flag caused use after free.
TEST_P(BufferDataTestES3,MapInvalidateThenBufferSubData)809 TEST_P(BufferDataTestES3, MapInvalidateThenBufferSubData)
810 {
811 // http://anglebug.com/5984
812 ANGLE_SKIP_TEST_IF(IsWindows() && IsOpenGL() && IsIntel());
813
814 // http://anglebug.com/5985
815 ANGLE_SKIP_TEST_IF(IsNexus5X() && IsOpenGLES());
816
817 const std::array<GLColor, 4> kInitialData = {GLColor::red, GLColor::red, GLColor::red,
818 GLColor::red};
819 const std::array<GLColor, 4> kUpdateData1 = {GLColor::white, GLColor::white, GLColor::white,
820 GLColor::white};
821 const std::array<GLColor, 4> kUpdateData2 = {GLColor::blue, GLColor::blue, GLColor::blue,
822 GLColor::blue};
823
824 GLBuffer buffer;
825 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
826 glBufferData(GL_UNIFORM_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW);
827 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
828 EXPECT_GL_NO_ERROR();
829
830 // Draw
831 constexpr char kVerifyUBO[] = R"(#version 300 es
832 precision mediump float;
833 uniform block {
834 uvec4 data;
835 } ubo;
836 uniform uint expect;
837 uniform vec4 successOutput;
838 out vec4 colorOut;
839 void main()
840 {
841 if (all(equal(ubo.data, uvec4(expect))))
842 colorOut = successOutput;
843 else
844 colorOut = vec4(1.0, 0, 0, 1.0);
845 })";
846
847 ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO);
848 glUseProgram(verifyUbo);
849
850 GLint expectLoc = glGetUniformLocation(verifyUbo, "expect");
851 EXPECT_NE(-1, expectLoc);
852 GLint successLoc = glGetUniformLocation(verifyUbo, "successOutput");
853 EXPECT_NE(-1, successLoc);
854
855 glUniform1ui(expectLoc, kInitialData[0].asUint());
856 glUniform4f(successLoc, 0, 1, 0, 1);
857
858 drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
859 EXPECT_GL_NO_ERROR();
860
861 // Dont't verify the buffer. This is testing GL_MAP_INVALIDATE_BUFFER_BIT while the buffer is
862 // in use by the GPU.
863
864 // Map the buffer and update it.
865 void *mappedBuffer = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(kInitialData),
866 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
867
868 memcpy(mappedBuffer, kUpdateData1.data(), sizeof(kInitialData));
869
870 glUnmapBuffer(GL_UNIFORM_BUFFER);
871 EXPECT_GL_NO_ERROR();
872
873 // Verify that the buffer has the updated value.
874 glUniform1ui(expectLoc, kUpdateData1[0].asUint());
875 glUniform4f(successLoc, 0, 0, 1, 1);
876
877 drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
878 EXPECT_GL_NO_ERROR();
879
880 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
881
882 // Update the buffer with glBufferSubData
883 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(kUpdateData2), kUpdateData2.data());
884 EXPECT_GL_NO_ERROR();
885
886 // Verify that the buffer has the updated value.
887 glUniform1ui(expectLoc, kUpdateData2[0].asUint());
888 glUniform4f(successLoc, 0, 1, 1, 1);
889
890 drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
891 EXPECT_GL_NO_ERROR();
892
893 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
894 }
895
896 class BufferStorageTestES3 : public BufferDataTest
897 {};
898
899 // Tests that proper error value is returned when bad size is passed in
TEST_P(BufferStorageTestES3,BufferStorageInvalidSize)900 TEST_P(BufferStorageTestES3, BufferStorageInvalidSize)
901 {
902 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
903
904 std::vector<GLfloat> data(6, 1.0f);
905
906 GLBuffer buffer;
907 glBindBuffer(GL_ARRAY_BUFFER, buffer);
908 glBufferStorageEXT(GL_ARRAY_BUFFER, 0, data.data(), 0);
909 EXPECT_GL_ERROR(GL_INVALID_VALUE);
910 }
911
912 // Tests that buffer storage can be allocated with the GL_MAP_PERSISTENT_BIT_EXT and
913 // GL_MAP_COHERENT_BIT_EXT flags
TEST_P(BufferStorageTestES3,BufferStorageFlagsPersistentCoherentWrite)914 TEST_P(BufferStorageTestES3, BufferStorageFlagsPersistentCoherentWrite)
915 {
916 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
917
918 std::vector<GLfloat> data(6, 1.0f);
919
920 GLBuffer buffer;
921 glBindBuffer(GL_ARRAY_BUFFER, buffer);
922 glBufferStorageEXT(GL_ARRAY_BUFFER, data.size(), data.data(),
923 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
924 ASSERT_GL_NO_ERROR();
925 }
926
927 // Verify that glBufferStorage makes a buffer immutable
TEST_P(BufferStorageTestES3,StorageBufferBufferData)928 TEST_P(BufferStorageTestES3, StorageBufferBufferData)
929 {
930 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
931 !IsGLExtensionEnabled("GL_EXT_buffer_storage"));
932
933 std::vector<GLfloat> data(6, 1.0f);
934
935 GLBuffer buffer;
936 glBindBuffer(GL_ARRAY_BUFFER, buffer);
937 glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), 0);
938 ASSERT_GL_NO_ERROR();
939
940 // Verify that calling glBufferStorageEXT again produces an error.
941 glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), 0);
942 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
943
944 // Verify that calling glBufferData after calling glBufferStorageEXT produces an error.
945 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_STATIC_DRAW);
946 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
947 }
948
949 // Verify that glBufferStorageEXT can be called after glBufferData
TEST_P(BufferStorageTestES3,BufferDataStorageBuffer)950 TEST_P(BufferStorageTestES3, BufferDataStorageBuffer)
951 {
952 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
953 !IsGLExtensionEnabled("GL_EXT_buffer_storage"));
954
955 std::vector<GLfloat> data(6, 1.0f);
956
957 GLBuffer buffer;
958 glBindBuffer(GL_ARRAY_BUFFER, buffer);
959 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_STATIC_DRAW);
960 ASSERT_GL_NO_ERROR();
961
962 // Verify that calling glBufferStorageEXT again produces an error.
963 glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), 0);
964 ASSERT_GL_NO_ERROR();
965 }
966
967 // Verify that we can perform subdata updates to a buffer marked with GL_DYNAMIC_STORAGE_BIT_EXT
968 // usage flag
TEST_P(BufferStorageTestES3,StorageBufferSubData)969 TEST_P(BufferStorageTestES3, StorageBufferSubData)
970 {
971 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
972 !IsGLExtensionEnabled("GL_EXT_buffer_storage"));
973
974 std::vector<GLfloat> data(6, 0.0f);
975
976 glUseProgram(mProgram);
977 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
978 glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), nullptr,
979 GL_DYNAMIC_STORAGE_BIT_EXT);
980 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * data.size(), data.data());
981 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
982 glEnableVertexAttribArray(mAttribLocation);
983
984 drawQuad(mProgram, "position", 0.5f);
985 EXPECT_PIXEL_COLOR_EQ(8, 8, GLColor::black);
986 EXPECT_GL_NO_ERROR();
987
988 std::vector<GLfloat> data2(6, 1.0f);
989 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * data2.size(), data2.data());
990
991 drawQuad(mProgram, "position", 0.5f);
992 EXPECT_PIXEL_COLOR_EQ(8, 8, GLColor::red);
993 EXPECT_GL_NO_ERROR();
994 }
995
996 // Test interaction between GL_OES_mapbuffer and GL_EXT_buffer_storage extensions.
TEST_P(BufferStorageTestES3,StorageBufferMapBufferOES)997 TEST_P(BufferStorageTestES3, StorageBufferMapBufferOES)
998 {
999 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
1000 !IsGLExtensionEnabled("GL_EXT_buffer_storage") ||
1001 !IsGLExtensionEnabled("GL_EXT_map_buffer_range"));
1002
1003 std::vector<uint8_t> data(1024);
1004 FillVectorWithRandomUBytes(&data);
1005
1006 GLBuffer buffer;
1007 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1008 glBufferStorageEXT(GL_ARRAY_BUFFER, data.size(), nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
1009
1010 // Validate that other map flags don't work.
1011 void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);
1012 EXPECT_EQ(nullptr, badMapPtr);
1013 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1014
1015 // Map and write.
1016 void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
1017 ASSERT_NE(nullptr, mapPtr);
1018 ASSERT_GL_NO_ERROR();
1019 memcpy(mapPtr, data.data(), data.size());
1020 glUnmapBufferOES(GL_ARRAY_BUFFER);
1021
1022 // Validate data with EXT_map_buffer_range
1023 void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);
1024 ASSERT_NE(nullptr, readMapPtr);
1025 ASSERT_GL_NO_ERROR();
1026 std::vector<uint8_t> actualData(data.size());
1027 memcpy(actualData.data(), readMapPtr, data.size());
1028 glUnmapBufferOES(GL_ARRAY_BUFFER);
1029
1030 EXPECT_EQ(data, actualData);
1031 }
1032
1033 ANGLE_INSTANTIATE_TEST_ES2(BufferDataTest);
1034
1035 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferDataTestES3);
1036 ANGLE_INSTANTIATE_TEST_ES3_AND(BufferDataTestES3, WithDirectSPIRVGeneration(ES3_VULKAN()));
1037
1038 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferStorageTestES3);
1039 ANGLE_INSTANTIATE_TEST_ES3(BufferStorageTestES3);
1040
1041 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IndexedBufferCopyTest);
1042 ANGLE_INSTANTIATE_TEST_ES3(IndexedBufferCopyTest);
1043
1044 #ifdef _WIN64
1045
1046 // Test a bug where an integer overflow bug could trigger a crash in D3D.
1047 // The test uses 8 buffers with a size just under 0x2000000 to overflow max uint
1048 // (with the internal D3D rounding to 16-byte values) and trigger the bug.
1049 // Only handle this bug on 64-bit Windows for now. Harder to repro on 32-bit.
1050 class BufferDataOverflowTest : public ANGLETest
1051 {
1052 protected:
BufferDataOverflowTest()1053 BufferDataOverflowTest() {}
1054 };
1055
1056 // See description above.
TEST_P(BufferDataOverflowTest,VertexBufferIntegerOverflow)1057 TEST_P(BufferDataOverflowTest, VertexBufferIntegerOverflow)
1058 {
1059 // These values are special, to trigger the rounding bug.
1060 unsigned int numItems = 0x7FFFFFE;
1061 constexpr GLsizei bufferCnt = 8;
1062
1063 std::vector<GLBuffer> buffers(bufferCnt);
1064
1065 std::stringstream vertexShaderStr;
1066
1067 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
1068 {
1069 vertexShaderStr << "attribute float attrib" << bufferIndex << ";\n";
1070 }
1071
1072 vertexShaderStr << "attribute vec2 position;\n"
1073 "varying float v_attrib;\n"
1074 "void main() {\n"
1075 " gl_Position = vec4(position, 0, 1);\n"
1076 " v_attrib = 0.0;\n";
1077
1078 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
1079 {
1080 vertexShaderStr << "v_attrib += attrib" << bufferIndex << ";\n";
1081 }
1082
1083 vertexShaderStr << "}";
1084
1085 constexpr char kFS[] =
1086 "varying highp float v_attrib;\n"
1087 "void main() {\n"
1088 " gl_FragColor = vec4(v_attrib, 0, 0, 1);\n"
1089 "}";
1090
1091 ANGLE_GL_PROGRAM(program, vertexShaderStr.str().c_str(), kFS);
1092 glUseProgram(program.get());
1093
1094 std::vector<GLfloat> data(numItems, 1.0f);
1095
1096 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
1097 {
1098 glBindBuffer(GL_ARRAY_BUFFER, buffers[bufferIndex].get());
1099 glBufferData(GL_ARRAY_BUFFER, numItems * sizeof(float), &data[0], GL_DYNAMIC_DRAW);
1100
1101 std::stringstream attribNameStr;
1102 attribNameStr << "attrib" << bufferIndex;
1103
1104 GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());
1105 ASSERT_NE(-1, attribLocation);
1106
1107 glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
1108 glEnableVertexAttribArray(attribLocation);
1109 }
1110
1111 GLint positionLocation = glGetAttribLocation(program.get(), "position");
1112 ASSERT_NE(-1, positionLocation);
1113 glDisableVertexAttribArray(positionLocation);
1114 glVertexAttrib2f(positionLocation, 1.0f, 1.0f);
1115
1116 EXPECT_GL_NO_ERROR();
1117 glDrawArrays(GL_TRIANGLES, 0, numItems);
1118 EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);
1119
1120 // Test that a small draw still works.
1121 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
1122 {
1123 std::stringstream attribNameStr;
1124 attribNameStr << "attrib" << bufferIndex;
1125 GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());
1126 ASSERT_NE(-1, attribLocation);
1127 glDisableVertexAttribArray(attribLocation);
1128 }
1129
1130 glDrawArrays(GL_TRIANGLES, 0, 3);
1131 EXPECT_GL_ERROR(GL_NO_ERROR);
1132 }
1133
1134 // Tests a security bug in our CopyBufferSubData validation (integer overflow).
TEST_P(BufferDataOverflowTest,CopySubDataValidation)1135 TEST_P(BufferDataOverflowTest, CopySubDataValidation)
1136 {
1137 GLBuffer readBuffer, writeBuffer;
1138
1139 glBindBuffer(GL_COPY_READ_BUFFER, readBuffer.get());
1140 glBindBuffer(GL_COPY_WRITE_BUFFER, writeBuffer.get());
1141
1142 constexpr int bufSize = 100;
1143
1144 glBufferData(GL_COPY_READ_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);
1145 glBufferData(GL_COPY_WRITE_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);
1146
1147 GLintptr big = std::numeric_limits<GLintptr>::max() - bufSize + 90;
1148
1149 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, big, 0, 50);
1150 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1151
1152 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, big, 50);
1153 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1154 }
1155
1156 ANGLE_INSTANTIATE_TEST_ES3(BufferDataOverflowTest);
1157
1158 #endif // _WIN64
1159