25f63425d857c4e829adf7860f683bd6df79d698
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / client / ring_buffer.cc
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.
4
5 // This file contains the implementation of the RingBuffer class.
6
7 #include "gpu/command_buffer/client/ring_buffer.h"
8
9 #include <algorithm>
10
11 #include "base/logging.h"
12 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
13
14 namespace gpu {
15
16 RingBuffer::RingBuffer(
17     Offset base_offset, unsigned int size, CommandBufferHelper* helper)
18     : helper_(helper),
19       base_offset_(base_offset),
20       size_(size),
21       free_offset_(0),
22       in_use_offset_(0) {
23 }
24
25 RingBuffer::~RingBuffer() {
26   // Free blocks pending tokens.
27   while (!blocks_.empty()) {
28     FreeOldestBlock();
29   }
30 }
31
32 void RingBuffer::FreeOldestBlock() {
33   DCHECK(!blocks_.empty()) << "no free blocks";
34   Block& block = blocks_.front();
35   DCHECK(block.state != IN_USE)
36       << "attempt to allocate more than maximum memory";
37   if (block.state == FREE_PENDING_TOKEN) {
38     helper_->WaitForToken(block.token);
39   }
40   in_use_offset_ += block.size;
41   if (in_use_offset_ == size_) {
42     in_use_offset_ = 0;
43   }
44   // If they match then the entire buffer is free.
45   if (in_use_offset_ == free_offset_) {
46     in_use_offset_ = 0;
47     free_offset_ = 0;
48   }
49   blocks_.pop_front();
50 }
51
52 RingBuffer::Offset RingBuffer::Alloc(unsigned int size) {
53   DCHECK_LE(size, size_) << "attempt to allocate more than maximum memory";
54   DCHECK(blocks_.empty() || blocks_.back().state != IN_USE)
55       << "Attempt to alloc another block before freeing the previous.";
56   // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
57   // return different pointers every time.
58   if (size == 0) size = 1;
59
60   // Wait until there is enough room.
61   while (size > GetLargestFreeSizeNoWaiting()) {
62     FreeOldestBlock();
63   }
64
65   if (size + free_offset_ > size_) {
66     // Add padding to fill space before wrapping around
67     blocks_.push_back(Block(free_offset_, size_ - free_offset_, PADDING));
68     free_offset_ = 0;
69   }
70
71   Offset offset = free_offset_;
72   blocks_.push_back(Block(offset, size, IN_USE));
73   free_offset_ += size;
74   if (free_offset_ == size_) {
75     free_offset_ = 0;
76   }
77   return offset + base_offset_;
78 }
79
80 void RingBuffer::FreePendingToken(RingBuffer::Offset offset,
81                                   unsigned int token) {
82   offset -= base_offset_;
83   DCHECK(!blocks_.empty()) << "no allocations to free";
84   for (Container::reverse_iterator it = blocks_.rbegin();
85         it != blocks_.rend();
86         ++it) {
87     Block& block = *it;
88     if (block.offset == offset) {
89       DCHECK(block.state == IN_USE)
90           << "block that corresponds to offset already freed";
91       block.token = token;
92       block.state = FREE_PENDING_TOKEN;
93       return;
94     }
95   }
96   NOTREACHED() << "attempt to free non-existant block";
97 }
98
99 unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() {
100   unsigned int last_token_read = helper_->last_token_read();
101   while (!blocks_.empty()) {
102     Block& block = blocks_.front();
103     if (block.token > last_token_read || block.state == IN_USE) break;
104     FreeOldestBlock();
105   }
106   if (free_offset_ == in_use_offset_) {
107     if (blocks_.empty()) {
108       // The entire buffer is free.
109       DCHECK_EQ(free_offset_, 0u);
110       return size_;
111     } else {
112       // The entire buffer is in use.
113       return 0;
114     }
115   } else if (free_offset_ > in_use_offset_) {
116     // It's free from free_offset_ to size_ and from 0 to in_use_offset_
117     return std::max(size_ - free_offset_, in_use_offset_);
118   } else {
119     // It's free from free_offset_ -> in_use_offset_;
120     return in_use_offset_ - free_offset_;
121   }
122 }
123
124 }  // namespace gpu