1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains the implementation of the RingBuffer class.
#include "../client/ring_buffer.h"
#include <algorithm>
#include "../client/cmd_buffer_helper.h"
namespace gpu {
RingBuffer::RingBuffer(
Offset base_offset, unsigned int size, CommandBufferHelper* helper)
: helper_(helper),
base_offset_(base_offset),
size_(size),
free_offset_(0),
in_use_offset_(0) {
}
RingBuffer::~RingBuffer() {
// Free blocks pending tokens.
while (!blocks_.empty()) {
FreeOldestBlock();
}
}
void RingBuffer::FreeOldestBlock() {
DCHECK(!blocks_.empty()) << "no free blocks";
Block& block = blocks_.front();
DCHECK(block.valid) << "attempt to allocate more than maximum memory";
helper_->WaitForToken(block.token);
in_use_offset_ += block.size;
if (in_use_offset_ == size_) {
in_use_offset_ = 0;
}
// If they match then the entire buffer is free.
if (in_use_offset_ == free_offset_) {
in_use_offset_ = 0;
free_offset_ = 0;
}
blocks_.pop_front();
}
RingBuffer::Offset RingBuffer::Alloc(unsigned int size) {
DCHECK_LE(size, size_) << "attempt to allocate more than maximum memory";
DCHECK(blocks_.empty() || blocks_.back().valid)
<< "Attempt to alloc another block before freeing the previous.";
// Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
// return different pointers every time.
if (size == 0) size = 1;
// Wait until there is enough room.
while (size > GetLargestFreeSizeNoWaiting()) {
FreeOldestBlock();
}
Offset offset = free_offset_;
blocks_.push_back(Block(offset, size));
free_offset_ += size;
if (free_offset_ == size_) {
free_offset_ = 0;
}
return offset + base_offset_;
}
void RingBuffer::FreePendingToken(RingBuffer::Offset offset,
unsigned int token) {
offset -= base_offset_;
DCHECK(!blocks_.empty()) << "no allocations to free";
for (Container::reverse_iterator it = blocks_.rbegin();
it != blocks_.rend();
++it) {
Block& block = *it;
if (block.offset == offset) {
DCHECK(!block.valid) << "block that corresponds to offset already freed";
block.token = token;
block.valid = true;
return;
}
}
NOTREACHED() << "attempt to free non-existant block";
}
unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() {
// TODO(gman): Should check what the current token is and free up to that
// point.
if (free_offset_ == in_use_offset_) {
if (blocks_.empty()) {
// The entire buffer is free.
DCHECK_EQ(free_offset_, 0u);
return size_;
} else {
// The entire buffer is in use.
return 0;
}
} else if (free_offset_ > in_use_offset_) {
// It's free from free_offset_ to size_
return size_ - free_offset_;
} else {
// It's free from free_offset_ -> in_use_offset_;
return in_use_offset_ - free_offset_;
}
}
} // namespace gpu
|