|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "gpu/command_buffer/service/buffer_manager.h" | 
|  | #include "gpu/command_buffer/service/error_state_mock.h" | 
|  | #include "gpu/command_buffer/service/feature_info.h" | 
|  | #include "gpu/command_buffer/service/gpu_service_test.h" | 
|  | #include "gpu/command_buffer/service/mocks.h" | 
|  | #include "gpu/command_buffer/service/test_helper.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "ui/gl/gl_mock.h" | 
|  |  | 
|  | using ::testing::_; | 
|  | using ::testing::Return; | 
|  | using ::testing::StrictMock; | 
|  |  | 
|  | namespace gpu { | 
|  | namespace gles2 { | 
|  |  | 
|  | class BufferManagerTestBase : public GpuServiceTest { | 
|  | protected: | 
|  | void SetUpBase( | 
|  | MemoryTracker* memory_tracker, | 
|  | FeatureInfo* feature_info, | 
|  | const char* extensions) { | 
|  | GpuServiceTest::SetUp(); | 
|  | if (feature_info) { | 
|  | TestHelper::SetupFeatureInfoInitExpectations(gl_.get(), extensions); | 
|  | feature_info->InitializeForTesting(); | 
|  | } | 
|  | error_state_.reset(new MockErrorState()); | 
|  | manager_.reset(new BufferManager(memory_tracker, feature_info)); | 
|  | } | 
|  |  | 
|  | void TearDown() override { | 
|  | manager_->MarkContextLost(); | 
|  | manager_->Destroy(); | 
|  | manager_.reset(); | 
|  | error_state_.reset(); | 
|  | GpuServiceTest::TearDown(); | 
|  | } | 
|  |  | 
|  | GLenum GetInitialTarget(const Buffer* buffer) const { | 
|  | return buffer->initial_target(); | 
|  | } | 
|  |  | 
|  | void DoBufferData( | 
|  | Buffer* buffer, GLenum target, GLsizeiptr size, GLenum usage, | 
|  | const GLvoid* data, GLenum error) { | 
|  | TestHelper::DoBufferData( | 
|  | gl_.get(), error_state_.get(), manager_.get(), | 
|  | buffer, target, size, usage, data, error); | 
|  | } | 
|  |  | 
|  | bool DoBufferSubData( | 
|  | Buffer* buffer, GLenum target, GLintptr offset, GLsizeiptr size, | 
|  | const GLvoid* data) { | 
|  | bool success = true; | 
|  | if (!buffer->CheckRange(offset, size)) { | 
|  | EXPECT_CALL(*error_state_, SetGLError(_, _, GL_INVALID_VALUE, _, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | success = false; | 
|  | } else if (!buffer->IsClientSideArray()) { | 
|  | EXPECT_CALL(*gl_, BufferSubData(target, offset, size, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | manager_->DoBufferSubData( | 
|  | error_state_.get(), buffer, target, offset, size, data); | 
|  | return success; | 
|  | } | 
|  |  | 
|  | void RunGetMaxValueForRangeUint8Test(bool enable_primitive_restart) | 
|  | { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const uint8_t data[] = {10, 9, 8, 7, 6, 0xFFu, 4, 3, 2, 1}; | 
|  | const uint8_t new_data[] = {100, 120, 110}; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); | 
|  | GLuint max_value; | 
|  | // Check entire range succeeds. | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 0, 10, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); | 
|  | if (enable_primitive_restart) { | 
|  | EXPECT_EQ(10u, max_value); | 
|  | } else { | 
|  | EXPECT_EQ(0xFFu, max_value); | 
|  | } | 
|  | // Check sub range succeeds. | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 4, 3, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); | 
|  | if (enable_primitive_restart) { | 
|  | EXPECT_EQ(6u, max_value); | 
|  | } else { | 
|  | EXPECT_EQ(0xFFu, max_value); | 
|  | } | 
|  | // Check changing sub range succeeds. | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 4, sizeof(new_data), | 
|  | new_data)); | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 4, 3, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); | 
|  | EXPECT_EQ(120u, max_value); | 
|  | max_value = 0; | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 0, 10, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); | 
|  | EXPECT_EQ(120u, max_value); | 
|  | // Check out of range fails. | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 0, 11, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 10, 1, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); | 
|  | } | 
|  |  | 
|  | void RunGetMaxValueForRangeUint16Test(bool enable_primitive_restart) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const uint16_t data[] = {10, 9, 8, 7, 6, 0xFFFF, 4, 3, 2, 1}; | 
|  | const uint16_t new_data[] = {100, 120, 110}; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); | 
|  | GLuint max_value; | 
|  | // Check entire range succeeds. | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 0, 10, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | if (enable_primitive_restart) { | 
|  | EXPECT_EQ(10u, max_value); | 
|  | } else { | 
|  | EXPECT_EQ(0xFFFFu, max_value); | 
|  | } | 
|  | // Check odd offset fails for GL_UNSIGNED_SHORT. | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 1, 10, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | // Check sub range succeeds. | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 8, 3, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | if (enable_primitive_restart) { | 
|  | EXPECT_EQ(6u, max_value); | 
|  | } else { | 
|  | EXPECT_EQ(0xFFFFu, max_value); | 
|  | } | 
|  | // Check changing sub range succeeds. | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 8, sizeof(new_data), | 
|  | new_data)); | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 8, 3, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_EQ(120u, max_value); | 
|  | max_value = 0; | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 0, 10, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_EQ(120u, max_value); | 
|  | // Check out of range fails. | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 0, 11, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 20, 1, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); | 
|  | } | 
|  |  | 
|  | void RunGetMaxValueForRangeUint32Test(bool enable_primitive_restart) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const uint32_t data[] = {10, 9, 8, 7, 6, 0xFFFFFFFFu, 4, 3, 2, 1}; | 
|  | const uint32_t new_data[] = {100, 120, 110}; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); | 
|  | GLuint max_value; | 
|  | // Check entire range succeeds. | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 0, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | if (enable_primitive_restart) { | 
|  | EXPECT_EQ(10u, max_value); | 
|  | } else { | 
|  | EXPECT_EQ(0xFFFFFFFFu, max_value); | 
|  | } | 
|  | // Check non aligned offsets fails for GL_UNSIGNED_INT. | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 1, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 2, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 3, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | // Check sub range succeeds. | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 16, 3, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | if (enable_primitive_restart) { | 
|  | EXPECT_EQ(6u, max_value); | 
|  | } else { | 
|  | EXPECT_EQ(0xFFFFFFFFu, max_value); | 
|  | } | 
|  | // Check changing sub range succeeds. | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 16, sizeof(new_data), | 
|  | new_data)); | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 16, 3, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_EQ(120u, max_value); | 
|  | max_value = 0; | 
|  | EXPECT_TRUE(buffer->GetMaxValueForRange( | 
|  | 0, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_EQ(120u, max_value); | 
|  | // Check out of range fails. | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 0, 11, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | EXPECT_FALSE(buffer->GetMaxValueForRange( | 
|  | 40, 1, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<BufferManager> manager_; | 
|  | std::unique_ptr<MockErrorState> error_state_; | 
|  | }; | 
|  |  | 
|  | class BufferManagerTest : public BufferManagerTestBase { | 
|  | protected: | 
|  | void SetUp() override { SetUpBase(NULL, NULL, ""); } | 
|  | }; | 
|  |  | 
|  | class BufferManagerMemoryTrackerTest : public BufferManagerTestBase { | 
|  | protected: | 
|  | void SetUp() override { | 
|  | mock_memory_tracker_ = new StrictMock<MockMemoryTracker>(); | 
|  | SetUpBase(mock_memory_tracker_.get(), NULL, ""); | 
|  | } | 
|  |  | 
|  | scoped_refptr<MockMemoryTracker> mock_memory_tracker_; | 
|  | }; | 
|  |  | 
|  | class BufferManagerClientSideArraysTest : public BufferManagerTestBase { | 
|  | protected: | 
|  | void SetUp() override { | 
|  | GpuDriverBugWorkarounds gpu_driver_bug_workarounds; | 
|  | gpu_driver_bug_workarounds.use_client_side_arrays_for_stream_buffers = true; | 
|  | feature_info_ = new FeatureInfo(gpu_driver_bug_workarounds); | 
|  | SetUpBase(NULL, feature_info_.get(), ""); | 
|  | } | 
|  |  | 
|  | scoped_refptr<FeatureInfo> feature_info_; | 
|  | }; | 
|  |  | 
|  | #define EXPECT_MEMORY_ALLOCATION_CHANGE(old_size, new_size)   \ | 
|  | EXPECT_CALL(*mock_memory_tracker_.get(),                          \ | 
|  | TrackMemoryAllocatedChange(old_size, new_size)) \ | 
|  | .Times(1).RetiresOnSaturation() | 
|  |  | 
|  | TEST_F(BufferManagerTest, Basic) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBuffer1Id = 1; | 
|  | const GLuint kServiceBuffer1Id = 11; | 
|  | const GLsizeiptr kBuffer1Size = 123; | 
|  | const GLuint kClientBuffer2Id = 2; | 
|  | // Check we can create buffer. | 
|  | manager_->CreateBuffer(kClientBuffer1Id, kServiceBuffer1Id); | 
|  | // Check buffer got created. | 
|  | Buffer* buffer1 = manager_->GetBuffer(kClientBuffer1Id); | 
|  | ASSERT_TRUE(buffer1 != NULL); | 
|  | EXPECT_EQ(0u, GetInitialTarget(buffer1)); | 
|  | EXPECT_EQ(0, buffer1->size()); | 
|  | EXPECT_EQ(static_cast<GLenum>(GL_STATIC_DRAW), buffer1->usage()); | 
|  | EXPECT_FALSE(buffer1->IsDeleted()); | 
|  | EXPECT_FALSE(buffer1->IsClientSideArray()); | 
|  | EXPECT_EQ(kServiceBuffer1Id, buffer1->service_id()); | 
|  | GLuint client_id = 0; | 
|  | EXPECT_TRUE(manager_->GetClientId(buffer1->service_id(), &client_id)); | 
|  | EXPECT_EQ(kClientBuffer1Id, client_id); | 
|  | manager_->SetTarget(buffer1, kTarget); | 
|  | EXPECT_EQ(kTarget, GetInitialTarget(buffer1)); | 
|  | // Check we and set its size. | 
|  | DoBufferData( | 
|  | buffer1, kTarget, kBuffer1Size, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_EQ(kBuffer1Size, buffer1->size()); | 
|  | EXPECT_EQ(static_cast<GLenum>(GL_DYNAMIC_DRAW), buffer1->usage()); | 
|  | // Check we get nothing for a non-existent buffer. | 
|  | EXPECT_TRUE(manager_->GetBuffer(kClientBuffer2Id) == NULL); | 
|  | // Check trying to a remove non-existent buffers does not crash. | 
|  | manager_->RemoveBuffer(kClientBuffer2Id); | 
|  | // Check that it gets deleted when the last reference is released. | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kServiceBuffer1Id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | // Check we can't get the buffer after we remove it. | 
|  | manager_->RemoveBuffer(kClientBuffer1Id); | 
|  | EXPECT_TRUE(manager_->GetBuffer(kClientBuffer1Id) == NULL); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerMemoryTrackerTest, Basic) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBuffer1Id = 1; | 
|  | const GLuint kServiceBuffer1Id = 11; | 
|  | const GLsizeiptr kBuffer1Size1 = 123; | 
|  | const GLsizeiptr kBuffer1Size2 = 456; | 
|  | // Check we can create buffer. | 
|  | EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0); | 
|  | manager_->CreateBuffer(kClientBuffer1Id, kServiceBuffer1Id); | 
|  | // Check buffer got created. | 
|  | Buffer* buffer1 = manager_->GetBuffer(kClientBuffer1Id); | 
|  | ASSERT_TRUE(buffer1 != NULL); | 
|  | manager_->SetTarget(buffer1, kTarget); | 
|  | // Check we and set its size. | 
|  | EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size1); | 
|  | DoBufferData( | 
|  | buffer1, kTarget, kBuffer1Size1, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size1, 0); | 
|  | EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size2); | 
|  | DoBufferData( | 
|  | buffer1, kTarget, kBuffer1Size2, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR); | 
|  | // On delete it will get freed. | 
|  | EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size2, 0); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, Destroy) { | 
|  | const GLuint kClient1Id = 1; | 
|  | const GLuint kService1Id = 11; | 
|  | // Check we can create buffer. | 
|  | manager_->CreateBuffer(kClient1Id, kService1Id); | 
|  | // Check buffer got created. | 
|  | Buffer* buffer1 = manager_->GetBuffer(kClient1Id); | 
|  | ASSERT_TRUE(buffer1 != NULL); | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kService1Id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | manager_->Destroy(); | 
|  | // Check the resources were released. | 
|  | buffer1 = manager_->GetBuffer(kClient1Id); | 
|  | ASSERT_TRUE(buffer1 == NULL); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, DoBufferSubData) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const uint8_t data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); | 
|  | EXPECT_TRUE(DoBufferSubData(buffer, kTarget, sizeof(data), 0, data)); | 
|  | EXPECT_FALSE(DoBufferSubData(buffer, kTarget, sizeof(data), 1, data)); | 
|  | EXPECT_FALSE(DoBufferSubData(buffer, kTarget, 0, sizeof(data) + 1, data)); | 
|  | EXPECT_FALSE(DoBufferSubData(buffer, kTarget, -1, sizeof(data), data)); | 
|  | EXPECT_FALSE(DoBufferSubData(buffer, kTarget, 0, -1, data)); | 
|  | DoBufferData(buffer, kTarget, 1, GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | const int size = 0x20000; | 
|  | std::unique_ptr<uint8_t[]> temp(new uint8_t[size]); | 
|  | EXPECT_FALSE(DoBufferSubData(buffer, kTarget, 0 - size, size, temp.get())); | 
|  | EXPECT_FALSE(DoBufferSubData(buffer, kTarget, 1, size / 2, temp.get())); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetRange) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const GLsizeiptr kDataSize = 10; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | DoBufferData(buffer, kTarget, kDataSize, GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | const char* buf = | 
|  | static_cast<const char*>(buffer->GetRange(0, kDataSize)); | 
|  | ASSERT_TRUE(buf != NULL); | 
|  | const char* buf1 = | 
|  | static_cast<const char*>(buffer->GetRange(1, kDataSize - 1)); | 
|  | EXPECT_EQ(buf + 1, buf1); | 
|  | EXPECT_TRUE(buffer->GetRange(kDataSize, 1) == NULL); | 
|  | EXPECT_TRUE(buffer->GetRange(0, kDataSize + 1) == NULL); | 
|  | EXPECT_TRUE(buffer->GetRange(-1, kDataSize) == NULL); | 
|  | EXPECT_TRUE(buffer->GetRange(-0, -1) == NULL); | 
|  | const int size = 0x20000; | 
|  | DoBufferData(buffer, kTarget, size / 2, GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | EXPECT_TRUE(buffer->GetRange(0 - size, size) == NULL); | 
|  | EXPECT_TRUE(buffer->GetRange(1, size / 2) == NULL); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) { | 
|  | RunGetMaxValueForRangeUint8Test(false); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetMaxValueForRangeUint8PrimitiveRestart) { | 
|  | RunGetMaxValueForRangeUint8Test(true); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) { | 
|  | RunGetMaxValueForRangeUint16Test(false); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetMaxValueForRangeUint16PrimitiveRestart) { | 
|  | RunGetMaxValueForRangeUint16Test(true); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) { | 
|  | RunGetMaxValueForRangeUint32Test(false); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, GetMaxValueForRangeUint32PrimitiveRestart) { | 
|  | RunGetMaxValueForRangeUint32Test(true); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, UseDeletedBuffer) { | 
|  | const GLenum kTarget = GL_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const GLsizeiptr kDataSize = 10; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | scoped_refptr<Buffer> buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer.get() != NULL); | 
|  | manager_->SetTarget(buffer.get(), kTarget); | 
|  | // Remove buffer | 
|  | manager_->RemoveBuffer(kClientBufferId); | 
|  | // Use it after removing | 
|  | DoBufferData( | 
|  | buffer.get(), kTarget, kDataSize, GL_STATIC_DRAW, NULL, GL_NO_ERROR); | 
|  | // Check that it gets deleted when the last reference is released. | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kServiceBufferId))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | buffer = NULL; | 
|  | } | 
|  |  | 
|  | // Test buffers get shadowed when they are supposed to be. | 
|  | TEST_F(BufferManagerClientSideArraysTest, StreamBuffersAreShadowed) { | 
|  | const GLenum kTarget = GL_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | static const uint32_t data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data), GL_STREAM_DRAW, data, GL_NO_ERROR); | 
|  | EXPECT_TRUE(buffer->IsClientSideArray()); | 
|  | EXPECT_EQ(0, memcmp(data, buffer->GetRange(0, sizeof(data)), sizeof(data))); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data), GL_DYNAMIC_DRAW, data, GL_NO_ERROR); | 
|  | EXPECT_FALSE(buffer->IsClientSideArray()); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, MaxValueCacheClearedCorrectly) { | 
|  | const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; | 
|  | const GLuint kClientBufferId = 1; | 
|  | const GLuint kServiceBufferId = 11; | 
|  | const uint32_t data1[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; | 
|  | const uint32_t data2[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; | 
|  | const uint32_t data3[] = {30, 29, 28}; | 
|  | manager_->CreateBuffer(kClientBufferId, kServiceBufferId); | 
|  | Buffer* buffer = manager_->GetBuffer(kClientBufferId); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | manager_->SetTarget(buffer, kTarget); | 
|  | GLuint max_value; | 
|  | // Load the buffer with some initial data, and then get the maximum value for | 
|  | // a range, which has the side effect of caching it. | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data1), GL_STATIC_DRAW, data1, GL_NO_ERROR); | 
|  | EXPECT_TRUE( | 
|  | buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, false, &max_value)); | 
|  | EXPECT_EQ(10u, max_value); | 
|  | // Check that any cached values are invalidated if the buffer is reloaded | 
|  | // with the same amount of data (but different content) | 
|  | ASSERT_EQ(sizeof(data2), sizeof(data1)); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data2), GL_STATIC_DRAW, data2, GL_NO_ERROR); | 
|  | EXPECT_TRUE( | 
|  | buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, false, &max_value)); | 
|  | EXPECT_EQ(20u, max_value); | 
|  | // Check that any cached values are invalidated if the buffer is reloaded | 
|  | // with entirely different content. | 
|  | ASSERT_NE(sizeof(data3), sizeof(data1)); | 
|  | DoBufferData( | 
|  | buffer, kTarget, sizeof(data3), GL_STATIC_DRAW, data3, GL_NO_ERROR); | 
|  | EXPECT_TRUE( | 
|  | buffer->GetMaxValueForRange(0, 3, GL_UNSIGNED_INT, false, &max_value)); | 
|  | EXPECT_EQ(30u, max_value); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, BindBufferConflicts) { | 
|  | manager_->set_allow_buffers_on_multiple_targets(false); | 
|  | GLuint client_id = 1; | 
|  | GLuint service_id = 101; | 
|  |  | 
|  | { | 
|  | // Once a buffer is bound to ELEMENT_ARRAY_BUFFER, it can't be bound to | 
|  | // any other targets except for GL_COPY_READ/WRITE_BUFFER. | 
|  | manager_->CreateBuffer(client_id, service_id); | 
|  | Buffer* buffer = manager_->GetBuffer(client_id); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER)); | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, GL_COPY_READ_BUFFER)); | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, GL_COPY_WRITE_BUFFER)); | 
|  | EXPECT_FALSE(manager_->SetTarget(buffer, GL_ARRAY_BUFFER)); | 
|  | EXPECT_FALSE(manager_->SetTarget(buffer, GL_PIXEL_PACK_BUFFER)); | 
|  | EXPECT_FALSE(manager_->SetTarget(buffer, GL_PIXEL_UNPACK_BUFFER)); | 
|  | EXPECT_FALSE(manager_->SetTarget(buffer, GL_TRANSFORM_FEEDBACK_BUFFER)); | 
|  | EXPECT_FALSE(manager_->SetTarget(buffer, GL_UNIFORM_BUFFER)); | 
|  | } | 
|  |  | 
|  | { | 
|  | // Except for ELEMENT_ARRAY_BUFFER, a buffer can switch to any targets. | 
|  | const GLenum kTargets[] = { | 
|  | GL_ARRAY_BUFFER, | 
|  | GL_COPY_READ_BUFFER, | 
|  | GL_COPY_WRITE_BUFFER, | 
|  | GL_PIXEL_PACK_BUFFER, | 
|  | GL_PIXEL_UNPACK_BUFFER, | 
|  | GL_TRANSFORM_FEEDBACK_BUFFER, | 
|  | GL_UNIFORM_BUFFER | 
|  | }; | 
|  | for (size_t ii = 0; ii < arraysize(kTargets); ++ii) { | 
|  | client_id++; | 
|  | service_id++; | 
|  | manager_->CreateBuffer(client_id, service_id); | 
|  | Buffer* buffer = manager_->GetBuffer(client_id); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  |  | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, kTargets[ii])); | 
|  | for (size_t jj = 0; jj < arraysize(kTargets); ++jj) { | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, kTargets[jj])); | 
|  | } | 
|  | EXPECT_EQ(kTargets[ii], GetInitialTarget(buffer)); | 
|  | } | 
|  | } | 
|  |  | 
|  | { | 
|  | // Once a buffer is bound to non ELEMENT_ARRAY_BUFFER target, it can't be | 
|  | // bound to ELEMENT_ARRAY_BUFFER target. | 
|  | const GLenum kTargets[] = { | 
|  | GL_ARRAY_BUFFER, | 
|  | GL_COPY_READ_BUFFER, | 
|  | GL_COPY_WRITE_BUFFER, | 
|  | GL_PIXEL_PACK_BUFFER, | 
|  | GL_PIXEL_UNPACK_BUFFER, | 
|  | GL_TRANSFORM_FEEDBACK_BUFFER, | 
|  | GL_UNIFORM_BUFFER | 
|  | }; | 
|  | for (size_t ii = 0; ii < arraysize(kTargets); ++ii) { | 
|  | client_id++; | 
|  | service_id++; | 
|  | manager_->CreateBuffer(client_id, service_id); | 
|  | Buffer* buffer = manager_->GetBuffer(client_id); | 
|  | ASSERT_TRUE(buffer != NULL); | 
|  |  | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, kTargets[ii])); | 
|  | for (size_t jj = 0; jj < arraysize(kTargets); ++jj) { | 
|  | EXPECT_TRUE(manager_->SetTarget(buffer, kTargets[jj])); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(BufferManagerTest, DeleteBufferAfterContextLost) { | 
|  | const GLuint kClient1Id = 1; | 
|  | const GLuint kService1Id = 11; | 
|  | manager_->CreateBuffer(kClient1Id, kService1Id); | 
|  | Buffer* buffer1 = manager_->GetBuffer(kClient1Id); | 
|  | ASSERT_TRUE(buffer1 != nullptr); | 
|  | manager_->MarkContextLost(); | 
|  | // Removing buffers after MarkContextLost cause no GL calls. | 
|  | manager_->RemoveBuffer(kClient1Id); | 
|  | manager_->Destroy(); | 
|  | // Check the resources were released. | 
|  | buffer1 = manager_->GetBuffer(kClient1Id); | 
|  | ASSERT_TRUE(buffer1 == nullptr); | 
|  | } | 
|  |  | 
|  | }  // namespace gles2 | 
|  | }  // namespace gpu | 
|  |  | 
|  |  |