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 if (blocks_[i].state == FREE_PENDING_TOKEN) { |
| 48 i = WaitForTokenAndFreeBlock(i); | 48 i = WaitForTokenAndFreeBlock(i); |
| 49 } else if (blocks_[i].state == FREE_PENDING_SERIAL) { | |
| 50 Block &block = blocks_[i]; | |
| 51 block.state = FREE; | |
| 52 CollapseFreeBlock(i); | |
|
piman
2014/01/11 02:02:32
This is probably ok in the current use, if we can
jadahl
2014/01/16 16:24:39
Where do you suggest we document this? Here?
| |
| 49 } | 53 } |
| 50 } | 54 } |
| 51 // These checks are not valid if the service has crashed or lost the context. | 55 // These checks are not valid if the service has crashed or lost the context. |
| 52 // DCHECK_EQ(blocks_.size(), 1u); | 56 // DCHECK_EQ(blocks_.size(), 1u); |
| 53 // DCHECK_EQ(blocks_[0].state, FREE); | 57 // DCHECK_EQ(blocks_[0].state, FREE); |
| 54 } | 58 } |
| 55 | 59 |
| 56 // Looks for a non-allocated block that is big enough. Search in the FREE | 60 // 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 | 61 // 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 | 62 // 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( | 110 void FencedAllocator::FreePendingToken( |
| 107 FencedAllocator::Offset offset, int32 token) { | 111 FencedAllocator::Offset offset, int32 token) { |
| 108 BlockIndex index = GetBlockByOffset(offset); | 112 BlockIndex index = GetBlockByOffset(offset); |
| 109 Block &block = blocks_[index]; | 113 Block &block = blocks_[index]; |
| 110 if (block.state == IN_USE) | 114 if (block.state == IN_USE) |
| 111 bytes_in_use_ -= block.size; | 115 bytes_in_use_ -= block.size; |
| 112 block.state = FREE_PENDING_TOKEN; | 116 block.state = FREE_PENDING_TOKEN; |
| 113 block.token = token; | 117 block.token = token; |
| 114 } | 118 } |
| 115 | 119 |
| 120 void FencedAllocator::FreePendingSerial( | |
| 121 FencedAllocator::Offset offset, uint32 serial) { | |
| 122 BlockIndex index = GetBlockByOffset(offset); | |
| 123 Block &block = blocks_[index]; | |
| 124 if (block.state == IN_USE) | |
| 125 bytes_in_use_ -= block.size; | |
| 126 block.state = FREE_PENDING_SERIAL; | |
| 127 block.serial = serial; | |
| 128 } | |
| 129 | |
| 116 // Gets the max of the size of the blocks marked as free. | 130 // Gets the max of the size of the blocks marked as free. |
| 117 unsigned int FencedAllocator::GetLargestFreeSize() { | 131 unsigned int FencedAllocator::GetLargestFreeSize() { |
| 118 FreeUnused(); | 132 FreeUnused(); |
| 119 unsigned int max_size = 0; | 133 unsigned int max_size = 0; |
| 120 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 134 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
| 121 Block &block = blocks_[i]; | 135 Block &block = blocks_[i]; |
| 122 if (block.state == FREE) | 136 if (block.state == FREE) |
| 123 max_size = std::max(max_size, block.size); | 137 max_size = std::max(max_size, block.size); |
| 124 } | 138 } |
| 125 return max_size; | 139 return max_size; |
| 126 } | 140 } |
| 127 | 141 |
| 128 // Gets the size of the largest segment of blocks that are either FREE or | 142 // Gets the size of the largest segment of blocks that are either FREE or |
| 129 // FREE_PENDING_TOKEN. | 143 // FREE_PENDING_TOKEN. |
| 130 unsigned int FencedAllocator::GetLargestFreeOrPendingSize() { | 144 unsigned int FencedAllocator::GetLargestFreeOrPendingSize() { |
| 131 unsigned int max_size = 0; | 145 unsigned int max_size = 0; |
| 132 unsigned int current_size = 0; | 146 unsigned int current_size = 0; |
| 133 for (unsigned int i = 0; i < blocks_.size(); ++i) { | 147 for (unsigned int i = 0; i < blocks_.size(); ++i) { |
| 134 Block &block = blocks_[i]; | 148 Block &block = blocks_[i]; |
| 135 if (block.state == IN_USE) { | 149 if (block.state == IN_USE || block.state == FREE_PENDING_SERIAL) { |
| 136 max_size = std::max(max_size, current_size); | 150 max_size = std::max(max_size, current_size); |
| 137 current_size = 0; | 151 current_size = 0; |
| 138 } else { | 152 } else { |
| 139 DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN); | 153 DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN); |
| 140 current_size += block.size; | 154 current_size += block.size; |
| 141 } | 155 } |
| 142 } | 156 } |
| 143 return std::max(max_size, current_size); | 157 return std::max(max_size, current_size); |
| 144 } | 158 } |
| 145 | 159 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 Block &block = blocks_[index]; | 211 Block &block = blocks_[index]; |
| 198 DCHECK_EQ(block.state, FREE_PENDING_TOKEN); | 212 DCHECK_EQ(block.state, FREE_PENDING_TOKEN); |
| 199 helper_->WaitForToken(block.token); | 213 helper_->WaitForToken(block.token); |
| 200 block.state = FREE; | 214 block.state = FREE; |
| 201 return CollapseFreeBlock(index); | 215 return CollapseFreeBlock(index); |
| 202 } | 216 } |
| 203 | 217 |
| 204 // Frees any blocks pending a token for which the token has been read. | 218 // Frees any blocks pending a token for which the token has been read. |
| 205 void FencedAllocator::FreeUnused() { | 219 void FencedAllocator::FreeUnused() { |
| 206 int32 last_token_read = helper_->last_token_read(); | 220 int32 last_token_read = helper_->last_token_read(); |
| 221 uint32 last_serial_read = helper_->last_serial_read(); | |
| 207 for (unsigned int i = 0; i < blocks_.size();) { | 222 for (unsigned int i = 0; i < blocks_.size();) { |
| 208 Block& block = blocks_[i]; | 223 Block& block = blocks_[i]; |
| 209 if (block.state == FREE_PENDING_TOKEN && block.token <= last_token_read) { | 224 if (block.state == FREE_PENDING_TOKEN && block.token <= last_token_read) { |
| 210 block.state = FREE; | 225 block.state = FREE; |
| 211 i = CollapseFreeBlock(i); | 226 i = CollapseFreeBlock(i); |
| 227 } else if (block.state == FREE_PENDING_SERIAL && | |
| 228 block.serial <= last_serial_read) { | |
|
reveman
2014/01/11 23:39:04
maybe use a switch statement here and above
| |
| 229 block.state = FREE; | |
| 230 i = CollapseFreeBlock(i); | |
| 212 } else { | 231 } else { |
| 213 ++i; | 232 ++i; |
| 214 } | 233 } |
| 215 } | 234 } |
| 216 } | 235 } |
| 217 | 236 |
| 218 // If the block is exactly the requested size, simply mark it IN_USE, otherwise | 237 // 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. | 238 // split it and mark the first one (of the requested size) IN_USE. |
| 220 FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, | 239 FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, |
| 221 unsigned int size) { | 240 unsigned int size) { |
| 222 Block &block = blocks_[index]; | 241 Block &block = blocks_[index]; |
| 223 DCHECK_GE(block.size, size); | 242 DCHECK_GE(block.size, size); |
| 224 DCHECK_EQ(block.state, FREE); | 243 DCHECK_EQ(block.state, FREE); |
| 225 Offset offset = block.offset; | 244 Offset offset = block.offset; |
| 226 bytes_in_use_ += size; | 245 bytes_in_use_ += size; |
| 227 if (block.size == size) { | 246 if (block.size == size) { |
| 228 block.state = IN_USE; | 247 block.state = IN_USE; |
| 229 return offset; | 248 return offset; |
| 230 } | 249 } |
| 231 Block newblock = { FREE, offset + size, block.size - size, kUnusedToken}; | 250 Block newblock = { |
| 251 FREE, offset + size, | |
| 252 block.size - size, | |
| 253 kUnusedToken, | |
| 254 kUnusedSerial | |
| 255 }; | |
| 232 block.state = IN_USE; | 256 block.state = IN_USE; |
| 233 block.size = size; | 257 block.size = size; |
| 234 // this is the last thing being done because it may invalidate block; | 258 // this is the last thing being done because it may invalidate block; |
| 235 blocks_.insert(blocks_.begin() + index + 1, newblock); | 259 blocks_.insert(blocks_.begin() + index + 1, newblock); |
| 236 return offset; | 260 return offset; |
| 237 } | 261 } |
| 238 | 262 |
| 239 // The blocks are in offset order, so we can do a binary search. | 263 // The blocks are in offset order, so we can do a binary search. |
| 240 FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { | 264 FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { |
| 241 Block templ = { IN_USE, offset, 0, kUnusedToken }; | 265 Block templ = { |
| 266 IN_USE, | |
| 267 offset, | |
| 268 0, | |
| 269 kUnusedToken, | |
| 270 kUnusedSerial | |
| 271 }; | |
| 242 Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), | 272 Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), |
| 243 templ, OffsetCmp()); | 273 templ, OffsetCmp()); |
| 244 DCHECK(it != blocks_.end() && it->offset == offset); | 274 DCHECK(it != blocks_.end() && it->offset == offset); |
| 245 return it-blocks_.begin(); | 275 return it-blocks_.begin(); |
| 246 } | 276 } |
| 247 | 277 |
| 248 } // namespace gpu | 278 } // namespace gpu |
| OLD | NEW |