cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / gpu / command_buffer / client / ring_buffer.cc
blob42e09bd3e1fcfe8c5e8c79b8cb16c6d831dcc717
1 // Copyright (c) 2011 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 // This file contains the implementation of the RingBuffer class.
7 #include "gpu/command_buffer/client/ring_buffer.h"
8 #include <algorithm>
9 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
11 namespace gpu {
13 RingBuffer::RingBuffer(
14 Offset base_offset, unsigned int size, CommandBufferHelper* helper)
15 : helper_(helper),
16 base_offset_(base_offset),
17 size_(size),
18 free_offset_(0),
19 in_use_offset_(0) {
22 RingBuffer::~RingBuffer() {
23 // Free blocks pending tokens.
24 while (!blocks_.empty()) {
25 FreeOldestBlock();
29 void RingBuffer::FreeOldestBlock() {
30 GPU_DCHECK(!blocks_.empty()) << "no free blocks";
31 Block& block = blocks_.front();
32 GPU_DCHECK(block.state != IN_USE)
33 << "attempt to allocate more than maximum memory";
34 if (block.state == FREE_PENDING_TOKEN) {
35 helper_->WaitForToken(block.token);
37 in_use_offset_ += block.size;
38 if (in_use_offset_ == size_) {
39 in_use_offset_ = 0;
41 // If they match then the entire buffer is free.
42 if (in_use_offset_ == free_offset_) {
43 in_use_offset_ = 0;
44 free_offset_ = 0;
46 blocks_.pop_front();
49 RingBuffer::Offset RingBuffer::Alloc(unsigned int size) {
50 GPU_DCHECK_LE(size, size_) << "attempt to allocate more than maximum memory";
51 GPU_DCHECK(blocks_.empty() || blocks_.back().state != IN_USE)
52 << "Attempt to alloc another block before freeing the previous.";
53 // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
54 // return different pointers every time.
55 if (size == 0) size = 1;
57 // Wait until there is enough room.
58 while (size > GetLargestFreeSizeNoWaiting()) {
59 FreeOldestBlock();
62 if (size + free_offset_ > size_) {
63 // Add padding to fill space before wrapping around
64 blocks_.push_back(Block(free_offset_, size_ - free_offset_, PADDING));
65 free_offset_ = 0;
68 Offset offset = free_offset_;
69 blocks_.push_back(Block(offset, size, IN_USE));
70 free_offset_ += size;
71 if (free_offset_ == size_) {
72 free_offset_ = 0;
74 return offset + base_offset_;
77 void RingBuffer::FreePendingToken(RingBuffer::Offset offset,
78 unsigned int token) {
79 offset -= base_offset_;
80 GPU_DCHECK(!blocks_.empty()) << "no allocations to free";
81 for (Container::reverse_iterator it = blocks_.rbegin();
82 it != blocks_.rend();
83 ++it) {
84 Block& block = *it;
85 if (block.offset == offset) {
86 GPU_DCHECK(block.state == IN_USE)
87 << "block that corresponds to offset already freed";
88 block.token = token;
89 block.state = FREE_PENDING_TOKEN;
90 return;
93 GPU_NOTREACHED() << "attempt to free non-existant block";
96 unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() {
97 unsigned int last_token_read = helper_->last_token_read();
98 while (!blocks_.empty()) {
99 Block& block = blocks_.front();
100 if (block.token > last_token_read || block.state == IN_USE) break;
101 FreeOldestBlock();
103 if (free_offset_ == in_use_offset_) {
104 if (blocks_.empty()) {
105 // The entire buffer is free.
106 GPU_DCHECK_EQ(free_offset_, 0u);
107 return size_;
108 } else {
109 // The entire buffer is in use.
110 return 0;
112 } else if (free_offset_ > in_use_offset_) {
113 // It's free from free_offset_ to size_ and from 0 to in_use_offset_
114 return std::max(size_ - free_offset_, in_use_offset_);
115 } else {
116 // It's free from free_offset_ -> in_use_offset_;
117 return in_use_offset_ - free_offset_;
121 } // namespace gpu