diff options
26 files changed, 2233 insertions, 1396 deletions
diff --git a/content/renderer/gpu/renderer_gl_context.cc b/content/renderer/gpu/renderer_gl_context.cc index 5630a32..04cab30 100644 --- a/content/renderer/gpu/renderer_gl_context.cc +++ b/content/renderer/gpu/renderer_gl_context.cc @@ -23,6 +23,7 @@ #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_lib.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/common/constants.h" #endif // ENABLE_GPU @@ -31,7 +32,9 @@ namespace { const int32 kCommandBufferSize = 1024 * 1024; // TODO(kbr): make the transfer buffer size configurable via context // creation attributes. -const int32 kTransferBufferSize = 1024 * 1024; +const size_t kStartTransferBufferSize = 1 * 1024 * 1024; +const size_t kMinTransferBufferSize = 1 * 256 * 1024; +const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; // Singleton used to initialize and terminate the gles2 library. class GLES2Initializer { @@ -281,7 +284,7 @@ RendererGLContext::RendererGLContext(GpuChannelHost* channel) parent_texture_id_(0), command_buffer_(NULL), gles2_helper_(NULL), - transfer_buffer_id_(-1), + transfer_buffer_(NULL), gles2_implementation_(NULL), last_error_(SUCCESS), frame_number_(0) { @@ -392,31 +395,24 @@ bool RendererGLContext::Initialize(bool onscreen, TRACE_EVENT0("gpu", "RendererGLContext::Initialize::CreateTransferBuffer"); // Create a transfer buffer used to copy resources between the renderer // process and the GPU process. - transfer_buffer_id_ = command_buffer_->CreateTransferBuffer( - kTransferBufferSize, gpu::kCommandBufferSharedMemoryId); - if (transfer_buffer_id_ < 0) { - Destroy(); - return false; - } - } - - // Map the buffer into the renderer process's address space. - gpu::Buffer transfer_buffer = - command_buffer_->GetTransferBuffer(transfer_buffer_id_); - if (!transfer_buffer.ptr) { - Destroy(); - return false; + transfer_buffer_ = new gpu::TransferBuffer(gles2_helper_); } // Create the object exposing the OpenGL API. gles2_implementation_ = new gpu::gles2::GLES2Implementation( gles2_helper_, - transfer_buffer.size, - transfer_buffer.ptr, - transfer_buffer_id_, + transfer_buffer_, share_resources, bind_generates_resources); + if (!gles2_implementation_->Initialize( + kStartTransferBufferSize, + kMinTransferBufferSize, + kMaxTransferBufferSize)) { + Destroy(); + return false; + } + return true; } @@ -437,10 +433,10 @@ void RendererGLContext::Destroy() { gles2_implementation_ = NULL; } - // Do not destroy this transfer buffer here, because commands are still - // in flight on the GPU process that may access them. When the command buffer - // is destroyed, the associated shared memory will be cleaned up. - transfer_buffer_id_ = -1; + if (transfer_buffer_) { + delete transfer_buffer_; + transfer_buffer_ = NULL; + } delete gles2_helper_; gles2_helper_ = NULL; diff --git a/content/renderer/gpu/renderer_gl_context.h b/content/renderer/gpu/renderer_gl_context.h index b3a8f74..e491e2c 100644 --- a/content/renderer/gpu/renderer_gl_context.h +++ b/content/renderer/gpu/renderer_gl_context.h @@ -25,6 +25,7 @@ class CommandBufferProxy; class GURL; namespace gpu { +class TransferBuffer; namespace gles2 { class GLES2CmdHelper; class GLES2Implementation; @@ -199,7 +200,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext>, uint32 parent_texture_id_; CommandBufferProxy* command_buffer_; gpu::gles2::GLES2CmdHelper* gles2_helper_; - int32 transfer_buffer_id_; + gpu::TransferBuffer* transfer_buffer_; gpu::gles2::GLES2Implementation* gles2_implementation_; Error last_error_; int frame_number_; diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index db0be00..04f21a9 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -3210,9 +3210,10 @@ TEST_F(GLES2ImplementationTest, %(name)s) { typedef %(name)s::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(%(cmd_args)s, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(%(cmd_args)s, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->%(name)s(%(args)s, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -4135,10 +4136,12 @@ TEST_F(GLES2ImplementationTest, %(name)s) { typedef %(name)s::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(%(name)s::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->%(name)s(1); diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc new file mode 100644 index 0000000..e6ddfad --- /dev/null +++ b/gpu/command_buffer/client/client_test_helper.cc @@ -0,0 +1,138 @@ +// 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. + +// Tests for GLES2Implementation. + +#include "gpu/command_buffer/client/client_test_helper.h" + +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/client/cmd_buffer_helper.h" +#include "testing/gmock/include/gmock/gmock.h" + +using ::testing::_; +using ::testing::Invoke; + +namespace gpu { + +MockCommandBufferBase::~MockCommandBufferBase() { +} + +bool MockCommandBufferBase::Initialize() { + return true; +} + +CommandBuffer::State MockCommandBufferBase::GetState() { + return state_; +} + +CommandBuffer::State MockCommandBufferBase::GetLastState() { + return state_; +} + +void MockCommandBufferBase::Flush(int32 put_offset) { + state_.put_offset = put_offset; +} + +void MockCommandBufferBase::SetGetOffset(int32 get_offset) { + state_.get_offset = get_offset; +} + +CommandBuffer::State MockCommandBufferBase::FlushSync( + int32 put_offset, int32 last_known_get) { + state_.put_offset = put_offset; + state_.get_offset = put_offset; + OnFlush(); + return state_; +} + +void MockCommandBufferBase::SetGetBuffer(int transfer_buffer_id) { + ring_buffer_buffer_ = GetTransferBuffer(transfer_buffer_id); + ring_buffer_ = static_cast<CommandBufferEntry*>(ring_buffer_buffer_.ptr); + state_.num_entries = ring_buffer_buffer_.size / sizeof(ring_buffer_[0]); + state_.token = 10000; // All token checks in the tests should pass. +} + +// Get's the Id of the next transfer buffer that will be returned +// by CreateTransferBuffer. This is useful for testing expected ids. +int32 MockCommandBufferBase::GetNextFreeTransferBufferId() { + for (size_t ii = 0; ii < arraysize(transfer_buffers_); ++ii) { + if (!transfer_buffers_[ii].get()) { + return kTransferBufferBaseId + ii; + } + } + return -1; +} + +int32 MockCommandBufferBase::CreateTransferBuffer( + size_t size, int32 id_request) { + int32 id = GetNextFreeTransferBufferId(); + if (id >= 0) { + int32 ndx = id - kTransferBufferBaseId; + transfer_buffers_[ndx].reset(new int8[size]); + transfer_buffer_buffers_[ndx].ptr = transfer_buffers_[ndx].get(); + transfer_buffer_buffers_[ndx].size = size; + } + return id; +} + +void MockCommandBufferBase::DestroyTransferBufferHelper(int32 id) { + GPU_DCHECK_GE(id, kTransferBufferBaseId); + GPU_DCHECK_LT(id, kTransferBufferBaseId + kMaxTransferBuffers); + id -= kTransferBufferBaseId; + transfer_buffers_[id].reset(); + transfer_buffer_buffers_[id] = Buffer(); +} + +Buffer MockCommandBufferBase::GetTransferBuffer(int32 id) { + GPU_DCHECK_GE(id, kTransferBufferBaseId); + GPU_DCHECK_LT(id, kTransferBufferBaseId + kMaxTransferBuffers); + return transfer_buffer_buffers_[id - kTransferBufferBaseId]; +} + +int32 MockCommandBufferBase::RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size, + int32 id_request) { + GPU_NOTREACHED(); + return -1; +} + +void MockCommandBufferBase::SetToken(int32 token) { + GPU_NOTREACHED(); + state_.token = token; +} + +void MockCommandBufferBase::SetParseError(error::Error error) { + GPU_NOTREACHED(); + state_.error = error; +} + +void MockCommandBufferBase::SetContextLostReason( + error::ContextLostReason reason) { + GPU_NOTREACHED(); + state_.context_lost_reason = reason; +} + +// GCC requires these declarations, but MSVC requires they not be present +#ifndef _MSC_VER +const int32 MockCommandBufferBase::kTransferBufferBaseId; +const int32 MockCommandBufferBase::kMaxTransferBuffers; +#endif + +MockClientCommandBuffer::MockClientCommandBuffer() { + DelegateToFake(); +} + +MockClientCommandBuffer::~MockClientCommandBuffer() { +} + +void MockClientCommandBuffer::DelegateToFake() { + ON_CALL(*this, DestroyTransferBuffer(_)) + .WillByDefault(Invoke( + this, &MockCommandBufferBase::DestroyTransferBufferHelper)); +} + +} // namespace gpu + + diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h new file mode 100644 index 0000000..1b32c24 --- /dev/null +++ b/gpu/command_buffer/client/client_test_helper.h @@ -0,0 +1,76 @@ +// 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. + +// Helper classes for implementing gpu client side unit tests. + +#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_ +#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_ + +#include "gpu/command_buffer/common/cmd_buffer_common.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/common/compiler_specific.h" +#include "gpu/command_buffer/common/scoped_ptr.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu { + +class CommandBufferHelper; + +class MockCommandBufferBase : public CommandBuffer { + public: + static const int32 kTransferBufferBaseId = 0x123; + static const int32 kMaxTransferBuffers = 6; + + MockCommandBufferBase() { } + virtual ~MockCommandBufferBase(); + + virtual bool Initialize() OVERRIDE; + virtual State GetState() OVERRIDE; + virtual State GetLastState() OVERRIDE; + virtual void Flush(int32 put_offset) OVERRIDE; + virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE; + virtual void SetGetBuffer(int transfer_buffer_id) OVERRIDE; + virtual void SetGetOffset(int32 get_offset) OVERRIDE; + virtual int32 CreateTransferBuffer(size_t size, int32 id_request) OVERRIDE; + virtual Buffer GetTransferBuffer(int32 id) OVERRIDE; + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size, + int32 id_request) OVERRIDE; + virtual void SetToken(int32 token) OVERRIDE; + virtual void SetParseError(error::Error error) OVERRIDE; + virtual void SetContextLostReason(error::ContextLostReason reason) OVERRIDE; + + // Get's the Id of the next transfer buffer that will be returned + // by CreateTransferBuffer. This is useful for testing expected ids. + int32 GetNextFreeTransferBufferId(); + + void DestroyTransferBufferHelper(int32 id); + + virtual void OnFlush() = 0; + + private: + scoped_array<int8> transfer_buffers_[kMaxTransferBuffers]; + Buffer transfer_buffer_buffers_[kMaxTransferBuffers]; + CommandBufferEntry* ring_buffer_; + Buffer ring_buffer_buffer_; + State state_; +}; + +class MockClientCommandBuffer : public MockCommandBufferBase { + public: + MockClientCommandBuffer(); + virtual ~MockClientCommandBuffer(); + + // This is so we can use all the gmock functions when Flush is called. + MOCK_METHOD0(OnFlush, void()); + MOCK_METHOD1(DestroyTransferBuffer, void(int32 id)); + + void DelegateToFake(); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_ + diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 2428c1e..8f1e415 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -11,6 +11,7 @@ #include <GLES2/gl2ext.h> #include "../client/mapped_memory.h" #include "../client/program_info_manager.h" +#include "../client/transfer_buffer.h" #include "../common/gles2_cmd_utils.h" #include "../common/id_allocator.h" #include "../common/trace_event.h" @@ -432,7 +433,7 @@ class ClientSideBufferHelper { } // Returns true if buffers were setup. - void SetupSimualtedClientSideBuffers( + void SetupSimulatedClientSideBuffers( GLES2Implementation* gl, GLES2CmdHelper* gl_helper, GLsizei num_elements) { @@ -535,87 +536,9 @@ class ClientSideBufferHelper { DISALLOW_COPY_AND_ASSIGN(ClientSideBufferHelper); }; -AlignedRingBuffer::~AlignedRingBuffer() { -} - -TransferBuffer::TransferBuffer( - CommandBufferHelper* helper, - int32 buffer_id, - void* buffer, - size_t buffer_size, - size_t result_size, - unsigned int alignment) - : helper_(helper), - buffer_size_(buffer_size), - result_size_(result_size), - alignment_(alignment), - usable_(true) { - Setup(buffer_id, buffer); -} - -TransferBuffer::~TransferBuffer() { -} - -void TransferBuffer::Setup(int32 buffer_id, void* buffer) { - GPU_CHECK(!ring_buffer_.get()); - ring_buffer_.reset(new AlignedRingBuffer( - alignment_, - buffer_id, - result_size_, - buffer_size_ - result_size_, - helper_, - static_cast<char*>(buffer) + result_size_)); - buffer_id_ = buffer_id; - result_buffer_ = buffer; - result_shm_offset_ = 0; -} - -void TransferBuffer::Free() { - if (buffer_id_) { - // TODO(gman): should we check the memory is unused? - helper_->command_buffer()->DestroyTransferBuffer(buffer_id_); - buffer_id_ = 0; - result_buffer_ = NULL; - result_shm_offset_ = 0; - ring_buffer_.reset(); - } -} - -void TransferBuffer::AllocateRingBuffer() { - if (!buffer_id_ && usable_) { - int32 id = helper_->command_buffer()->CreateTransferBuffer( - buffer_size_, -1); - if (id == -1) { - usable_ = false; - return; - } - gpu::Buffer shm = helper_->command_buffer()->GetTransferBuffer(id); - Setup(id, shm.ptr); - } -} - -AlignedRingBuffer* TransferBuffer::GetBuffer() { - AllocateRingBuffer(); - return ring_buffer_.get(); -} - -void* TransferBuffer::GetResultBuffer() { - AllocateRingBuffer(); - return result_buffer_; -} - -int TransferBuffer::GetResultOffset() { - AllocateRingBuffer(); - return result_shm_offset_; -} - -int TransferBuffer::GetShmId() { - AllocateRingBuffer(); - return buffer_id_; -} - #if !defined(_MSC_VER) const size_t GLES2Implementation::kMaxSizeOfSimpleResult; +const unsigned int GLES2Implementation::kStartingOffset; #endif COMPILE_ASSERT(gpu::kInvalidResource == 0, @@ -635,19 +558,11 @@ GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() { GLES2Implementation::GLES2Implementation( GLES2CmdHelper* helper, - size_t transfer_buffer_size, - void* transfer_buffer, - int32 transfer_buffer_id, + TransferBufferInterface* transfer_buffer, bool share_resources, bool bind_generates_resource) : helper_(helper), - transfer_buffer_( - helper, - transfer_buffer_id, - transfer_buffer, - transfer_buffer_size, - GLES2Implementation::kStartingOffset, - GLES2Implementation::kAlignment), + transfer_buffer_(transfer_buffer), angle_pack_reverse_row_order_status(kUnknownExtensionStatus), pack_alignment_(4), unpack_alignment_(4), @@ -665,18 +580,38 @@ GLES2Implementation::GLES2Implementation( sharing_resources_(share_resources), bind_generates_resource_(bind_generates_resource), use_count_(0) { + GPU_DCHECK(helper); + GPU_DCHECK(transfer_buffer); GPU_CLIENT_LOG_CODE_BLOCK({ debug_ = CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableGPUClientLogging); }); memset(&reserved_ids_, 0, sizeof(reserved_ids_)); +} + +bool GLES2Implementation::Initialize( + unsigned int starting_transfer_buffer_size, + unsigned int min_transfer_buffer_size, + unsigned int max_transfer_buffer_size) { + GPU_DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size); + GPU_DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size); + GPU_DCHECK_GE(min_transfer_buffer_size, kStartingOffset); + + if (!transfer_buffer_->Initialize( + starting_transfer_buffer_size, + kStartingOffset, + min_transfer_buffer_size, + max_transfer_buffer_size, + kAlignment)) { + return false; + } mapped_memory_.reset(new MappedMemoryManager(helper_)); SetSharedMemoryChunkSizeMultiple(1024 * 1024 * 2); - if (share_resources) { - if (!bind_generates_resource) { + if (sharing_resources_) { + if (!bind_generates_resource_) { for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) { id_handlers_[i].reset(new StrictSharedIdHandler( this, static_cast<id_namespaces::IdNamespaces>(i))); @@ -734,6 +669,8 @@ GLES2Implementation::GLES2Implementation( reserved_ids_[0], reserved_ids_[1])); #endif + + return true; } GLES2Implementation::~GLES2Implementation() { @@ -747,6 +684,18 @@ GLES2Implementation::~GLES2Implementation() { Finish(); } +void* GLES2Implementation::GetResultBuffer() { + return transfer_buffer_->GetResultBuffer(); +} + +int32 GLES2Implementation::GetResultShmId() { + return transfer_buffer_->GetShmId(); +} + +uint32 GLES2Implementation::GetResultShmOffset() { + return transfer_buffer_->GetResultOffset(); +} + void GLES2Implementation::SetSharedMemoryChunkSizeMultiple( unsigned int multiple) { mapped_memory_->set_chunk_size_multiple(multiple); @@ -759,7 +708,7 @@ void GLES2Implementation::FreeUnusedSharedMemory() { void GLES2Implementation::FreeEverything() { Finish(); FreeUnusedSharedMemory(); - transfer_buffer_.Free(); + transfer_buffer_->Free(); helper_->FreeRingBuffer(); } @@ -861,27 +810,18 @@ bool GLES2Implementation::GetBucketContents(uint32 bucket_id, uint32 size = *result; data->resize(size); if (size > 0u) { - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return false; - } - uint32 max_size = transfer_buffer->GetLargestFreeOrPendingSize(); uint32 offset = 0; while (size) { - uint32 part_size = std::min(max_size, size); - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + if (!buffer.valid()) { return false; } helper_->GetBucketData( - bucket_id, offset, part_size, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer)); + bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset()); WaitForCmd(); - memcpy(&(*data)[offset], buffer, part_size); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - offset += part_size; - size -= part_size; + memcpy(&(*data)[offset], buffer.address(), buffer.size()); + offset += buffer.size(); + size -= buffer.size(); } // Free the bucket. This is not required but it does free up the memory. // and we don't have to wait for the result so from the client's perspective @@ -896,26 +836,18 @@ void GLES2Implementation::SetBucketContents( GPU_DCHECK(data); helper_->SetBucketSize(bucket_id, size); if (size > 0u) { - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - uint32 max_size = transfer_buffer->GetLargestFreeOrPendingSize(); uint32 offset = 0; while (size) { - uint32 part_size = std::min(static_cast<size_t>(max_size), size); - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + if (!buffer.valid()) { return; } - memcpy(buffer, static_cast<const int8*>(data) + offset, part_size); + memcpy(buffer.address(), static_cast<const int8*>(data) + offset, + buffer.size()); helper_->SetBucketData( - bucket_id, offset, part_size, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer)); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - offset += part_size; - size -= part_size; + bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset()); + offset += buffer.size(); + size -= buffer.size(); } } } @@ -1124,7 +1056,7 @@ void GLES2Implementation::DrawElements( } } if (have_client_side) { - client_side_buffer_helper_->SetupSimualtedClientSideBuffers( + client_side_buffer_helper_->SetupSimulatedClientSideBuffers( this, helper_, num_elements); } helper_->DrawElements(mode, count, type, offset); @@ -1190,27 +1122,18 @@ void GLES2Implementation::GenSharedIdsCHROMIUM( << namespace_id << ", " << id_offset << ", " << n << ", " << static_cast<void*>(ids) << ")"); TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM"); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - GLsizei max_size = transfer_buffer->GetLargestFreeOrPendingSize(); - GLsizei max_num_per = max_size / sizeof(ids[0]); while (n) { - GLsizei num = std::min(n, max_num_per); - GLint* id_buffer = transfer_buffer->AllocTyped<GLint>(num); - if (!id_buffer) { + ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_); + if (!id_buffer.valid()) { return; } helper_->GenSharedIdsCHROMIUM( - namespace_id, id_offset, num, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(id_buffer)); + namespace_id, id_offset, id_buffer.num_elements(), + id_buffer.shm_id(), id_buffer.offset()); WaitForCmd(); - memcpy(ids, id_buffer, sizeof(*ids) * num); - transfer_buffer->FreePendingToken(id_buffer, helper_->InsertToken()); - n -= num; - ids += num; + memcpy(ids, id_buffer.address(), sizeof(*ids) * id_buffer.num_elements()); + n -= id_buffer.num_elements(); + ids += id_buffer.num_elements(); } GPU_CLIENT_LOG_CODE_BLOCK({ for (GLsizei i = 0; i < n; ++i) { @@ -1230,27 +1153,18 @@ void GLES2Implementation::DeleteSharedIdsCHROMIUM( } }); TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM"); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - GLsizei max_size = transfer_buffer->GetLargestFreeOrPendingSize(); - GLsizei max_num_per = max_size / sizeof(ids[0]); while (n) { - GLsizei num = std::min(n, max_num_per); - GLint* id_buffer = transfer_buffer->AllocTyped<GLint>(num); - if (!id_buffer) { + ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_); + if (!id_buffer.valid()) { return; } - memcpy(id_buffer, ids, sizeof(*ids) * num); + memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements()); helper_->DeleteSharedIdsCHROMIUM( - namespace_id, num, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(id_buffer)); + namespace_id, id_buffer.num_elements(), + id_buffer.shm_id(), id_buffer.offset()); WaitForCmd(); - transfer_buffer->FreePendingToken(id_buffer, helper_->InsertToken()); - n -= num; - ids += num; + n -= id_buffer.num_elements(); + ids += id_buffer.num_elements(); } } @@ -1265,27 +1179,18 @@ void GLES2Implementation::RegisterSharedIdsCHROMIUM( } }); TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM"); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - GLsizei max_size = transfer_buffer->GetLargestFreeOrPendingSize(); - GLsizei max_num_per = max_size / sizeof(ids[0]); while (n) { - GLsizei num = std::min(n, max_num_per); - GLint* id_buffer = transfer_buffer->AllocTyped<GLint>(n); - if (!id_buffer) { + ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_); + if (!id_buffer.valid()) { return; } - memcpy(id_buffer, ids, sizeof(*ids) * n); + memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements()); helper_->RegisterSharedIdsCHROMIUM( - namespace_id, n, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(id_buffer)); + namespace_id, id_buffer.num_elements(), + id_buffer.shm_id(), id_buffer.offset()); WaitForCmd(); - transfer_buffer->FreePendingToken(id_buffer, helper_->InsertToken()); - n -= num; - ids += num; + n -= id_buffer.num_elements(); + ids += id_buffer.num_elements(); } } @@ -1438,28 +1343,26 @@ void GLES2Implementation::ShaderBinary( SetGLError(GL_INVALID_VALUE, "glShaderBinary length < 0."); return; } - GLsizei shader_id_size = n * sizeof(*shaders); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { + // TODO(gman): ShaderBinary should use buckets. + unsigned int shader_id_size = n * sizeof(*shaders); + ScopedTransferBufferArray<GLint> buffer( + shader_id_size + length, helper_, transfer_buffer_); + if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) { + SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary: out of memory."); return; } - int8* buffer = transfer_buffer->AllocTyped<int8>(shader_id_size + length); - if (!buffer) { - return; - } - void* shader_ids = buffer; - void* shader_data = buffer + shader_id_size; + void* shader_ids = buffer.elements(); + void* shader_data = buffer.elements() + shader_id_size; memcpy(shader_ids, shaders, shader_id_size); memcpy(shader_data, binary, length); helper_->ShaderBinary( n, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(shader_ids), + buffer.shm_id(), + buffer.offset(), binaryformat, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(shader_data), + buffer.shm_id(), + buffer.offset() + shader_id_size, length); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); } void GLES2Implementation::PixelStorei(GLenum pname, GLint param) { @@ -1555,11 +1458,6 @@ void GLES2Implementation::ShaderSource( // Concatenate all the strings in to a bucket on the service. helper_->SetBucketSize(kResultBucketId, total_size); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - uint32 max_size = transfer_buffer->GetLargestFreeOrPendingSize(); uint32 offset = 0; for (GLsizei ii = 0; ii <= count; ++ii) { const char* src = ii < count ? source[ii] : ""; @@ -1567,19 +1465,16 @@ void GLES2Implementation::ShaderSource( uint32 size = ii < count ? (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1; while (size) { - uint32 part_size = std::min(size, max_size); - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + if (!buffer.valid()) { return; } - memcpy(buffer, src, part_size); - helper_->SetBucketData(kResultBucketId, offset, part_size, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer)); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - offset += part_size; - src += part_size; - size -= part_size; + memcpy(buffer.address(), src, buffer.size()); + helper_->SetBucketData(kResultBucketId, offset, buffer.size(), + buffer.shm_id(), buffer.offset()); + offset += buffer.size(); + src += buffer.size(); + size -= buffer.size(); } } } @@ -1592,25 +1487,41 @@ void GLES2Implementation::ShaderSource( void GLES2Implementation::BufferDataHelper( GLenum target, GLsizeiptr size, const void* data, GLenum usage) { - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - GLsizeiptr max_size = transfer_buffer->GetLargestFreeOrPendingSize(); - if (size > max_size || !data) { + if (size == 0) { + return; + } + + if (size < 0) { + SetGLError(GL_INVALID_VALUE, "glBufferData: size < 0"); + return; + } + + // If there is no data just send BufferData + if (!data) { helper_->BufferData(target, size, 0, 0, usage); - if (data != NULL) { - BufferSubDataHelper(target, 0, size, data); - } return; } - void* buffer = transfer_buffer->Alloc(size); - memcpy(buffer, data, size); - helper_->BufferData( - target, - size, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer), - usage); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); + // See if we can send all at once. + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + if (!buffer.valid()) { + return; + } + + if (buffer.size() >= static_cast<unsigned int>(size)) { + memcpy(buffer.address(), data, size); + helper_->BufferData( + target, + size, + buffer.shm_id(), + buffer.offset(), + usage); + return; + } + + // Make the buffer with BufferData then send via BufferSubData + helper_->BufferData(target, size, 0, 0, usage); + BufferSubDataHelperImpl(target, 0, size, data, &buffer); } void GLES2Implementation::BufferData( @@ -1635,26 +1546,31 @@ void GLES2Implementation::BufferSubDataHelper( return; } + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + BufferSubDataHelperImpl(target, offset, size, data, &buffer); +} + +void GLES2Implementation::BufferSubDataHelperImpl( + GLenum target, GLintptr offset, GLsizeiptr size, const void* data, + ScopedTransferBufferPtr* buffer) { + GPU_DCHECK(buffer); + GPU_DCHECK_GT(size, 0); + const int8* source = static_cast<const int8*>(data); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - GLsizeiptr max_size = transfer_buffer->GetLargestFreeOrPendingSize(); while (size) { - GLsizeiptr part_size = std::min(size, max_size); - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { - return; + if (!buffer->valid() || buffer->size() == 0) { + buffer->Reset(size); + if (!buffer->valid()) { + return; + } } - memcpy(buffer, source, part_size); - helper_->BufferSubData(target, offset, part_size, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer)); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - offset += part_size; - source += part_size; - size -= part_size; + memcpy(buffer->address(), source, buffer->size()); + helper_->BufferSubData( + target, offset, buffer->size(), buffer->shm_id(), buffer->offset()); + offset += buffer->size(); + source += buffer->size(); + size -= buffer->size(); + buffer->Release(); } } @@ -1783,42 +1699,44 @@ void GLES2Implementation::TexImage2D( return; } - // Check if we can send it all at once. - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - unsigned int max_size = transfer_buffer->GetLargestFreeOrPendingSize(); - if (size > max_size || !pixels) { - // No, so send it using TexSubImage2D. + // If there's no data just issue TexImage2D + if (!pixels) { helper_->TexImage2D( target, level, internalformat, width, height, border, format, type, 0, 0); - if (pixels) { - TexSubImage2DImpl( - target, level, 0, 0, width, height, format, type, pixels, GL_TRUE); - } return; } - void* buffer = transfer_buffer->Alloc(size); - if (!buffer) { + // Check if we can send it all at once. + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + if (!buffer.valid()) { return; } - bool copy_success = true; - if (unpack_flip_y_) { - copy_success = CopyRectToBufferFlipped( - pixels, width, height, format, type, buffer); - } else { - memcpy(buffer, pixels, size); - } - if (copy_success) { - helper_->TexImage2D( - target, level, internalformat, width, height, border, format, type, - transfer_buffer->GetShmId(), transfer_buffer->GetOffset(buffer)); + if (buffer.size() >= size) { + bool copy_success = true; + if (unpack_flip_y_) { + copy_success = CopyRectToBufferFlipped( + pixels, width, height, format, type, buffer.address()); + } else { + memcpy(buffer.address(), pixels, size); + } + + if (copy_success) { + helper_->TexImage2D( + target, level, internalformat, width, height, border, format, type, + buffer.shm_id(), buffer.offset()); + } + return; } - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); + + // No, so send it using TexSubImage2D. + helper_->TexImage2D( + target, level, internalformat, width, height, border, format, type, + 0, 0); + TexSubImage2DImpl( + target, level, 0, 0, width, height, format, type, pixels, GL_TRUE, + &buffer); } void GLES2Implementation::TexSubImage2D( @@ -1833,15 +1751,7 @@ void GLES2Implementation::TexSubImage2D( << GLES2Util::GetStringTextureFormat(format) << ", " << GLES2Util::GetStringPixelType(type) << ", " << static_cast<const void*>(pixels) << ")"); - TexSubImage2DImpl( - target, level, xoffset, yoffset, width, height, format, type, pixels, - GL_FALSE); -} -void GLES2Implementation::TexSubImage2DImpl( - GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, - GLsizei height, GLenum format, GLenum type, const void* pixels, - GLboolean internal) { if (level < 0 || height < 0 || width < 0) { SetGLError(GL_INVALID_VALUE, "glTexSubImage2D dimension < 0"); return; @@ -1849,12 +1759,41 @@ void GLES2Implementation::TexSubImage2DImpl( if (height == 0 || width == 0) { return; } - const int8* source = static_cast<const int8*>(pixels); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { + + uint32 temp_size; + if (!GLES2Util::ComputeImageDataSize( + width, height, format, type, unpack_alignment_, &temp_size)) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage2D: size to large"); return; } - GLsizeiptr max_size = transfer_buffer->GetLargestFreeOrPendingSize(); + + ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_); + TexSubImage2DImpl( + target, level, xoffset, yoffset, width, height, format, type, pixels, + GL_FALSE, &buffer); +} + +static GLint ComputeNumRowsThatFitInBuffer( + GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size, + unsigned int size) { + GPU_DCHECK_GE(unpadded_row_size, 0); + if (padded_row_size == 0) { + return 1; + } + GLint num_rows = size / padded_row_size; + return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size; +} + +void GLES2Implementation::TexSubImage2DImpl( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLenum type, const void* pixels, + GLboolean internal, ScopedTransferBufferPtr* buffer) { + GPU_DCHECK(buffer); + GPU_DCHECK_GE(level, 0); + GPU_DCHECK_GT(height, 0); + GPU_DCHECK_GT(width, 0); + + const int8* source = static_cast<const int8*>(pixels); uint32 temp_size; if (!GLES2Util::ComputeImageDataSize( width, 1, format, type, unpack_alignment_, &temp_size)) { @@ -1874,70 +1813,37 @@ void GLES2Implementation::TexSubImage2DImpl( } GLint original_yoffset = yoffset; - if (padded_row_size <= max_size) { - // Transfer by rows. - GLint max_rows = max_size / std::max(padded_row_size, - static_cast<GLsizeiptr>(1)); - while (height) { - GLint num_rows = std::min(height, max_rows); - GLsizeiptr part_size = - (num_rows - 1) * padded_row_size + unpadded_row_size; - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { + // Transfer by rows. + while (height) { + unsigned int desired_size = + padded_row_size * (height - 1) + unpadded_row_size; + if (!buffer->valid() || buffer->size() == 0) { + buffer->Reset(desired_size); + if (!buffer->valid()) { return; } - GLint y; - if (unpack_flip_y_) { - CopyRectToBufferFlipped( - source, width, num_rows, format, type, buffer); - // GPU_DCHECK(copy_success); // can't check this because bot fails! - y = original_yoffset + height - num_rows; - } else { - memcpy(buffer, source, part_size); - y = yoffset; - } - helper_->TexSubImage2D( - target, level, xoffset, y, width, num_rows, format, type, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer), internal); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - yoffset += num_rows; - source += num_rows * padded_row_size; - height -= num_rows; } - } else { - // Transfer by sub rows. Because GL has no maximum texture dimensions. - uint32 temp; - GLES2Util::ComputeImageDataSize( - 1, 1, format, type, unpack_alignment_, &temp); - GLsizeiptr element_size = temp; - max_size -= max_size % element_size; - GLint max_sub_row_pixels = max_size / element_size; - for (; height; --height) { - GLint temp_width = width; - GLint temp_xoffset = xoffset; - const int8* row_source = source; - while (temp_width) { - GLint num_pixels = std::min(width, max_sub_row_pixels); - GLsizeiptr part_size = num_pixels * element_size; - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { - return; - } - memcpy(buffer, row_source, part_size); - GLint y = unpack_flip_y_ ? (original_yoffset + height - 1) : yoffset; - helper_->TexSubImage2D( - target, level, temp_xoffset, y, num_pixels, 1, format, type, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer), internal); - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - row_source += part_size; - temp_xoffset += num_pixels; - temp_width -= num_pixels; - } - ++yoffset; - source += padded_row_size; + + GLint num_rows = ComputeNumRowsThatFitInBuffer( + padded_row_size, unpadded_row_size, buffer->size()); + num_rows = std::min(num_rows, height); + GLint y; + if (unpack_flip_y_) { + CopyRectToBufferFlipped( + source, width, num_rows, format, type, buffer->address()); + y = original_yoffset + height - num_rows; + } else { + temp_size = padded_row_size * (num_rows - 1) + unpadded_row_size; + memcpy(buffer->address(), source, temp_size); + y = yoffset; } + helper_->TexSubImage2D( + target, level, xoffset, y, width, num_rows, format, type, + buffer->shm_id(), buffer->offset(), internal); + buffer->Release(); + yoffset += num_rows; + source += num_rows * padded_row_size; + height -= num_rows; } } @@ -2095,19 +2001,15 @@ void GLES2Implementation::GetAttachedShaders( TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders"); typedef gles2::GetAttachedShaders::Result Result; uint32 size = Result::ComputeSize(maxcount); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - Result* result = transfer_buffer->AllocTyped<Result>(size); + Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size)); if (!result) { return; } result->SetNumResults(0); helper_->GetAttachedShaders( program, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(result), + transfer_buffer_->GetShmId(), + transfer_buffer_->GetOffset(result), size); int32 token = helper_->InsertToken(); WaitForCmd(); @@ -2120,7 +2022,7 @@ void GLES2Implementation::GetAttachedShaders( GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]); } }); - transfer_buffer->FreePendingToken(result, token); + transfer_buffer_->FreePendingToken(result, token); } void GLES2Implementation::GetShaderPrecisionFormat( @@ -2281,16 +2183,8 @@ void GLES2Implementation::ReadPixels( TRACE_EVENT0("gpu", "GLES2::ReadPixels"); typedef gles2::ReadPixels::Result Result; - Result* result = GetResultAs<Result*>(); - if (!result) { - return; - } + int8* dest = reinterpret_cast<int8*>(pixels); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - GLsizeiptr max_size = transfer_buffer->GetLargestFreeOrPendingSize(); uint32 temp_size; if (!GLES2Util::ComputeImageDataSize( width, 1, format, type, pack_alignment_, &temp_size)) { @@ -2303,107 +2197,61 @@ void GLES2Implementation::ReadPixels( SetGLError(GL_INVALID_VALUE, "glReadPixels: size too large."); return; } - GLsizeiptr padded_row_size = temp_size - unpadded_row_size; + GLsizei padded_row_size = temp_size - unpadded_row_size; if (padded_row_size < 0 || unpadded_row_size < 0) { SetGLError(GL_INVALID_VALUE, "glReadPixels: size too large."); return; } - // Check if we have enough space to transfer at least an entire row. - if (padded_row_size <= max_size) { - // Transfer by rows. - // The max rows we can transfer. - GLint max_rows = max_size / std::max(padded_row_size, - static_cast<GLsizeiptr>(1)); - while (height) { - // Compute how many rows to transfer. - GLint num_rows = std::min(height, max_rows); - // Compute how much space those rows will take. The last row will not - // include padding. - GLsizeiptr part_size = - unpadded_row_size + padded_row_size * (num_rows - 1); - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { - return; + // Transfer by rows. + // The max rows we can transfer. + while (height) { + GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size; + ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_); + if (!buffer.valid()) { + return; + } + GLint num_rows = ComputeNumRowsThatFitInBuffer( + padded_row_size, unpadded_row_size, buffer.size()); + num_rows = std::min(num_rows, height); + // NOTE: We must look up the address of the result area AFTER allocation + // of the transfer buffer since the transfer buffer may be reallocated. + Result* result = GetResultAs<Result*>(); + if (!result) { + return; + } + *result = 0; // mark as failed. + helper_->ReadPixels( + xoffset, yoffset, width, num_rows, format, type, + buffer.shm_id(), buffer.offset(), + GetResultShmId(), GetResultShmOffset()); + WaitForCmd(); + if (*result != 0) { + // when doing a y-flip we have to iterate through top-to-bottom chunks + // of the dst. The service side handles reversing the rows within a + // chunk. + int8* rows_dst; + if (pack_reverse_row_order_) { + rows_dst = dest + (height - num_rows) * padded_row_size; + } else { + rows_dst = dest; } - *result = 0; // mark as failed. - helper_->ReadPixels( - xoffset, yoffset, width, num_rows, format, type, - transfer_buffer->GetShmId(), transfer_buffer->GetOffset(buffer), - GetResultShmId(), GetResultShmOffset()); - WaitForCmd(); - if (*result != 0) { - // when doing a y-flip we have to iterate through top-to-bottom chunks - // of the dst. The service side handles reversing the rows within a - // chunk. - int8* rows_dst; - if (pack_reverse_row_order_) { - rows_dst = dest + (height - num_rows) * padded_row_size; - } else { - rows_dst = dest; - } - // We have to copy 1 row at a time to avoid writing pad bytes. - const int8* src = static_cast<const int8*>(buffer); - for (GLint yy = 0; yy < num_rows; ++yy) { - memcpy(rows_dst, src, unpadded_row_size); - rows_dst += padded_row_size; - src += padded_row_size; - } - if (!pack_reverse_row_order_) { - dest = rows_dst; - } + // We have to copy 1 row at a time to avoid writing pad bytes. + const int8* src = static_cast<const int8*>(buffer.address()); + for (GLint yy = 0; yy < num_rows; ++yy) { + memcpy(rows_dst, src, unpadded_row_size); + rows_dst += padded_row_size; + src += padded_row_size; } - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - // If it was not marked as successful exit. - if (*result == 0) { - return; + if (!pack_reverse_row_order_) { + dest = rows_dst; } - yoffset += num_rows; - height -= num_rows; } - } else { - // Transfer by sub rows. Because GL has no maximum texture dimensions. - GLES2Util::ComputeImageDataSize( - 1, 1, format, type, pack_alignment_, &temp_size); - GLsizeiptr element_size = temp_size; - max_size -= max_size % element_size; - GLint max_sub_row_pixels = max_size / element_size; - if (pack_reverse_row_order_) { - // start at the last row when flipping y. - dest = dest + (height - 1) * padded_row_size; - } - for (; height; --height) { - GLint temp_width = width; - GLint temp_xoffset = xoffset; - int8* row_dest = dest; - while (temp_width) { - GLint num_pixels = std::min(width, max_sub_row_pixels); - GLsizeiptr part_size = num_pixels * element_size; - void* buffer = transfer_buffer->Alloc(part_size); - if (!buffer) { - return; - } - *result = 0; // mark as failed. - helper_->ReadPixels( - temp_xoffset, yoffset, temp_width, 1, format, type, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(buffer), - GetResultShmId(), GetResultShmOffset()); - WaitForCmd(); - if (*result != 0) { - memcpy(row_dest, buffer, part_size); - } - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); - // If it was not marked as successful exit. - if (*result == 0) { - return; - } - row_dest += part_size; - temp_xoffset += num_pixels; - temp_width -= num_pixels; - } - ++yoffset; - dest += pack_reverse_row_order_ ? -padded_row_size : padded_row_size; + // If it was not marked as successful exit. + if (*result == 0) { + return; } + yoffset += num_rows; + height -= num_rows; } } @@ -2615,7 +2463,7 @@ void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) { bool have_client_side = client_side_buffer_helper_->HaveEnabledClientSideBuffers(); if (have_client_side) { - client_side_buffer_helper_->SetupSimualtedClientSideBuffers( + client_side_buffer_helper_->SetupSimulatedClientSideBuffers( this, helper_, first + count); } #endif @@ -2971,11 +2819,7 @@ void GLES2Implementation::GetMultipleIntegervCHROMIUM( } uint32 size_needed = count * sizeof(pnames[0]) + num_results * sizeof(results[0]); - AlignedRingBuffer* transfer_buffer = transfer_buffer_.GetBuffer(); - if (!transfer_buffer) { - return; - } - void* buffer = transfer_buffer->Alloc(size_needed); + void* buffer = transfer_buffer_->Alloc(size_needed); if (!buffer) { return; } @@ -2984,16 +2828,16 @@ void GLES2Implementation::GetMultipleIntegervCHROMIUM( memcpy(pnames_buffer, pnames, count * sizeof(GLenum)); memset(results_buffer, 0, num_results * sizeof(GLint)); helper_->GetMultipleIntegervCHROMIUM( - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(pnames_buffer), + transfer_buffer_->GetShmId(), + transfer_buffer_->GetOffset(pnames_buffer), count, - transfer_buffer->GetShmId(), - transfer_buffer->GetOffset(results_buffer), + transfer_buffer_->GetShmId(), + transfer_buffer_->GetOffset(results_buffer), size); WaitForCmd(); memcpy(results, results_buffer, size); // TODO(gman): We should be able to free without a token. - transfer_buffer->FreePendingToken(buffer, helper_->InsertToken()); + transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken()); GPU_CLIENT_LOG(" returned"); GPU_CLIENT_LOG_CODE_BLOCK({ for (int i = 0; i < num_results; ++i) { diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 0d1a633..d8adc44 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -74,12 +74,13 @@ namespace gpu { class MappedMemoryManager; +class ScopedTransferBufferPtr; +class TransferBufferInterface; namespace gles2 { class ClientSideBufferHelper; class ProgramInfoManager; -class AlignedRingBuffer; // Base class for IdHandlers class IdHandlerInterface { @@ -97,84 +98,6 @@ class IdHandlerInterface { virtual bool MarkAsUsedForBind(GLuint id) = 0; }; -// Wraps RingBufferWrapper to provide aligned allocations. -class AlignedRingBuffer : public RingBufferWrapper { - public: - AlignedRingBuffer( - unsigned int alignment, - int32 shm_id, - RingBuffer::Offset base_offset, - unsigned int size, - CommandBufferHelper* helper, - void* base) - : RingBufferWrapper(base_offset, size, helper, base), - alignment_(alignment), - shm_id_(shm_id) { - } - ~AlignedRingBuffer(); - - // Overrriden from RingBufferWrapper - void* Alloc(unsigned int size) { - return RingBufferWrapper::Alloc(RoundToAlignment(size)); - } - - template <typename T>T* AllocTyped(unsigned int count) { - return static_cast<T*>(Alloc(count * sizeof(T))); - } - - int32 GetShmId() const { - return shm_id_; - } - - private: - unsigned int RoundToAlignment(unsigned int size) { - return (size + alignment_ - 1) & ~(alignment_ - 1); - } - - unsigned int alignment_; - int32 shm_id_; -}; - -// Manages the transfer buffer. -class TransferBuffer { - public: - TransferBuffer( - CommandBufferHelper* helper, - int32 buffer_id, - void* buffer, - size_t buffer_size, - size_t result_size, - unsigned int alignment); - ~TransferBuffer(); - - AlignedRingBuffer* GetBuffer(); - int GetShmId(); - void* GetResultBuffer(); - int GetResultOffset(); - - void Free(); - - // This is for unit testing only. - bool HaveBuffer() const { - return buffer_id_ != 0; - } - - private: - void AllocateRingBuffer(); - - void Setup(int32 buffer_id, void* buffer); - - CommandBufferHelper* helper_; - scoped_ptr<AlignedRingBuffer> ring_buffer_; - unsigned int buffer_size_; - unsigned int result_size_; - unsigned int alignment_; - int32 buffer_id_; - void* result_buffer_; - uint32 result_shm_offset_; - bool usable_; -}; - // This class emulates GLES2 over command buffers. It can be used by a client // program so that the program does not need deal with shared memory and command // buffer management. See gl2_lib.h. Note that there is a performance gain to @@ -235,14 +158,17 @@ class GLES2Implementation { GLES2Implementation( GLES2CmdHelper* helper, - size_t transfer_buffer_size, - void* transfer_buffer, - int32 transfer_buffer_id, + TransferBufferInterface* transfer_buffer, bool share_resources, bool bind_generates_resource); ~GLES2Implementation(); + bool Initialize( + unsigned int starting_transfer_buffer_size, + unsigned int min_transfer_buffer_size, + unsigned int max_transfer_buffer_size); + // The GLES2CmdHelper being used by this GLES2Implementation. You can use // this to issue cmds at a lower level for certain kinds of optimization. GLES2CmdHelper* helper() const { @@ -402,16 +328,12 @@ class GLES2Implementation { // Gets the value of the result. template <typename T> T GetResultAs() { - return static_cast<T>(transfer_buffer_.GetResultBuffer()); + return static_cast<T>(GetResultBuffer()); } - int32 GetResultShmId() { - return transfer_buffer_.GetShmId(); - } - - uint32 GetResultShmOffset() { - return transfer_buffer_.GetResultOffset(); - } + void* GetResultBuffer(); + int32 GetResultShmId(); + uint32 GetResultShmOffset(); // Lazily determines if GL_ANGLE_pack_reverse_row_order is available bool IsAnglePackReverseRowOrderAvailable(); @@ -472,6 +394,9 @@ class GLES2Implementation { GLenum target, GLsizeiptr size, const void* data, GLenum usage); void BufferSubDataHelper( GLenum target, GLintptr offset, GLsizeiptr size, const void* data); + void BufferSubDataHelperImpl( + GLenum target, GLintptr offset, GLsizeiptr size, const void* data, + ScopedTransferBufferPtr* buffer); // Helper for GetVertexAttrib bool GetVertexAttribHelper(GLuint index, GLenum pname, uint32* param); @@ -485,7 +410,7 @@ class GLES2Implementation { void TexSubImage2DImpl( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels, - GLboolean internal); + GLboolean internal, ScopedTransferBufferPtr* buffer); // Helpers for query functions. bool GetHelper(GLenum pname, GLint* params); @@ -507,8 +432,8 @@ class GLES2Implementation { GLES2Util util_; GLES2CmdHelper* helper_; + TransferBufferInterface* transfer_buffer_; scoped_ptr<IdHandlerInterface> id_handlers_[id_namespaces::kNumIdNamespaces]; - TransferBuffer transfer_buffer_; std::string last_error_; std::queue<int32> swap_buffers_tokens_; diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 46f60ae..c354e9e 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Tests for the Command Buffer Helper. +// Tests for GLES2Implementation. #include "gpu/command_buffer/client/gles2_implementation.h" #include <GLES2/gl2ext.h> +#include "gpu/command_buffer/client/client_test_helper.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/common/compiler_specific.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gmock/include/gmock/gmock.h" @@ -22,162 +25,19 @@ using testing::InSequence; using testing::Invoke; using testing::Mock; using testing::Sequence; +using testing::StrictMock; using testing::Truly; using testing::Return; namespace gpu { - -class GLES2MockCommandBufferHelper : public CommandBuffer { - public: - static const int32 kTransferBufferBaseId = 0x123; - static const int32 kMaxTransferBuffers = 6; - - GLES2MockCommandBufferHelper() { } - virtual ~GLES2MockCommandBufferHelper() { } - - // CommandBuffer implementation: - virtual bool Initialize() { - return true; - } - - virtual State GetState() { - return state_; - } - - virtual State GetLastState() { - return state_; - } - - virtual void Flush(int32 put_offset) { - state_.put_offset = put_offset; - } - - virtual State FlushSync(int32 put_offset, int32 last_known_get) { - state_.put_offset = put_offset; - state_.get_offset = put_offset; - // Warning: This is a hack. We just happen to know that the default - // transfer buffer will be the first transfer buffer. - OnFlush(transfer_buffer_buffers_[0].ptr); - return state_; - } - - virtual void SetGetBuffer(int transfer_buffer_id) { - ring_buffer_buffer_ = GetTransferBuffer(transfer_buffer_id); - ring_buffer_ = static_cast<CommandBufferEntry*>(ring_buffer_buffer_.ptr); - state_.num_entries = ring_buffer_buffer_.size / sizeof(ring_buffer_[0]); - state_.token = 10000; // All token checks in the tests should pass. - } - - virtual void SetGetOffset(int32 get_offset) { - state_.get_offset = get_offset; - } - - // Get's the Id of the next transfer buffer that will be returned - // by CreateTransferBuffer. This is useful for testing expected ids. - int32 GetNextFreeTransferBufferId() { - for (size_t ii = 0; ii < arraysize(transfer_buffers_); ++ii) { - if (!transfer_buffers_[ii].get()) { - return kTransferBufferBaseId + ii; - } - } - return -1; - } - - virtual int32 CreateTransferBuffer(size_t size, int32 id_request) { - int32 id = GetNextFreeTransferBufferId(); - if (id >= 0) { - int32 ndx = id - kTransferBufferBaseId; - transfer_buffers_[ndx].reset(new int8[size]); - transfer_buffer_buffers_[ndx].ptr = transfer_buffers_[ndx].get(); - transfer_buffer_buffers_[ndx].size = size; - } - return id; - } - - void DestroyTransferBufferHelper(int32 id) { - GPU_DCHECK_GE(id, kTransferBufferBaseId); - GPU_DCHECK_LT(id, kTransferBufferBaseId + kMaxTransferBuffers); - id -= kTransferBufferBaseId; - transfer_buffers_[id].reset(); - transfer_buffer_buffers_[id] = Buffer(); - } - - virtual Buffer GetTransferBuffer(int32 id) { - GPU_DCHECK_GE(id, kTransferBufferBaseId); - GPU_DCHECK_LT(id, kTransferBufferBaseId + kMaxTransferBuffers); - return transfer_buffer_buffers_[id - kTransferBufferBaseId]; - } - - virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, - size_t size, - int32 id_request) { - GPU_NOTREACHED(); - return -1; - } - - virtual void SetToken(int32 token) { - GPU_NOTREACHED(); - state_.token = token; - } - - virtual void SetParseError(error::Error error) { - GPU_NOTREACHED(); - state_.error = error; - } - - virtual void SetContextLostReason(error::ContextLostReason reason) { - GPU_NOTREACHED(); - state_.context_lost_reason = reason; - } - - virtual void OnFlush(void* transfer_buffer) = 0; - - private: - scoped_array<int8> transfer_buffers_[kMaxTransferBuffers]; - Buffer transfer_buffer_buffers_[kMaxTransferBuffers]; - CommandBufferEntry* ring_buffer_; - Buffer ring_buffer_buffer_; - State state_; -}; - -class MockGLES2CommandBuffer : public GLES2MockCommandBufferHelper { - public: - MockGLES2CommandBuffer() { - DelegateToFake(); - } - - virtual ~MockGLES2CommandBuffer() { - } - - // This is so we can use all the gmock functions when Flush is called. - MOCK_METHOD1(OnFlush, void(void* result)); - MOCK_METHOD1(DestroyTransferBuffer, void(int32 id)); - - void DelegateToFake() { - ON_CALL(*this, DestroyTransferBuffer(_)) - .WillByDefault(Invoke( - this, &GLES2MockCommandBufferHelper::DestroyTransferBufferHelper)); - } -}; - -// GCC requires these declarations, but MSVC requires they not be present -#ifndef _MSC_VER -const int32 GLES2MockCommandBufferHelper::kTransferBufferBaseId; -const int32 GLES2MockCommandBufferHelper::kMaxTransferBuffers; -#endif - namespace gles2 { -ACTION_P(SetMemory, obj) { - memcpy(arg0, &obj, sizeof(obj)); +ACTION_P2(SetMemory, dst, obj) { + memcpy(dst, &obj, sizeof(obj)); } -ACTION_P2(SetMemoryAtOffset, offset, obj) { - memcpy(static_cast<char*>(arg0) + offset, &obj, sizeof(obj)); -} - -ACTION_P3(SetMemoryAtOffsetFromArray, offset, array, size) { - memcpy(static_cast<char*>(arg0) + offset, array, size); +ACTION_P3(SetMemoryFromArray, dst, array, size) { + memcpy(dst, array, size); } // Used to help set the transfer buffer result to SizedResult of a single value. @@ -216,211 +76,229 @@ struct Str7 { }; #pragma pack(pop) -class GLES2CommandBufferTestBase : public testing::Test { - protected: - static const int32 kNumCommandEntries = 400; - static const int32 kCommandBufferSizeBytes = - kNumCommandEntries * sizeof(CommandBufferEntry); - static const size_t kTransferBufferSize = 256; - static const uint8 kInitialValue = 0xBD; +class MockTransferBuffer : public TransferBufferInterface { + public: + struct ExpectedMemoryInfo { + uint32 offset; + int32 id; + uint8* ptr; + }; - GLES2CommandBufferTestBase() - : commands_(NULL), - token_(0), - offset_(0), - initial_offset_(0), - alignment_(0), - transfer_buffer_id_(-1) { + MockTransferBuffer( + CommandBuffer* command_buffer, + unsigned int size, + unsigned int result_size, + unsigned int alignment) + : command_buffer_(command_buffer), + size_(size), + result_size_(result_size), + alignment_(alignment), + actual_buffer_index_(0), + expected_buffer_index_(0), + last_alloc_(NULL), + expected_offset_(result_size), + actual_offset_(result_size) { + // We have to allocate the buffers here because + // we need to know their address before GLES2Implementation::Initialize + // is called. + for (int ii = 0; ii < kNumBuffers; ++ii) { + buffer_ids_[ii] = command_buffer_->CreateTransferBuffer( + size_ + ii * alignment_, -1); + EXPECT_NE(-1, buffer_ids_[ii]); + buffers_[ii] = command_buffer_->GetTransferBuffer(buffer_ids_[ii]); + } } - void SetupCommandBuffer(unsigned int offset, unsigned alignment) { - initial_offset_ = offset; - offset_ = offset; - alignment_ = alignment; - - command_buffer_.reset(new MockGLES2CommandBuffer()); - command_buffer_->Initialize(); + virtual ~MockTransferBuffer() { } + + bool Initialize( + unsigned int starting_buffer_size, + unsigned int result_size, + unsigned int /* min_buffer_size */, + unsigned int /* max_buffer_size */, + unsigned int alignment) OVERRIDE; + virtual int GetShmId() OVERRIDE; + virtual void* GetResultBuffer() OVERRIDE; + virtual int GetResultOffset() OVERRIDE; + virtual void Free() OVERRIDE; + virtual bool HaveBuffer() const OVERRIDE; + virtual void* AllocUpTo( + unsigned int size, unsigned int* size_allocated) OVERRIDE; + virtual void* Alloc(unsigned int size) OVERRIDE; + virtual RingBuffer::Offset GetOffset(void* pointer) const OVERRIDE; + virtual void FreePendingToken(void* p, unsigned int /* token */) OVERRIDE; - transfer_buffer_id_ = - command_buffer_->CreateTransferBuffer(kTransferBufferSize, -1); - transfer_buffer_ = command_buffer_->GetTransferBuffer(transfer_buffer_id_); - ClearTransferBuffer(); - - helper_.reset(new GLES2CmdHelper(command_buffer_.get())); - helper_->Initialize(kCommandBufferSizeBytes); + size_t MaxTransferBufferSize() { + return size_ - result_size_; } - const void* GetPut() { - return helper_->GetSpace(0); + unsigned int RoundToAlignment(unsigned int size) { + return (size + alignment_ - 1) & ~(alignment_ - 1); } - size_t MaxTransferBufferSize() { - return kTransferBufferSize - initial_offset_; + bool InSync() { + return expected_buffer_index_ == actual_buffer_index_; } - void ClearCommands() { - Buffer ring_buffer = helper_->get_ring_buffer(); - memset(ring_buffer.ptr, kInitialValue, ring_buffer.size); + ExpectedMemoryInfo GetExpectedMemory(size_t size) { + ExpectedMemoryInfo mem; + mem.offset = AllocateExpectedTransferBuffer(size); + mem.id = GetExpectedTransferBufferId(); + mem.ptr = static_cast<uint8*>( + GetExpectedTransferAddressFromOffset(mem.offset, size)); + return mem; } - bool NoCommandsWritten() { - return static_cast<const uint8*>(static_cast<const void*>(commands_))[0] == - kInitialValue; + ExpectedMemoryInfo GetExpectedResultMemory(size_t size) { + ExpectedMemoryInfo mem; + mem.offset = GetExpectedResultBufferOffset(); + mem.id = GetExpectedResultBufferId(); + mem.ptr = static_cast<uint8*>( + GetExpectedTransferAddressFromOffset(mem.offset, size)); + return mem; } - void ClearTransferBuffer() { - memset(transfer_buffer_.ptr, kInitialValue, kTransferBufferSize); + private: + static const int kNumBuffers = 2; + + uint8* actual_buffer() const { + return static_cast<uint8*>(buffers_[actual_buffer_index_].ptr); } - unsigned int RoundToAlignment(unsigned int size) { - return (size + alignment_ - 1) & ~(alignment_ - 1); + uint8* expected_buffer() const { + return static_cast<uint8*>(buffers_[expected_buffer_index_].ptr); } - int GetNextToken() { - return ++token_; + uint32 AllocateExpectedTransferBuffer(size_t size) { + EXPECT_LE(size, MaxTransferBufferSize()); + + // Toggle which buffer we get each time to simulate the buffer being + // reallocated. + expected_buffer_index_ = (expected_buffer_index_ + 1) % kNumBuffers; + + if (expected_offset_ + size > size_) { + expected_offset_ = result_size_; + } + uint32 offset = expected_offset_; + expected_offset_ += RoundToAlignment(size); + + // Make sure each buffer has a different offset. + return offset + expected_buffer_index_ * alignment_; } - int32 GetNextFreeTransferBufferId() { - return command_buffer_->GetNextFreeTransferBufferId(); + void* GetExpectedTransferAddressFromOffset(uint32 offset, size_t size) { + EXPECT_GE(offset, expected_buffer_index_ * alignment_); + EXPECT_LE(offset + size, size_ + expected_buffer_index_ * alignment_); + return expected_buffer() + offset; } - uint32 AllocateTransferBuffer(size_t size) { - if (offset_ + size > kTransferBufferSize) { - offset_ = initial_offset_; - } - uint32 offset = offset_; - offset_ += RoundToAlignment(size); - return offset; + int GetExpectedResultBufferId() { + return buffer_ids_[expected_buffer_index_]; } - void* GetTransferAddressFromOffset(uint32 offset, size_t size) { - EXPECT_LE(offset + size, transfer_buffer_.size); - return static_cast<int8*>(transfer_buffer_.ptr) + offset; + uint32 GetExpectedResultBufferOffset() { + return expected_buffer_index_ * alignment_; } - template <typename T> - T* GetTransferAddressFromOffsetAs(uint32 offset, size_t size) { - return static_cast<T*>(GetTransferAddressFromOffset(offset, size)); + int GetExpectedTransferBufferId() { + return buffer_ids_[expected_buffer_index_]; } - Buffer transfer_buffer_; - CommandBufferEntry* commands_; - scoped_ptr<MockGLES2CommandBuffer> command_buffer_; - scoped_ptr<GLES2CmdHelper> helper_; - int token_; - uint32 offset_; - uint32 initial_offset_; + CommandBuffer* command_buffer_; + size_t size_; + size_t result_size_; uint32 alignment_; - int32 transfer_buffer_id_; + int buffer_ids_[kNumBuffers]; + gpu::Buffer buffers_[kNumBuffers]; + int actual_buffer_index_; + int expected_buffer_index_; + void* last_alloc_; + uint32 expected_offset_; + uint32 actual_offset_; + + DISALLOW_COPY_AND_ASSIGN(MockTransferBuffer); }; -// GCC requires these declarations, but MSVC requires they not be present -#ifndef _MSC_VER -const int32 GLES2CommandBufferTestBase::kNumCommandEntries; -const int32 GLES2CommandBufferTestBase::kCommandBufferSizeBytes; -const size_t GLES2CommandBufferTestBase::kTransferBufferSize; -const uint8 GLES2CommandBufferTestBase::kInitialValue; -#endif +bool MockTransferBuffer::Initialize( + unsigned int starting_buffer_size, + unsigned int result_size, + unsigned int /* min_buffer_size */, + unsigned int /* max_buffer_size */, + unsigned int alignment) { + // Just check they match. + return size_ == starting_buffer_size && + result_size_ == result_size && + alignment_ == alignment; +}; -class TransferBufferTest : public GLES2CommandBufferTestBase { - protected: - static const unsigned int kStartingOffset = 64; - static const unsigned int kAlignment = 4; +int MockTransferBuffer::GetShmId() { + return buffer_ids_[actual_buffer_index_]; +} - TransferBufferTest() { } +void* MockTransferBuffer::GetResultBuffer() { + return actual_buffer() + actual_buffer_index_ * alignment_; +} - virtual void SetUp() { - SetupCommandBuffer( - GLES2Implementation::kStartingOffset, - GLES2Implementation::kAlignment); +int MockTransferBuffer::GetResultOffset() { + return actual_buffer_index_ * alignment_; +} - transfer_buffer_id_ = - command_buffer_->CreateTransferBuffer(kTransferBufferSize, -1); +void MockTransferBuffer::Free() { + GPU_NOTREACHED(); +} - transfer_buffer_.reset(new TransferBuffer( - helper_.get(), - transfer_buffer_id_, - GetTransferAddressFromOffset(0, 0), - kTransferBufferSize, - kStartingOffset, - kAlignment)); - } +bool MockTransferBuffer::HaveBuffer() const { + return true; +} - virtual void TearDown() { - transfer_buffer_.reset(); - } +void* MockTransferBuffer::AllocUpTo( + unsigned int size, unsigned int* size_allocated) { + EXPECT_TRUE(size_allocated != NULL); + EXPECT_TRUE(last_alloc_ == NULL); - scoped_ptr<TransferBuffer> transfer_buffer_; -}; + // Toggle which buffer we get each time to simulate the buffer being + // reallocated. + actual_buffer_index_ = (actual_buffer_index_ + 1) % kNumBuffers; -// GCC requires these declarations, but MSVC requires they not be present -#ifndef _MSC_VER -const unsigned int TransferBufferTest::kStartingOffset; -const unsigned int TransferBufferTest::kAlignment; -#endif + size = std::min(static_cast<size_t>(size), MaxTransferBufferSize()); + if (actual_offset_ + size > size_) { + actual_offset_ = result_size_; + } + uint32 offset = actual_offset_; + actual_offset_ += RoundToAlignment(size); + *size_allocated = size; -TEST_F(TransferBufferTest, Basic) { - EXPECT_TRUE(transfer_buffer_->HaveBuffer()); - EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId()); + // Make sure each buffer has a different offset. + last_alloc_ = actual_buffer() + offset + actual_buffer_index_ * alignment_; + return last_alloc_; } -TEST_F(TransferBufferTest, Free) { - EXPECT_TRUE(transfer_buffer_->HaveBuffer()); +void* MockTransferBuffer::Alloc(unsigned int size) { + EXPECT_LE(size, MaxTransferBufferSize()); + unsigned int temp = 0; + void* p = AllocUpTo(size, &temp); + EXPECT_EQ(temp, size); + return p; +} - // Free buffer. - EXPECT_CALL(*command_buffer_, DestroyTransferBuffer(_)) - .Times(1) - .RetiresOnSaturation(); - transfer_buffer_->Free(); - // See it's freed. - EXPECT_FALSE(transfer_buffer_->HaveBuffer()); - // See that it gets reallocated. - EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId()); - EXPECT_TRUE(transfer_buffer_->HaveBuffer()); - - // Free buffer. - EXPECT_CALL(*command_buffer_, DestroyTransferBuffer(_)) - .Times(1) - .RetiresOnSaturation(); - transfer_buffer_->Free(); - // See it's freed. - EXPECT_FALSE(transfer_buffer_->HaveBuffer()); - // See that it gets reallocated. - EXPECT_TRUE(transfer_buffer_->GetResultBuffer() != NULL); - EXPECT_TRUE(transfer_buffer_->HaveBuffer()); - - // Free buffer. - EXPECT_CALL(*command_buffer_, DestroyTransferBuffer(_)) - .Times(1) - .RetiresOnSaturation(); - transfer_buffer_->Free(); - // See it's freed. - EXPECT_FALSE(transfer_buffer_->HaveBuffer()); - // See that it gets reallocated. - EXPECT_TRUE(transfer_buffer_->GetBuffer() != NULL); - EXPECT_TRUE(transfer_buffer_->HaveBuffer()); - - // Free buffer. - EXPECT_CALL(*command_buffer_, DestroyTransferBuffer(_)) - .Times(1) - .RetiresOnSaturation(); - transfer_buffer_->Free(); - // See it's freed. - EXPECT_FALSE(transfer_buffer_->HaveBuffer()); - // See that it gets reallocated. - transfer_buffer_->GetResultOffset(); - EXPECT_TRUE(transfer_buffer_->HaveBuffer()); - - // Test freeing twice. - EXPECT_CALL(*command_buffer_, DestroyTransferBuffer(_)) - .Times(1) - .RetiresOnSaturation(); - transfer_buffer_->Free(); - transfer_buffer_->Free(); +RingBuffer::Offset MockTransferBuffer::GetOffset(void* pointer) const { + // Make sure each buffer has a different offset. + return static_cast<uint8*>(pointer) - actual_buffer(); } -class GLES2ImplementationTest : public GLES2CommandBufferTestBase { +void MockTransferBuffer::FreePendingToken(void* p, unsigned int /* token */) { + EXPECT_EQ(last_alloc_, p); + last_alloc_ = NULL; +} + +class GLES2ImplementationTest : public testing::Test { protected: + static const uint8 kInitialValue = 0xBD; + static const int32 kNumCommandEntries = 400; + static const int32 kCommandBufferSizeBytes = + kNumCommandEntries * sizeof(CommandBufferEntry); + static const size_t kTransferBufferSize = 256; + static const GLint kMaxCombinedTextureImageUnits = 8; static const GLint kMaxCubeMapTextureSize = 64; static const GLint kMaxFragmentUniformVectors = 16; @@ -441,22 +319,33 @@ class GLES2ImplementationTest : public GLES2CommandBufferTestBase { static const GLuint kRenderbuffersStartId = 1; static const GLuint kTexturesStartId = 1; - GLES2ImplementationTest() { } + typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo; - virtual void SetUp() { - Initialize(false, true); + GLES2ImplementationTest() + : commands_(NULL), + token_(0) { } - virtual void TearDown() { - Mock::VerifyAndClear(gl_.get()); - EXPECT_CALL(*command_buffer_, OnFlush(_)).Times(AnyNumber()); - gl_.reset(); + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; + + bool NoCommandsWritten() { + return static_cast<const uint8*>(static_cast<const void*>(commands_))[0] == + kInitialValue; } void Initialize(bool shared_resources, bool bind_generates_resource) { - SetupCommandBuffer( + command_buffer_.reset(new StrictMock<MockClientCommandBuffer>()); + ASSERT_TRUE(command_buffer_->Initialize()); + + transfer_buffer_.reset(new MockTransferBuffer( + command_buffer(), + kTransferBufferSize, GLES2Implementation::kStartingOffset, - GLES2Implementation::kAlignment); + GLES2Implementation::kAlignment)); + + helper_.reset(new GLES2CmdHelper(command_buffer())); + helper_->Initialize(kCommandBufferSizeBytes); GLES2Implementation::GLState state; state.max_combined_texture_image_units = kMaxCombinedTextureImageUnits; @@ -475,14 +364,13 @@ class GLES2ImplementationTest : public GLES2CommandBufferTestBase { // This just happens to work for now because GLState has 1 GLint per // state. If GLState gets more complicated this code will need to get // more complicated. - AllocateTransferBuffer(sizeof(state)); // in - uint32 offset = AllocateTransferBuffer(sizeof(state)); // out + ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(state) * 2); { InSequence sequence; - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemoryAtOffset(offset, state)) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(mem1.ptr + sizeof(state), state)) .RetiresOnSaturation(); GetNextToken(); // eat the token that starting up will use. @@ -500,9 +388,9 @@ class GLES2ImplementationTest : public GLES2CommandBufferTestBase { while (num_ids) { GLuint num = std::min(num_ids, max_num_per); size_t size = num * sizeof(ids[0]); - uint32 offset = AllocateTransferBuffer(size); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemoryAtOffsetFromArray(offset, ids, size)) + ExpectedMemoryInfo mem = GetExpectedMemory(size); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemoryFromArray(mem.ptr, ids, size)) .RetiresOnSaturation(); GetNextToken(); start += num; @@ -514,36 +402,93 @@ class GLES2ImplementationTest : public GLES2CommandBufferTestBase { gl_.reset(new GLES2Implementation( helper_.get(), - kTransferBufferSize, - transfer_buffer_.ptr, - transfer_buffer_id_, + transfer_buffer_.get(), shared_resources, bind_generates_resource)); + ASSERT_TRUE(gl_->Initialize( + kTransferBufferSize, + kTransferBufferSize, + kTransferBufferSize)); } - EXPECT_CALL(*command_buffer_, OnFlush(_)) + EXPECT_CALL(*command_buffer(), OnFlush()) .Times(1) .RetiresOnSaturation(); helper_->CommandBufferHelper::Finish(); + ::testing::Mock::VerifyAndClearExpectations(gl_.get()); + Buffer ring_buffer = helper_->get_ring_buffer(); commands_ = static_cast<CommandBufferEntry*>(ring_buffer.ptr) + - command_buffer_->GetState().put_offset; + command_buffer()->GetState().put_offset; ClearCommands(); + EXPECT_TRUE(transfer_buffer_->InSync()); + + ::testing::Mock::VerifyAndClearExpectations(command_buffer()); + } + + MockClientCommandBuffer* command_buffer() const { + return command_buffer_.get(); + } + + int GetNextToken() { + return ++token_; + } + + const void* GetPut() { + return helper_->GetSpace(0); + } + + void ClearCommands() { + Buffer ring_buffer = helper_->get_ring_buffer(); + memset(ring_buffer.ptr, kInitialValue, ring_buffer.size); + } + + size_t MaxTransferBufferSize() { + return transfer_buffer_->MaxTransferBufferSize(); + } + + ExpectedMemoryInfo GetExpectedMemory(size_t size) { + return transfer_buffer_->GetExpectedMemory(size); + } + + ExpectedMemoryInfo GetExpectedResultMemory(size_t size) { + return transfer_buffer_->GetExpectedResultMemory(size); } Sequence sequence_; + scoped_ptr<MockClientCommandBuffer> command_buffer_; + scoped_ptr<GLES2CmdHelper> helper_; + scoped_ptr<MockTransferBuffer> transfer_buffer_; scoped_ptr<GLES2Implementation> gl_; + CommandBufferEntry* commands_; + int token_; }; +void GLES2ImplementationTest::SetUp() { + Initialize(false, true); +} + +void GLES2ImplementationTest::TearDown() { + Mock::VerifyAndClear(gl_.get()); + EXPECT_CALL(*command_buffer(), OnFlush()).Times(AnyNumber()); + gl_.reset(); +} + class GLES2ImplementationStrictSharedTest : public GLES2ImplementationTest { protected: - virtual void SetUp() { - Initialize(true, false); - } + virtual void SetUp() OVERRIDE; }; +void GLES2ImplementationStrictSharedTest::SetUp() { + Initialize(true, false); +} + // GCC requires these declarations, but MSVC requires they not be present #ifndef _MSC_VER +const uint8 GLES2ImplementationTest::kInitialValue; +const int32 GLES2ImplementationTest::kNumCommandEntries; +const int32 GLES2ImplementationTest::kCommandBufferSizeBytes; +const size_t GLES2ImplementationTest::kTransferBufferSize; const GLint GLES2ImplementationTest::kMaxCombinedTextureImageUnits; const GLint GLES2ImplementationTest::kMaxCubeMapTextureSize; const GLint GLES2ImplementationTest::kMaxFragmentUniformVectors; @@ -565,7 +510,7 @@ const GLuint GLES2ImplementationTest::kTexturesStartId; #endif TEST_F(GLES2ImplementationTest, ShaderSource) { - const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation + const uint32 kBucketId = GLES2Implementation::kResultBucketId; const GLuint kShaderId = 456; const char* kString1 = "foobar"; const char* kString2 = "barfoo"; @@ -573,9 +518,12 @@ TEST_F(GLES2ImplementationTest, ShaderSource) { const size_t kString2Size = strlen(kString2); const size_t kString3Size = 1; // Want the NULL; const size_t kSourceSize = kString1Size + kString2Size + kString3Size; - const size_t kPaddedString1Size = RoundToAlignment(kString1Size); - const size_t kPaddedString2Size = RoundToAlignment(kString2Size); - const size_t kPaddedString3Size = RoundToAlignment(kString3Size); + const size_t kPaddedString1Size = + transfer_buffer_->RoundToAlignment(kString1Size); + const size_t kPaddedString2Size = + transfer_buffer_->RoundToAlignment(kString2Size); + const size_t kPaddedString3Size = + transfer_buffer_->RoundToAlignment(kString3Size); struct Cmds { cmd::SetBucketSize set_bucket_size; cmd::SetBucketData set_bucket_data1; @@ -587,20 +535,22 @@ TEST_F(GLES2ImplementationTest, ShaderSource) { ShaderSourceBucket shader_source_bucket; cmd::SetBucketSize clear_bucket_size; }; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kPaddedString1Size); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kPaddedString2Size); + ExpectedMemoryInfo mem3 = GetExpectedMemory(kPaddedString3Size); + Cmds expected; expected.set_bucket_size.Init(kBucketId, kSourceSize); expected.set_bucket_data1.Init( - kBucketId, 0, kString1Size, transfer_buffer_id_, - AllocateTransferBuffer(kPaddedString1Size)); + kBucketId, 0, kString1Size, mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.set_bucket_data2.Init( - kBucketId, kString1Size, kString2Size, transfer_buffer_id_, - AllocateTransferBuffer(kPaddedString2Size)); + kBucketId, kString1Size, kString2Size, mem2.id, mem2.offset); expected.set_token2.Init(GetNextToken()); expected.set_bucket_data3.Init( kBucketId, kString1Size + kString2Size, - kString3Size, transfer_buffer_id_, - AllocateTransferBuffer(kPaddedString3Size)); + kString3Size, mem3.id, mem3.offset); expected.set_token3.Init(GetNextToken()); expected.shader_source_bucket.Init(kShaderId, kBucketId); expected.clear_bucket_size.Init(kBucketId, 0); @@ -613,7 +563,7 @@ TEST_F(GLES2ImplementationTest, ShaderSource) { } TEST_F(GLES2ImplementationTest, GetShaderSource) { - const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation + const uint32 kBucketId = GLES2Implementation::kResultBucketId; const GLuint kShaderId = 456; const Str7 kString = {"foobar"}; const char kBad = 0x12; @@ -625,25 +575,29 @@ TEST_F(GLES2ImplementationTest, GetShaderSource) { cmd::SetToken set_token1; cmd::SetBucketSize set_bucket_size2; }; - uint32 offset = AllocateTransferBuffer(sizeof(kString)); + + ExpectedMemoryInfo result1 = GetExpectedResultMemory(sizeof(uint32)); + ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(kString)); + Cmds expected; expected.set_bucket_size1.Init(kBucketId, 0); expected.get_shader_source.Init(kShaderId, kBucketId); - expected.get_bucket_size.Init(kBucketId, transfer_buffer_id_, 0); + expected.get_bucket_size.Init(kBucketId, result1.id, result1.offset); expected.get_bucket_data.Init( - kBucketId, 0, sizeof(kString), transfer_buffer_id_, offset); + kBucketId, 0, sizeof(kString), mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.set_bucket_size2.Init(kBucketId, 0); char buf[sizeof(kString) + 1]; memset(buf, kBad, sizeof(buf)); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(sizeof(kString)))) - .WillOnce(SetMemoryAtOffset(offset, kString)) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(sizeof(kString)))) + .WillOnce(SetMemory(mem1.ptr, kString)) .RetiresOnSaturation(); GLsizei length = 0; gl_->GetShaderSource(kShaderId, sizeof(buf), &length, buf); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); EXPECT_EQ(sizeof(kString) - 1, static_cast<size_t>(length)); EXPECT_STREQ(kString.str, buf); EXPECT_EQ(buf[sizeof(kString)], kBad); @@ -685,33 +639,34 @@ TEST_F(GLES2ImplementationTest, DrawArraysClientSideBuffers) { arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]); const GLsizei kEmuOffset1 = 0; const GLsizei kEmuOffset2 = kSize1; - const GLsizei kTotalSize = kSize1 + kSize2; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize1); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize2); + Cmds expected; expected.enable1.Init(kAttribIndex1); expected.enable2.Init(kAttribIndex2); expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId); expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW); expected.copy_data1.Init( - GL_ARRAY_BUFFER, kEmuOffset1, kSize1, transfer_buffer_id_, - AllocateTransferBuffer(kSize1)); + GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); - expected.set_pointer1.Init(kAttribIndex1, kNumComponents1, - GL_FLOAT, GL_FALSE, 0, kEmuOffset1); + expected.set_pointer1.Init( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1); expected.copy_data2.Init( - GL_ARRAY_BUFFER, kEmuOffset2, kSize2, transfer_buffer_id_, - AllocateTransferBuffer(kSize2)); + GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem2.id, mem2.offset); expected.set_token2.Init(GetNextToken()); - expected.set_pointer2.Init(kAttribIndex2, kNumComponents2, - GL_FLOAT, GL_FALSE, 0, kEmuOffset2); + expected.set_pointer2.Init( + kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, 0, kEmuOffset2); expected.draw.Init(GL_POINTS, kFirst, kCount); expected.restore.Init(GL_ARRAY_BUFFER, 0); gl_->EnableVertexAttribArray(kAttribIndex1); gl_->EnableVertexAttribArray(kAttribIndex2); - gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1, - GL_FLOAT, GL_FALSE, kClientStride, verts); - gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2, - GL_FLOAT, GL_FALSE, kClientStride, verts); + gl_->VertexAttribPointer( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, verts); + gl_->VertexAttribPointer( + kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, kClientStride, verts); gl_->DrawArrays(GL_POINTS, kFirst, kCount); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } @@ -760,8 +715,12 @@ TEST_F(GLES2ImplementationTest, DrawElementsClientSideBuffers) { arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]); const GLsizei kEmuOffset1 = 0; const GLsizei kEmuOffset2 = kSize1; - const GLsizei kTotalSize = kSize1 + kSize2; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kIndexSize); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1); + ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2); + Cmds expected; expected.enable1.Init(kAttribIndex1); expected.enable2.Init(kAttribIndex2); @@ -769,20 +728,17 @@ TEST_F(GLES2ImplementationTest, DrawElementsClientSideBuffers) { expected.set_index_size.Init( GL_ELEMENT_ARRAY_BUFFER, kIndexSize, 0, 0, GL_DYNAMIC_DRAW); expected.copy_data0.Init( - GL_ELEMENT_ARRAY_BUFFER, 0, kIndexSize, transfer_buffer_id_, - AllocateTransferBuffer(kIndexSize)); + GL_ELEMENT_ARRAY_BUFFER, 0, kIndexSize, mem1.id, mem1.offset); expected.set_token0.Init(GetNextToken()); expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId); expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW); expected.copy_data1.Init( - GL_ARRAY_BUFFER, kEmuOffset1, kSize1, transfer_buffer_id_, - AllocateTransferBuffer(kSize1)); + GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset); expected.set_token1.Init(GetNextToken()); - expected.set_pointer1.Init(kAttribIndex1, kNumComponents1, - GL_FLOAT, GL_FALSE, 0, kEmuOffset1); + expected.set_pointer1.Init( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1); expected.copy_data2.Init( - GL_ARRAY_BUFFER, kEmuOffset2, kSize2, transfer_buffer_id_, - AllocateTransferBuffer(kSize2)); + GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset); expected.set_token2.Init(GetNextToken()); expected.set_pointer2.Init(kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, 0, kEmuOffset2); @@ -838,33 +794,36 @@ TEST_F(GLES2ImplementationTest, arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]); const GLsizei kEmuOffset1 = 0; const GLsizei kEmuOffset2 = kSize1; - const GLsizei kTotalSize = kSize1 + kSize2; + + ExpectedMemoryInfo mem1 = GetExpectedResultMemory(sizeof(uint32)); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1); + ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2); + + Cmds expected; expected.enable1.Init(kAttribIndex1); expected.enable2.Init(kAttribIndex2); expected.bind_to_index.Init(GL_ELEMENT_ARRAY_BUFFER, kClientIndexBufferId); expected.get_max.Init(kClientIndexBufferId, kCount, GL_UNSIGNED_SHORT, - kIndexOffset, transfer_buffer_id_, 0); + kIndexOffset, mem1.id, mem1.offset); expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId); expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW); expected.copy_data1.Init( - GL_ARRAY_BUFFER, kEmuOffset1, kSize1, transfer_buffer_id_, - AllocateTransferBuffer(kSize1)); + GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset); expected.set_token1.Init(GetNextToken()); expected.set_pointer1.Init(kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1); expected.copy_data2.Init( - GL_ARRAY_BUFFER, kEmuOffset2, kSize2, transfer_buffer_id_, - AllocateTransferBuffer(kSize2)); + GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset); expected.set_token2.Init(GetNextToken()); expected.set_pointer2.Init(kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, 0, kEmuOffset2); expected.draw.Init(GL_POINTS, kCount, GL_UNSIGNED_SHORT, kIndexOffset); expected.restore.Init(GL_ARRAY_BUFFER, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(kMaxIndex)) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(mem1.ptr,kMaxIndex)) .RetiresOnSaturation(); gl_->EnableVertexAttribArray(kAttribIndex1); @@ -897,16 +856,19 @@ TEST_F(GLES2ImplementationTest, GetVertexBufferPointerv) { VertexAttribPointer set_pointer; GetVertexAttribPointerv get_pointer; }; + + ExpectedMemoryInfo mem1 = GetExpectedResultMemory(16); + Cmds expected; expected.bind.Init(GL_ARRAY_BUFFER, kBufferId); expected.set_pointer.Init(kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, kStride2, kOffset2); expected.get_pointer.Init(kAttribIndex2, GL_VERTEX_ATTRIB_ARRAY_POINTER, - transfer_buffer_id_, 0); + mem1.id, mem1.offset); // One call to flush to way for GetVertexAttribPointerv - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<uint32>(kOffset2))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(mem1.ptr, SizedResultHelper<uint32>(kOffset2))) .RetiresOnSaturation(); // Set one client side buffer. @@ -952,6 +914,10 @@ TEST_F(GLES2ImplementationTest, GetVertexAttrib) { GetVertexAttribiv get1; // for getting the buffer from attrib2 GetVertexAttribfv get2; // for getting the value from attrib1 }; + + ExpectedMemoryInfo mem1 = GetExpectedResultMemory(16); + ExpectedMemoryInfo mem2 = GetExpectedResultMemory(16); + Cmds expected; expected.enable.Init(kAttribIndex1); expected.bind.Init(GL_ARRAY_BUFFER, kBufferId); @@ -959,17 +925,19 @@ TEST_F(GLES2ImplementationTest, GetVertexAttrib) { kStride2, kOffset2); expected.get1.Init(kAttribIndex2, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, - transfer_buffer_id_, 0); + mem1.id, mem1.offset); expected.get2.Init(kAttribIndex1, GL_CURRENT_VERTEX_ATTRIB, - transfer_buffer_id_, 0); + mem2.id, mem2.offset); FourFloats current_attrib(1.2f, 3.4f, 5.6f, 7.8f); // One call to flush to way for GetVertexAttribiv - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<GLuint>(kBufferId))) - .WillOnce(SetMemory(SizedResultHelper<FourFloats>(current_attrib))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory( + mem1.ptr, SizedResultHelper<GLuint>(kBufferId))) + .WillOnce(SetMemory( + mem2.ptr, SizedResultHelper<FourFloats>(current_attrib))) .RetiresOnSaturation(); gl_->EnableVertexAttribArray(kAttribIndex1); @@ -1025,11 +993,14 @@ TEST_F(GLES2ImplementationTest, ReservedIds) { GetError get; }; Cmds expected; - expected.get.Init(transfer_buffer_id_, 0); + + ExpectedMemoryInfo mem1 = GetExpectedResultMemory(sizeof(GetError::Result)); + + expected.get.Init(mem1.id, mem1.offset); // One call to flush to wait for GetError - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(mem1.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); gl_->BindBuffer( @@ -1060,24 +1031,29 @@ TEST_F(GLES2ImplementationTest, ReadPixels2Reads) { const GLenum kFormat = GL_RGBA; const GLenum kType = GL_UNSIGNED_BYTE; + ExpectedMemoryInfo mem1 = + GetExpectedMemory(kWidth * kHeight / 2 * kBytesPerPixel); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(ReadPixels::Result)); + ExpectedMemoryInfo mem2 = + GetExpectedMemory(kWidth * kHeight / 2 * kBytesPerPixel); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(ReadPixels::Result)); + Cmds expected; expected.read1.Init( 0, 0, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, - AllocateTransferBuffer(kWidth * kHeight / 2 * kBytesPerPixel), - transfer_buffer_id_, 0); + mem1.id, mem1.offset, result1.id, result1.offset); expected.set_token1.Init(GetNextToken()); expected.read2.Init( 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, - AllocateTransferBuffer(kWidth * kHeight / 2 * kBytesPerPixel), - transfer_buffer_id_, 0); + mem2.id, mem2.offset, result2.id, result2.offset); expected.set_token2.Init(GetNextToken()); scoped_array<int8> buffer(new int8[kWidth * kHeight * kBytesPerPixel]); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(static_cast<uint32>(1))) - .WillOnce(SetMemory(static_cast<uint32>(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, static_cast<uint32>(1))) + .WillOnce(SetMemory(result2.ptr, static_cast<uint32>(1))) .RetiresOnSaturation(); gl_->ReadPixels(0, 0, kWidth, kHeight, kFormat, kType, buffer.get()); @@ -1095,16 +1071,19 @@ TEST_F(GLES2ImplementationTest, ReadPixelsBadFormatType) { const GLenum kFormat = 0; const GLenum kType = 0; + ExpectedMemoryInfo mem1 = + GetExpectedMemory(kWidth * kHeight * kBytesPerPixel); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(ReadPixels::Result)); + Cmds expected; expected.read.Init( - 0, 0, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, - AllocateTransferBuffer(kWidth * kHeight * kBytesPerPixel), - transfer_buffer_id_, 0); + 0, 0, kWidth, kHeight, kFormat, kType, + mem1.id, mem1.offset, result1.id, result1.offset); expected.set_token.Init(GetNextToken()); scoped_array<int8> buffer(new int8[kWidth * kHeight * kBytesPerPixel]); - EXPECT_CALL(*command_buffer_, OnFlush(_)) + EXPECT_CALL(*command_buffer(), OnFlush()) .Times(1) .RetiresOnSaturation(); @@ -1120,17 +1099,18 @@ TEST_F(GLES2ImplementationTest, FreeUnusedSharedMemory) { const GLintptr kOffset = 15; const GLsizeiptr kSize = 16; - uint32 offset = 0; + ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize); + Cmds expected; expected.buf.Init( - kTarget, kOffset, kSize, transfer_buffer_id_, offset); + kTarget, kOffset, kSize, mem1.id, mem1.offset); expected.set_token.Init(GetNextToken()); void* mem = gl_->MapBufferSubDataCHROMIUM( kTarget, kOffset, kSize, GL_WRITE_ONLY); ASSERT_TRUE(mem != NULL); gl_->UnmapBufferSubDataCHROMIUM(mem); - EXPECT_CALL(*command_buffer_, DestroyTransferBuffer(_)) + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) .Times(1) .RetiresOnSaturation(); gl_->FreeUnusedSharedMemory(); @@ -1148,7 +1128,8 @@ TEST_F(GLES2ImplementationTest, MapUnmapBufferSubDataCHROMIUM) { uint32 offset = 0; Cmds expected; expected.buf.Init( - kTarget, kOffset, kSize, GetNextFreeTransferBufferId(), offset); + kTarget, kOffset, kSize, + command_buffer()->GetNextFreeTransferBufferId(), offset); expected.set_token.Init(GetNextToken()); void* mem = gl_->MapBufferSubDataCHROMIUM( @@ -1163,12 +1144,21 @@ TEST_F(GLES2ImplementationTest, MapUnmapBufferSubDataCHROMIUMBadArgs) { const GLintptr kOffset = 15; const GLsizeiptr kSize = 16; + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result3 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result4 = + GetExpectedResultMemory(sizeof(GetError::Result)); + // Calls to flush to wait for GetError - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); void* mem; @@ -1203,7 +1193,8 @@ TEST_F(GLES2ImplementationTest, MapUnmapTexSubImage2DCHROMIUM) { Cmds expected; expected.tex.Init( GL_TEXTURE_2D, kLevel, kXOffset, kYOffset, kWidth, kHeight, kFormat, - kType, GetNextFreeTransferBufferId(), offset, GL_FALSE); + kType, + command_buffer()->GetNextFreeTransferBufferId(), offset, GL_FALSE); expected.set_token.Init(GetNextToken()); void* mem = gl_->MapTexSubImage2DCHROMIUM( @@ -1230,15 +1221,30 @@ TEST_F(GLES2ImplementationTest, MapUnmapTexSubImage2DCHROMIUMBadArgs) { const GLenum kFormat = GL_RGBA; const GLenum kType = GL_UNSIGNED_BYTE; + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result3 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result4 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result5 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result6 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result7 = + GetExpectedResultMemory(sizeof(GetError::Result)); + // Calls to flush to wait for GetError - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result5.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result6.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result7.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); void* mem; @@ -1333,13 +1339,18 @@ TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMValidArgs) { }; const GLsizei kNumPnames = arraysize(pnames); const GLsizeiptr kResultsSize = num_results * sizeof(results[0]); - const uint32 kPnamesOffset = - AllocateTransferBuffer(kNumPnames * sizeof(pnames[0])); - const uint32 kResultsOffset = AllocateTransferBuffer(kResultsSize); + const size_t kPNamesSize = kNumPnames * sizeof(pnames[0]); + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kPNamesSize + kResultsSize); + ExpectedMemoryInfo result1 = GetExpectedResultMemory( + sizeof(GetError::Result)); + + const uint32 kPnamesOffset = mem1.offset; + const uint32 kResultsOffset = mem1.offset + kPNamesSize; Cmds expected; expected.get_multiple.Init( - transfer_buffer_id_, kPnamesOffset, kNumPnames, - transfer_buffer_id_, kResultsOffset, kResultsSize); + mem1.id, kPnamesOffset, kNumPnames, + mem1.id, kResultsOffset, kResultsSize); expected.set_token.Init(GetNextToken()); const GLint kSentinel = 0x12345678; @@ -1349,10 +1360,10 @@ TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMValidArgs) { 1, 0, 1, 0, 1, -1, }; // One call to flush to wait for results - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemoryAtOffsetFromArray( - kResultsOffset, returned_results, sizeof(returned_results))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemoryFromArray(mem1.ptr + kPNamesSize, + returned_results, sizeof(returned_results))) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); gl_->GetMultipleIntegervCHROMIUM( @@ -1374,12 +1385,21 @@ TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMBadArgs) { const GLsizei kNumPnames = arraysize(pnames); const GLsizeiptr kResultsSize = num_results * sizeof(results[0]); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result3 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result4 = + GetExpectedResultMemory(sizeof(GetError::Result)); + // Calls to flush to wait for GetError - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); const GLint kSentinel = 0x12345678; @@ -1422,19 +1442,25 @@ TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMBadArgs) { } TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) { - const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation + const uint32 kBucketId = GLES2Implementation::kResultBucketId; const GLuint kProgramId = 123; const char kBad = 0x12; GLsizei size = 0; const Str7 kString = {"foobar"}; char buf[20]; + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(cmd::GetBucketSize::Result)); + ExpectedMemoryInfo mem1 = + GetExpectedMemory(sizeof(kString)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + memset(buf, kBad, sizeof(buf)); - uint32 offset = AllocateTransferBuffer(sizeof(kString)); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(sizeof(kString)))) - .WillOnce(SetMemoryAtOffset(offset, kString)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(sizeof(kString)))) + .WillOnce(SetMemory(mem1.ptr, kString)) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); struct Cmds { @@ -1448,9 +1474,9 @@ TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) { Cmds expected; expected.set_bucket_size1.Init(kBucketId, 0); expected.get_program_info.Init(kProgramId, kBucketId); - expected.get_bucket_size.Init(kBucketId, transfer_buffer_id_, 0); + expected.get_bucket_size.Init(kBucketId, result1.id, result1.offset); expected.get_bucket_data.Init( - kBucketId, 0, sizeof(kString), transfer_buffer_id_, offset); + kBucketId, 0, sizeof(kString), mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.set_bucket_size2.Init(kBucketId, 0); gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), &size, &buf); @@ -1462,19 +1488,28 @@ TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) { } TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMBadArgs) { - const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation + const uint32 kBucketId = GLES2Implementation::kResultBucketId; const GLuint kProgramId = 123; GLsizei size = 0; const Str7 kString = {"foobar"}; char buf[20]; - uint32 offset = AllocateTransferBuffer(sizeof(kString)); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(sizeof(kString)))) - .WillOnce(SetMemoryAtOffset(offset, kString)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(cmd::GetBucketSize::Result)); + ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(kString)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result3 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result4 = + GetExpectedResultMemory(sizeof(GetError::Result)); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(sizeof(kString)))) + .WillOnce(SetMemory(mem1.ptr, kString)) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); // try bufsize not big enough. @@ -1489,9 +1524,9 @@ TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMBadArgs) { Cmds expected; expected.set_bucket_size1.Init(kBucketId, 0); expected.get_program_info.Init(kProgramId, kBucketId); - expected.get_bucket_size.Init(kBucketId, transfer_buffer_id_, 0); + expected.get_bucket_size.Init(kBucketId, result1.id, result1.offset); expected.get_bucket_data.Init( - kBucketId, 0, sizeof(kString), transfer_buffer_id_, offset); + kBucketId, 0, sizeof(kString), mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.set_bucket_size2.Init(kBucketId, 0); gl_->GetProgramInfoCHROMIUM(kProgramId, 6, &size, &buf); @@ -1546,8 +1581,11 @@ TEST_F(GLES2ImplementationTest, GetIntegerCacheRead) { EXPECT_EQ(pv.expected, v); } - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetError::Result)); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError()); } @@ -1582,8 +1620,11 @@ TEST_F(GLES2ImplementationTest, GetIntegerCacheWrite) { EXPECT_EQ(pv.expected, v); } - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetError::Result)); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError()); } @@ -1663,11 +1704,13 @@ TEST_F(GLES2ImplementationTest, TexImage2D) { 31, 32, 33, 33, 34, 35, 35, 36, 37, 123, 124, 125, 41, 42, 43, 43, 44, 45, 45, 46, 47, }; - uint32 offset = AllocateTransferBuffer(sizeof(pixels)); + + ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(pixels)); + Cmds expected; expected.tex_image_2d.Init( kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, - transfer_buffer_id_, offset); + mem1.id, mem1.offset); expected.set_token.Init(GetNextToken()); gl_->TexImage2D( kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, @@ -1675,14 +1718,14 @@ TEST_F(GLES2ImplementationTest, TexImage2D) { EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); EXPECT_TRUE(CheckRect( kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, false, - pixels, GetTransferAddressFromOffsetAs<uint8>(offset, sizeof(pixels)))); + pixels, mem1.ptr)); ClearCommands(); - uint32 offset2 = AllocateTransferBuffer(sizeof(pixels)); + ExpectedMemoryInfo mem2 = GetExpectedMemory(sizeof(pixels)); Cmds2 expected2; expected2.tex_image_2d.Init( kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, - transfer_buffer_id_, offset2); + mem2.id, mem2.offset); expected2.set_token.Init(GetNextToken()); const void* commands2 = GetPut(); gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE); @@ -1692,7 +1735,7 @@ TEST_F(GLES2ImplementationTest, TexImage2D) { EXPECT_EQ(0, memcmp(&expected2, commands2, sizeof(expected2))); EXPECT_TRUE(CheckRect( kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, true, - pixels, GetTransferAddressFromOffsetAs<uint8>(offset2, sizeof(pixels)))); + pixels, mem2.ptr)); } // Test TexImage2D with 2 writes @@ -1731,27 +1774,29 @@ TEST_F(GLES2ImplementationTest, TexImage2D2Writes) { for (uint32 ii = 0; ii < size; ++ii) { pixels[ii] = static_cast<uint8>(ii); } - uint32 offset1 = AllocateTransferBuffer(half_size); - uint32 offset2 = AllocateTransferBuffer(half_size); + + ExpectedMemoryInfo mem1 = GetExpectedMemory(half_size); + ExpectedMemoryInfo mem2 = GetExpectedMemory(half_size); + Cmds expected; expected.tex_image_2d.Init( kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, 0, 0); expected.tex_sub_image_2d1.Init( kTarget, kLevel, 0, 0, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, offset1, true); + mem1.id, mem1.offset, true); expected.set_token1.Init(GetNextToken()); expected.tex_sub_image_2d2.Init( kTarget, kLevel, 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, offset2, true); + mem2.id, mem2.offset, true); expected.set_token2.Init(GetNextToken()); // TODO(gman): Make it possible to run this test - // EXPECT_CALL(*command_buffer_, OnFlush(_)) + // EXPECT_CALL(*command_buffer(), OnFlush()) // .WillOnce(CheckRectAction( // kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, // false, pixels.get(), - // GetTransferAddressFromOffsetAs<uint8>(offset1, half_size))) + // GetExpectedTransferAddressFromOffsetAs<uint8>(offset1, half_size))) // .RetiresOnSaturation(); gl_->TexImage2D( @@ -1760,31 +1805,30 @@ TEST_F(GLES2ImplementationTest, TexImage2D2Writes) { EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); EXPECT_TRUE(CheckRect( kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, false, - pixels.get() + kHeight / 2 * padded_row_size, - GetTransferAddressFromOffsetAs<uint8>(offset2, half_size))); + pixels.get() + kHeight / 2 * padded_row_size, mem2.ptr)); ClearCommands(); const void* commands2 = GetPut(); - uint32 offset3 = AllocateTransferBuffer(half_size); - uint32 offset4 = AllocateTransferBuffer(half_size); + ExpectedMemoryInfo mem3 = GetExpectedMemory(half_size); + ExpectedMemoryInfo mem4 = GetExpectedMemory(half_size); expected.tex_image_2d.Init( kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, 0, 0); expected.tex_sub_image_2d1.Init( kTarget, kLevel, 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, offset3, true); + mem3.id, mem3.offset, true); expected.set_token1.Init(GetNextToken()); expected.tex_sub_image_2d2.Init( kTarget, kLevel, 0, 0, kWidth, kHeight / 2, kFormat, kType, - transfer_buffer_id_, offset4, true); + mem4.id, mem4.offset, true); expected.set_token2.Init(GetNextToken()); // TODO(gman): Make it possible to run this test - // EXPECT_CALL(*command_buffer_, OnFlush(_)) + // EXPECT_CALL(*command_buffer(), OnFlush()) // .WillOnce(CheckRectAction( // kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, // true, pixels.get(), - // GetTransferAddressFromOffsetAs<uint8>(offset3, half_size))) + // GetExpectedTransferAddressFromOffsetAs<uint8>(offset3, half_size))) // .RetiresOnSaturation(); gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE); @@ -1794,145 +1838,7 @@ TEST_F(GLES2ImplementationTest, TexImage2D2Writes) { EXPECT_EQ(0, memcmp(&expected, commands2, sizeof(expected))); EXPECT_TRUE(CheckRect( kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, true, - pixels.get() + kHeight / 2 * padded_row_size, - GetTransferAddressFromOffsetAs<uint8>(offset4, half_size))); -} - -// Test TexImage2D with sub rows -TEST_F(GLES2ImplementationTest, TexImage2DSubRows) { - struct Cmds { - TexImage2D tex_image_2d; - TexSubImage2D tex_sub_image_2d1; - cmd::SetToken set_token1; - TexSubImage2D tex_sub_image_2d2; - cmd::SetToken set_token2; - TexSubImage2D tex_sub_image_2d3; - cmd::SetToken set_token3; - TexSubImage2D tex_sub_image_2d4; - cmd::SetToken set_token4; - }; - const GLenum kTarget = GL_TEXTURE_2D; - const GLint kLevel = 0; - const GLenum kFormat = GL_RGB; - const GLint kBorder = 0; - const GLenum kType = GL_UNSIGNED_BYTE; - const GLint kPixelStoreUnpackAlignment = 4; - const GLsizei kHeight = 2; - const GLsizei kWidth = (MaxTransferBufferSize() / 3) * 2; - - uint32 size = 0; - uint32 unpadded_row_size = 0; - uint32 padded_row_size = 0; - ASSERT_TRUE(ComputeImageDataSizes( - kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, - &size, &unpadded_row_size, &padded_row_size)); - uint32 part_size = kWidth * 3 / 2; - - scoped_array<uint8> pixels(new uint8[size]); - for (uint32 ii = 0; ii < size; ++ii) { - pixels[ii] = static_cast<uint8>(ii); - } - uint32 offset1 = AllocateTransferBuffer(part_size); - uint32 offset2 = AllocateTransferBuffer(part_size); - uint32 offset3 = AllocateTransferBuffer(part_size); - uint32 offset4 = AllocateTransferBuffer(part_size); - Cmds expected; - expected.tex_image_2d.Init( - kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, - 0, 0); - expected.tex_sub_image_2d1.Init( - kTarget, kLevel, 0, 0, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset1, true); - expected.set_token1.Init(GetNextToken()); - expected.tex_sub_image_2d2.Init( - kTarget, kLevel, kWidth / 2, 0, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset2, true); - expected.set_token2.Init(GetNextToken()); - expected.tex_sub_image_2d3.Init( - kTarget, kLevel, 0, 1, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset3, true); - expected.set_token3.Init(GetNextToken()); - expected.tex_sub_image_2d4.Init( - kTarget, kLevel, kWidth / 2, 1, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset4, true); - expected.set_token4.Init(GetNextToken()); - - // TODO(gman): Make it possible to run this test - // EXPECT_CALL(*command_buffer_, OnFlush(_)) - // .WillOnce(CheckRectAction( - // kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - // pixels.get(), - // GetTransferAddressFromOffsetAs<uint8>(offset1, part_size))) - // .WillOnce(CheckRectAction( - // kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - // pixels.get() + part_size, - // GetTransferAddressFromOffsetAs<uint8>(offset2, part_size))) - // .WillOnce(CheckRectAction( - // kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - // pixels.get() + padded_row_size, - // GetTransferAddressFromOffsetAs<uint8>(offset3, part_size))) - // .RetiresOnSaturation(); - - gl_->TexImage2D( - kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, - pixels.get()); - EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); - EXPECT_TRUE(CheckRect( - kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - pixels.get() + padded_row_size + part_size, - GetTransferAddressFromOffsetAs<uint8>(offset4, part_size))); - - ClearCommands(); - const void* commands2 = GetPut(); - offset1 = AllocateTransferBuffer(part_size); - offset2 = AllocateTransferBuffer(part_size); - offset3 = AllocateTransferBuffer(part_size); - offset4 = AllocateTransferBuffer(part_size); - expected.tex_image_2d.Init( - kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, - 0, 0); - expected.tex_sub_image_2d1.Init( - kTarget, kLevel, 0, 1, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset1, true); - expected.set_token1.Init(GetNextToken()); - expected.tex_sub_image_2d2.Init( - kTarget, kLevel, kWidth / 2, 1, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset2, true); - expected.set_token2.Init(GetNextToken()); - expected.tex_sub_image_2d3.Init( - kTarget, kLevel, 0, 0, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset3, true); - expected.set_token3.Init(GetNextToken()); - expected.tex_sub_image_2d4.Init( - kTarget, kLevel, kWidth / 2, 0, kWidth / 2, 1, kFormat, kType, - transfer_buffer_id_, offset4, true); - expected.set_token4.Init(GetNextToken()); - - // TODO(gman): Make it possible to run this test - // EXPECT_CALL(*command_buffer_, OnFlush(_)) - // .WillOnce(CheckRectAction( - // kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - // pixels.get(), - // GetTransferAddressFromOffsetAs<uint8>(offset1, part_size))) - // .WillOnce(CheckRectAction( - // kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - // pixels.get() + part_size, - // GetTransferAddressFromOffsetAs<uint8>(offset2, part_size))) - // .WillOnce(CheckRectAction( - // kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - // pixels.get() + padded_row_size, - // GetTransferAddressFromOffsetAs<uint8>(offset3, part_size))) - // .RetiresOnSaturation(); - - gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE); - gl_->TexImage2D( - kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType, - pixels.get()); - EXPECT_EQ(0, memcmp(&expected, commands2, sizeof(expected))); - EXPECT_TRUE(CheckRect( - kWidth / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, false, - pixels.get() + padded_row_size + part_size, - GetTransferAddressFromOffsetAs<uint8>(offset4, part_size))); + pixels.get() + kHeight / 2 * padded_row_size, mem4.ptr)); } // Test TexSubImage2D with GL_PACK_FLIP_Y set and partial multirow transfers @@ -1963,8 +1869,9 @@ TEST_F(GLES2ImplementationTest, TexSubImage2DFlipY) { ASSERT_TRUE(GLES2Util::ComputeImageDataSize( kSubImageWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment, &sub_2_high_size)); - uint32 offset1 = AllocateTransferBuffer(sub_2_high_size); - uint32 offset2 = AllocateTransferBuffer(sub_2_high_size); + + ExpectedMemoryInfo mem1 = GetExpectedMemory(sub_2_high_size); + ExpectedMemoryInfo mem2 = GetExpectedMemory(sub_2_high_size); Cmds expected; expected.pixel_store_i1.Init(GL_UNPACK_ALIGNMENT, kPixelStoreUnpackAlignment); @@ -1973,11 +1880,11 @@ TEST_F(GLES2ImplementationTest, TexSubImage2DFlipY) { kType, 0, NULL); expected.tex_sub_image_2d1.Init(kTarget, kLevel, kSubImageXOffset, kSubImageYOffset + 2, kSubImageWidth, 2, kFormat, kType, - transfer_buffer_id_, offset1, false); + mem1.id, mem1.offset, false); expected.set_token1.Init(GetNextToken()); expected.tex_sub_image_2d2.Init(kTarget, kLevel, kSubImageXOffset, - kSubImageYOffset, kSubImageWidth , 2, kFormat, kType, transfer_buffer_id_, - offset2, false); + kSubImageYOffset, kSubImageWidth , 2, kFormat, kType, + mem2.id, mem2.offset, false); expected.set_token2.Init(GetNextToken()); gl_->PixelStorei(GL_UNPACK_ALIGNMENT, kPixelStoreUnpackAlignment); @@ -2000,7 +1907,7 @@ TEST_F(GLES2ImplementationTest, TexSubImage2DFlipY) { EXPECT_TRUE(CheckRect( kSubImageWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment, true, reinterpret_cast<uint8*>(pixels.get() + 2 * kSubImageWidth), - GetTransferAddressFromOffsetAs<uint8>(offset2, sub_2_high_size))); + mem2.ptr)); } // Test that GenBuffer does not call GenSharedIds. @@ -2041,8 +1948,11 @@ TEST_F(GLES2ImplementationStrictSharedTest, BindsNotCached) { for (size_t ii = 0; ii < num_pairs; ++ii) { const PNameValue& pv = pairs[ii]; GLint v = -1; - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<GLuint>(pv.expected))) + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetIntegerv::Result)); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, + SizedResultHelper<GLuint>(pv.expected))) .RetiresOnSaturation(); gl_->GetIntegerv(pv.pname, &v); EXPECT_EQ(pv.expected, v); @@ -2052,13 +1962,26 @@ TEST_F(GLES2ImplementationStrictSharedTest, BindsNotCached) { TEST_F(GLES2ImplementationStrictSharedTest, CanNotDeleteIdsWeDidNotCreate) { GLuint id = 0x12345678; - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result3 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result4 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result5 = + GetExpectedResultMemory(sizeof(GetError::Result)); + ExpectedMemoryInfo result6 = + GetExpectedResultMemory(sizeof(GetError::Result)); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result5.ptr, GLuint(GL_NO_ERROR))) + .WillOnce(SetMemory(result6.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); gl_->DeleteBuffers(1, &id); @@ -2078,28 +2001,32 @@ TEST_F(GLES2ImplementationStrictSharedTest, CanNotDeleteIdsWeDidNotCreate) { TEST_F(GLES2ImplementationTest, CreateStreamTextureCHROMIUM) { const GLuint kTextureId = 123; const GLuint kResult = 456; - const uint32 kResultOffset = 0; struct Cmds { CreateStreamTextureCHROMIUM create_stream; }; + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(CreateStreamTextureCHROMIUM::Result)); + ExpectedMemoryInfo result2 = + GetExpectedResultMemory(sizeof(GetError::Result)); + Cmds expected; - expected.create_stream.Init(kTextureId, transfer_buffer_id_, kResultOffset); + expected.create_stream.Init(kTextureId, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemoryAtOffset(kResultOffset, kResult)) - .WillOnce(SetMemory(GLuint(GL_NO_ERROR))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, kResult)) + .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR))) .RetiresOnSaturation(); GLuint handle = gl_->CreateStreamTextureCHROMIUM(kTextureId); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); EXPECT_EQ(handle, kResult); EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError()); - EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } TEST_F(GLES2ImplementationTest, GetString) { - const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation + const uint32 kBucketId = GLES2Implementation::kResultBucketId; const Str7 kString = {"foobar"}; // GL_CHROMIUM_map_sub GL_CHROMIUM_flipy are hard coded into // GLES2Implementation. @@ -2113,21 +2040,23 @@ TEST_F(GLES2ImplementationTest, GetString) { cmd::SetToken set_token1; cmd::SetBucketSize set_bucket_size2; }; - uint32 offset = AllocateTransferBuffer(sizeof(kString)); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(cmd::GetBucketSize::Result)); + ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(kString)); Cmds expected; expected.set_bucket_size1.Init(kBucketId, 0); expected.get_string.Init(GL_EXTENSIONS, kBucketId); - expected.get_bucket_size.Init(kBucketId, transfer_buffer_id_, 0); + expected.get_bucket_size.Init(kBucketId, result1.id, result1.offset); expected.get_bucket_data.Init( - kBucketId, 0, sizeof(kString), transfer_buffer_id_, offset); + kBucketId, 0, sizeof(kString), mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.set_bucket_size2.Init(kBucketId, 0); char buf[sizeof(kString) + 1]; memset(buf, kBad, sizeof(buf)); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(sizeof(kString)))) - .WillOnce(SetMemoryAtOffset(offset, kString)) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(sizeof(kString)))) + .WillOnce(SetMemory(mem1.ptr, kString)) .RetiresOnSaturation(); const GLubyte* result = gl_->GetString(GL_EXTENSIONS); @@ -2136,7 +2065,7 @@ TEST_F(GLES2ImplementationTest, GetString) { } TEST_F(GLES2ImplementationTest, PixelStoreiGLPackReverseRowOrderANGLE) { - const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation + const uint32 kBucketId = GLES2Implementation::kResultBucketId; const Str7 kString = {"foobar"}; struct Cmds { cmd::SetBucketSize set_bucket_size1; @@ -2147,20 +2076,24 @@ TEST_F(GLES2ImplementationTest, PixelStoreiGLPackReverseRowOrderANGLE) { cmd::SetBucketSize set_bucket_size2; PixelStorei pixel_store; }; - uint32 offset = AllocateTransferBuffer(sizeof(kString)); + + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(cmd::GetBucketSize::Result)); + ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(kString)); + Cmds expected; expected.set_bucket_size1.Init(kBucketId, 0); expected.get_string.Init(GL_EXTENSIONS, kBucketId); - expected.get_bucket_size.Init(kBucketId, transfer_buffer_id_, 0); + expected.get_bucket_size.Init(kBucketId, result1.id, result1.offset); expected.get_bucket_data.Init( - kBucketId, 0, sizeof(kString), transfer_buffer_id_, offset); + kBucketId, 0, sizeof(kString), mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.set_bucket_size2.Init(kBucketId, 0); expected.pixel_store.Init(GL_PACK_REVERSE_ROW_ORDER_ANGLE, 1); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(sizeof(kString)))) - .WillOnce(SetMemoryAtOffset(offset, kString)) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(sizeof(kString)))) + .WillOnce(SetMemory(mem1.ptr, kString)) .RetiresOnSaturation(); gl_->PixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, 1); @@ -2190,16 +2123,18 @@ TEST_F(GLES2ImplementationTest, BufferDataLargerThanTransferBuffer) { const unsigned kUsableSize = kTransferBufferSize - GLES2Implementation::kStartingOffset; uint8 buf[kUsableSize * 2] = { 0, }; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kUsableSize); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kUsableSize); + Cmds expected; expected.set_size.Init( GL_ARRAY_BUFFER, arraysize(buf), 0, 0, GL_DYNAMIC_DRAW); expected.copy_data1.Init( - GL_ARRAY_BUFFER, 0, kUsableSize, transfer_buffer_id_, - AllocateTransferBuffer(kUsableSize)); + GL_ARRAY_BUFFER, 0, kUsableSize, mem1.id, mem1.offset); expected.set_token1.Init(GetNextToken()); expected.copy_data2.Init( - GL_ARRAY_BUFFER, kUsableSize, kUsableSize, transfer_buffer_id_, - AllocateTransferBuffer(kUsableSize)); + GL_ARRAY_BUFFER, kUsableSize, kUsableSize, mem2.id, mem2.offset); expected.set_token2.Init(GetNextToken()); gl_->BufferData(GL_ARRAY_BUFFER, arraysize(buf), buf, GL_DYNAMIC_DRAW); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index e8cf5f9..fae58d97 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h @@ -130,10 +130,12 @@ TEST_F(GLES2ImplementationTest, CheckFramebufferStatus) { typedef CheckFramebufferStatus::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(CheckFramebufferStatus::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->CheckFramebufferStatus(1); @@ -551,9 +553,10 @@ TEST_F(GLES2ImplementationTest, GetBooleanv) { typedef GetBooleanv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetBooleanv(123, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -567,9 +570,10 @@ TEST_F(GLES2ImplementationTest, GetBufferParameteriv) { typedef GetBufferParameteriv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, GL_BUFFER_SIZE, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, GL_BUFFER_SIZE, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetBufferParameteriv(123, GL_BUFFER_SIZE, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -583,9 +587,10 @@ TEST_F(GLES2ImplementationTest, GetFloatv) { typedef GetFloatv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetFloatv(123, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -599,11 +604,12 @@ TEST_F(GLES2ImplementationTest, GetFramebufferAttachmentParameteriv) { typedef GetFramebufferAttachmentParameteriv::Result Result; Result::Type result = 0; Cmds expected; + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); expected.cmd.Init( 123, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, - transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetFramebufferAttachmentParameteriv( 123, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, @@ -619,9 +625,10 @@ TEST_F(GLES2ImplementationTest, GetIntegerv) { typedef GetIntegerv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetIntegerv(123, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -635,9 +642,10 @@ TEST_F(GLES2ImplementationTest, GetProgramiv) { typedef GetProgramiv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, GL_DELETE_STATUS, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, GL_DELETE_STATUS, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetProgramiv(123, GL_DELETE_STATUS, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -652,9 +660,10 @@ TEST_F(GLES2ImplementationTest, GetRenderbufferParameteriv) { typedef GetRenderbufferParameteriv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, GL_RENDERBUFFER_RED_SIZE, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, GL_RENDERBUFFER_RED_SIZE, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetRenderbufferParameteriv(123, GL_RENDERBUFFER_RED_SIZE, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -668,9 +677,10 @@ TEST_F(GLES2ImplementationTest, GetShaderiv) { typedef GetShaderiv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, GL_SHADER_TYPE, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, GL_SHADER_TYPE, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetShaderiv(123, GL_SHADER_TYPE, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -686,9 +696,10 @@ TEST_F(GLES2ImplementationTest, GetTexParameterfv) { typedef GetTexParameterfv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetTexParameterfv(123, GL_TEXTURE_MAG_FILTER, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -702,9 +713,10 @@ TEST_F(GLES2ImplementationTest, GetTexParameteriv) { typedef GetTexParameteriv::Result Result; Result::Type result = 0; Cmds expected; - expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); + expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetTexParameteriv(123, GL_TEXTURE_MAG_FILTER, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -721,10 +733,11 @@ TEST_F(GLES2ImplementationTest, GetVertexAttribfv) { typedef GetVertexAttribfv::Result Result; Result::Type result = 0; Cmds expected; + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); expected.cmd.Init( - 123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + 123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetVertexAttribfv(123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -738,10 +751,11 @@ TEST_F(GLES2ImplementationTest, GetVertexAttribiv) { typedef GetVertexAttribiv::Result Result; Result::Type result = 0; Cmds expected; + ExpectedMemoryInfo result1 = GetExpectedResultMemory(4); expected.cmd.Init( - 123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, transfer_buffer_id_, 0); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(SizedResultHelper<Result::Type>(1))) + 123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, result1.id, result1.offset); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1))) .RetiresOnSaturation(); gl_->GetVertexAttribiv(123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &result); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); @@ -766,10 +780,12 @@ TEST_F(GLES2ImplementationTest, IsBuffer) { typedef IsBuffer::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsBuffer::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsBuffer(1); @@ -784,10 +800,12 @@ TEST_F(GLES2ImplementationTest, IsEnabled) { typedef IsEnabled::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsEnabled::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsEnabled(1); @@ -802,10 +820,12 @@ TEST_F(GLES2ImplementationTest, IsFramebuffer) { typedef IsFramebuffer::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsFramebuffer::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsFramebuffer(1); @@ -820,10 +840,12 @@ TEST_F(GLES2ImplementationTest, IsProgram) { typedef IsProgram::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsProgram::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsProgram(1); @@ -838,10 +860,12 @@ TEST_F(GLES2ImplementationTest, IsRenderbuffer) { typedef IsRenderbuffer::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsRenderbuffer::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsRenderbuffer(1); @@ -856,10 +880,12 @@ TEST_F(GLES2ImplementationTest, IsShader) { typedef IsShader::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsShader::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsShader(1); @@ -874,10 +900,12 @@ TEST_F(GLES2ImplementationTest, IsTexture) { typedef IsTexture::Result Result; Cmds expected; - expected.cmd.Init(1, transfer_buffer_id_, 0); + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsTexture::Result)); + expected.cmd.Init(1, result1.id, result1.offset); - EXPECT_CALL(*command_buffer_, OnFlush(_)) - .WillOnce(SetMemory(uint32(1))) + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) .RetiresOnSaturation(); GLboolean result = gl_->IsTexture(1); diff --git a/gpu/command_buffer/client/ring_buffer.h b/gpu/command_buffer/client/ring_buffer.h index e3a3980..582d4ee 100644 --- a/gpu/command_buffer/client/ring_buffer.h +++ b/gpu/command_buffer/client/ring_buffer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -165,12 +165,12 @@ class RingBufferWrapper { } // Gets a pointer to a memory block given the base memory and the offset. - void* GetPointer(RingBuffer::Offset offset) { + void* GetPointer(RingBuffer::Offset offset) const { return static_cast<int8*>(base_) + offset; } // Gets the offset to a memory block given the base memory and the address. - RingBuffer::Offset GetOffset(void* pointer) { + RingBuffer::Offset GetOffset(void* pointer) const { return static_cast<int8*>(pointer) - static_cast<int8*>(base_); } diff --git a/gpu/command_buffer/client/transfer_buffer.cc b/gpu/command_buffer/client/transfer_buffer.cc new file mode 100644 index 0000000..28bb0e6 --- /dev/null +++ b/gpu/command_buffer/client/transfer_buffer.cc @@ -0,0 +1,211 @@ +// 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. + +// A class to Manage a growing transfer buffer. + +#include "../client/transfer_buffer.h" +#include "../client/cmd_buffer_helper.h" + +namespace gpu { + +AlignedRingBuffer::~AlignedRingBuffer() { +} + +TransferBuffer::TransferBuffer( + CommandBufferHelper* helper) + : helper_(helper), + result_size_(0), + min_buffer_size_(0), + max_buffer_size_(0), + alignment_(), + buffer_id_(-1), + result_buffer_(NULL), + result_shm_offset_(0), + usable_(true) { +} + +TransferBuffer::~TransferBuffer() { + Free(); +} + +bool TransferBuffer::Initialize( + unsigned int starting_buffer_size, + unsigned int result_size, + unsigned int min_buffer_size, + unsigned int max_buffer_size, + unsigned int alignment) { + result_size_ = result_size; + min_buffer_size_ = min_buffer_size; + max_buffer_size_ = max_buffer_size; + alignment_ = alignment; + ReallocateRingBuffer(starting_buffer_size - result_size); + return HaveBuffer(); +} + +void TransferBuffer::Free() { + if (HaveBuffer()) { + helper_->Finish(); + helper_->command_buffer()->DestroyTransferBuffer(buffer_id_); + buffer_id_ = -1; + buffer_.ptr = NULL; + buffer_.size = 0; + result_buffer_ = NULL; + result_shm_offset_ = 0; + ring_buffer_.reset(); + } +} + +bool TransferBuffer::HaveBuffer() const { + return buffer_id_ != -1; +} + +RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const { + return ring_buffer_->GetOffset(pointer); +} + +void TransferBuffer::FreePendingToken(void* p, unsigned int token) { + ring_buffer_->FreePendingToken(p, token); +} + +void TransferBuffer::AllocateRingBuffer(unsigned int size) { + for (;size >= min_buffer_size_; size /= 2) { + int32 id = helper_->command_buffer()->CreateTransferBuffer(size, -1); + if (id != -1) { + buffer_ = helper_->command_buffer()->GetTransferBuffer(id); + ring_buffer_.reset(new AlignedRingBuffer( + alignment_, + id, + result_size_, + buffer_.size - result_size_, + helper_, + static_cast<char*>(buffer_.ptr) + result_size_)); + buffer_id_ = id; + result_buffer_ = buffer_.ptr; + result_shm_offset_ = 0; + return; + } + // we failed so don't try larger than this. + max_buffer_size_ = size / 2; + } + usable_ = false; +} + +// Returns the integer i such as 2^i <= n < 2^(i+1) +static int Log2Floor(uint32 n) { + if (n == 0) + return -1; + int log = 0; + uint32 value = n; + for (int i = 4; i >= 0; --i) { + int shift = (1 << i); + uint32 x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + GPU_DCHECK_EQ(value, 1u); + return log; +} + +// Returns the integer i such as 2^(i-1) < n <= 2^i +static int Log2Ceiling(uint32 n) { + if (n == 0) { + return -1; + } else { + // Log2Floor returns -1 for 0, so the following works correctly for n=1. + return 1 + Log2Floor(n - 1); + } +} + +static unsigned int ComputePOTSize(unsigned int dimension) { + return (dimension == 0) ? 0 : 1 << Log2Ceiling(dimension); +} + +void TransferBuffer::ReallocateRingBuffer(unsigned int size) { + // What size buffer would we ask for if we needed a new one? + unsigned int needed_buffer_size = ComputePOTSize(size + result_size_); + needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_); + needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_); + + if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_.size)) { + if (HaveBuffer()) { + Free(); + } + AllocateRingBuffer(needed_buffer_size); + } +} + +void* TransferBuffer::AllocUpTo( + unsigned int size, unsigned int* size_allocated) { + GPU_DCHECK(size_allocated); + + ReallocateRingBuffer(size); + + if (!HaveBuffer()) { + return NULL; + } + + unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize(); + *size_allocated = std::min(max_size, size); + return ring_buffer_->Alloc(*size_allocated); +} + +void* TransferBuffer::Alloc(unsigned int size) { + ReallocateRingBuffer(size); + + if (!HaveBuffer()) { + return NULL; + } + + unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize(); + if (size > max_size) { + return NULL; + } + + return ring_buffer_->Alloc(size); +} + +void* TransferBuffer::GetResultBuffer() { + ReallocateRingBuffer(result_size_); + return result_buffer_; +} + +int TransferBuffer::GetResultOffset() { + ReallocateRingBuffer(result_size_); + return result_shm_offset_; +} + +int TransferBuffer::GetShmId() { + ReallocateRingBuffer(result_size_); + return buffer_id_; +} + +unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const { + return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0; +} + +unsigned int TransferBuffer::GetMaxAllocation() const { + return HaveBuffer() ? max_buffer_size_ - result_size_ : 0; +} + +void ScopedTransferBufferPtr::Release() { + if (buffer_) { + transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken()); + buffer_ = NULL; + size_ = 0; + } +} + +void ScopedTransferBufferPtr::Reset(unsigned int new_size) { + Release(); + // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so + // that address will return a pointer just like malloc, and so that GetShmId + // will be valid. That has the side effect that we'll insert a token on free. + // We could add code skip the token for a zero size buffer but it doesn't seem + // worth the complication. + buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_); +} + +} // namespace gpu diff --git a/gpu/command_buffer/client/transfer_buffer.h b/gpu/command_buffer/client/transfer_buffer.h new file mode 100644 index 0000000..654465c --- /dev/null +++ b/gpu/command_buffer/client/transfer_buffer.h @@ -0,0 +1,221 @@ +// 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. + +#ifndef GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_ +#define GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_ + +#include "../common/buffer.h" +#include "../common/compiler_specific.h" +#include "../common/gles2_cmd_utils.h" +#include "../common/scoped_ptr.h" +#include "../client/ring_buffer.h" + +namespace gpu { + +class CommandBufferHelper; + +// Wraps RingBufferWrapper to provide aligned allocations. +class AlignedRingBuffer : public RingBufferWrapper { + public: + AlignedRingBuffer( + unsigned int alignment, + int32 shm_id, + RingBuffer::Offset base_offset, + unsigned int size, + CommandBufferHelper* helper, + void* base) + : RingBufferWrapper(base_offset, size, helper, base), + alignment_(alignment), + shm_id_(shm_id) { + } + ~AlignedRingBuffer(); + + // Hiding Alloc from RingBufferWrapper + void* Alloc(unsigned int size) { + return RingBufferWrapper::Alloc(RoundToAlignment(size)); + } + + int32 GetShmId() const { + return shm_id_; + } + + private: + unsigned int RoundToAlignment(unsigned int size) { + return (size + alignment_ - 1) & ~(alignment_ - 1); + } + + unsigned int alignment_; + int32 shm_id_; +}; + +// Interface for managing the transfer buffer. +class TransferBufferInterface { + public: + TransferBufferInterface() { } + virtual ~TransferBufferInterface() { } + + virtual bool Initialize( + unsigned int buffer_size, + unsigned int result_size, + unsigned int min_buffer_size, + unsigned int max_buffer_size, + unsigned int alignment) = 0; + + virtual int GetShmId() = 0; + virtual void* GetResultBuffer() = 0; + virtual int GetResultOffset() = 0; + + virtual void Free() = 0; + + virtual bool HaveBuffer() const = 0; + + // Allocates up to size bytes. + virtual void* AllocUpTo(unsigned int size, unsigned int* size_allocated) = 0; + + // Allocates size bytes. + // Note: Alloc will fail if it can not return size bytes. + virtual void* Alloc(unsigned int size) = 0; + + virtual RingBuffer::Offset GetOffset(void* pointer) const = 0; + + virtual void FreePendingToken(void* p, unsigned int token) = 0; +}; + +// Class that manages the transfer buffer. +class TransferBuffer : public TransferBufferInterface { + public: + TransferBuffer(CommandBufferHelper* helper); + virtual ~TransferBuffer(); + + // Overridden from TransferBufferInterface. + virtual bool Initialize( + unsigned int buffer_size, + unsigned int result_size, + unsigned int min_buffer_size, + unsigned int max_buffer_size, + unsigned int alignment) OVERRIDE; + virtual int GetShmId() OVERRIDE; + virtual void* GetResultBuffer() OVERRIDE; + virtual int GetResultOffset() OVERRIDE; + virtual void Free() OVERRIDE; + virtual bool HaveBuffer() const OVERRIDE; + virtual void* AllocUpTo( + unsigned int size, unsigned int* size_allocated) OVERRIDE; + virtual void* Alloc(unsigned int size) OVERRIDE; + virtual RingBuffer::Offset GetOffset(void* pointer) const OVERRIDE; + virtual void FreePendingToken(void* p, unsigned int token) OVERRIDE; + + // These are for testing. + unsigned int GetCurrentMaxAllocationWithoutRealloc() const; + unsigned int GetMaxAllocation() const; + + private: + // Tries to reallocate the ring buffer if it's not large enough for size. + void ReallocateRingBuffer(unsigned int size); + + void AllocateRingBuffer(unsigned int size); + + CommandBufferHelper* helper_; + scoped_ptr<AlignedRingBuffer> ring_buffer_; + + // size reserved for results + unsigned int result_size_; + + // min size we'll consider successful + unsigned int min_buffer_size_; + + // max size we'll let the buffer grow + unsigned int max_buffer_size_; + + // alignment for allocations + unsigned int alignment_; + + // the current buffer. + gpu::Buffer buffer_; + + // id of buffer. -1 = no buffer + int32 buffer_id_; + + // address of result area + void* result_buffer_; + + // offset to result area + uint32 result_shm_offset_; + + // false if we failed to allocate min_buffer_size + bool usable_; +}; + +// A class that will manage the lifetime of a transferbuffer allocation. +class ScopedTransferBufferPtr { + public: + ScopedTransferBufferPtr( + unsigned int size, + CommandBufferHelper* helper, + TransferBufferInterface* transfer_buffer) + : buffer_(NULL), + size_(0), + helper_(helper), + transfer_buffer_(transfer_buffer) { + Reset(size); + } + + ~ScopedTransferBufferPtr() { + Release(); + } + + bool valid() const { + return buffer_ != NULL; + } + + unsigned int size() const { + return size_; + } + + int shm_id() const { + return transfer_buffer_->GetShmId(); + } + + RingBuffer::Offset offset() const { + return transfer_buffer_->GetOffset(buffer_); + } + + void* address() const { + return buffer_; + } + + void Release(); + + void Reset(unsigned int new_size); + + private: + void* buffer_; + unsigned int size_; + CommandBufferHelper* helper_; + TransferBufferInterface* transfer_buffer_; + DISALLOW_COPY_AND_ASSIGN(ScopedTransferBufferPtr); +}; + +template <typename T> +class ScopedTransferBufferArray : public ScopedTransferBufferPtr { + public: + ScopedTransferBufferArray( + unsigned int num_elements, + CommandBufferHelper* helper, TransferBufferInterface* transfer_buffer) + : ScopedTransferBufferPtr( + num_elements * sizeof(T), helper, transfer_buffer) { + } + + T* elements() { + return static_cast<T*>(address()); + } + + unsigned int num_elements() const { + return size() / sizeof(T); + } +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_ diff --git a/gpu/command_buffer/client/transfer_buffer_unittest.cc b/gpu/command_buffer/client/transfer_buffer_unittest.cc new file mode 100644 index 0000000..26b2057 --- /dev/null +++ b/gpu/command_buffer/client/transfer_buffer_unittest.cc @@ -0,0 +1,434 @@ +// 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. + +// Tests for the Command Buffer Helper. + +#include "gpu/command_buffer/client/transfer_buffer.h" + +#include "gpu/command_buffer/client/client_test_helper.h" +#include "gpu/command_buffer/client/cmd_buffer_helper.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/common/compiler_specific.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrictMock; + +namespace gpu { + +class TransferBufferTest : public testing::Test { + protected: + static const int32 kNumCommandEntries = 400; + static const int32 kCommandBufferSizeBytes = + kNumCommandEntries * sizeof(CommandBufferEntry); + static const unsigned int kStartingOffset = 64; + static const unsigned int kAlignment = 4; + static const size_t kTransferBufferSize = 256; + + TransferBufferTest() + : transfer_buffer_id_(0) { + } + + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; + + MockClientCommandBuffer* command_buffer() const { + return command_buffer_.get(); + } + + scoped_ptr<MockClientCommandBuffer> command_buffer_; + scoped_ptr<CommandBufferHelper> helper_; + scoped_ptr<TransferBuffer> transfer_buffer_; + int32 transfer_buffer_id_; +}; + +void TransferBufferTest::SetUp() { + command_buffer_.reset(new StrictMock<MockClientCommandBuffer>()); + ASSERT_TRUE(command_buffer_->Initialize()); + + helper_.reset(new CommandBufferHelper(command_buffer())); + ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes)); + + transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId(); + + transfer_buffer_.reset(new TransferBuffer(helper_.get())); + ASSERT_TRUE(transfer_buffer_->Initialize( + kTransferBufferSize, + kStartingOffset, + kTransferBufferSize, + kTransferBufferSize, + kAlignment)); +} + +void TransferBufferTest::TearDown() { + if (transfer_buffer_->HaveBuffer()) { + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + } + transfer_buffer_.reset(); +} + +// GCC requires these declarations, but MSVC requires they not be present +#ifndef _MSC_VER +const int32 TransferBufferTest::kNumCommandEntries; +const int32 TransferBufferTest::kCommandBufferSizeBytes; +const unsigned int TransferBufferTest::kStartingOffset; +const unsigned int TransferBufferTest::kAlignment; +const size_t TransferBufferTest::kTransferBufferSize; +#endif + +TEST_F(TransferBufferTest, Basic) { + EXPECT_TRUE(transfer_buffer_->HaveBuffer()); + EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId()); + EXPECT_EQ( + kTransferBufferSize - kStartingOffset, + transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); +} + +TEST_F(TransferBufferTest, Free) { + EXPECT_TRUE(transfer_buffer_->HaveBuffer()); + EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId()); + + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + // See that it gets reallocated. + EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId()); + EXPECT_TRUE(transfer_buffer_->HaveBuffer()); + + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + // See that it gets reallocated. + EXPECT_TRUE(transfer_buffer_->GetResultBuffer() != NULL); + EXPECT_TRUE(transfer_buffer_->HaveBuffer()); + + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + // See that it gets reallocated. + unsigned int size = 0; + void* data = transfer_buffer_->AllocUpTo(1, &size); + EXPECT_TRUE(data != NULL); + EXPECT_TRUE(transfer_buffer_->HaveBuffer()); + transfer_buffer_->FreePendingToken(data, 1); + + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + // See that it gets reallocated. + transfer_buffer_->GetResultOffset(); + EXPECT_TRUE(transfer_buffer_->HaveBuffer()); + + EXPECT_EQ( + kTransferBufferSize - kStartingOffset, + transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + + // Test freeing twice. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + transfer_buffer_->Free(); +} + +TEST_F(TransferBufferTest, TooLargeAllocation) { + // Check that we can't allocate large than max size. + void* ptr = transfer_buffer_->Alloc(kTransferBufferSize + 1); + EXPECT_TRUE(ptr == NULL); + // Check we if we try to allocate larger than max we get max. + unsigned int size_allocated = 0; + ptr = transfer_buffer_->AllocUpTo( + kTransferBufferSize + 1, &size_allocated); + ASSERT_TRUE(ptr != NULL); + EXPECT_EQ(kTransferBufferSize - kStartingOffset, size_allocated); + transfer_buffer_->FreePendingToken(ptr, 1); +} + +class MockClientCommandBufferCanFail : public MockClientCommandBuffer { + public: + MockClientCommandBufferCanFail() { + } + virtual ~MockClientCommandBufferCanFail() { + } + + MOCK_METHOD2(CreateTransferBuffer, int32(size_t size, int32 id_request)); + + int32 RealCreateTransferBuffer(size_t size, int32 id_request) { + return MockCommandBufferBase::CreateTransferBuffer(size, id_request); + } +}; + +class TransferBufferExpandContractTest : public testing::Test { + protected: + static const int32 kNumCommandEntries = 400; + static const int32 kCommandBufferSizeBytes = + kNumCommandEntries * sizeof(CommandBufferEntry); + static const unsigned int kStartingOffset = 64; + static const unsigned int kAlignment = 4; + static const size_t kStartTransferBufferSize = 256; + static const size_t kMaxTransferBufferSize = 1024; + static const size_t kMinTransferBufferSize = 128; + + TransferBufferExpandContractTest() + : transfer_buffer_id_(0) { + } + + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; + + MockClientCommandBufferCanFail* command_buffer() const { + return command_buffer_.get(); + } + + scoped_ptr<MockClientCommandBufferCanFail> command_buffer_; + scoped_ptr<CommandBufferHelper> helper_; + scoped_ptr<TransferBuffer> transfer_buffer_; + int32 transfer_buffer_id_; +}; + +void TransferBufferExpandContractTest::SetUp() { + command_buffer_.reset(new StrictMock<MockClientCommandBufferCanFail>()); + ASSERT_TRUE(command_buffer_->Initialize()); + + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kCommandBufferSizeBytes, _)) + .WillOnce(Invoke( + command_buffer(), + &MockClientCommandBufferCanFail::RealCreateTransferBuffer)) + .RetiresOnSaturation(); + + helper_.reset(new CommandBufferHelper(command_buffer())); + ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes)); + + transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId(); + + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kStartTransferBufferSize, _)) + .WillOnce(Invoke( + command_buffer(), + &MockClientCommandBufferCanFail::RealCreateTransferBuffer)) + .RetiresOnSaturation(); + + transfer_buffer_.reset(new TransferBuffer(helper_.get())); + ASSERT_TRUE(transfer_buffer_->Initialize( + kStartTransferBufferSize, + kStartingOffset, + kMinTransferBufferSize, + kMaxTransferBufferSize, + kAlignment)); +} + +void TransferBufferExpandContractTest::TearDown() { + if (transfer_buffer_->HaveBuffer()) { + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + } + transfer_buffer_.reset(); +} + +// GCC requires these declarations, but MSVC requires they not be present +#ifndef _MSC_VER +const int32 TransferBufferExpandContractTest::kNumCommandEntries; +const int32 TransferBufferExpandContractTest::kCommandBufferSizeBytes; +const unsigned int TransferBufferExpandContractTest::kStartingOffset; +const unsigned int TransferBufferExpandContractTest::kAlignment; +const size_t TransferBufferExpandContractTest::kStartTransferBufferSize; +const size_t TransferBufferExpandContractTest::kMaxTransferBufferSize; +const size_t TransferBufferExpandContractTest::kMinTransferBufferSize; +#endif + +TEST_F(TransferBufferExpandContractTest, Expand) { + // Check it starts at starting size. + EXPECT_EQ( + kStartTransferBufferSize - kStartingOffset, + transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kStartTransferBufferSize * 2, _)) + .WillOnce(Invoke( + command_buffer(), + &MockClientCommandBufferCanFail::RealCreateTransferBuffer)) + .RetiresOnSaturation(); + + // Try next power of 2. + const size_t kSize1 = 512 - kStartingOffset; + unsigned int size_allocated = 0; + void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated); + ASSERT_TRUE(ptr != NULL); + EXPECT_EQ(kSize1, size_allocated); + EXPECT_EQ(kSize1, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + transfer_buffer_->FreePendingToken(ptr, 1); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kMaxTransferBufferSize, _)) + .WillOnce(Invoke( + command_buffer(), + &MockClientCommandBufferCanFail::RealCreateTransferBuffer)) + .RetiresOnSaturation(); + + // Try next power of 2. + const size_t kSize2 = 1024 - kStartingOffset; + ptr = transfer_buffer_->AllocUpTo(kSize2, &size_allocated); + ASSERT_TRUE(ptr != NULL); + EXPECT_EQ(kSize2, size_allocated); + EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + transfer_buffer_->FreePendingToken(ptr, 1); + + // Try next one more. Should not go past max. + size_allocated = 0; + const size_t kSize3 = kSize2 + 1; + ptr = transfer_buffer_->AllocUpTo(kSize3, &size_allocated); + EXPECT_EQ(kSize2, size_allocated); + EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + transfer_buffer_->FreePendingToken(ptr, 1); +} + +TEST_F(TransferBufferExpandContractTest, Contract) { + // Check it starts at starting size. + EXPECT_EQ( + kStartTransferBufferSize - kStartingOffset, + transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + + // Try to allocate again, fail first request + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kStartTransferBufferSize, _)) + .WillOnce(Return(-1)) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kMinTransferBufferSize, _)) + .WillOnce(Invoke( + command_buffer(), + &MockClientCommandBufferCanFail::RealCreateTransferBuffer)) + .RetiresOnSaturation(); + + const size_t kSize1 = 256 - kStartingOffset; + const size_t kSize2 = 128 - kStartingOffset; + unsigned int size_allocated = 0; + void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated); + ASSERT_TRUE(ptr != NULL); + EXPECT_EQ(kSize2, size_allocated); + EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + transfer_buffer_->FreePendingToken(ptr, 1); + + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + + // Try to allocate again, + EXPECT_CALL(*command_buffer(), + CreateTransferBuffer(kMinTransferBufferSize, _)) + .WillOnce(Invoke( + command_buffer(), + &MockClientCommandBufferCanFail::RealCreateTransferBuffer)) + .RetiresOnSaturation(); + + ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated); + ASSERT_TRUE(ptr != NULL); + EXPECT_EQ(kSize2, size_allocated); + EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc()); + transfer_buffer_->FreePendingToken(ptr, 1); +} + +TEST_F(TransferBufferExpandContractTest, OutOfMemory) { + // Free buffer. + EXPECT_CALL(*command_buffer(), OnFlush()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_)) + .Times(1) + .RetiresOnSaturation(); + transfer_buffer_->Free(); + // See it's freed. + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); + + // Try to allocate again, fail both requests. + EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _)) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)) + .RetiresOnSaturation(); + + const size_t kSize1 = 512 - kStartingOffset; + unsigned int size_allocated = 0; + void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated); + ASSERT_TRUE(ptr == NULL); + EXPECT_FALSE(transfer_buffer_->HaveBuffer()); +} + +} // namespace gpu + + diff --git a/gpu/command_buffer/common/compiler_specific.h b/gpu/command_buffer/common/compiler_specific.h new file mode 100644 index 0000000..8cbc713 --- /dev/null +++ b/gpu/command_buffer/common/compiler_specific.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef GPU_COMMAND_BUFFER_COMMON_COMPILER_SPECIFIC_H_ +#define GPU_COMMAND_BUFFER_COMMON_COMPILER_SPECIFIC_H_ +#pragma once + +// Annotate a virtual method indicating it must be overriding a virtual +// method in the parent class. +// Use like: +// virtual void foo() OVERRIDE; +#ifndef OVERRIDE +#ifdef _MSC_VER +#define OVERRIDE override +#elif defined(__clang__) +#define OVERRIDE override +#else +#define OVERRIDE +#endif +#endif + +#endif // GPU_COMMAND_BUFFER_COMMON_COMPILER_SPECIFIC_H_ diff --git a/gpu/demos/framework/window.cc b/gpu/demos/framework/window.cc index ca07a25..722eaf0 100644 --- a/gpu/demos/framework/window.cc +++ b/gpu/demos/framework/window.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_lib.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/demos/framework/demo.h" #include "gpu/demos/framework/demo_factory.h" @@ -19,6 +20,7 @@ using gpu::CommandBufferService; using gpu::GpuScheduler; using gpu::gles2::GLES2CmdHelper; using gpu::gles2::GLES2Implementation; +using gpu::TransferBuffer; namespace { const int32 kCommandBufferSize = 1024 * 1024; @@ -103,19 +105,24 @@ bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) { if (!gles2_cmd_helper_->Initialize(kCommandBufferSize)) return false; - int32 transfer_buffer_id = - command_buffer_->CreateTransferBuffer(kTransferBufferSize, -1); - Buffer transfer_buffer = - command_buffer_->GetTransferBuffer(transfer_buffer_id); - if (transfer_buffer.ptr == NULL) return false; + transfer_buffer_.reset(new gpu::TransferBuffer(gles2_cmd_helper_.get())); ::gles2::Initialize(); - ::gles2::SetGLContext(new GLES2Implementation(gles2_cmd_helper_.get(), - transfer_buffer.size, - transfer_buffer.ptr, - transfer_buffer_id, - false, - true)); + GLES2Implementation* gles2_implementation = new GLES2Implementation( + gles2_cmd_helper_.get(), + transfer_buffer_.get(), + false, + true); + + ::gles2::SetGLContext(gles2_implementation); + + if (!gles2_implementation->Initialize( + kTransferBufferSize, + kTransferBufferSize, + kTransferBufferSize)) { + return false; + } + return true; } diff --git a/gpu/demos/framework/window.h b/gpu/demos/framework/window.h index 4c6cd46..80b8b67 100644 --- a/gpu/demos/framework/window.h +++ b/gpu/demos/framework/window.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -15,6 +15,9 @@ #include "ui/gfx/native_widget_types.h" namespace gpu { + +class TransferBuffer; + namespace demos { class Demo; @@ -52,6 +55,7 @@ class Window { scoped_refptr<gfx::GLContext> context_; scoped_refptr<gfx::GLSurface> surface_; scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_cmd_helper_; + scoped_ptr<gpu::TransferBuffer> transfer_buffer_; DISALLOW_COPY_AND_ASSIGN(Window); }; diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc index 47fcd51..1b540f4 100644 --- a/gpu/gles2_conform_support/egl/display.cc +++ b/gpu/gles2_conform_support/egl/display.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "gpu/command_buffer/client/gles2_lib.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/gles2_conform_support/egl/config.h" #include "gpu/gles2_conform_support/egl/surface.h" @@ -21,8 +22,7 @@ namespace egl { Display::Display(EGLNativeDisplayType display_id) : display_id_(display_id), - is_initialized_(false), - transfer_buffer_id_(-1) { + is_initialized_(false) { } Display::~Display() { @@ -131,15 +131,11 @@ EGLSurface Display::CreateWindowSurface(EGLConfig config, if (!cmd_helper->Initialize(kCommandBufferSize)) return false; - int32 transfer_buffer_id = - command_buffer->CreateTransferBuffer(kTransferBufferSize, -1); - gpu::Buffer transfer_buffer = - command_buffer->GetTransferBuffer(transfer_buffer_id); - if (transfer_buffer.ptr == NULL) - return false; + scoped_ptr<gpu::TransferBuffer> transfer_buffer(new gpu::TransferBuffer( + cmd_helper.get())); command_buffer_.reset(command_buffer.release()); - transfer_buffer_id_ = transfer_buffer_id; + transfer_buffer_.reset(transfer_buffer.release()); gles2_cmd_helper_.reset(cmd_helper.release()); surface_.reset(new Surface(win)); @@ -171,23 +167,26 @@ EGLContext Display::CreateContext(EGLConfig config, EGLContext share_ctx, const EGLint* attrib_list) { DCHECK(IsValidConfig(config)); - // TODO(alokp): Command buffer does not support shared contexts. + // TODO(alokp): Add support for shared contexts. if (share_ctx != NULL) return EGL_NO_CONTEXT; DCHECK(command_buffer_ != NULL); - DCHECK(transfer_buffer_id_ != -1); - gpu::Buffer buffer = command_buffer_->GetTransferBuffer(transfer_buffer_id_); - DCHECK(buffer.ptr != NULL); + DCHECK(transfer_buffer_.get()); bool share_resources = share_ctx != NULL; context_.reset(new gpu::gles2::GLES2Implementation( gles2_cmd_helper_.get(), - buffer.size, - buffer.ptr, - transfer_buffer_id_, + transfer_buffer_.get(), share_resources, true)); + if (!context_->Initialize( + kTransferBufferSize / 2, + kTransferBufferSize, + kTransferBufferSize * 2)) { + return EGL_NO_CONTEXT; + } + context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets"); context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs"); diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h index 19571b3..f7e20e8 100644 --- a/gpu/gles2_conform_support/egl/display.h +++ b/gpu/gles2_conform_support/egl/display.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -19,6 +19,7 @@ namespace gpu { class CommandBufferService; class GpuScheduler; +class TransferBuffer; namespace gles2 { class GLES2CmdHelper; @@ -71,7 +72,7 @@ class Display { scoped_refptr<gfx::GLContext> gl_context_; scoped_refptr<gfx::GLSurface> gl_surface_; scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_cmd_helper_; - int32 transfer_buffer_id_; + scoped_ptr<gpu::TransferBuffer> transfer_buffer_; // TODO(alokp): Support more than one config, surface, and context. scoped_ptr<Config> config_; diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index f9f945b..c24c4d1 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -51,6 +51,7 @@ 'command_buffer/common/cmd_buffer_common.h', 'command_buffer/common/cmd_buffer_common.cc', 'command_buffer/common/command_buffer.h', + 'command_buffer/common/compiler_specific.h', 'command_buffer/common/constants.h', 'command_buffer/common/gles2_cmd_ids_autogen.h', 'command_buffer/common/gles2_cmd_ids.h', @@ -198,6 +199,8 @@ 'command_buffer/client/mapped_memory.h', 'command_buffer/client/ring_buffer.cc', 'command_buffer/client/ring_buffer.h', + 'command_buffer/client/transfer_buffer.cc', + 'command_buffer/client/transfer_buffer.h', ], }, { @@ -302,12 +305,15 @@ ], 'sources': [ '<@(gles2_c_lib_source_files)', + 'command_buffer/client/client_test_helper.cc', + 'command_buffer/client/client_test_helper.h', 'command_buffer/client/cmd_buffer_helper_test.cc', 'command_buffer/client/fenced_allocator_test.cc', 'command_buffer/client/gles2_implementation_unittest.cc', 'command_buffer/client/mapped_memory_unittest.cc', 'command_buffer/client/program_info_manager_unittest.cc', 'command_buffer/client/ring_buffer_test.cc', + 'command_buffer/client/transfer_buffer_unittest.cc', 'command_buffer/common/bitfield_helpers_test.cc', 'command_buffer/common/command_buffer_mock.cc', 'command_buffer/common/command_buffer_mock.h', diff --git a/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons b/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons index 2bfed5d..050e419 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons +++ b/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons @@ -35,6 +35,7 @@ command_buffer_client_srcs = [ 'command_buffer/client/gles2_lib.cc', 'command_buffer/client/mapped_memory.cc', 'command_buffer/client/ring_buffer.cc', + 'command_buffer/client/transfer_buffer.cc', 'command_buffer/common/id_allocator.cc', ] diff --git a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.cc b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.cc index 2fc4bd6..a3220f9 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.cc +++ b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.cc @@ -7,6 +7,7 @@ #include "native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.h" #include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "native_client/src/shared/ppapi_proxy/command_buffer_nacl.h" #include "native_client/src/shared/ppapi_proxy/object_serialize.h" #include "native_client/src/shared/ppapi_proxy/plugin_callback.h" @@ -25,8 +26,10 @@ namespace ppapi_proxy { namespace { -const int32 kRingBufferSize = 4096 * 1024; -const int32 kTransferBufferSize = 4096 * 1024; +const size_t kRingBufferSize = 4 * 1024 * 1024; +const size_t kStartTransferBufferSize = 4 * 1024 * 1024; +const size_t kMinTransferBufferSize = 256 * 1024; +const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; int32_t GetNumAttribs(const int32_t* attrib_list) { int32_t num = 0; @@ -181,6 +184,7 @@ PluginGraphics3D::~PluginGraphics3D() { DebugPrintf("PluginGraphics3D::~PluginGraphics3D()\n"); // Explicitly tear down scopted pointers; ordering below matters. gles2_implementation_.reset(); + transfer_buffer_.reset(); gles2_helper_.reset(); command_buffer_.reset(); // Invalidate the cache. @@ -213,19 +217,16 @@ bool PluginGraphics3D::InitFromBrowserResource(PP_Resource res) { if (command_buffer_->Initialize()) { gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get())); if (gles2_helper_->Initialize(kRingBufferSize)) { - // Request id -1 to signify 'don't care' - int32 transfer_buffer_id = - command_buffer_->CreateTransferBuffer(kTransferBufferSize, -1); - gpu::Buffer transfer_buffer = - command_buffer_->GetTransferBuffer(transfer_buffer_id); - if (transfer_buffer.ptr) { - gles2_implementation_.reset(new gpu::gles2::GLES2Implementation( - gles2_helper_.get(), - transfer_buffer.size, - transfer_buffer.ptr, - transfer_buffer_id, - false, - true)); + transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get())); + gles2_implementation_.reset(new gpu::gles2::GLES2Implementation( + gles2_helper_.get(), + transfer_buffer_.get(), + false, + true)); + if (gles2_implementation_->Initialize( + kStartTransferBufferSize, + kMinTransferBufferSize, + kMaxTransferBufferSize)) { return true; } } diff --git a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.h b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.h index 115cc25..84af986 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.h +++ b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_graphics_3d.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -15,6 +15,7 @@ namespace gpu { class CommandBuffer; +class TransferBuffer; namespace gles2 { class GLES2CmdHelper; class GLES2Implementation; @@ -63,6 +64,7 @@ class PluginGraphics3D : public PluginResource { // GLES2 Implementation objects. scoped_ptr<gpu::CommandBuffer> command_buffer_; scoped_ptr<gpu::gles2::GLES2Implementation> gles2_implementation_; + scoped_ptr<gpu::TransferBuffer> transfer_buffer_; scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_; PP_Instance instance_id_; diff --git a/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp b/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp index 58dad08..80f2a11 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp +++ b/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp @@ -34,6 +34,7 @@ '<(DEPTH)/gpu/command_buffer/client/gles2_cmd_helper.cc', '<(DEPTH)/gpu/command_buffer/client/gles2_implementation.cc', '<(DEPTH)/gpu/command_buffer/client/program_info_manager.cc', + '<(DEPTH)/gpu/command_buffer/client/transfer_buffer.cc', '<(DEPTH)/gpu/command_buffer/client/gles2_lib.cc', '<(DEPTH)/gpu/command_buffer/client/mapped_memory.cc', '<(DEPTH)/gpu/command_buffer/client/ring_buffer.cc', diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc index d444516..37b3d0b 100644 --- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc +++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -7,24 +7,23 @@ #include "base/logging.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "ppapi/c/pp_errors.h" namespace ppapi { PPB_Graphics3D_Shared::PPB_Graphics3D_Shared(PP_Instance instance) - : Resource(instance), - transfer_buffer_id_(-1) { + : Resource(instance) { } PPB_Graphics3D_Shared::PPB_Graphics3D_Shared(const HostResource& host_resource) - : Resource(host_resource), - transfer_buffer_id_(-1) { + : Resource(host_resource) { } PPB_Graphics3D_Shared::~PPB_Graphics3D_Shared() { // Make sure that GLES2 implementation has already been destroyed. - DCHECK_EQ(transfer_buffer_id_, -1); DCHECK(!gles2_helper_.get()); + DCHECK(!transfer_buffer_.get()); DCHECK(!gles2_impl_.get()); } @@ -110,39 +109,30 @@ bool PPB_Graphics3D_Shared::CreateGLES2Impl(int32 command_buffer_size, // Create a transfer buffer used to copy resources between the renderer // process and the GPU process. - transfer_buffer_id_ = - command_buffer->CreateTransferBuffer(transfer_buffer_size, -1); - if (transfer_buffer_id_ < 0) - return false; - - // Map the buffer into the renderer process's address space. - gpu::Buffer transfer_buffer = - command_buffer->GetTransferBuffer(transfer_buffer_id_); - if (!transfer_buffer.ptr) - return false; + const int32 kMinTransferBufferSize = 256 * 1024; + const int32 kMaxTransferBufferSize = 16 * 1024 * 1024; + transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get())); // Create the object exposing the OpenGL API. gles2_impl_.reset(new gpu::gles2::GLES2Implementation( gles2_helper_.get(), - transfer_buffer.size, - transfer_buffer.ptr, - transfer_buffer_id_, + transfer_buffer_.get(), false, true)); + if (!gles2_impl_->Initialize( + transfer_buffer_size, + kMinTransferBufferSize, + std::max(kMaxTransferBufferSize, transfer_buffer_size))) { + return false; + } + return true; } void PPB_Graphics3D_Shared::DestroyGLES2Impl() { gles2_impl_.reset(); - - if (transfer_buffer_id_ != -1) { - gpu::CommandBuffer* command_buffer = GetCommandBuffer(); - DCHECK(command_buffer); - command_buffer->DestroyTransferBuffer(transfer_buffer_id_); - transfer_buffer_id_ = -1; - } - + transfer_buffer_.reset(); gles2_helper_.reset(); } diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.h b/ppapi/shared_impl/ppb_graphics_3d_shared.h index 8804181..2a89e40 100644 --- a/ppapi/shared_impl/ppb_graphics_3d_shared.h +++ b/ppapi/shared_impl/ppb_graphics_3d_shared.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -15,6 +15,7 @@ namespace gpu { class CommandBuffer; +class TransferBuffer; namespace gles2 { class GLES2CmdHelper; class GLES2Implementation; @@ -68,8 +69,8 @@ class PPAPI_SHARED_EXPORT PPB_Graphics3D_Shared void DestroyGLES2Impl(); private: - int32 transfer_buffer_id_; scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_; + scoped_ptr<gpu::TransferBuffer> transfer_buffer_; scoped_ptr<gpu::gles2::GLES2Implementation> gles2_impl_; // Callback that needs to be executed when swap-buffers is completed. diff --git a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc index 510f642..c2c0f39 100644 --- a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc +++ b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc @@ -28,6 +28,7 @@ #include "base/synchronization/lock.h" #include "gpu/command_buffer/client/gles2_lib.h" #include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/common/constants.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gpu_scheduler.h" @@ -46,6 +47,7 @@ using gpu::CommandBufferService; using gpu::gles2::GLES2CmdHelper; using gpu::gles2::GLES2Implementation; using gpu::GpuScheduler; +using gpu::TransferBuffer; namespace webkit { namespace gpu { @@ -190,7 +192,7 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { scoped_refptr<gfx::GLContext> context_; scoped_refptr<gfx::GLSurface> surface_; scoped_ptr<GLES2CmdHelper> gles2_helper_; - int32 transfer_buffer_id_; + scoped_ptr<TransferBuffer> transfer_buffer_; scoped_ptr<GLES2Implementation> gles2_implementation_; Error last_error_; @@ -202,7 +204,9 @@ namespace { const int32 kCommandBufferSize = 1024 * 1024; // TODO(kbr): make the transfer buffer size configurable via context // creation attributes. -const int32 kTransferBufferSize = 1024 * 1024; +const size_t kStartTransferBufferSize = 4 * 1024 * 1024; +const size_t kMinTransferBufferSize = 1 * 256 * 1024; +const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; static base::LazyInstance< std::set<WebGraphicsContext3DInProcessCommandBufferImpl*> > @@ -392,7 +396,6 @@ GLInProcessContext::GLInProcessContext(GLInProcessContext* parent) : parent_(parent ? parent->AsWeakPtr() : base::WeakPtr<GLInProcessContext>()), parent_texture_id_(0), - transfer_buffer_id_(-1), last_error_(SUCCESS) { } @@ -529,31 +532,22 @@ bool GLInProcessContext::Initialize(bool onscreen, } // Create a transfer buffer. - transfer_buffer_id_ = - command_buffer_->CreateTransferBuffer( - kTransferBufferSize, ::gpu::kCommandBufferSharedMemoryId); - if (transfer_buffer_id_ < 0) { - Destroy(); - return false; - } - - // Map the buffer. - Buffer transfer_buffer = - command_buffer_->GetTransferBuffer(transfer_buffer_id_); - if (!transfer_buffer.ptr) { - Destroy(); - return false; - } + transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get())); // Create the object exposing the OpenGL API. gles2_implementation_.reset(new GLES2Implementation( gles2_helper_.get(), - transfer_buffer.size, - transfer_buffer.ptr, - transfer_buffer_id_, + transfer_buffer_.get(), true, false)); + if (!gles2_implementation_->Initialize( + kStartTransferBufferSize, + kMinTransferBufferSize, + kMaxTransferBufferSize)) { + return false; + } + return true; } @@ -574,13 +568,8 @@ void GLInProcessContext::Destroy() { gles2_implementation_.reset(); } - if (command_buffer_.get() && transfer_buffer_id_ != -1) { - command_buffer_->DestroyTransferBuffer(transfer_buffer_id_); - transfer_buffer_id_ = -1; - } - + transfer_buffer_.reset(); gles2_helper_.reset(); - command_buffer_.reset(); } |