OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file contains the implementation of the FencedAllocator class. | 5 // This file contains the implementation of the FencedAllocator class. |
6 | 6 |
7 #include "../client/fenced_allocator.h" | 7 #include "../client/fenced_allocator.h" |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include "../client/cmd_buffer_helper.h" | 9 #include "../client/cmd_buffer_helper.h" |
10 | 10 |
11 namespace gpu { | 11 namespace gpu { |
12 | 12 |
13 #ifndef COMPILER_MSVC | 13 #ifndef COMPILER_MSVC |
14 const FencedAllocator::Offset FencedAllocator::kInvalidOffset; | 14 const FencedAllocator::Offset FencedAllocator::kInvalidOffset; |
15 #endif | 15 #endif |
16 | 16 |
17 FencedAllocator::~FencedAllocator() { | 17 FencedAllocator::~FencedAllocator() { |
18 // Free blocks pending tokens. | 18 // Free blocks pending tokens. |
19 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 19 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
20 if (blocks_[i].state == FREE_PENDING_TOKEN) { | 20 if (blocks_[i].state == FREE_PENDING_TOKEN) { |
21 i = WaitForTokenAndFreeBlock(i); | 21 i = WaitForTokenAndFreeBlock(i); |
22 } | 22 } |
23 } | 23 } |
24 DCHECK_EQ(blocks_.size(), 1u); | 24 // These checks are not valid if the service has crashed or lost the context. |
25 DCHECK_EQ(blocks_[0].state, FREE); | 25 // DCHECK_EQ(blocks_.size(), 1u); |
| 26 // DCHECK_EQ(blocks_[0].state, FREE); |
26 } | 27 } |
27 | 28 |
28 // Looks for a non-allocated block that is big enough. Search in the FREE | 29 // Looks for a non-allocated block that is big enough. Search in the FREE |
29 // blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN | 30 // blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN |
30 // blocks, waiting for them. The current implementation isn't smart about | 31 // blocks, waiting for them. The current implementation isn't smart about |
31 // optimizing what to wait for, just looks inside the block in order (first-fit | 32 // optimizing what to wait for, just looks inside the block in order (first-fit |
32 // as well). | 33 // as well). |
33 FencedAllocator::Offset FencedAllocator::Alloc(unsigned int size) { | 34 FencedAllocator::Offset FencedAllocator::Alloc(unsigned int size) { |
34 // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to | 35 // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to |
35 // return different pointers every time. | 36 // return different pointers every time. |
(...skipping 22 matching lines...) Expand all Loading... |
58 // Looks for the corresponding block, mark it FREE, and collapse it if | 59 // Looks for the corresponding block, mark it FREE, and collapse it if |
59 // necessary. | 60 // necessary. |
60 void FencedAllocator::Free(FencedAllocator::Offset offset) { | 61 void FencedAllocator::Free(FencedAllocator::Offset offset) { |
61 BlockIndex index = GetBlockByOffset(offset); | 62 BlockIndex index = GetBlockByOffset(offset); |
62 DCHECK_NE(blocks_[index].state, FREE); | 63 DCHECK_NE(blocks_[index].state, FREE); |
63 blocks_[index].state = FREE; | 64 blocks_[index].state = FREE; |
64 CollapseFreeBlock(index); | 65 CollapseFreeBlock(index); |
65 } | 66 } |
66 | 67 |
67 // Looks for the corresponding block, mark it FREE_PENDING_TOKEN. | 68 // Looks for the corresponding block, mark it FREE_PENDING_TOKEN. |
68 void FencedAllocator::FreePendingToken(FencedAllocator::Offset offset, | 69 void FencedAllocator::FreePendingToken( |
69 unsigned int token) { | 70 FencedAllocator::Offset offset, int32 token) { |
70 BlockIndex index = GetBlockByOffset(offset); | 71 BlockIndex index = GetBlockByOffset(offset); |
71 Block &block = blocks_[index]; | 72 Block &block = blocks_[index]; |
72 block.state = FREE_PENDING_TOKEN; | 73 block.state = FREE_PENDING_TOKEN; |
73 block.token = token; | 74 block.token = token; |
74 } | 75 } |
75 | 76 |
76 // Gets the max of the size of the blocks marked as free. | 77 // Gets the max of the size of the blocks marked as free. |
77 unsigned int FencedAllocator::GetLargestFreeSize() { | 78 unsigned int FencedAllocator::GetLargestFreeSize() { |
78 unsigned int max_size = 0; | 79 unsigned int max_size = 0; |
79 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 80 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 // Waits for the block's token, then mark the block as free, then collapse it. | 148 // Waits for the block's token, then mark the block as free, then collapse it. |
148 FencedAllocator::BlockIndex FencedAllocator::WaitForTokenAndFreeBlock( | 149 FencedAllocator::BlockIndex FencedAllocator::WaitForTokenAndFreeBlock( |
149 BlockIndex index) { | 150 BlockIndex index) { |
150 Block &block = blocks_[index]; | 151 Block &block = blocks_[index]; |
151 DCHECK_EQ(block.state, FREE_PENDING_TOKEN); | 152 DCHECK_EQ(block.state, FREE_PENDING_TOKEN); |
152 helper_->WaitForToken(block.token); | 153 helper_->WaitForToken(block.token); |
153 block.state = FREE; | 154 block.state = FREE; |
154 return CollapseFreeBlock(index); | 155 return CollapseFreeBlock(index); |
155 } | 156 } |
156 | 157 |
| 158 // Frees any blocks pending a token for which the token has been read. |
| 159 void FencedAllocator::FreeUnused() { |
| 160 int32 last_token_read = helper_->last_token_read(); |
| 161 for (unsigned int i = 0; i < blocks_.size();) { |
| 162 Block& block = blocks_[i]; |
| 163 if (block.state == FREE_PENDING_TOKEN && block.token <= last_token_read) { |
| 164 block.state = FREE; |
| 165 i = CollapseFreeBlock(i); |
| 166 } else { |
| 167 ++i; |
| 168 } |
| 169 } |
| 170 } |
| 171 |
157 // If the block is exactly the requested size, simply mark it IN_USE, otherwise | 172 // If the block is exactly the requested size, simply mark it IN_USE, otherwise |
158 // split it and mark the first one (of the requested size) IN_USE. | 173 // split it and mark the first one (of the requested size) IN_USE. |
159 FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, | 174 FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, |
160 unsigned int size) { | 175 unsigned int size) { |
161 Block &block = blocks_[index]; | 176 Block &block = blocks_[index]; |
162 DCHECK_GE(block.size, size); | 177 DCHECK_GE(block.size, size); |
163 DCHECK_EQ(block.state, FREE); | 178 DCHECK_EQ(block.state, FREE); |
164 Offset offset = block.offset; | 179 Offset offset = block.offset; |
165 if (block.size == size) { | 180 if (block.size == size) { |
166 block.state = IN_USE; | 181 block.state = IN_USE; |
(...skipping 10 matching lines...) Expand all Loading... |
177 // The blocks are in offset order, so we can do a binary search. | 192 // The blocks are in offset order, so we can do a binary search. |
178 FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { | 193 FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { |
179 Block templ = { IN_USE, offset, 0, kUnusedToken }; | 194 Block templ = { IN_USE, offset, 0, kUnusedToken }; |
180 Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), | 195 Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), |
181 templ, OffsetCmp()); | 196 templ, OffsetCmp()); |
182 DCHECK(it != blocks_.end() && it->offset == offset); | 197 DCHECK(it != blocks_.end() && it->offset == offset); |
183 return it-blocks_.begin(); | 198 return it-blocks_.begin(); |
184 } | 199 } |
185 | 200 |
186 } // namespace gpu | 201 } // namespace gpu |
OLD | NEW |