• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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