|  | // Copyright (c) 2016 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/gpu_service_test.h" | 
|  | #include "gpu/command_buffer/service/indexed_buffer_binding_host.h" | 
|  | #include "ui/gl/gl_mock.h" | 
|  |  | 
|  | namespace gpu { | 
|  | namespace gles2 { | 
|  |  | 
|  | namespace { | 
|  | const uint32_t kMaxBindings = 16; | 
|  | const GLuint kBufferClientId = 87; | 
|  | const GLuint kBufferServiceId = 987; | 
|  | }  // namespace anonymous | 
|  |  | 
|  | class IndexedBufferBindingHostTest : public GpuServiceTest { | 
|  | public: | 
|  | IndexedBufferBindingHostTest() | 
|  | : host_(new IndexedBufferBindingHost(kMaxBindings, true)), | 
|  | buffer_manager_(new BufferManager(nullptr, nullptr)) { | 
|  | buffer_manager_->CreateBuffer(kBufferClientId, kBufferServiceId); | 
|  | buffer_ = buffer_manager_->GetBuffer(kBufferClientId); | 
|  | DCHECK(buffer_.get()); | 
|  | } | 
|  |  | 
|  | ~IndexedBufferBindingHostTest() override {} | 
|  |  | 
|  | protected: | 
|  | void SetUp() override { | 
|  | GpuServiceTest::SetUpWithGLVersion("4.1", ""); | 
|  | } | 
|  |  | 
|  | void TearDown() override { | 
|  | host_->RemoveBoundBuffer(buffer_.get()); | 
|  | buffer_ = nullptr; | 
|  | buffer_manager_->MarkContextLost(); | 
|  | buffer_manager_->Destroy(); | 
|  | buffer_manager_.reset(); | 
|  | GpuServiceTest::TearDown(); | 
|  | } | 
|  |  | 
|  | void SetBufferSize(GLenum target, GLsizeiptr size) { | 
|  | buffer_manager_->SetInfo( | 
|  | buffer_.get(), target, size, GL_STATIC_DRAW, false); | 
|  | } | 
|  |  | 
|  | scoped_refptr<IndexedBufferBindingHost> host_; | 
|  | std::unique_ptr<BufferManager> buffer_manager_; | 
|  | scoped_refptr<Buffer> buffer_; | 
|  | }; | 
|  |  | 
|  | TEST_F(IndexedBufferBindingHostTest, DoBindBufferRangeUninitializedBuffer) { | 
|  | const GLenum kTarget = GL_TRANSFORM_FEEDBACK_BUFFER; | 
|  | const GLuint kIndex = 2; | 
|  | const GLintptr kOffset = 4; | 
|  | const GLsizeiptr kSize = 8; | 
|  |  | 
|  | EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, kBufferServiceId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | host_->DoBindBufferRange(kTarget, kIndex, buffer_.get(), kOffset, kSize); | 
|  |  | 
|  | for (uint32_t index = 0; index < kMaxBindings; ++index) { | 
|  | if (index != kIndex) { | 
|  | EXPECT_EQ(nullptr, host_->GetBufferBinding(index)); | 
|  | } else { | 
|  | EXPECT_EQ(buffer_.get(), host_->GetBufferBinding(index)); | 
|  | EXPECT_EQ(kSize, host_->GetBufferSize(index)); | 
|  | EXPECT_EQ(kOffset, host_->GetBufferStart(index)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(IndexedBufferBindingHostTest, DoBindBufferRangeBufferWithoutEnoughSize) { | 
|  | const GLenum kTarget = GL_TRANSFORM_FEEDBACK_BUFFER; | 
|  | const GLuint kIndex = 2; | 
|  | const GLintptr kOffset = 4; | 
|  | const GLsizeiptr kSize = 8; | 
|  | const GLsizeiptr kBufferSize = kOffset + kSize - 2; | 
|  |  | 
|  | SetBufferSize(kTarget, kBufferSize); | 
|  |  | 
|  | GLsizeiptr clamped_size = ((kBufferSize - kOffset) >> 2) << 2; | 
|  |  | 
|  | EXPECT_CALL(*gl_, BindBufferRange(kTarget, kIndex, kBufferServiceId, kOffset, | 
|  | clamped_size)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | host_->DoBindBufferRange(kTarget, kIndex, buffer_.get(), kOffset, kSize); | 
|  |  | 
|  | for (uint32_t index = 0; index < kMaxBindings; ++index) { | 
|  | if (index != kIndex) { | 
|  | EXPECT_EQ(nullptr, host_->GetBufferBinding(index)); | 
|  | } else { | 
|  | EXPECT_EQ(buffer_.get(), host_->GetBufferBinding(index)); | 
|  | EXPECT_EQ(kSize, host_->GetBufferSize(index)); | 
|  | EXPECT_EQ(kOffset, host_->GetBufferStart(index)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now adjust buffer size to be big enough. | 
|  | EXPECT_CALL(*gl_, BindBufferRange(kTarget, kIndex, kBufferServiceId, kOffset, | 
|  | kSize)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | SetBufferSize(kTarget, kOffset + kSize); | 
|  | host_->OnBufferData(kTarget, buffer_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(IndexedBufferBindingHostTest, RestoreBindings) { | 
|  | const GLenum kTarget = GL_UNIFORM_BUFFER; | 
|  | const GLuint kIndex = 2; | 
|  | const GLuint kOtherIndex = 10; | 
|  | const GLintptr kOffset = 4; | 
|  | const GLsizeiptr kSize = 8; | 
|  | const GLsizeiptr kBufferSize = kOffset + kSize - 2; | 
|  |  | 
|  | GLsizeiptr clamped_size = ((kBufferSize - kOffset) >> 2) << 2; | 
|  |  | 
|  | SetBufferSize(kTarget, kBufferSize); | 
|  | // Set up host | 
|  | EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, kBufferServiceId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | host_->DoBindBufferBase(kTarget, kIndex, buffer_.get()); | 
|  | // Set up the second host | 
|  | scoped_refptr<IndexedBufferBindingHost> other = | 
|  | new IndexedBufferBindingHost(kMaxBindings, true); | 
|  | EXPECT_CALL(*gl_, BindBufferRange(kTarget, kOtherIndex, kBufferServiceId, | 
|  | kOffset, clamped_size)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | other->DoBindBufferRange(kTarget, kOtherIndex, buffer_.get(), kOffset, kSize); | 
|  |  | 
|  | { | 
|  | // Switching from |other| to |host_|. | 
|  | EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, kBufferServiceId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBufferBase(kTarget, kOtherIndex, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | host_->RestoreBindings(other.get()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // Switching from |host_| to |other|. | 
|  | EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBufferRange(kTarget, kOtherIndex, kBufferServiceId, | 
|  | kOffset, clamped_size)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | other->RestoreBindings(host_.get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace gles2 | 
|  | }  // namespace gpu | 
|  |  | 
|  |  |