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"
9 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
13 RingBuffer::RingBuffer(
14 Offset base_offset
, unsigned int size
, CommandBufferHelper
* helper
)
16 base_offset_(base_offset
),
22 RingBuffer::~RingBuffer() {
23 // Free blocks pending tokens.
24 while (!blocks_
.empty()) {
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_
) {
41 // If they match then the entire buffer is free.
42 if (in_use_offset_
== free_offset_
) {
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()) {
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
));
68 Offset offset
= free_offset_
;
69 blocks_
.push_back(Block(offset
, size
, IN_USE
));
71 if (free_offset_
== size_
) {
74 return offset
+ base_offset_
;
77 void RingBuffer::FreePendingToken(RingBuffer::Offset offset
,
79 offset
-= base_offset_
;
80 GPU_DCHECK(!blocks_
.empty()) << "no allocations to free";
81 for (Container::reverse_iterator it
= blocks_
.rbegin();
85 if (block
.offset
== offset
) {
86 GPU_DCHECK(block
.state
== IN_USE
)
87 << "block that corresponds to offset already freed";
89 block
.state
= FREE_PENDING_TOKEN
;
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;
103 if (free_offset_
== in_use_offset_
) {
104 if (blocks_
.empty()) {
105 // The entire buffer is free.
106 GPU_DCHECK_EQ(free_offset_
, 0u);
109 // The entire buffer is in use.
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_
);
116 // It's free from free_offset_ -> in_use_offset_;
117 return in_use_offset_
- free_offset_
;