1 // Copyright (c) 2012 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. 4 5 // This file contains the definition of the FencedAllocator class. 6 7 #ifndef GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_ 8 #define GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_ 9 10 #include <vector> 11 12 #include "base/logging.h" 13 #include "gpu/command_buffer/common/types.h" 14 #include "gpu/gpu_export.h" 15 16 namespace gpu { 17 class CommandBufferHelper; 18 19 // FencedAllocator provides a mechanism to manage allocations within a fixed 20 // block of memory (storing the book-keeping externally). Furthermore this 21 // class allows to free data "pending" the passage of a command buffer token, 22 // that is, the memory won't be reused until the command buffer has processed 23 // that token. 24 // 25 // NOTE: Although this class is intended to be used in the command buffer 26 // environment which is multi-process, this class isn't "thread safe", because 27 // it isn't meant to be shared across modules. It is thread-compatible though 28 // (see http://www.corp.google.com/eng/doc/cpp_primer.html#thread_safety). 29 class GPU_EXPORT FencedAllocator { 30 public: 31 typedef unsigned int Offset; 32 // Invalid offset, returned by Alloc in case of failure. 33 static const Offset kInvalidOffset = 0xffffffffU; 34 35 // Creates a FencedAllocator. Note that the size of the buffer is passed, but 36 // not its base address: everything is handled as offsets into the buffer. 37 FencedAllocator(unsigned int size, 38 CommandBufferHelper *helper); 39 40 ~FencedAllocator(); 41 42 // Allocates a block of memory. If the buffer is out of directly available 43 // memory, this function may wait until memory that was freed "pending a 44 // token" can be re-used. 45 // 46 // Parameters: 47 // size: the size of the memory block to allocate. 48 // 49 // Returns: 50 // the offset of the allocated memory block, or kInvalidOffset if out of 51 // memory. 52 Offset Alloc(unsigned int size); 53 54 // Frees a block of memory. 55 // 56 // Parameters: 57 // offset: the offset of the memory block to free. 58 void Free(Offset offset); 59 60 // Frees a block of memory, pending the passage of a token. That memory won't 61 // be re-allocated until the token has passed through the command stream. 62 // 63 // Parameters: 64 // offset: the offset of the memory block to free. 65 // token: the token value to wait for before re-using the memory. 66 void FreePendingToken(Offset offset, int32 token); 67 68 // Frees any blocks pending a token for which the token has been read. 69 void FreeUnused(); 70 71 // Gets the size of the largest free block that is available without waiting. 72 unsigned int GetLargestFreeSize(); 73 74 // Gets the size of the largest free block that can be allocated if the 75 // caller can wait. Allocating a block of this size will succeed, but may 76 // block. 77 unsigned int GetLargestFreeOrPendingSize(); 78 79 // Checks for consistency inside the book-keeping structures. Used for 80 // testing. 81 bool CheckConsistency(); 82 83 // True if any memory is allocated. 84 bool InUse(); 85 86 // Return bytes of memory that is IN_USE 87 size_t bytes_in_use() const { return bytes_in_use_; } 88 89 private: 90 // Status of a block of memory, for book-keeping. 91 enum State { 92 IN_USE, 93 FREE, 94 FREE_PENDING_TOKEN 95 }; 96 97 // Book-keeping sturcture that describes a block of memory. 98 struct Block { 99 State state; 100 Offset offset; 101 unsigned int size; 102 int32 token; // token to wait for in the FREE_PENDING_TOKEN case. 103 }; 104 105 // Comparison functor for memory block sorting. 106 class OffsetCmp { 107 public: 108 bool operator() (const Block &left, const Block &right) { 109 return left.offset < right.offset; 110 } 111 }; 112 113 typedef std::vector<Block> Container; 114 typedef unsigned int BlockIndex; 115 116 static const int32 kUnusedToken = 0; 117 118 // Gets the index of a memory block, given its offset. 119 BlockIndex GetBlockByOffset(Offset offset); 120 121 // Collapse a free block with its neighbours if they are free. Returns the 122 // index of the collapsed block. 123 // NOTE: this will invalidate block indices. 124 BlockIndex CollapseFreeBlock(BlockIndex index); 125 126 // Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns 127 // the new index of that block (since it may have been collapsed). 128 // NOTE: this will invalidate block indices. 129 BlockIndex WaitForTokenAndFreeBlock(BlockIndex index); 130 131 // Allocates a block of memory inside a given block, splitting it in two 132 // (unless that block is of the exact requested size). 133 // NOTE: this will invalidate block indices. 134 // Returns the offset of the allocated block (NOTE: this is different from 135 // the other functions that return a block index). 136 Offset AllocInBlock(BlockIndex index, unsigned int size); 137 138 CommandBufferHelper *helper_; 139 Container blocks_; 140 size_t bytes_in_use_; 141 142 DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator); 143 }; 144 145 // This class functions just like FencedAllocator, but its API uses pointers 146 // instead of offsets. 147 class FencedAllocatorWrapper { 148 public: 149 FencedAllocatorWrapper(unsigned int size, 150 CommandBufferHelper* helper, 151 void* base) 152 : allocator_(size, helper), 153 base_(base) { } 154 155 // Allocates a block of memory. If the buffer is out of directly available 156 // memory, this function may wait until memory that was freed "pending a 157 // token" can be re-used. 158 // 159 // Parameters: 160 // size: the size of the memory block to allocate. 161 // 162 // Returns: 163 // the pointer to the allocated memory block, or NULL if out of 164 // memory. 165 void *Alloc(unsigned int size) { 166 FencedAllocator::Offset offset = allocator_.Alloc(size); 167 return GetPointer(offset); 168 } 169 170 // Allocates a block of memory. If the buffer is out of directly available 171 // memory, this function may wait until memory that was freed "pending a 172 // token" can be re-used. 173 // This is a type-safe version of Alloc, returning a typed pointer. 174 // 175 // Parameters: 176 // count: the number of elements to allocate. 177 // 178 // Returns: 179 // the pointer to the allocated memory block, or NULL if out of 180 // memory. 181 template <typename T> T *AllocTyped(unsigned int count) { 182 return static_cast<T *>(Alloc(count * sizeof(T))); 183 } 184 185 // Frees a block of memory. 186 // 187 // Parameters: 188 // pointer: the pointer to the memory block to free. 189 void Free(void *pointer) { 190 DCHECK(pointer); 191 allocator_.Free(GetOffset(pointer)); 192 } 193 194 // Frees a block of memory, pending the passage of a token. That memory won't 195 // be re-allocated until the token has passed through the command stream. 196 // 197 // Parameters: 198 // pointer: the pointer to the memory block to free. 199 // token: the token value to wait for before re-using the memory. 200 void FreePendingToken(void *pointer, int32 token) { 201 DCHECK(pointer); 202 allocator_.FreePendingToken(GetOffset(pointer), token); 203 } 204 205 // Frees any blocks pending a token for which the token has been read. 206 void FreeUnused() { 207 allocator_.FreeUnused(); 208 } 209 210 // Gets a pointer to a memory block given the base memory and the offset. 211 // It translates FencedAllocator::kInvalidOffset to NULL. 212 void *GetPointer(FencedAllocator::Offset offset) { 213 return (offset == FencedAllocator::kInvalidOffset) ? 214 NULL : static_cast<char *>(base_) + offset; 215 } 216 217 // Gets the offset to a memory block given the base memory and the address. 218 // It translates NULL to FencedAllocator::kInvalidOffset. 219 FencedAllocator::Offset GetOffset(void *pointer) { 220 return pointer ? 221 static_cast<FencedAllocator::Offset>( 222 static_cast<char*>(pointer) - static_cast<char*>(base_)) : 223 FencedAllocator::kInvalidOffset; 224 } 225 226 // Gets the size of the largest free block that is available without waiting. 227 unsigned int GetLargestFreeSize() { 228 return allocator_.GetLargestFreeSize(); 229 } 230 231 // Gets the size of the largest free block that can be allocated if the 232 // caller can wait. 233 unsigned int GetLargestFreeOrPendingSize() { 234 return allocator_.GetLargestFreeOrPendingSize(); 235 } 236 237 // Checks for consistency inside the book-keeping structures. Used for 238 // testing. 239 bool CheckConsistency() { 240 return allocator_.CheckConsistency(); 241 } 242 243 // True if any memory is allocated. 244 bool InUse() { 245 return allocator_.InUse(); 246 } 247 248 FencedAllocator &allocator() { return allocator_; } 249 250 size_t bytes_in_use() const { return allocator_.bytes_in_use(); } 251 252 private: 253 FencedAllocator allocator_; 254 void* base_; 255 DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper); 256 }; 257 258 } // namespace gpu 259 260 #endif // GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_ 261