cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / gpu / command_buffer / client / transfer_buffer.cc
blobf4fe66c9d647b4fce1d322bd0575a77653c34752
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"
8 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
10 namespace gpu {
12 AlignedRingBuffer::~AlignedRingBuffer() {
15 TransferBuffer::TransferBuffer(
16 CommandBufferHelper* helper)
17 : helper_(helper),
18 result_size_(0),
19 default_buffer_size_(0),
20 min_buffer_size_(0),
21 max_buffer_size_(0),
22 alignment_(0),
23 size_to_flush_(0),
24 bytes_since_last_flush_(0),
25 buffer_id_(-1),
26 result_buffer_(NULL),
27 result_shm_offset_(0),
28 usable_(true) {
31 TransferBuffer::~TransferBuffer() {
32 Free();
35 bool TransferBuffer::Initialize(
36 unsigned int default_buffer_size,
37 unsigned int result_size,
38 unsigned int min_buffer_size,
39 unsigned int max_buffer_size,
40 unsigned int alignment,
41 unsigned int size_to_flush) {
42 result_size_ = result_size;
43 default_buffer_size_ = default_buffer_size;
44 min_buffer_size_ = min_buffer_size;
45 max_buffer_size_ = max_buffer_size;
46 alignment_ = alignment;
47 size_to_flush_ = size_to_flush;
48 ReallocateRingBuffer(default_buffer_size_ - result_size);
49 return HaveBuffer();
52 void TransferBuffer::Free() {
53 if (HaveBuffer()) {
54 helper_->Finish();
55 helper_->command_buffer()->DestroyTransferBuffer(buffer_id_);
56 buffer_id_ = -1;
57 buffer_.ptr = NULL;
58 buffer_.size = 0;
59 result_buffer_ = NULL;
60 result_shm_offset_ = 0;
61 ring_buffer_.reset();
62 bytes_since_last_flush_ = 0;
66 bool TransferBuffer::HaveBuffer() const {
67 return buffer_id_ != -1;
70 RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
71 return ring_buffer_->GetOffset(pointer);
74 void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
75 ring_buffer_->FreePendingToken(p, token);
76 if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
77 helper_->Flush();
78 bytes_since_last_flush_ = 0;
82 void TransferBuffer::AllocateRingBuffer(unsigned int size) {
83 for (;size >= min_buffer_size_; size /= 2) {
84 int32 id = -1;
85 gpu::Buffer buffer =
86 helper_->command_buffer()->CreateTransferBuffer(size, &id);
87 if (id != -1) {
88 buffer_ = buffer;
89 ring_buffer_.reset(new AlignedRingBuffer(
90 alignment_,
91 id,
92 result_size_,
93 buffer_.size - result_size_,
94 helper_,
95 static_cast<char*>(buffer_.ptr) + result_size_));
96 buffer_id_ = id;
97 result_buffer_ = buffer_.ptr;
98 result_shm_offset_ = 0;
99 return;
101 // we failed so don't try larger than this.
102 max_buffer_size_ = size / 2;
104 usable_ = false;
107 // Returns the integer i such as 2^i <= n < 2^(i+1)
108 static int Log2Floor(uint32 n) {
109 if (n == 0)
110 return -1;
111 int log = 0;
112 uint32 value = n;
113 for (int i = 4; i >= 0; --i) {
114 int shift = (1 << i);
115 uint32 x = value >> shift;
116 if (x != 0) {
117 value = x;
118 log += shift;
121 GPU_DCHECK_EQ(value, 1u);
122 return log;
125 // Returns the integer i such as 2^(i-1) < n <= 2^i
126 static int Log2Ceiling(uint32 n) {
127 if (n == 0) {
128 return -1;
129 } else {
130 // Log2Floor returns -1 for 0, so the following works correctly for n=1.
131 return 1 + Log2Floor(n - 1);
135 static unsigned int ComputePOTSize(unsigned int dimension) {
136 return (dimension == 0) ? 0 : 1 << Log2Ceiling(dimension);
139 void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
140 // What size buffer would we ask for if we needed a new one?
141 unsigned int needed_buffer_size = ComputePOTSize(size + result_size_);
142 needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_);
143 needed_buffer_size = std::max(needed_buffer_size, default_buffer_size_);
144 needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_);
146 if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_.size)) {
147 if (HaveBuffer()) {
148 Free();
150 AllocateRingBuffer(needed_buffer_size);
154 void* TransferBuffer::AllocUpTo(
155 unsigned int size, unsigned int* size_allocated) {
156 GPU_DCHECK(size_allocated);
158 ReallocateRingBuffer(size);
160 if (!HaveBuffer()) {
161 return NULL;
164 unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
165 *size_allocated = std::min(max_size, size);
166 bytes_since_last_flush_ += *size_allocated;
167 return ring_buffer_->Alloc(*size_allocated);
170 void* TransferBuffer::Alloc(unsigned int size) {
171 ReallocateRingBuffer(size);
173 if (!HaveBuffer()) {
174 return NULL;
177 unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
178 if (size > max_size) {
179 return NULL;
182 bytes_since_last_flush_ += size;
183 return ring_buffer_->Alloc(size);
186 void* TransferBuffer::GetResultBuffer() {
187 ReallocateRingBuffer(result_size_);
188 return result_buffer_;
191 int TransferBuffer::GetResultOffset() {
192 ReallocateRingBuffer(result_size_);
193 return result_shm_offset_;
196 int TransferBuffer::GetShmId() {
197 ReallocateRingBuffer(result_size_);
198 return buffer_id_;
201 unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const {
202 return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
205 unsigned int TransferBuffer::GetMaxAllocation() const {
206 return HaveBuffer() ? max_buffer_size_ - result_size_ : 0;
209 void ScopedTransferBufferPtr::Release() {
210 if (buffer_) {
211 transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken());
212 buffer_ = NULL;
213 size_ = 0;
217 void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
218 Release();
219 // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
220 // that address will return a pointer just like malloc, and so that GetShmId
221 // will be valid. That has the side effect that we'll insert a token on free.
222 // We could add code skip the token for a zero size buffer but it doesn't seem
223 // worth the complication.
224 buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
227 } // namespace gpu