// 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 "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->Initialize(); } error_state_.reset(new MockErrorState()); manager_.reset(new BufferManager(memory_tracker, feature_info)); } void TearDown() override { manager_->Destroy(false); 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; } scoped_ptr manager_; scoped_ptr 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(); SetUpBase(mock_memory_tracker_.get(), NULL, ""); } scoped_refptr mock_memory_tracker_; }; class BufferManagerClientSideArraysTest : public BufferManagerTestBase { protected: void SetUp() override { feature_info_ = new FeatureInfo(); feature_info_->workarounds_.use_client_side_arrays_for_stream_buffers = true; SetUpBase(NULL, feature_info_.get(), ""); } scoped_refptr feature_info_; }; #define EXPECT_MEMORY_ALLOCATION_CHANGE(old_size, new_size, pool) \ EXPECT_CALL(*mock_memory_tracker_.get(), \ TrackMemoryAllocatedChange(old_size, new_size, pool)) \ .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(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(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, MemoryTracker::kManaged); 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, MemoryTracker::kManaged); DoBufferData( buffer1, kTarget, kBuffer1Size1, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR); EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size1, 0, MemoryTracker::kManaged); EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size2, MemoryTracker::kManaged); DoBufferData( buffer1, kTarget, kBuffer1Size2, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR); // On delete it will get freed. EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size2, 0, MemoryTracker::kManaged); } 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(true); // 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 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; scoped_ptr temp(new uint8[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(buffer->GetRange(0, kDataSize)); ASSERT_TRUE(buf != NULL); const char* buf1 = static_cast(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) { const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; const GLuint kClientBufferId = 1; const GLuint kServiceBufferId = 11; const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; const uint8 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, &max_value)); EXPECT_EQ(10u, max_value); // Check sub range succeeds. EXPECT_TRUE(buffer->GetMaxValueForRange( 4, 3, GL_UNSIGNED_BYTE, &max_value)); EXPECT_EQ(6u, 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, &max_value)); EXPECT_EQ(120u, max_value); max_value = 0; EXPECT_TRUE(buffer->GetMaxValueForRange( 0, 10, GL_UNSIGNED_BYTE, &max_value)); EXPECT_EQ(120u, max_value); // Check out of range fails. EXPECT_FALSE(buffer->GetMaxValueForRange( 0, 11, GL_UNSIGNED_BYTE, &max_value)); EXPECT_FALSE(buffer->GetMaxValueForRange( 10, 1, GL_UNSIGNED_BYTE, &max_value)); } TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) { const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; const GLuint kClientBufferId = 1; const GLuint kServiceBufferId = 11; const uint16 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; const uint16 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, &max_value)); EXPECT_EQ(10u, max_value); // Check odd offset fails for GL_UNSIGNED_SHORT. EXPECT_FALSE(buffer->GetMaxValueForRange( 1, 10, GL_UNSIGNED_SHORT, &max_value)); // Check sub range succeeds. EXPECT_TRUE(buffer->GetMaxValueForRange( 8, 3, GL_UNSIGNED_SHORT, &max_value)); EXPECT_EQ(6u, 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, &max_value)); EXPECT_EQ(120u, max_value); max_value = 0; EXPECT_TRUE(buffer->GetMaxValueForRange( 0, 10, GL_UNSIGNED_SHORT, &max_value)); EXPECT_EQ(120u, max_value); // Check out of range fails. EXPECT_FALSE(buffer->GetMaxValueForRange( 0, 11, GL_UNSIGNED_SHORT, &max_value)); EXPECT_FALSE(buffer->GetMaxValueForRange( 20, 1, GL_UNSIGNED_SHORT, &max_value)); } TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) { const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; const GLuint kClientBufferId = 1; const GLuint kServiceBufferId = 11; const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; const uint32 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, &max_value)); EXPECT_EQ(10u, max_value); // Check non aligned offsets fails for GL_UNSIGNED_INT. EXPECT_FALSE( buffer->GetMaxValueForRange(1, 10, GL_UNSIGNED_INT, &max_value)); EXPECT_FALSE( buffer->GetMaxValueForRange(2, 10, GL_UNSIGNED_INT, &max_value)); EXPECT_FALSE( buffer->GetMaxValueForRange(3, 10, GL_UNSIGNED_INT, &max_value)); // Check sub range succeeds. EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value)); EXPECT_EQ(6u, 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, &max_value)); EXPECT_EQ(120u, max_value); max_value = 0; EXPECT_TRUE(buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value)); EXPECT_EQ(120u, max_value); // Check out of range fails. EXPECT_FALSE( buffer->GetMaxValueForRange(0, 11, GL_UNSIGNED_INT, &max_value)); EXPECT_FALSE( buffer->GetMaxValueForRange(40, 1, GL_UNSIGNED_INT, &max_value)); } 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 = 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 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 data1[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; const uint32 data2[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; const uint32 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, &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, &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, &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])); } } } } } // namespace gles2 } // namespace gpu