Path: blob/main_old/src/tests/gl_tests/BufferDataTest.cpp
1693 views
//1// Copyright 2015 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56#include "test_utils/ANGLETest.h"7#include "test_utils/gl_raii.h"89#include "util/random_utils.h"1011#include <stdint.h>1213using namespace angle;1415class BufferDataTest : public ANGLETest16{17protected:18BufferDataTest()19{20setWindowWidth(16);21setWindowHeight(16);22setConfigRedBits(8);23setConfigGreenBits(8);24setConfigBlueBits(8);25setConfigAlphaBits(8);26setConfigDepthBits(24);2728mBuffer = 0;29mProgram = 0;30mAttribLocation = -1;31}3233void testSetUp() override34{35constexpr char kVS[] = R"(attribute vec4 position;36attribute float in_attrib;37varying float v_attrib;38void main()39{40v_attrib = in_attrib;41gl_Position = position;42})";4344constexpr char kFS[] = R"(precision mediump float;45varying float v_attrib;46void main()47{48gl_FragColor = vec4(v_attrib, 0, 0, 1);49})";5051glGenBuffers(1, &mBuffer);52ASSERT_NE(mBuffer, 0U);5354mProgram = CompileProgram(kVS, kFS);55ASSERT_NE(mProgram, 0U);5657mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");58ASSERT_NE(mAttribLocation, -1);5960glClearColor(0, 0, 0, 0);61glClearDepthf(0.0);62glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);6364glDisable(GL_DEPTH_TEST);6566ASSERT_GL_NO_ERROR();67}6869void testTearDown() override70{71glDeleteBuffers(1, &mBuffer);72glDeleteProgram(mProgram);73}7475GLuint mBuffer;76GLuint mProgram;77GLint mAttribLocation;78};7980// If glBufferData was not called yet the capturing must not try to81// read the data. http://anglebug.com/609382TEST_P(BufferDataTest, Uninitialized)83{84// Trigger frame capture to try capturing the85// generated but uninitialized buffer86glBindBuffer(GL_ARRAY_BUFFER, mBuffer);87swapBuffers();88}8990TEST_P(BufferDataTest, ZeroNonNULLData)91{92glBindBuffer(GL_ARRAY_BUFFER, mBuffer);93EXPECT_GL_NO_ERROR();9495char *zeroData = new char[0];96glBufferData(GL_ARRAY_BUFFER, 0, zeroData, GL_STATIC_DRAW);97EXPECT_GL_NO_ERROR();9899glBufferSubData(GL_ARRAY_BUFFER, 0, 0, zeroData);100EXPECT_GL_NO_ERROR();101102delete[] zeroData;103}104105TEST_P(BufferDataTest, NULLResolvedData)106{107glBindBuffer(GL_ARRAY_BUFFER, mBuffer);108glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_DYNAMIC_DRAW);109110glUseProgram(mProgram);111glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);112glEnableVertexAttribArray(mAttribLocation);113glBindBuffer(GL_ARRAY_BUFFER, 0);114115drawQuad(mProgram, "position", 0.5f);116}117118// Internally in D3D, we promote dynamic data to static after many draw loops. This code tests119// path.120TEST_P(BufferDataTest, RepeatedDrawWithDynamic)121{122std::vector<GLfloat> data;123for (int i = 0; i < 16; ++i)124{125data.push_back(static_cast<GLfloat>(i));126}127128glUseProgram(mProgram);129glBindBuffer(GL_ARRAY_BUFFER, mBuffer);130glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);131glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);132glBindBuffer(GL_ARRAY_BUFFER, 0);133glEnableVertexAttribArray(mAttribLocation);134135for (int drawCount = 0; drawCount < 40; ++drawCount)136{137drawQuad(mProgram, "position", 0.5f);138}139140EXPECT_GL_NO_ERROR();141}142143// Tests for a bug where vertex attribute translation was not being invalidated when switching to144// DYNAMIC145TEST_P(BufferDataTest, RepeatedDrawDynamicBug)146{147// http://anglebug.com/2843: Seems to be an Intel driver bug.148ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsWindows());149150glUseProgram(mProgram);151152GLint positionLocation = glGetAttribLocation(mProgram, "position");153ASSERT_NE(-1, positionLocation);154155auto quadVertices = GetQuadVertices();156for (angle::Vector3 &vertex : quadVertices)157{158vertex.x() *= 1.0f;159vertex.y() *= 1.0f;160vertex.z() = 0.0f;161}162163// Set up quad vertices with DYNAMIC data164GLBuffer positionBuffer;165glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);166glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * quadVertices.size() * 3, quadVertices.data(),167GL_DYNAMIC_DRAW);168glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);169glEnableVertexAttribArray(positionLocation);170glBindBuffer(GL_ARRAY_BUFFER, 0);171EXPECT_GL_NO_ERROR();172173// Set up color data so red is drawn174std::vector<GLfloat> data(6, 1.0f);175176// Set data to DYNAMIC177glBindBuffer(GL_ARRAY_BUFFER, mBuffer);178glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);179glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);180glEnableVertexAttribArray(mAttribLocation);181EXPECT_GL_NO_ERROR();182183// Draw enough times to promote data to DIRECT mode184for (int i = 0; i < 20; i++)185{186glDrawArrays(GL_TRIANGLES, 0, 6);187}188189// Verify red was drawn190EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);191192// Set up color value so black is drawn193std::fill(data.begin(), data.end(), 0.0f);194195// Update the data, changing back to DYNAMIC mode.196glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);197198// This draw should produce a black quad199glDrawArrays(GL_TRIANGLES, 0, 6);200EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);201EXPECT_GL_NO_ERROR();202}203204class IndexedBufferCopyTest : public ANGLETest205{206protected:207IndexedBufferCopyTest()208{209setWindowWidth(16);210setWindowHeight(16);211setConfigRedBits(8);212setConfigGreenBits(8);213setConfigBlueBits(8);214setConfigAlphaBits(8);215setConfigDepthBits(24);216}217218void testSetUp() override219{220constexpr char kVS[] = R"(attribute vec3 in_attrib;221varying vec3 v_attrib;222void main()223{224v_attrib = in_attrib;225gl_Position = vec4(0.0, 0.0, 0.5, 1.0);226gl_PointSize = 100.0;227})";228229constexpr char kFS[] = R"(precision mediump float;230varying vec3 v_attrib;231void main()232{233gl_FragColor = vec4(v_attrib, 1);234})";235236glGenBuffers(2, mBuffers);237ASSERT_NE(mBuffers[0], 0U);238ASSERT_NE(mBuffers[1], 0U);239240glGenBuffers(1, &mElementBuffer);241ASSERT_NE(mElementBuffer, 0U);242243mProgram = CompileProgram(kVS, kFS);244ASSERT_NE(mProgram, 0U);245246mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");247ASSERT_NE(mAttribLocation, -1);248249glClearColor(0, 0, 0, 0);250glDisable(GL_DEPTH_TEST);251glClear(GL_COLOR_BUFFER_BIT);252253ASSERT_GL_NO_ERROR();254}255256void testTearDown() override257{258glDeleteBuffers(2, mBuffers);259glDeleteBuffers(1, &mElementBuffer);260glDeleteProgram(mProgram);261}262263GLuint mBuffers[2];264GLuint mElementBuffer;265GLuint mProgram;266GLint mAttribLocation;267};268269// The following test covers an ANGLE bug where our index ranges270// weren't updated from CopyBufferSubData calls271// https://code.google.com/p/angleproject/issues/detail?id=709272TEST_P(IndexedBufferCopyTest, IndexRangeBug)273{274// http://anglebug.com/4092275ANGLE_SKIP_TEST_IF(isSwiftshader());276// TODO(geofflang): Figure out why this fails on AMD OpenGL (http://anglebug.com/1291)277ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());278279unsigned char vertexData[] = {255, 0, 0, 0, 0, 0};280unsigned int indexData[] = {0, 1};281282glBindBuffer(GL_ARRAY_BUFFER, mBuffers[0]);283glBufferData(GL_ARRAY_BUFFER, sizeof(char) * 6, vertexData, GL_STATIC_DRAW);284285glUseProgram(mProgram);286glVertexAttribPointer(mAttribLocation, 3, GL_UNSIGNED_BYTE, GL_TRUE, 3, nullptr);287glEnableVertexAttribArray(mAttribLocation);288289ASSERT_GL_NO_ERROR();290291glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);292glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 1, indexData, GL_STATIC_DRAW);293294glUseProgram(mProgram);295296ASSERT_GL_NO_ERROR();297298glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);299300EXPECT_GL_NO_ERROR();301EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);302303glBindBuffer(GL_COPY_READ_BUFFER, mBuffers[1]);304glBufferData(GL_COPY_READ_BUFFER, 4, &indexData[1], GL_STATIC_DRAW);305306glBindBuffer(GL_COPY_WRITE_BUFFER, mElementBuffer);307308glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(int));309310ASSERT_GL_NO_ERROR();311312glClear(GL_COLOR_BUFFER_BIT);313EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);314315unsigned char newData[] = {0, 255, 0};316glBufferSubData(GL_ARRAY_BUFFER, 3, 3, newData);317318glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);319320EXPECT_GL_NO_ERROR();321EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);322}323324class BufferDataTestES3 : public BufferDataTest325{};326327// The following test covers an ANGLE bug where the buffer storage328// is not resized by Buffer11::getLatestBufferStorage when needed.329// https://code.google.com/p/angleproject/issues/detail?id=897330TEST_P(BufferDataTestES3, BufferResizing)331{332glBindBuffer(GL_ARRAY_BUFFER, mBuffer);333ASSERT_GL_NO_ERROR();334335// Allocate a buffer with one byte336uint8_t singleByte[] = {0xaa};337glBufferData(GL_ARRAY_BUFFER, 1, singleByte, GL_STATIC_DRAW);338339// Resize the buffer340// To trigger the bug, the buffer need to be big enough because some hardware copy buffers341// by chunks of pages instead of the minimum number of bytes needed.342const size_t numBytes = 4096 * 4;343glBufferData(GL_ARRAY_BUFFER, numBytes, nullptr, GL_STATIC_DRAW);344345// Copy the original data to the buffer346uint8_t srcBytes[numBytes];347for (size_t i = 0; i < numBytes; ++i)348{349srcBytes[i] = static_cast<uint8_t>(i);350}351352void *dest = glMapBufferRange(GL_ARRAY_BUFFER, 0, numBytes,353GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);354355ASSERT_GL_NO_ERROR();356357memcpy(dest, srcBytes, numBytes);358glUnmapBuffer(GL_ARRAY_BUFFER);359360EXPECT_GL_NO_ERROR();361362// Create a new buffer and copy the data to it363GLuint readBuffer;364glGenBuffers(1, &readBuffer);365glBindBuffer(GL_COPY_WRITE_BUFFER, readBuffer);366uint8_t zeros[numBytes];367for (size_t i = 0; i < numBytes; ++i)368{369zeros[i] = 0;370}371glBufferData(GL_COPY_WRITE_BUFFER, numBytes, zeros, GL_STATIC_DRAW);372glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numBytes);373374ASSERT_GL_NO_ERROR();375376// Read back the data and compare it to the original377uint8_t *data = reinterpret_cast<uint8_t *>(378glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numBytes, GL_MAP_READ_BIT));379380ASSERT_GL_NO_ERROR();381382for (size_t i = 0; i < numBytes; ++i)383{384EXPECT_EQ(srcBytes[i], data[i]);385}386glUnmapBuffer(GL_COPY_WRITE_BUFFER);387388glDeleteBuffers(1, &readBuffer);389390EXPECT_GL_NO_ERROR();391}392393// Test to verify mapping a buffer after copying to it contains flushed/updated data394TEST_P(BufferDataTestES3, CopyBufferSubDataMapReadTest)395{396const char simpleVertex[] = R"(attribute vec2 position;397attribute vec4 color;398varying vec4 vColor;399void main()400{401gl_Position = vec4(position, 0, 1);402vColor = color;403}404)";405const char simpleFragment[] = R"(precision mediump float;406varying vec4 vColor;407void main()408{409gl_FragColor = vColor;410}411)";412413const uint32_t numComponents = 3;414const uint32_t width = 4;415const uint32_t height = 4;416const size_t numElements = width * height * numComponents;417std::vector<uint8_t> srcData(numElements);418std::vector<uint8_t> dstData(numElements);419420for (uint8_t i = 0; i < srcData.size(); i++)421{422srcData[i] = 128;423}424for (uint8_t i = 0; i < dstData.size(); i++)425{426dstData[i] = 0;427}428429GLBuffer srcBuffer;430GLBuffer dstBuffer;431432glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);433glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);434ASSERT_GL_NO_ERROR();435436glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dstBuffer);437glBufferData(GL_PIXEL_UNPACK_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);438ASSERT_GL_NO_ERROR();439440ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);441glUseProgram(program);442443GLint colorLoc = glGetAttribLocation(program, "color");444ASSERT_NE(-1, colorLoc);445446glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);447glVertexAttribPointer(colorLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);448glEnableVertexAttribArray(colorLoc);449450drawQuad(program, "position", 0.5f, 1.0f, true);451ASSERT_GL_NO_ERROR();452453glCopyBufferSubData(GL_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, 0, numElements);454455// With GL_MAP_READ_BIT, we expect the data to be flushed and updated to match srcData456uint8_t *data = reinterpret_cast<uint8_t *>(457glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_READ_BIT));458EXPECT_GL_NO_ERROR();459for (size_t i = 0; i < numElements; ++i)460{461EXPECT_EQ(srcData[i], data[i]);462}463glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);464EXPECT_GL_NO_ERROR();465}466467// Test to verify mapping a buffer after copying to it contains expected data468// with GL_MAP_UNSYNCHRONIZED_BIT469TEST_P(BufferDataTestES3, MapBufferUnsynchronizedReadTest)470{471const char simpleVertex[] = R"(attribute vec2 position;472attribute vec4 color;473varying vec4 vColor;474void main()475{476gl_Position = vec4(position, 0, 1);477vColor = color;478}479)";480const char simpleFragment[] = R"(precision mediump float;481varying vec4 vColor;482void main()483{484gl_FragColor = vColor;485}486)";487488const uint32_t numComponents = 3;489const uint32_t width = 4;490const uint32_t height = 4;491const size_t numElements = width * height * numComponents;492std::vector<uint8_t> srcData(numElements);493std::vector<uint8_t> dstData(numElements);494495for (uint8_t i = 0; i < srcData.size(); i++)496{497srcData[i] = 128;498}499for (uint8_t i = 0; i < dstData.size(); i++)500{501dstData[i] = 0;502}503504GLBuffer srcBuffer;505GLBuffer dstBuffer;506507glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);508glBufferData(GL_ARRAY_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);509ASSERT_GL_NO_ERROR();510511glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dstBuffer);512glBufferData(GL_PIXEL_UNPACK_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);513ASSERT_GL_NO_ERROR();514515ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);516glUseProgram(program);517518GLint colorLoc = glGetAttribLocation(program, "color");519ASSERT_NE(-1, colorLoc);520521glBindBuffer(GL_ARRAY_BUFFER, srcBuffer);522glVertexAttribPointer(colorLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);523glEnableVertexAttribArray(colorLoc);524525drawQuad(program, "position", 0.5f, 1.0f, true);526ASSERT_GL_NO_ERROR();527528glCopyBufferSubData(GL_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, 0, numElements);529530// Synchronize.531glFinish();532533// Map with GL_MAP_UNSYNCHRONIZED_BIT and overwrite buffers data with srcData534uint8_t *data = reinterpret_cast<uint8_t *>(glMapBufferRange(535GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));536EXPECT_GL_NO_ERROR();537memcpy(data, srcData.data(), srcData.size());538glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);539EXPECT_GL_NO_ERROR();540541// Map without GL_MAP_UNSYNCHRONIZED_BIT and read data. We expect it to be srcData542data = reinterpret_cast<uint8_t *>(543glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, numElements, GL_MAP_READ_BIT));544EXPECT_GL_NO_ERROR();545for (size_t i = 0; i < numElements; ++i)546{547EXPECT_EQ(srcData[i], data[i]);548}549glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);550EXPECT_GL_NO_ERROR();551}552553// Verify the functionality of glMapBufferRange()'s GL_MAP_UNSYNCHRONIZED_BIT554// NOTE: On Vulkan, if we ever use memory that's not `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`, then555// this could incorrectly pass.556TEST_P(BufferDataTestES3, MapBufferRangeUnsynchronizedBit)557{558// We can currently only control the behavior of the Vulkan backend's synchronizing operation's559ANGLE_SKIP_TEST_IF(!IsVulkan());560561const size_t numElements = 10;562std::vector<uint8_t> srcData(numElements);563std::vector<uint8_t> dstData(numElements);564565for (uint8_t i = 0; i < srcData.size(); i++)566{567srcData[i] = i;568}569for (uint8_t i = 0; i < dstData.size(); i++)570{571dstData[i] = static_cast<uint8_t>(i + dstData.size());572}573574GLBuffer srcBuffer;575GLBuffer dstBuffer;576577glBindBuffer(GL_COPY_READ_BUFFER, srcBuffer);578ASSERT_GL_NO_ERROR();579glBindBuffer(GL_COPY_WRITE_BUFFER, dstBuffer);580ASSERT_GL_NO_ERROR();581582glBufferData(GL_COPY_READ_BUFFER, srcData.size(), srcData.data(), GL_STATIC_DRAW);583ASSERT_GL_NO_ERROR();584glBufferData(GL_COPY_WRITE_BUFFER, dstData.size(), dstData.data(), GL_STATIC_READ);585ASSERT_GL_NO_ERROR();586587glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, numElements);588589// With GL_MAP_UNSYNCHRONIZED_BIT, we expect the data to be stale and match dstData590// NOTE: We are specifying GL_MAP_WRITE_BIT so we can use GL_MAP_UNSYNCHRONIZED_BIT. This is591// venturing into undefined behavior, since we are actually planning on reading from this592// pointer.593auto *data = reinterpret_cast<uint8_t *>(glMapBufferRange(594GL_COPY_WRITE_BUFFER, 0, numElements, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));595EXPECT_GL_NO_ERROR();596for (size_t i = 0; i < numElements; ++i)597{598// Allow for the possibility that data matches either "dstData" or "srcData"599if (dstData[i] != data[i])600{601EXPECT_EQ(srcData[i], data[i]);602}603}604glUnmapBuffer(GL_COPY_WRITE_BUFFER);605EXPECT_GL_NO_ERROR();606607// Without GL_MAP_UNSYNCHRONIZED_BIT, we expect the data to be copied and match srcData608data = reinterpret_cast<uint8_t *>(609glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, numElements, GL_MAP_READ_BIT));610EXPECT_GL_NO_ERROR();611for (size_t i = 0; i < numElements; ++i)612{613EXPECT_EQ(srcData[i], data[i]);614}615glUnmapBuffer(GL_COPY_WRITE_BUFFER);616EXPECT_GL_NO_ERROR();617}618619// Verify OES_mapbuffer is present if EXT_map_buffer_range is.620TEST_P(BufferDataTest, ExtensionDependency)621{622if (IsGLExtensionEnabled("GL_EXT_map_buffer_range"))623{624ASSERT_TRUE(IsGLExtensionEnabled("GL_OES_mapbuffer"));625}626}627628// Test mapping with the OES extension.629TEST_P(BufferDataTest, MapBufferOES)630{631if (!IsGLExtensionEnabled("GL_EXT_map_buffer_range"))632{633// Needed for test validation.634return;635}636637std::vector<uint8_t> data(1024);638FillVectorWithRandomUBytes(&data);639640GLBuffer buffer;641glBindBuffer(GL_ARRAY_BUFFER, buffer.get());642glBufferData(GL_ARRAY_BUFFER, data.size(), nullptr, GL_STATIC_DRAW);643644// Validate that other map flags don't work.645void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);646EXPECT_EQ(nullptr, badMapPtr);647EXPECT_GL_ERROR(GL_INVALID_ENUM);648649// Map and write.650void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);651ASSERT_NE(nullptr, mapPtr);652ASSERT_GL_NO_ERROR();653memcpy(mapPtr, data.data(), data.size());654glUnmapBufferOES(GL_ARRAY_BUFFER);655656// Validate data with EXT_map_buffer_range657void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);658ASSERT_NE(nullptr, readMapPtr);659ASSERT_GL_NO_ERROR();660std::vector<uint8_t> actualData(data.size());661memcpy(actualData.data(), readMapPtr, data.size());662glUnmapBufferOES(GL_ARRAY_BUFFER);663664EXPECT_EQ(data, actualData);665}666667// Test to verify mapping a dynamic buffer with GL_MAP_UNSYNCHRONIZED_BIT to modify a portion668// won't affect draw calls using other portions.669TEST_P(BufferDataTest, MapDynamicBufferUnsynchronizedEXTTest)670{671ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_map_buffer_range"));672673const char simpleVertex[] = R"(attribute vec2 position;674attribute vec4 color;675varying vec4 vColor;676void main()677{678gl_Position = vec4(position, 0, 1);679vColor = color;680}681)";682const char simpleFragment[] = R"(precision mediump float;683varying vec4 vColor;684void main()685{686gl_FragColor = vColor;687}688)";689690constexpr int kNumVertices = 6;691692std::vector<GLubyte> color(8 * kNumVertices);693for (int i = 0; i < kNumVertices; ++i)694{695color[4 * i] = 255;696color[4 * i + 3] = 255;697}698GLBuffer buffer;699glBindBuffer(GL_ARRAY_BUFFER, buffer.get());700glBufferData(GL_ARRAY_BUFFER, color.size(), color.data(), GL_DYNAMIC_DRAW);701702ANGLE_GL_PROGRAM(program, simpleVertex, simpleFragment);703glUseProgram(program);704705GLint colorLoc = glGetAttribLocation(program, "color");706ASSERT_NE(-1, colorLoc);707708glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);709glEnableVertexAttribArray(colorLoc);710711glViewport(0, 0, 2, 2);712drawQuad(program, "position", 0.5f, 1.0f, true);713ASSERT_GL_NO_ERROR();714715// Map with GL_MAP_UNSYNCHRONIZED_BIT and overwrite buffers data at offset 24716uint8_t *data = reinterpret_cast<uint8_t *>(717glMapBufferRangeEXT(GL_ARRAY_BUFFER, 4 * kNumVertices, 4 * kNumVertices,718GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));719EXPECT_GL_NO_ERROR();720for (int i = 0; i < kNumVertices; ++i)721{722data[4 * i] = 0;723data[4 * i + 1] = 255;724data[4 * i + 2] = 0;725data[4 * i + 3] = 255;726}727glUnmapBufferOES(GL_ARRAY_BUFFER);728EXPECT_GL_NO_ERROR();729730// Re-draw using offset = 0 but to different viewport731glViewport(0, 2, 2, 2);732drawQuad(program, "position", 0.5f, 1.0f, true);733ASSERT_GL_NO_ERROR();734735// Change vertex attribute to use buffer starting from offset 24736glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0,737reinterpret_cast<void *>(4 * kNumVertices));738739glViewport(2, 2, 2, 2);740drawQuad(program, "position", 0.5f, 1.0f, true);741ASSERT_GL_NO_ERROR();742743EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);744EXPECT_PIXEL_COLOR_EQ(1, 3, GLColor::red);745EXPECT_PIXEL_COLOR_EQ(3, 3, GLColor::green);746}747748// Tests a null crash bug caused by copying from null back-end buffer pointer749// when calling bufferData again after drawing without calling bufferData in D3D11.750TEST_P(BufferDataTestES3, DrawWithNotCallingBufferData)751{752ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());753glUseProgram(drawRed);754755GLint mem = 0;756GLBuffer buffer;757glBindBuffer(GL_ARRAY_BUFFER, buffer);758glEnableVertexAttribArray(0);759glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);760glDrawArrays(GL_TRIANGLES, 0, 3);761glBindBuffer(GL_COPY_WRITE_BUFFER, buffer);762glBufferData(GL_COPY_WRITE_BUFFER, 1, &mem, GL_STREAM_DRAW);763ASSERT_GL_NO_ERROR();764}765766// Tests a bug where copying buffer data immediately after creation hit a nullptr in D3D11.767TEST_P(BufferDataTestES3, NoBufferInitDataCopyBug)768{769constexpr GLsizei size = 64;770771GLBuffer sourceBuffer;772glBindBuffer(GL_COPY_READ_BUFFER, sourceBuffer);773glBufferData(GL_COPY_READ_BUFFER, size, nullptr, GL_STATIC_DRAW);774775GLBuffer destBuffer;776glBindBuffer(GL_ARRAY_BUFFER, destBuffer);777glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW);778779glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, 0, size);780ASSERT_GL_NO_ERROR();781}782783// Ensures that calling glBufferData on a mapped buffer results in an unmapped buffer784TEST_P(BufferDataTestES3, BufferDataUnmap)785{786// Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to787// BufferData happens on a mapped buffer:788//789// If any portion of the buffer object is mapped in the current context or790// any context current to another thread, it is as though UnmapBuffer791// (see section 2.10.3) is executed in each such context prior to deleting792// the existing data store.793//794795std::vector<uint8_t> data1(16);796std::vector<uint8_t> data2(16);797798GLBuffer dataBuffer;799glBindBuffer(GL_ARRAY_BUFFER, dataBuffer);800glBufferData(GL_ARRAY_BUFFER, data1.size(), data1.data(), GL_STATIC_DRAW);801802// Map the buffer once803glMapBufferRange(GL_ARRAY_BUFFER, 0, data1.size(),804GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |805GL_MAP_UNSYNCHRONIZED_BIT);806807// Then repopulate the buffer. This should cause the buffer to become unmapped.808glBufferData(GL_ARRAY_BUFFER, data2.size(), data2.data(), GL_STATIC_DRAW);809ASSERT_GL_NO_ERROR();810811// Try to unmap the buffer, this should fail812bool result = glUnmapBuffer(GL_ARRAY_BUFFER);813ASSERT_EQ(result, false);814EXPECT_GL_ERROR(GL_INVALID_OPERATION);815816// Try to map the buffer again, which should succeed817glMapBufferRange(GL_ARRAY_BUFFER, 0, data2.size(),818GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |819GL_MAP_UNSYNCHRONIZED_BIT);820ASSERT_GL_NO_ERROR();821}822823// Ensures that mapping buffer with GL_MAP_INVALIDATE_BUFFER_BIT followed by glBufferSubData calls824// works. Regression test for the Vulkan backend where that flag caused use after free.825TEST_P(BufferDataTestES3, MapInvalidateThenBufferSubData)826{827// http://anglebug.com/5984828ANGLE_SKIP_TEST_IF(IsWindows() && IsOpenGL() && IsIntel());829830// http://anglebug.com/5985831ANGLE_SKIP_TEST_IF(IsNexus5X() && IsOpenGLES());832833const std::array<GLColor, 4> kInitialData = {GLColor::red, GLColor::red, GLColor::red,834GLColor::red};835const std::array<GLColor, 4> kUpdateData1 = {GLColor::white, GLColor::white, GLColor::white,836GLColor::white};837const std::array<GLColor, 4> kUpdateData2 = {GLColor::blue, GLColor::blue, GLColor::blue,838GLColor::blue};839840GLBuffer buffer;841glBindBuffer(GL_UNIFORM_BUFFER, buffer);842glBufferData(GL_UNIFORM_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW);843glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);844EXPECT_GL_NO_ERROR();845846// Draw847constexpr char kVerifyUBO[] = R"(#version 300 es848precision mediump float;849uniform block {850uvec4 data;851} ubo;852uniform uint expect;853uniform vec4 successOutput;854out vec4 colorOut;855void main()856{857if (all(equal(ubo.data, uvec4(expect))))858colorOut = successOutput;859else860colorOut = vec4(1.0, 0, 0, 1.0);861})";862863ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO);864glUseProgram(verifyUbo);865866GLint expectLoc = glGetUniformLocation(verifyUbo, "expect");867EXPECT_NE(-1, expectLoc);868GLint successLoc = glGetUniformLocation(verifyUbo, "successOutput");869EXPECT_NE(-1, successLoc);870871glUniform1ui(expectLoc, kInitialData[0].asUint());872glUniform4f(successLoc, 0, 1, 0, 1);873874drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);875EXPECT_GL_NO_ERROR();876877// Dont't verify the buffer. This is testing GL_MAP_INVALIDATE_BUFFER_BIT while the buffer is878// in use by the GPU.879880// Map the buffer and update it.881void *mappedBuffer = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(kInitialData),882GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);883884memcpy(mappedBuffer, kUpdateData1.data(), sizeof(kInitialData));885886glUnmapBuffer(GL_UNIFORM_BUFFER);887EXPECT_GL_NO_ERROR();888889// Verify that the buffer has the updated value.890glUniform1ui(expectLoc, kUpdateData1[0].asUint());891glUniform4f(successLoc, 0, 0, 1, 1);892893drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);894EXPECT_GL_NO_ERROR();895896EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);897898// Update the buffer with glBufferSubData899glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(kUpdateData2), kUpdateData2.data());900EXPECT_GL_NO_ERROR();901902// Verify that the buffer has the updated value.903glUniform1ui(expectLoc, kUpdateData2[0].asUint());904glUniform4f(successLoc, 0, 1, 1, 1);905906drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);907EXPECT_GL_NO_ERROR();908909EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);910}911912class BufferStorageTestES3 : public BufferDataTest913{};914915// Tests that proper error value is returned when bad size is passed in916TEST_P(BufferStorageTestES3, BufferStorageInvalidSize)917{918ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));919920std::vector<GLfloat> data(6, 1.0f);921922GLBuffer buffer;923glBindBuffer(GL_ARRAY_BUFFER, buffer);924glBufferStorageEXT(GL_ARRAY_BUFFER, 0, data.data(), 0);925EXPECT_GL_ERROR(GL_INVALID_VALUE);926}927928// Tests that buffer storage can be allocated with the GL_MAP_PERSISTENT_BIT_EXT and929// GL_MAP_COHERENT_BIT_EXT flags930TEST_P(BufferStorageTestES3, BufferStorageFlagsPersistentCoherentWrite)931{932ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));933934std::vector<GLfloat> data(6, 1.0f);935936GLBuffer buffer;937glBindBuffer(GL_ARRAY_BUFFER, buffer);938glBufferStorageEXT(GL_ARRAY_BUFFER, data.size(), data.data(),939GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);940ASSERT_GL_NO_ERROR();941}942943// Verify that glBufferStorage makes a buffer immutable944TEST_P(BufferStorageTestES3, StorageBufferBufferData)945{946ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||947!IsGLExtensionEnabled("GL_EXT_buffer_storage"));948949std::vector<GLfloat> data(6, 1.0f);950951GLBuffer buffer;952glBindBuffer(GL_ARRAY_BUFFER, buffer);953glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), 0);954ASSERT_GL_NO_ERROR();955956// Verify that calling glBufferStorageEXT again produces an error.957glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), 0);958EXPECT_GL_ERROR(GL_INVALID_OPERATION);959960// Verify that calling glBufferData after calling glBufferStorageEXT produces an error.961glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_STATIC_DRAW);962EXPECT_GL_ERROR(GL_INVALID_OPERATION);963}964965// Verify that glBufferStorageEXT can be called after glBufferData966TEST_P(BufferStorageTestES3, BufferDataStorageBuffer)967{968ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||969!IsGLExtensionEnabled("GL_EXT_buffer_storage"));970971std::vector<GLfloat> data(6, 1.0f);972973GLBuffer buffer;974glBindBuffer(GL_ARRAY_BUFFER, buffer);975glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_STATIC_DRAW);976ASSERT_GL_NO_ERROR();977978// Verify that calling glBufferStorageEXT again produces an error.979glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), 0);980ASSERT_GL_NO_ERROR();981}982983// Verify that we can perform subdata updates to a buffer marked with GL_DYNAMIC_STORAGE_BIT_EXT984// usage flag985TEST_P(BufferStorageTestES3, StorageBufferSubData)986{987ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||988!IsGLExtensionEnabled("GL_EXT_buffer_storage"));989990std::vector<GLfloat> data(6, 0.0f);991992glUseProgram(mProgram);993glBindBuffer(GL_ARRAY_BUFFER, mBuffer);994glBufferStorageEXT(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), nullptr,995GL_DYNAMIC_STORAGE_BIT_EXT);996glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * data.size(), data.data());997glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);998glEnableVertexAttribArray(mAttribLocation);9991000drawQuad(mProgram, "position", 0.5f);1001EXPECT_PIXEL_COLOR_EQ(8, 8, GLColor::black);1002EXPECT_GL_NO_ERROR();10031004std::vector<GLfloat> data2(6, 1.0f);1005glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * data2.size(), data2.data());10061007drawQuad(mProgram, "position", 0.5f);1008EXPECT_PIXEL_COLOR_EQ(8, 8, GLColor::red);1009EXPECT_GL_NO_ERROR();1010}10111012// Test interaction between GL_OES_mapbuffer and GL_EXT_buffer_storage extensions.1013TEST_P(BufferStorageTestES3, StorageBufferMapBufferOES)1014{1015ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||1016!IsGLExtensionEnabled("GL_EXT_buffer_storage") ||1017!IsGLExtensionEnabled("GL_EXT_map_buffer_range"));10181019std::vector<uint8_t> data(1024);1020FillVectorWithRandomUBytes(&data);10211022GLBuffer buffer;1023glBindBuffer(GL_ARRAY_BUFFER, buffer.get());1024glBufferStorageEXT(GL_ARRAY_BUFFER, data.size(), nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);10251026// Validate that other map flags don't work.1027void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);1028EXPECT_EQ(nullptr, badMapPtr);1029EXPECT_GL_ERROR(GL_INVALID_ENUM);10301031// Map and write.1032void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);1033ASSERT_NE(nullptr, mapPtr);1034ASSERT_GL_NO_ERROR();1035memcpy(mapPtr, data.data(), data.size());1036glUnmapBufferOES(GL_ARRAY_BUFFER);10371038// Validate data with EXT_map_buffer_range1039void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);1040ASSERT_NE(nullptr, readMapPtr);1041ASSERT_GL_NO_ERROR();1042std::vector<uint8_t> actualData(data.size());1043memcpy(actualData.data(), readMapPtr, data.size());1044glUnmapBufferOES(GL_ARRAY_BUFFER);10451046EXPECT_EQ(data, actualData);1047}10481049// Verify persistently mapped buffers can use glCopyBufferSubData1050// Tests a pattern used by Fortnite's GLES backend1051TEST_P(BufferStorageTestES3, StorageCopyBufferSubDataMapped)1052{1053ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||1054!IsGLExtensionEnabled("GL_EXT_buffer_storage") ||1055!IsGLExtensionEnabled("GL_EXT_map_buffer_range"));10561057const std::array<GLColor, 4> kInitialData = {GLColor::red, GLColor::green, GLColor::blue,1058GLColor::yellow};10591060// Set up the read buffer1061GLBuffer readBuffer;1062glBindBuffer(GL_ARRAY_BUFFER, readBuffer.get());1063glBufferData(GL_ARRAY_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW);10641065// Set up the write buffer to be persistently mapped1066GLBuffer writeBuffer;1067glBindBuffer(GL_COPY_WRITE_BUFFER, writeBuffer.get());1068glBufferStorageEXT(GL_COPY_WRITE_BUFFER, 16, nullptr,1069GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);1070void *readMapPtr =1071glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, 16,1072GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);1073ASSERT_NE(nullptr, readMapPtr);1074ASSERT_GL_NO_ERROR();10751076// Verify we can copy into the write buffer1077glBindBuffer(GL_COPY_READ_BUFFER, readBuffer.get());1078glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 16);1079ASSERT_GL_NO_ERROR();10801081// Flush the buffer.1082glFinish();10831084// Check the contents1085std::array<GLColor, 4> resultingData;1086memcpy(resultingData.data(), readMapPtr, resultingData.size() * sizeof(GLColor));1087glUnmapBuffer(GL_COPY_WRITE_BUFFER);1088EXPECT_EQ(kInitialData, resultingData);1089ASSERT_GL_NO_ERROR();1090}10911092// Verify persistently mapped buffers can use glBufferSubData1093TEST_P(BufferStorageTestES3, StorageBufferSubDataMapped)1094{1095ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||1096!IsGLExtensionEnabled("GL_EXT_buffer_storage") ||1097!IsGLExtensionEnabled("GL_EXT_map_buffer_range"));10981099const std::array<GLColor, 4> kUpdateData1 = {GLColor::red, GLColor::green, GLColor::blue,1100GLColor::yellow};11011102// Set up the buffer to be persistently mapped and dynamic1103GLBuffer buffer;1104glBindBuffer(GL_ARRAY_BUFFER, buffer.get());1105glBufferStorageEXT(GL_ARRAY_BUFFER, 16, nullptr,1106GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT |1107GL_MAP_COHERENT_BIT_EXT | GL_DYNAMIC_STORAGE_BIT_EXT);1108void *readMapPtr = glMapBufferRange(1109GL_ARRAY_BUFFER, 0, 16,1110GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);1111ASSERT_NE(nullptr, readMapPtr);1112ASSERT_GL_NO_ERROR();11131114// Verify we can push new data into the buffer1115glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLColor) * kUpdateData1.size(), kUpdateData1.data());1116ASSERT_GL_NO_ERROR();11171118// Flush the buffer.1119glFinish();11201121// Check the contents1122std::array<GLColor, 4> persistentData1;1123memcpy(persistentData1.data(), readMapPtr, persistentData1.size() * sizeof(GLColor));1124EXPECT_EQ(kUpdateData1, persistentData1);1125glUnmapBuffer(GL_ARRAY_BUFFER);1126ASSERT_GL_NO_ERROR();1127}11281129ANGLE_INSTANTIATE_TEST_ES2(BufferDataTest);11301131GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferDataTestES3);1132ANGLE_INSTANTIATE_TEST_ES3_AND(BufferDataTestES3, WithDirectSPIRVGeneration(ES3_VULKAN()));11331134GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferStorageTestES3);1135ANGLE_INSTANTIATE_TEST_ES3(BufferStorageTestES3);11361137GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IndexedBufferCopyTest);1138ANGLE_INSTANTIATE_TEST_ES3(IndexedBufferCopyTest);11391140#ifdef _WIN6411411142// Test a bug where an integer overflow bug could trigger a crash in D3D.1143// The test uses 8 buffers with a size just under 0x2000000 to overflow max uint1144// (with the internal D3D rounding to 16-byte values) and trigger the bug.1145// Only handle this bug on 64-bit Windows for now. Harder to repro on 32-bit.1146class BufferDataOverflowTest : public ANGLETest1147{1148protected:1149BufferDataOverflowTest() {}1150};11511152// See description above.1153TEST_P(BufferDataOverflowTest, VertexBufferIntegerOverflow)1154{1155// These values are special, to trigger the rounding bug.1156unsigned int numItems = 0x7FFFFFE;1157constexpr GLsizei bufferCnt = 8;11581159std::vector<GLBuffer> buffers(bufferCnt);11601161std::stringstream vertexShaderStr;11621163for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)1164{1165vertexShaderStr << "attribute float attrib" << bufferIndex << ";\n";1166}11671168vertexShaderStr << "attribute vec2 position;\n"1169"varying float v_attrib;\n"1170"void main() {\n"1171" gl_Position = vec4(position, 0, 1);\n"1172" v_attrib = 0.0;\n";11731174for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)1175{1176vertexShaderStr << "v_attrib += attrib" << bufferIndex << ";\n";1177}11781179vertexShaderStr << "}";11801181constexpr char kFS[] =1182"varying highp float v_attrib;\n"1183"void main() {\n"1184" gl_FragColor = vec4(v_attrib, 0, 0, 1);\n"1185"}";11861187ANGLE_GL_PROGRAM(program, vertexShaderStr.str().c_str(), kFS);1188glUseProgram(program.get());11891190std::vector<GLfloat> data(numItems, 1.0f);11911192for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)1193{1194glBindBuffer(GL_ARRAY_BUFFER, buffers[bufferIndex].get());1195glBufferData(GL_ARRAY_BUFFER, numItems * sizeof(float), &data[0], GL_DYNAMIC_DRAW);11961197std::stringstream attribNameStr;1198attribNameStr << "attrib" << bufferIndex;11991200GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());1201ASSERT_NE(-1, attribLocation);12021203glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);1204glEnableVertexAttribArray(attribLocation);1205}12061207GLint positionLocation = glGetAttribLocation(program.get(), "position");1208ASSERT_NE(-1, positionLocation);1209glDisableVertexAttribArray(positionLocation);1210glVertexAttrib2f(positionLocation, 1.0f, 1.0f);12111212EXPECT_GL_NO_ERROR();1213glDrawArrays(GL_TRIANGLES, 0, numItems);1214EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);12151216// Test that a small draw still works.1217for (GLsizei bufferIndex = 0; bufferIndex < bufferCnt; ++bufferIndex)1218{1219std::stringstream attribNameStr;1220attribNameStr << "attrib" << bufferIndex;1221GLint attribLocation = glGetAttribLocation(program.get(), attribNameStr.str().c_str());1222ASSERT_NE(-1, attribLocation);1223glDisableVertexAttribArray(attribLocation);1224}12251226glDrawArrays(GL_TRIANGLES, 0, 3);1227EXPECT_GL_ERROR(GL_NO_ERROR);1228}12291230// Tests a security bug in our CopyBufferSubData validation (integer overflow).1231TEST_P(BufferDataOverflowTest, CopySubDataValidation)1232{1233GLBuffer readBuffer, writeBuffer;12341235glBindBuffer(GL_COPY_READ_BUFFER, readBuffer.get());1236glBindBuffer(GL_COPY_WRITE_BUFFER, writeBuffer.get());12371238constexpr int bufSize = 100;12391240glBufferData(GL_COPY_READ_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);1241glBufferData(GL_COPY_WRITE_BUFFER, bufSize, nullptr, GL_STATIC_DRAW);12421243GLintptr big = std::numeric_limits<GLintptr>::max() - bufSize + 90;12441245glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, big, 0, 50);1246EXPECT_GL_ERROR(GL_INVALID_VALUE);12471248glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, big, 50);1249EXPECT_GL_ERROR(GL_INVALID_VALUE);1250}12511252ANGLE_INSTANTIATE_TEST_ES3(BufferDataOverflowTest);12531254#endif // _WIN64125512561257