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