Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "gpu/command_buffer/client/fenced_allocator.h" | 7 #include "gpu/command_buffer/client/fenced_allocator.h" |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 | 35 |
| 36 FencedAllocator::FencedAllocator(unsigned int size, | 36 FencedAllocator::FencedAllocator(unsigned int size, |
| 37 CommandBufferHelper *helper) | 37 CommandBufferHelper *helper) |
| 38 : helper_(helper), | 38 : helper_(helper), |
| 39 bytes_in_use_(0) { | 39 bytes_in_use_(0) { |
| 40 Block block = { FREE, 0, RoundDown(size), kUnusedToken }; | 40 Block block = { FREE, 0, RoundDown(size), kUnusedToken }; |
| 41 blocks_.push_back(block); | 41 blocks_.push_back(block); |
| 42 } | 42 } |
| 43 | 43 |
| 44 FencedAllocator::~FencedAllocator() { | 44 FencedAllocator::~FencedAllocator() { |
| 45 // Free blocks pending tokens. | 45 // Free blocks pending tokens and serials. |
| 46 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 46 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
| 47 if (blocks_[i].state == FREE_PENDING_TOKEN) { | 47 switch (blocks_[i].state) { |
| 48 i = WaitForTokenAndFreeBlock(i); | 48 case FREE_PENDING_TOKEN: |
| 49 i = WaitForTokenAndFreeBlock(i); | |
| 50 break; | |
| 51 case FREE_PENDING_SERIAL: | |
| 52 blocks_[i].state = FREE; | |
| 53 CollapseFreeBlock(i); | |
|
reveman
2014/01/16 17:24:49
I don't think it makes sense free this immediately
piman
2014/01/16 21:22:50
That is actually not needed to ensure things on th
jadahl
2014/01/17 08:50:25
We could just helper_->Finish() before the loop to
reveman
2014/01/17 16:56:47
If we're adding an async-token, then some command
| |
| 54 break; | |
| 55 default: | |
| 56 break; | |
| 49 } | 57 } |
| 50 } | 58 } |
| 51 // These checks are not valid if the service has crashed or lost the context. | 59 // These checks are not valid if the service has crashed or lost the context. |
| 52 // DCHECK_EQ(blocks_.size(), 1u); | 60 // DCHECK_EQ(blocks_.size(), 1u); |
| 53 // DCHECK_EQ(blocks_[0].state, FREE); | 61 // DCHECK_EQ(blocks_[0].state, FREE); |
| 54 } | 62 } |
| 55 | 63 |
| 56 // Looks for a non-allocated block that is big enough. Search in the FREE | 64 // Looks for a non-allocated block that is big enough. Search in the FREE |
| 57 // blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN | 65 // blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN |
| 58 // blocks, waiting for them. The current implementation isn't smart about | 66 // blocks, waiting for them. The current implementation isn't smart about |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 void FencedAllocator::FreePendingToken( | 114 void FencedAllocator::FreePendingToken( |
| 107 FencedAllocator::Offset offset, int32 token) { | 115 FencedAllocator::Offset offset, int32 token) { |
| 108 BlockIndex index = GetBlockByOffset(offset); | 116 BlockIndex index = GetBlockByOffset(offset); |
| 109 Block &block = blocks_[index]; | 117 Block &block = blocks_[index]; |
| 110 if (block.state == IN_USE) | 118 if (block.state == IN_USE) |
| 111 bytes_in_use_ -= block.size; | 119 bytes_in_use_ -= block.size; |
| 112 block.state = FREE_PENDING_TOKEN; | 120 block.state = FREE_PENDING_TOKEN; |
| 113 block.token = token; | 121 block.token = token; |
| 114 } | 122 } |
| 115 | 123 |
| 124 void FencedAllocator::FreePendingSerial( | |
| 125 FencedAllocator::Offset offset, uint32 serial) { | |
| 126 BlockIndex index = GetBlockByOffset(offset); | |
| 127 Block &block = blocks_[index]; | |
| 128 if (block.state == IN_USE) | |
| 129 bytes_in_use_ -= block.size; | |
| 130 block.state = FREE_PENDING_SERIAL; | |
| 131 block.serial = serial; | |
| 132 } | |
| 133 | |
| 116 // Gets the max of the size of the blocks marked as free. | 134 // Gets the max of the size of the blocks marked as free. |
| 117 unsigned int FencedAllocator::GetLargestFreeSize() { | 135 unsigned int FencedAllocator::GetLargestFreeSize() { |
| 118 FreeUnused(); | 136 FreeUnused(); |
| 119 unsigned int max_size = 0; | 137 unsigned int max_size = 0; |
| 120 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 138 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
| 121 Block &block = blocks_[i]; | 139 Block &block = blocks_[i]; |
| 122 if (block.state == FREE) | 140 if (block.state == FREE) |
| 123 max_size = std::max(max_size, block.size); | 141 max_size = std::max(max_size, block.size); |
| 124 } | 142 } |
| 125 return max_size; | 143 return max_size; |
| 126 } | 144 } |
| 127 | 145 |
| 128 // Gets the size of the largest segment of blocks that are either FREE or | 146 // Gets the size of the largest segment of blocks that are either FREE or |
| 129 // FREE_PENDING_TOKEN. | 147 // FREE_PENDING_TOKEN. |
| 130 unsigned int FencedAllocator::GetLargestFreeOrPendingSize() { | 148 unsigned int FencedAllocator::GetLargestFreeOrPendingSize() { |
| 131 unsigned int max_size = 0; | 149 unsigned int max_size = 0; |
| 132 unsigned int current_size = 0; | 150 unsigned int current_size = 0; |
| 133 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 151 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
| 134 Block &block = blocks_[i]; | 152 Block &block = blocks_[i]; |
| 135 if (block.state == IN_USE) { | 153 switch (block.state) { |
| 136 max_size = std::max(max_size, current_size); | 154 case IN_USE: |
| 137 current_size = 0; | 155 case FREE_PENDING_SERIAL: |
| 138 } else { | 156 max_size = std::max(max_size, current_size); |
| 139 DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN); | 157 current_size = 0; |
| 140 current_size += block.size; | 158 break; |
| 159 default: | |
| 160 DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN); | |
| 161 current_size += block.size; | |
| 162 break; | |
| 141 } | 163 } |
| 142 } | 164 } |
| 143 return std::max(max_size, current_size); | 165 return std::max(max_size, current_size); |
| 144 } | 166 } |
| 145 | 167 |
| 146 // Makes sure that: | 168 // Makes sure that: |
| 147 // - there is at least one block. | 169 // - there is at least one block. |
| 148 // - there are no contiguous FREE blocks (they should have been collapsed). | 170 // - there are no contiguous FREE blocks (they should have been collapsed). |
| 149 // - the successive offsets match the block sizes, and they are in order. | 171 // - the successive offsets match the block sizes, and they are in order. |
| 150 bool FencedAllocator::CheckConsistency() { | 172 bool FencedAllocator::CheckConsistency() { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 BlockIndex index) { | 218 BlockIndex index) { |
| 197 Block &block = blocks_[index]; | 219 Block &block = blocks_[index]; |
| 198 DCHECK_EQ(block.state, FREE_PENDING_TOKEN); | 220 DCHECK_EQ(block.state, FREE_PENDING_TOKEN); |
| 199 helper_->WaitForToken(block.token); | 221 helper_->WaitForToken(block.token); |
| 200 block.state = FREE; | 222 block.state = FREE; |
| 201 return CollapseFreeBlock(index); | 223 return CollapseFreeBlock(index); |
| 202 } | 224 } |
| 203 | 225 |
| 204 // Frees any blocks pending a token for which the token has been read. | 226 // Frees any blocks pending a token for which the token has been read. |
| 205 void FencedAllocator::FreeUnused() { | 227 void FencedAllocator::FreeUnused() { |
| 206 int32 last_token_read = helper_->last_token_read(); | |
| 207 for (unsigned int i = 0; i < blocks_.size();) { | 228 for (unsigned int i = 0; i < blocks_.size();) { |
| 208 Block& block = blocks_[i]; | 229 Block& block = blocks_[i]; |
| 209 if (block.state == FREE_PENDING_TOKEN && block.token <= last_token_read) { | 230 switch (block.state) { |
| 210 block.state = FREE; | 231 case FREE_PENDING_TOKEN: |
| 211 i = CollapseFreeBlock(i); | 232 if (helper_->HasTokenPassed(block.token)) { |
| 212 } else { | 233 block.state = FREE; |
| 213 ++i; | 234 i = CollapseFreeBlock(i); |
| 235 } else { | |
| 236 ++i; | |
| 237 } | |
| 238 break; | |
| 239 case FREE_PENDING_SERIAL: | |
| 240 if (helper_->HasSerialPassed(block.serial)) { | |
| 241 block.state = FREE; | |
| 242 i = CollapseFreeBlock(i); | |
| 243 } else { | |
| 244 ++i; | |
| 245 } | |
| 246 break; | |
| 247 default: | |
| 248 ++i; | |
| 249 break; | |
| 214 } | 250 } |
| 215 } | 251 } |
| 216 } | 252 } |
| 217 | 253 |
| 218 // If the block is exactly the requested size, simply mark it IN_USE, otherwise | 254 // If the block is exactly the requested size, simply mark it IN_USE, otherwise |
| 219 // split it and mark the first one (of the requested size) IN_USE. | 255 // split it and mark the first one (of the requested size) IN_USE. |
| 220 FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, | 256 FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, |
| 221 unsigned int size) { | 257 unsigned int size) { |
| 222 Block &block = blocks_[index]; | 258 Block &block = blocks_[index]; |
| 223 DCHECK_GE(block.size, size); | 259 DCHECK_GE(block.size, size); |
| 224 DCHECK_EQ(block.state, FREE); | 260 DCHECK_EQ(block.state, FREE); |
| 225 Offset offset = block.offset; | 261 Offset offset = block.offset; |
| 226 bytes_in_use_ += size; | 262 bytes_in_use_ += size; |
| 227 if (block.size == size) { | 263 if (block.size == size) { |
| 228 block.state = IN_USE; | 264 block.state = IN_USE; |
| 229 return offset; | 265 return offset; |
| 230 } | 266 } |
| 231 Block newblock = { FREE, offset + size, block.size - size, kUnusedToken}; | 267 Block newblock = { |
| 268 FREE, offset + size, | |
| 269 block.size - size, | |
| 270 kUnusedToken, | |
| 271 kUnusedSerial | |
| 272 }; | |
| 232 block.state = IN_USE; | 273 block.state = IN_USE; |
| 233 block.size = size; | 274 block.size = size; |
| 234 // this is the last thing being done because it may invalidate block; | 275 // this is the last thing being done because it may invalidate block; |
| 235 blocks_.insert(blocks_.begin() + index + 1, newblock); | 276 blocks_.insert(blocks_.begin() + index + 1, newblock); |
| 236 return offset; | 277 return offset; |
| 237 } | 278 } |
| 238 | 279 |
| 239 // The blocks are in offset order, so we can do a binary search. | 280 // The blocks are in offset order, so we can do a binary search. |
| 240 FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { | 281 FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { |
| 241 Block templ = { IN_USE, offset, 0, kUnusedToken }; | 282 Block templ = { |
| 283 IN_USE, | |
| 284 offset, | |
| 285 0, | |
| 286 kUnusedToken, | |
| 287 kUnusedSerial | |
| 288 }; | |
| 242 Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), | 289 Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), |
| 243 templ, OffsetCmp()); | 290 templ, OffsetCmp()); |
| 244 DCHECK(it != blocks_.end() && it->offset == offset); | 291 DCHECK(it != blocks_.end() && it->offset == offset); |
| 245 return it-blocks_.begin(); | 292 return it-blocks_.begin(); |
| 246 } | 293 } |
| 247 | 294 |
| 248 } // namespace gpu | 295 } // namespace gpu |
| OLD | NEW |