fenced_allocator.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 "../../gpu_export.h"
13#include "../common/logging.h"
14#include "../common/types.h"
15
16namespace gpu {
17class 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).
29class 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 private:
87  // Status of a block of memory, for book-keeping.
88  enum State {
89    IN_USE,
90    FREE,
91    FREE_PENDING_TOKEN
92  };
93
94  // Book-keeping sturcture that describes a block of memory.
95  struct Block {
96    State state;
97    Offset offset;
98    unsigned int size;
99    int32 token;  // token to wait for in the FREE_PENDING_TOKEN case.
100  };
101
102  // Comparison functor for memory block sorting.
103  class OffsetCmp {
104   public:
105    bool operator() (const Block &left, const Block &right) {
106      return left.offset < right.offset;
107    }
108  };
109
110  typedef std::vector<Block> Container;
111  typedef unsigned int BlockIndex;
112
113  static const int32 kUnusedToken = 0;
114
115  // Gets the index of a memory block, given its offset.
116  BlockIndex GetBlockByOffset(Offset offset);
117
118  // Collapse a free block with its neighbours if they are free. Returns the
119  // index of the collapsed block.
120  // NOTE: this will invalidate block indices.
121  BlockIndex CollapseFreeBlock(BlockIndex index);
122
123  // Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns
124  // the new index of that block (since it may have been collapsed).
125  // NOTE: this will invalidate block indices.
126  BlockIndex WaitForTokenAndFreeBlock(BlockIndex index);
127
128  // Allocates a block of memory inside a given block, splitting it in two
129  // (unless that block is of the exact requested size).
130  // NOTE: this will invalidate block indices.
131  // Returns the offset of the allocated block (NOTE: this is different from
132  // the other functions that return a block index).
133  Offset AllocInBlock(BlockIndex index, unsigned int size);
134
135  CommandBufferHelper *helper_;
136  Container blocks_;
137
138  DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator);
139};
140
141// This class functions just like FencedAllocator, but its API uses pointers
142// instead of offsets.
143class FencedAllocatorWrapper {
144 public:
145  FencedAllocatorWrapper(unsigned int size,
146                         CommandBufferHelper* helper,
147                         void* base)
148      : allocator_(size, helper),
149        base_(base) { }
150
151  // Allocates a block of memory. If the buffer is out of directly available
152  // memory, this function may wait until memory that was freed "pending a
153  // token" can be re-used.
154  //
155  // Parameters:
156  //   size: the size of the memory block to allocate.
157  //
158  // Returns:
159  //   the pointer to the allocated memory block, or NULL if out of
160  //   memory.
161  void *Alloc(unsigned int size) {
162    FencedAllocator::Offset offset = allocator_.Alloc(size);
163    return GetPointer(offset);
164  }
165
166  // Allocates a block of memory. If the buffer is out of directly available
167  // memory, this function may wait until memory that was freed "pending a
168  // token" can be re-used.
169  // This is a type-safe version of Alloc, returning a typed pointer.
170  //
171  // Parameters:
172  //   count: the number of elements to allocate.
173  //
174  // Returns:
175  //   the pointer to the allocated memory block, or NULL if out of
176  //   memory.
177  template <typename T> T *AllocTyped(unsigned int count) {
178    return static_cast<T *>(Alloc(count * sizeof(T)));
179  }
180
181  // Frees a block of memory.
182  //
183  // Parameters:
184  //   pointer: the pointer to the memory block to free.
185  void Free(void *pointer) {
186    GPU_DCHECK(pointer);
187    allocator_.Free(GetOffset(pointer));
188  }
189
190  // Frees a block of memory, pending the passage of a token. That memory won't
191  // be re-allocated until the token has passed through the command stream.
192  //
193  // Parameters:
194  //   pointer: the pointer to the memory block to free.
195  //   token: the token value to wait for before re-using the memory.
196  void FreePendingToken(void *pointer, int32 token) {
197    GPU_DCHECK(pointer);
198    allocator_.FreePendingToken(GetOffset(pointer), token);
199  }
200
201  // Frees any blocks pending a token for which the token has been read.
202  void FreeUnused() {
203    allocator_.FreeUnused();
204  }
205
206  // Gets a pointer to a memory block given the base memory and the offset.
207  // It translates FencedAllocator::kInvalidOffset to NULL.
208  void *GetPointer(FencedAllocator::Offset offset) {
209    return (offset == FencedAllocator::kInvalidOffset) ?
210        NULL : static_cast<char *>(base_) + offset;
211  }
212
213  // Gets the offset to a memory block given the base memory and the address.
214  // It translates NULL to FencedAllocator::kInvalidOffset.
215  FencedAllocator::Offset GetOffset(void *pointer) {
216    return pointer ?
217        static_cast<FencedAllocator::Offset>(
218            static_cast<char*>(pointer) - static_cast<char*>(base_)) :
219        FencedAllocator::kInvalidOffset;
220  }
221
222  // Gets the size of the largest free block that is available without waiting.
223  unsigned int GetLargestFreeSize() {
224    return allocator_.GetLargestFreeSize();
225  }
226
227  // Gets the size of the largest free block that can be allocated if the
228  // caller can wait.
229  unsigned int GetLargestFreeOrPendingSize() {
230    return allocator_.GetLargestFreeOrPendingSize();
231  }
232
233  // Checks for consistency inside the book-keeping structures. Used for
234  // testing.
235  bool CheckConsistency() {
236    return allocator_.CheckConsistency();
237  }
238
239  // True if any memory is allocated.
240  bool InUse() {
241    return allocator_.InUse();
242  }
243
244  FencedAllocator &allocator() { return allocator_; }
245
246 private:
247  FencedAllocator allocator_;
248  void* base_;
249  DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper);
250};
251
252}  // namespace gpu
253
254#endif  // GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_
255