blob: e63b5b25e8cc1cd21836d8fc44440b5b0bd94902 [file] [log] [blame]
Jamie Madillfa05f602015-05-07 13:47:11 -04001//
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
Corentin Wallezd3970de2015-05-14 11:07:48 -04007#include "test_utils/ANGLETest.h"
Jamie Madilld2f0c742016-11-02 10:34:41 -04008#include "test_utils/gl_raii.h"
Jamie Madill80b95282014-05-06 13:57:43 -04009
Jamie Madillcc6ac252017-01-25 12:57:21 -080010#include "random_utils.h"
11
Corentin Wallez178e5972015-09-14 11:52:44 -070012#include <stdint.h>
Jamie Madill18afd772014-08-04 13:22:22 -040013
Jamie Madillfa05f602015-05-07 13:47:11 -040014using namespace angle;
Austin Kinross18b931d2014-09-29 12:58:31 -070015
Jamie Madill80b95282014-05-06 13:57:43 -040016class BufferDataTest : public ANGLETest
17{
Jamie Madill5c1e58d2014-08-04 10:47:58 -040018 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040019 BufferDataTest()
Jamie Madill80b95282014-05-06 13:57:43 -040020 {
21 setWindowWidth(16);
22 setWindowHeight(16);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27 setConfigDepthBits(24);
Austin Kinross18b931d2014-09-29 12:58:31 -070028
29 mBuffer = 0;
30 mProgram = 0;
31 mAttribLocation = -1;
Jamie Madill80b95282014-05-06 13:57:43 -040032 }
33
Jamie Madill3dfcdcb2015-08-10 14:28:54 -040034 void SetUp() override
Jamie Madill80b95282014-05-06 13:57:43 -040035 {
36 ANGLETest::SetUp();
37
38 const char * vsSource = SHADER_SOURCE
39 (
40 attribute vec4 position;
41 attribute float in_attrib;
42 varying float v_attrib;
43 void main()
44 {
45 v_attrib = in_attrib;
46 gl_Position = position;
47 }
48 );
49
50 const char * fsSource = SHADER_SOURCE
51 (
52 precision mediump float;
53 varying float v_attrib;
54 void main()
55 {
56 gl_FragColor = vec4(v_attrib, 0, 0, 1);
57 }
58 );
59
60 glGenBuffers(1, &mBuffer);
61 ASSERT_NE(mBuffer, 0U);
62
Jamie Madill5599c8f2014-08-26 13:16:39 -040063 mProgram = CompileProgram(vsSource, fsSource);
Jamie Madill80b95282014-05-06 13:57:43 -040064 ASSERT_NE(mProgram, 0U);
65
66 mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");
67 ASSERT_NE(mAttribLocation, -1);
68
69 glClearColor(0, 0, 0, 0);
70 glClearDepthf(0.0);
71 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
72
73 glDisable(GL_DEPTH_TEST);
74
75 ASSERT_GL_NO_ERROR();
76 }
77
Jamie Madill3dfcdcb2015-08-10 14:28:54 -040078 void TearDown() override
Jamie Madill80b95282014-05-06 13:57:43 -040079 {
80 glDeleteBuffers(1, &mBuffer);
81 glDeleteProgram(mProgram);
82
83 ANGLETest::TearDown();
84 }
85
86 GLuint mBuffer;
87 GLuint mProgram;
88 GLint mAttribLocation;
89};
90
Jamie Madillfa05f602015-05-07 13:47:11 -040091TEST_P(BufferDataTest, NULLData)
Jamie Madill80b95282014-05-06 13:57:43 -040092{
93 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
94 EXPECT_GL_NO_ERROR();
95
96 const int numIterations = 128;
97 for (int i = 0; i < numIterations; ++i)
98 {
99 GLsizei bufferSize = sizeof(GLfloat) * (i + 1);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800100 glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW);
Jamie Madill80b95282014-05-06 13:57:43 -0400101 EXPECT_GL_NO_ERROR();
102
103 for (int j = 0; j < bufferSize; j++)
104 {
105 for (int k = 0; k < bufferSize - j; k++)
106 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800107 glBufferSubData(GL_ARRAY_BUFFER, k, j, nullptr);
Jamie Madille2e406c2016-06-02 13:04:10 -0400108 ASSERT_GL_NO_ERROR();
Jamie Madill80b95282014-05-06 13:57:43 -0400109 }
110 }
111 }
112}
113
Jamie Madillfa05f602015-05-07 13:47:11 -0400114TEST_P(BufferDataTest, ZeroNonNULLData)
Jamie Madille09f1c82014-06-12 11:10:12 -0400115{
116 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
117 EXPECT_GL_NO_ERROR();
118
119 char *zeroData = new char[0];
120 glBufferData(GL_ARRAY_BUFFER, 0, zeroData, GL_STATIC_DRAW);
121 EXPECT_GL_NO_ERROR();
122
123 glBufferSubData(GL_ARRAY_BUFFER, 0, 0, zeroData);
124 EXPECT_GL_NO_ERROR();
125
126 delete [] zeroData;
127}
128
Jamie Madillfa05f602015-05-07 13:47:11 -0400129TEST_P(BufferDataTest, NULLResolvedData)
Jamie Madillee009b82014-09-19 13:17:51 -0400130{
131 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800132 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_DYNAMIC_DRAW);
Jamie Madillee009b82014-09-19 13:17:51 -0400133
134 glUseProgram(mProgram);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800135 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
Jamie Madillee009b82014-09-19 13:17:51 -0400136 glEnableVertexAttribArray(mAttribLocation);
137 glBindBuffer(GL_ARRAY_BUFFER, 0);
138
139 drawQuad(mProgram, "position", 0.5f);
140}
141
Jamie Madille50bf152015-01-20 16:04:41 -0500142// Tests that a huge allocation returns GL_OUT_OF_MEMORY
143// TODO(jmadill): Figure out how to test this reliably on the Chromium bots
Jamie Madillfa05f602015-05-07 13:47:11 -0400144TEST_P(BufferDataTest, DISABLED_HugeSetDataShouldNotCrash)
Jamie Madill80b95282014-05-06 13:57:43 -0400145{
146 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
147 EXPECT_GL_NO_ERROR();
148
Jamie Madill18afd772014-08-04 13:22:22 -0400149 GLsizei allocSize = std::numeric_limits<GLsizei>::max() >> 2;
Jamie Madill80b95282014-05-06 13:57:43 -0400150
Yunchao Hed7297bf2017-04-19 15:27:10 +0800151 uint8_t *data = nullptr;
Yunchao He4f285442017-04-21 12:15:49 +0800152 while (data == nullptr && allocSize >= 4)
Jamie Madill80b95282014-05-06 13:57:43 -0400153 {
Jamie Madill18afd772014-08-04 13:22:22 -0400154 data = new (std::nothrow) uint8_t[allocSize];
155
Yunchao He4f285442017-04-21 12:15:49 +0800156 if (data == nullptr)
Jamie Madill18afd772014-08-04 13:22:22 -0400157 {
Jamie Madill4f2bf3a2014-08-20 16:03:52 -0400158 allocSize >>= 1;
Jamie Madill18afd772014-08-04 13:22:22 -0400159 }
Jamie Madill80b95282014-05-06 13:57:43 -0400160 }
161
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800162 ASSERT_NE(static_cast<uint8_t *>(nullptr), data);
Jamie Madill18afd772014-08-04 13:22:22 -0400163 memset(data, 0, allocSize);
Jamie Madill80b95282014-05-06 13:57:43 -0400164
165 float * fValue = reinterpret_cast<float*>(data);
166 for (unsigned int f = 0; f < 6; f++)
167 {
168 fValue[f] = 1.0f;
169 }
170
Jamie Madill18afd772014-08-04 13:22:22 -0400171 glBufferData(GL_ARRAY_BUFFER, allocSize, data, GL_STATIC_DRAW);
Jamie Madill80b95282014-05-06 13:57:43 -0400172
173 GLenum error = glGetError();
174 if (error == GL_NO_ERROR)
175 {
176 // If we didn't fail because of an out of memory error, try drawing a quad
177 // using the large buffer
178
179 // DISABLED because it takes a long time, but left for posterity
180
181 //glUseProgram(mProgram);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800182 // glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
183 // glEnableVertexAttribArray(mAttribLocation);
184 // glBindBuffer(GL_ARRAY_BUFFER, 0);
185 // drawQuad(mProgram, "position", 0.5f);
186 // swapBuffers();
Jamie Madill80b95282014-05-06 13:57:43 -0400187
188 //// Draw operations can also generate out-of-memory, which is in-spec
189 //error = glGetError();
190 //if (error == GL_NO_ERROR)
191 //{
192 // GLint viewportSize[4];
193 // glGetIntegerv(GL_VIEWPORT, viewportSize);
194
195 // GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
196 // GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
197
198 // EXPECT_PIXEL_EQ(midPixelX, midPixelY, 255, 0, 0, 255);
199 //}
200 //else
201 //{
202 // EXPECT_EQ(GL_OUT_OF_MEMORY, error);
203 //}
204 }
205 else
206 {
Corentin Wallez322653b2015-06-17 18:33:56 +0200207 EXPECT_GLENUM_EQ(GL_OUT_OF_MEMORY, error);
Jamie Madill80b95282014-05-06 13:57:43 -0400208 }
209
210 delete[] data;
211}
212
Jamie Madill52b09c22016-04-11 14:12:31 -0400213// Internally in D3D, we promote dynamic data to static after many draw loops. This code tests
214// path.
215TEST_P(BufferDataTest, RepeatedDrawWithDynamic)
216{
217 std::vector<GLfloat> data;
218 for (int i = 0; i < 16; ++i)
219 {
220 data.push_back(static_cast<GLfloat>(i));
221 }
222
223 glUseProgram(mProgram);
224 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
225 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
226 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
227 glBindBuffer(GL_ARRAY_BUFFER, 0);
228 glEnableVertexAttribArray(mAttribLocation);
229
230 for (int drawCount = 0; drawCount < 40; ++drawCount)
231 {
232 drawQuad(mProgram, "position", 0.5f);
233 }
234
235 EXPECT_GL_NO_ERROR();
236}
237
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400238class IndexedBufferCopyTest : public ANGLETest
239{
240 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -0400241 IndexedBufferCopyTest()
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400242 {
243 setWindowWidth(16);
244 setWindowHeight(16);
245 setConfigRedBits(8);
246 setConfigGreenBits(8);
247 setConfigBlueBits(8);
248 setConfigAlphaBits(8);
249 setConfigDepthBits(24);
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400250 }
251
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400252 void SetUp() override
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400253 {
254 ANGLETest::SetUp();
255
256 const char * vsSource = SHADER_SOURCE
257 (
258 attribute vec3 in_attrib;
259 varying vec3 v_attrib;
260 void main()
261 {
262 v_attrib = in_attrib;
263 gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
264 gl_PointSize = 100.0;
265 }
266 );
267
268 const char * fsSource = SHADER_SOURCE
269 (
270 precision mediump float;
271 varying vec3 v_attrib;
272 void main()
273 {
274 gl_FragColor = vec4(v_attrib, 1);
275 }
276 );
277
278 glGenBuffers(2, mBuffers);
279 ASSERT_NE(mBuffers[0], 0U);
280 ASSERT_NE(mBuffers[1], 0U);
281
282 glGenBuffers(1, &mElementBuffer);
283 ASSERT_NE(mElementBuffer, 0U);
284
Jamie Madill5599c8f2014-08-26 13:16:39 -0400285 mProgram = CompileProgram(vsSource, fsSource);
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400286 ASSERT_NE(mProgram, 0U);
287
288 mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");
289 ASSERT_NE(mAttribLocation, -1);
290
291 glClearColor(0, 0, 0, 0);
292 glDisable(GL_DEPTH_TEST);
293 glClear(GL_COLOR_BUFFER_BIT);
294
295 ASSERT_GL_NO_ERROR();
296 }
297
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400298 void TearDown() override
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400299 {
300 glDeleteBuffers(2, mBuffers);
301 glDeleteBuffers(1, &mElementBuffer);
302 glDeleteProgram(mProgram);
303
304 ANGLETest::TearDown();
305 }
306
307 GLuint mBuffers[2];
308 GLuint mElementBuffer;
309 GLuint mProgram;
310 GLint mAttribLocation;
311};
312
313// The following test covers an ANGLE bug where our index ranges
314// weren't updated from CopyBufferSubData calls
315// https://code.google.com/p/angleproject/issues/detail?id=709
Jamie Madillfa05f602015-05-07 13:47:11 -0400316TEST_P(IndexedBufferCopyTest, IndexRangeBug)
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400317{
Geoff Lange0cc2a42016-01-20 10:58:17 -0500318 // TODO(geofflang): Figure out why this fails on AMD OpenGL (http://anglebug.com/1291)
Jamie Madill518b9fa2016-03-02 11:26:02 -0500319 if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Lange0cc2a42016-01-20 10:58:17 -0500320 {
321 std::cout << "Test disabled on AMD OpenGL." << std::endl;
322 return;
323 }
324
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400325 unsigned char vertexData[] = { 255, 0, 0, 0, 0, 0 };
326 unsigned int indexData[] = { 0, 1 };
327
328 glBindBuffer(GL_ARRAY_BUFFER, mBuffers[0]);
329 glBufferData(GL_ARRAY_BUFFER, sizeof(char) * 6, vertexData, GL_STATIC_DRAW);
330
331 glUseProgram(mProgram);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800332 glVertexAttribPointer(mAttribLocation, 3, GL_UNSIGNED_BYTE, GL_TRUE, 3, nullptr);
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400333 glEnableVertexAttribArray(mAttribLocation);
334
335 ASSERT_GL_NO_ERROR();
336
337 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
338 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 1, indexData, GL_STATIC_DRAW);
339
340 glUseProgram(mProgram);
341
342 ASSERT_GL_NO_ERROR();
343
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800344 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400345
346 EXPECT_GL_NO_ERROR();
347 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
348
349 glBindBuffer(GL_COPY_READ_BUFFER, mBuffers[1]);
350 glBufferData(GL_COPY_READ_BUFFER, 4, &indexData[1], GL_STATIC_DRAW);
351
352 glBindBuffer(GL_COPY_WRITE_BUFFER, mElementBuffer);
353
354 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(int));
355
356 ASSERT_GL_NO_ERROR();
357
358 glClear(GL_COLOR_BUFFER_BIT);
359 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
360
361 unsigned char newData[] = { 0, 255, 0 };
362 glBufferSubData(GL_ARRAY_BUFFER, 3, 3, newData);
363
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800364 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
Jamie Madill5c1e58d2014-08-04 10:47:58 -0400365
366 EXPECT_GL_NO_ERROR();
367 EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
368}
Gregoire Payen de La Garanderie4b3a29e2015-01-23 15:46:22 +0000369
Jamie Madillfa05f602015-05-07 13:47:11 -0400370class BufferDataTestES3 : public BufferDataTest
Gregoire Payen de La Garanderie4b3a29e2015-01-23 15:46:22 +0000371{
372};
373
374// The following test covers an ANGLE bug where the buffer storage
375// is not resized by Buffer11::getLatestBufferStorage when needed.
376// https://code.google.com/p/angleproject/issues/detail?id=897
Jamie Madillfa05f602015-05-07 13:47:11 -0400377TEST_P(BufferDataTestES3, BufferResizing)
Gregoire Payen de La Garanderie4b3a29e2015-01-23 15:46:22 +0000378{
379 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
380 ASSERT_GL_NO_ERROR();
381
382 // Allocate a buffer with one byte
383 uint8_t singleByte[] = { 0xaa };
384 glBufferData(GL_ARRAY_BUFFER, 1, singleByte, GL_STATIC_DRAW);
385
386 // Resize the buffer
387 // To trigger the bug, the buffer need to be big enough because some hardware copy buffers
388 // by chunks of pages instead of the minimum number of bytes neeeded.
389 const size_t numBytes = 4096*4;
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800390 glBufferData(GL_ARRAY_BUFFER, numBytes, nullptr, GL_STATIC_DRAW);
Gregoire Payen de La Garanderie4b3a29e2015-01-23 15:46:22 +0000391
392 // Copy the original data to the buffer
393 uint8_t srcBytes[numBytes];
394 for (size_t i = 0; i < numBytes; ++i)
395 {
Minmin Gong794e0002015-04-07 18:31:54 -0700396 srcBytes[i] = static_cast<uint8_t>(i);
Gregoire Payen de La Garanderie4b3a29e2015-01-23 15:46:22 +0000397 }
398
399 void *dest = glMapBufferRange(GL_ARRAY_BUFFER, 0, numBytes, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
400
401 ASSERT_GL_NO_ERROR();
402
403 memcpy(dest, srcBytes, numBytes);
404 glUnmapBuffer(GL_ARRAY_BUFFER);
405
406 EXPECT_GL_NO_ERROR();
407
408 // Create a new buffer and copy the data to it
409 GLuint readBuffer;
410 glGenBuffers(1, &readBuffer);
411 glBindBuffer(GL_COPY_WRITE_BUFFER, readBuffer);
412 uint8_t zeros[numBytes];
413 for (size_t i = 0; i < numBytes; ++i)
414 {
415 zeros[i] = 0;
416 }
417 glBufferData(GL_COPY_WRITE_BUFFER, numBytes, zeros, GL_STATIC_DRAW);
418 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numBytes);
419
420 ASSERT_GL_NO_ERROR();
421
422 // Read back the data and compare it to the original
423 uint8_t *data = reinterpret_cast<uint8_t*>(glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numBytes, GL_MAP_READ_BIT));
424
425 ASSERT_GL_NO_ERROR();
426
427 for (size_t i = 0; i < numBytes; ++i)
428 {
429 EXPECT_EQ(srcBytes[i], data[i]);
430 }
431 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
432
433 glDeleteBuffers(1, &readBuffer);
434
435 EXPECT_GL_NO_ERROR();
436}
Jamie Madillfa05f602015-05-07 13:47:11 -0400437
Jamie Madillcc6ac252017-01-25 12:57:21 -0800438// Verify OES_mapbuffer is present if EXT_map_buffer_range is.
439TEST_P(BufferDataTest, ExtensionDependency)
440{
441 if (extensionEnabled("GL_EXT_map_buffer_range"))
442 {
443 ASSERT_TRUE(extensionEnabled("GL_OES_mapbuffer"));
444 }
445}
446
447// Test mapping with the OES extension.
448TEST_P(BufferDataTest, MapBufferOES)
449{
450 if (!extensionEnabled("GL_EXT_map_buffer_range"))
451 {
452 // Needed for test validation.
453 return;
454 }
455
456 std::vector<uint8_t> data(1024);
457 FillVectorWithRandomUBytes(&data);
458
459 GLBuffer buffer;
460 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
461 glBufferData(GL_ARRAY_BUFFER, data.size(), nullptr, GL_STATIC_DRAW);
462
463 // Validate that other map flags don't work.
464 void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);
465 EXPECT_EQ(nullptr, badMapPtr);
466 EXPECT_GL_ERROR(GL_INVALID_ENUM);
467
468 // Map and write.
469 void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
470 ASSERT_NE(nullptr, mapPtr);
471 ASSERT_GL_NO_ERROR();
472 memcpy(mapPtr, data.data(), data.size());
473 glUnmapBufferOES(GL_ARRAY_BUFFER);
474
475 // Validate data with EXT_map_buffer_range
476 void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);
477 ASSERT_NE(nullptr, readMapPtr);
478 ASSERT_GL_NO_ERROR();
479 std::vector<uint8_t> actualData(data.size());
480 memcpy(actualData.data(), readMapPtr, data.size());
481 glUnmapBufferOES(GL_ARRAY_BUFFER);
482
483 EXPECT_EQ(data, actualData);
484}
485
Jamie Madillfa05f602015-05-07 13:47:11 -0400486// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
Geoff Lange0cc2a42016-01-20 10:58:17 -0500487ANGLE_INSTANTIATE_TEST(BufferDataTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES());
488ANGLE_INSTANTIATE_TEST(BufferDataTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
489ANGLE_INSTANTIATE_TEST(IndexedBufferCopyTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Jamie Madillfa05f602015-05-07 13:47:11 -0400490
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400491#ifdef _WIN64
492
493// Test a bug where an integer overflow bug could trigger a crash in D3D.
494// The test uses 8 buffers with a size just under 0x2000000 to overflow max uint
495// (with the internal D3D rounding to 16-byte values) and trigger the bug.
496// Only handle this bug on 64-bit Windows for now. Harder to repro on 32-bit.
497class BufferDataOverflowTest : public ANGLETest
498{
499 protected:
500 BufferDataOverflowTest()
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400501 {
502 }
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400503};
504
505// See description above.
506TEST_P(BufferDataOverflowTest, VertexBufferIntegerOverflow)
507{
508 // These values are special, to trigger the rounding bug.
509 unsigned int numItems = 0x7FFFFFE;
Jamie Madilld2f0c742016-11-02 10:34:41 -0400510 constexpr GLsizei bufferCnt = 8;
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400511
Jamie Madilld2f0c742016-11-02 10:34:41 -0400512 std::vector<GLBuffer> buffers(bufferCnt);
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400513
514 std::stringstream vertexShaderStr;
515
516 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
517 {
518 vertexShaderStr << "attribute float attrib" << bufferIndex << ";\n";
519 }
520
521 vertexShaderStr << "attribute vec2 position;\n"
522 "varying float v_attrib;\n"
523 "void main() {\n"
524 " gl_Position = vec4(position, 0, 1);\n"
525 " v_attrib = 0.0;\n";
526
527 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
528 {
529 vertexShaderStr << "v_attrib += attrib" << bufferIndex << ";\n";
530 }
531
532 vertexShaderStr << "}";
533
534 const std::string &fragmentShader =
535 "varying highp float v_attrib;\n"
536 "void main() {\n"
537 " gl_FragColor = vec4(v_attrib, 0, 0, 1);\n"
538 "}";
539
Jamie Madilld2f0c742016-11-02 10:34:41 -0400540 ANGLE_GL_PROGRAM(program, vertexShaderStr.str(), fragmentShader);
541 glUseProgram(program.get());
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400542
543 std::vector<GLfloat> data(numItems, 1.0f);
544
545 for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)
546 {
Jamie Madilld2f0c742016-11-02 10:34:41 -0400547 glBindBuffer(GL_ARRAY_BUFFER, buffers[bufferIndex].get());
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400548 glBufferData(GL_ARRAY_BUFFER, numItems * sizeof(float), &data[0], GL_DYNAMIC_DRAW);
549
550 std::stringstream attribNameStr;
551 attribNameStr << "attrib" << bufferIndex;
552
Jamie Madilld2f0c742016-11-02 10:34:41 -0400553 GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400554 ASSERT_NE(-1, attribLocation);
555
556 glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
557 glEnableVertexAttribArray(attribLocation);
558 }
559
Jamie Madilld2f0c742016-11-02 10:34:41 -0400560 GLint positionLocation = glGetAttribLocation(program.get(), "position");
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400561 ASSERT_NE(-1, positionLocation);
562 glDisableVertexAttribArray(positionLocation);
563 glVertexAttrib2f(positionLocation, 1.0f, 1.0f);
564
565 EXPECT_GL_NO_ERROR();
566 glDrawArrays(GL_TRIANGLES, 0, numItems);
567 EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);
568}
569
Jamie Madilld2f0c742016-11-02 10:34:41 -0400570// Tests a security bug in our CopyBufferSubData validation (integer overflow).
571TEST_P(BufferDataOverflowTest, CopySubDataValidation)
572{
573 GLBuffer readBuffer, writeBuffer;
574
575 glBindBuffer(GL_COPY_READ_BUFFER, readBuffer.get());
576 glBindBuffer(GL_COPY_WRITE_BUFFER, writeBuffer.get());
577
578 constexpr int bufSize = 100;
579
580 glBufferData(GL_COPY_READ_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);
581 glBufferData(GL_COPY_WRITE_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);
582
583 GLintptr big = std::numeric_limits<GLintptr>::max() - bufSize + 90;
584
585 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, big, 0, 50);
586 EXPECT_GL_ERROR(GL_INVALID_VALUE);
587
588 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, big, 50);
589 EXPECT_GL_ERROR(GL_INVALID_VALUE);
590}
591
Jamie Madill3dfcdcb2015-08-10 14:28:54 -0400592ANGLE_INSTANTIATE_TEST(BufferDataOverflowTest, ES3_D3D11());
593
594#endif // _WIN64