summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/client/transfer_buffer.cc
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-27 23:06:19 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-27 23:06:19 +0000
commit06b73aa26473f9ec6bec009d11329a10cad27350 (patch)
tree953a5ab22e1fd30e918a47a0eebd72860c0bad69 /gpu/command_buffer/client/transfer_buffer.cc
parentd052176a98e0f9803b276dc43daa08b3fd310055 (diff)
downloadchromium_src-06b73aa26473f9ec6bec009d11329a10cad27350.zip
chromium_src-06b73aa26473f9ec6bec009d11329a10cad27350.tar.gz
chromium_src-06b73aa26473f9ec6bec009d11329a10cad27350.tar.bz2
Revert "Revert 119430 - Make transferbuffer increase in size dynamically"
This reverts commit 2f38c45427c68fe731c1f5c05256b6c141a6a590. BUG=101431 TEST= TBR=apatrick@chromium.org Review URL: http://codereview.chromium.org/9121057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119509 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu/command_buffer/client/transfer_buffer.cc')
-rw-r--r--gpu/command_buffer/client/transfer_buffer.cc211
1 files changed, 211 insertions, 0 deletions
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