Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / gpu / command_buffer / client / transfer_buffer.cc
blobdde802096b42376e51df81afcb9d643dc889f508
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // A class to Manage a growing transfer buffer.
7 #include "gpu/command_buffer/client/transfer_buffer.h"
9 #include "base/bits.h"
10 #include "base/logging.h"
11 #include "base/trace_event/trace_event.h"
12 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
14 namespace gpu {
16 TransferBuffer::TransferBuffer(
17 CommandBufferHelper* helper)
18 : helper_(helper),
19 result_size_(0),
20 default_buffer_size_(0),
21 min_buffer_size_(0),
22 max_buffer_size_(0),
23 alignment_(0),
24 size_to_flush_(0),
25 bytes_since_last_flush_(0),
26 buffer_id_(-1),
27 result_buffer_(NULL),
28 result_shm_offset_(0),
29 usable_(true) {
32 TransferBuffer::~TransferBuffer() {
33 Free();
36 bool TransferBuffer::Initialize(
37 unsigned int default_buffer_size,
38 unsigned int result_size,
39 unsigned int min_buffer_size,
40 unsigned int max_buffer_size,
41 unsigned int alignment,
42 unsigned int size_to_flush) {
43 result_size_ = result_size;
44 default_buffer_size_ = default_buffer_size;
45 min_buffer_size_ = min_buffer_size;
46 max_buffer_size_ = max_buffer_size;
47 alignment_ = alignment;
48 size_to_flush_ = size_to_flush;
49 ReallocateRingBuffer(default_buffer_size_ - result_size);
50 return HaveBuffer();
53 void TransferBuffer::Free() {
54 if (HaveBuffer()) {
55 TRACE_EVENT0("gpu", "TransferBuffer::Free");
56 helper_->Finish();
57 helper_->command_buffer()->DestroyTransferBuffer(buffer_id_);
58 buffer_id_ = -1;
59 buffer_ = NULL;
60 result_buffer_ = NULL;
61 result_shm_offset_ = 0;
62 ring_buffer_.reset();
63 bytes_since_last_flush_ = 0;
67 bool TransferBuffer::HaveBuffer() const {
68 DCHECK(buffer_id_ == -1 || buffer_.get());
69 return buffer_id_ != -1;
72 RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
73 return ring_buffer_->GetOffset(pointer);
76 void TransferBuffer::DiscardBlock(void* p) {
77 ring_buffer_->DiscardBlock(p);
80 void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
81 ring_buffer_->FreePendingToken(p, token);
82 if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
83 helper_->Flush();
84 bytes_since_last_flush_ = 0;
88 unsigned int TransferBuffer::GetSize() const {
89 return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
92 unsigned int TransferBuffer::GetFreeSize() const {
93 return HaveBuffer() ? ring_buffer_->GetTotalFreeSizeNoWaiting() : 0;
96 void TransferBuffer::AllocateRingBuffer(unsigned int size) {
97 for (;size >= min_buffer_size_; size /= 2) {
98 int32 id = -1;
99 scoped_refptr<gpu::Buffer> buffer =
100 helper_->command_buffer()->CreateTransferBuffer(size, &id);
101 if (id != -1) {
102 DCHECK(buffer.get());
103 buffer_ = buffer;
104 ring_buffer_.reset(new RingBuffer(
105 alignment_,
106 result_size_,
107 buffer_->size() - result_size_,
108 helper_,
109 static_cast<char*>(buffer_->memory()) + result_size_));
110 buffer_id_ = id;
111 result_buffer_ = buffer_->memory();
112 result_shm_offset_ = 0;
113 return;
115 // we failed so don't try larger than this.
116 max_buffer_size_ = size / 2;
118 usable_ = false;
121 static unsigned int ComputePOTSize(unsigned int dimension) {
122 return (dimension == 0) ? 0 : 1 << base::bits::Log2Ceiling(dimension);
125 void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
126 // What size buffer would we ask for if we needed a new one?
127 unsigned int needed_buffer_size = ComputePOTSize(size + result_size_);
128 needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_);
129 needed_buffer_size = std::max(needed_buffer_size, default_buffer_size_);
130 needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_);
132 if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_->size())) {
133 if (HaveBuffer()) {
134 Free();
136 AllocateRingBuffer(needed_buffer_size);
140 void* TransferBuffer::AllocUpTo(
141 unsigned int size, unsigned int* size_allocated) {
142 DCHECK(size_allocated);
144 ReallocateRingBuffer(size);
146 if (!HaveBuffer()) {
147 return NULL;
150 unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
151 *size_allocated = std::min(max_size, size);
152 bytes_since_last_flush_ += *size_allocated;
153 return ring_buffer_->Alloc(*size_allocated);
156 void* TransferBuffer::Alloc(unsigned int size) {
157 ReallocateRingBuffer(size);
159 if (!HaveBuffer()) {
160 return NULL;
163 unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
164 if (size > max_size) {
165 return NULL;
168 bytes_since_last_flush_ += size;
169 return ring_buffer_->Alloc(size);
172 void* TransferBuffer::GetResultBuffer() {
173 ReallocateRingBuffer(result_size_);
174 return result_buffer_;
177 int TransferBuffer::GetResultOffset() {
178 ReallocateRingBuffer(result_size_);
179 return result_shm_offset_;
182 int TransferBuffer::GetShmId() {
183 ReallocateRingBuffer(result_size_);
184 return buffer_id_;
187 unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const {
188 return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
191 unsigned int TransferBuffer::GetMaxAllocation() const {
192 return HaveBuffer() ? max_buffer_size_ - result_size_ : 0;
195 void ScopedTransferBufferPtr::Release() {
196 if (buffer_) {
197 transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken());
198 buffer_ = NULL;
199 size_ = 0;
203 void ScopedTransferBufferPtr::Discard() {
204 if (buffer_) {
205 transfer_buffer_->DiscardBlock(buffer_);
206 buffer_ = NULL;
207 size_ = 0;
211 void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
212 Release();
213 // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
214 // that address will return a pointer just like malloc, and so that GetShmId
215 // will be valid. That has the side effect that we'll insert a token on free.
216 // We could add code skip the token for a zero size buffer but it doesn't seem
217 // worth the complication.
218 buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
221 } // namespace gpu