| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file contains the definition of the FencedAllocator class. |
| |
| #ifndef GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_ |
| #define GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_ |
| |
| #include <stdint.h> |
| |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "gpu/gpu_export.h" |
| |
| namespace gpu { |
| class CommandBufferHelper; |
| |
| // FencedAllocator provides a mechanism to manage allocations within a fixed |
| // block of memory (storing the book-keeping externally). Furthermore this |
| // class allows to free data "pending" the passage of a command buffer token, |
| // that is, the memory won't be reused until the command buffer has processed |
| // that token. |
| // |
| // NOTE: Although this class is intended to be used in the command buffer |
| // environment which is multi-process, this class isn't "thread safe", because |
| // it isn't meant to be shared across modules. It is thread-compatible though |
| // (see http://www.corp.google.com/eng/doc/cpp_primer.html#thread_safety). |
| class GPU_EXPORT FencedAllocator { |
| public: |
| typedef unsigned int Offset; |
| // Invalid offset, returned by Alloc in case of failure. |
| static const Offset kInvalidOffset = 0xffffffffU; |
| |
| // Allocation alignment, must be a power of two. |
| static const unsigned int kAllocAlignment = 16; |
| |
| // Creates a FencedAllocator. Note that the size of the buffer is passed, but |
| // not its base address: everything is handled as offsets into the buffer. |
| FencedAllocator(unsigned int size, |
| CommandBufferHelper *helper, |
| const base::Closure& poll_callback); |
| |
| ~FencedAllocator(); |
| |
| // Allocates a block of memory. If the buffer is out of directly available |
| // memory, this function may wait until memory that was freed "pending a |
| // token" can be re-used. |
| // |
| // Parameters: |
| // size: the size of the memory block to allocate. |
| // |
| // Returns: |
| // the offset of the allocated memory block, or kInvalidOffset if out of |
| // memory. |
| Offset Alloc(unsigned int size); |
| |
| // Frees a block of memory. |
| // |
| // Parameters: |
| // offset: the offset of the memory block to free. |
| void Free(Offset offset); |
| |
| // Frees a block of memory, pending the passage of a token. That memory won't |
| // be re-allocated until the token has passed through the command stream. |
| // |
| // Parameters: |
| // offset: the offset of the memory block to free. |
| // token: the token value to wait for before re-using the memory. |
| void FreePendingToken(Offset offset, int32 token); |
| |
| // Frees any blocks pending a token for which the token has been read. |
| void FreeUnused(); |
| |
| // Gets the size of the largest free block that is available without waiting. |
| unsigned int GetLargestFreeSize(); |
| |
| // Gets the size of the largest free block that can be allocated if the |
| // caller can wait. Allocating a block of this size will succeed, but may |
| // block. |
| unsigned int GetLargestFreeOrPendingSize(); |
| |
| // Checks for consistency inside the book-keeping structures. Used for |
| // testing. |
| bool CheckConsistency(); |
| |
| // True if any memory is allocated. |
| bool InUse(); |
| |
| // Return bytes of memory that is IN_USE |
| size_t bytes_in_use() const { return bytes_in_use_; } |
| |
| private: |
| // Status of a block of memory, for book-keeping. |
| enum State { |
| IN_USE, |
| FREE, |
| FREE_PENDING_TOKEN |
| }; |
| |
| // Book-keeping sturcture that describes a block of memory. |
| struct Block { |
| State state; |
| Offset offset; |
| unsigned int size; |
| int32_t token; // token to wait for in the FREE_PENDING_TOKEN case. |
| }; |
| |
| // Comparison functor for memory block sorting. |
| class OffsetCmp { |
| public: |
| bool operator() (const Block &left, const Block &right) { |
| return left.offset < right.offset; |
| } |
| }; |
| |
| typedef std::vector<Block> Container; |
| typedef unsigned int BlockIndex; |
| |
| static const int32_t kUnusedToken = 0; |
| |
| // Gets the index of a memory block, given its offset. |
| BlockIndex GetBlockByOffset(Offset offset); |
| |
| // Collapse a free block with its neighbours if they are free. Returns the |
| // index of the collapsed block. |
| // NOTE: this will invalidate block indices. |
| BlockIndex CollapseFreeBlock(BlockIndex index); |
| |
| // Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns |
| // the new index of that block (since it may have been collapsed). |
| // NOTE: this will invalidate block indices. |
| BlockIndex WaitForTokenAndFreeBlock(BlockIndex index); |
| |
| // Allocates a block of memory inside a given block, splitting it in two |
| // (unless that block is of the exact requested size). |
| // NOTE: this will invalidate block indices. |
| // Returns the offset of the allocated block (NOTE: this is different from |
| // the other functions that return a block index). |
| Offset AllocInBlock(BlockIndex index, unsigned int size); |
| |
| CommandBufferHelper *helper_; |
| base::Closure poll_callback_; |
| Container blocks_; |
| size_t bytes_in_use_; |
| |
| DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator); |
| }; |
| |
| // This class functions just like FencedAllocator, but its API uses pointers |
| // instead of offsets. |
| class FencedAllocatorWrapper { |
| public: |
| FencedAllocatorWrapper(unsigned int size, |
| CommandBufferHelper* helper, |
| const base::Closure& poll_callback, |
| void* base) |
| : allocator_(size, helper, poll_callback), |
| base_(base) { } |
| |
| // Allocates a block of memory. If the buffer is out of directly available |
| // memory, this function may wait until memory that was freed "pending a |
| // token" can be re-used. |
| // |
| // Parameters: |
| // size: the size of the memory block to allocate. |
| // |
| // Returns: |
| // the pointer to the allocated memory block, or NULL if out of |
| // memory. |
| void *Alloc(unsigned int size) { |
| FencedAllocator::Offset offset = allocator_.Alloc(size); |
| return GetPointer(offset); |
| } |
| |
| // Allocates a block of memory. If the buffer is out of directly available |
| // memory, this function may wait until memory that was freed "pending a |
| // token" can be re-used. |
| // This is a type-safe version of Alloc, returning a typed pointer. |
| // |
| // Parameters: |
| // count: the number of elements to allocate. |
| // |
| // Returns: |
| // the pointer to the allocated memory block, or NULL if out of |
| // memory. |
| template <typename T> T *AllocTyped(unsigned int count) { |
| return static_cast<T *>(Alloc(count * sizeof(T))); |
| } |
| |
| // Frees a block of memory. |
| // |
| // Parameters: |
| // pointer: the pointer to the memory block to free. |
| void Free(void *pointer) { |
| DCHECK(pointer); |
| allocator_.Free(GetOffset(pointer)); |
| } |
| |
| // Frees a block of memory, pending the passage of a token. That memory won't |
| // be re-allocated until the token has passed through the command stream. |
| // |
| // Parameters: |
| // pointer: the pointer to the memory block to free. |
| // token: the token value to wait for before re-using the memory. |
| void FreePendingToken(void *pointer, int32 token) { |
| DCHECK(pointer); |
| allocator_.FreePendingToken(GetOffset(pointer), token); |
| } |
| |
| // Frees any blocks pending a token for which the token has been read. |
| void FreeUnused() { |
| allocator_.FreeUnused(); |
| } |
| |
| // Gets a pointer to a memory block given the base memory and the offset. |
| // It translates FencedAllocator::kInvalidOffset to NULL. |
| void *GetPointer(FencedAllocator::Offset offset) { |
| return (offset == FencedAllocator::kInvalidOffset) ? |
| NULL : static_cast<char *>(base_) + offset; |
| } |
| |
| // Gets the offset to a memory block given the base memory and the address. |
| // It translates NULL to FencedAllocator::kInvalidOffset. |
| FencedAllocator::Offset GetOffset(void *pointer) { |
| return pointer ? |
| static_cast<FencedAllocator::Offset>( |
| static_cast<char*>(pointer) - static_cast<char*>(base_)) : |
| FencedAllocator::kInvalidOffset; |
| } |
| |
| // Gets the size of the largest free block that is available without waiting. |
| unsigned int GetLargestFreeSize() { |
| return allocator_.GetLargestFreeSize(); |
| } |
| |
| // Gets the size of the largest free block that can be allocated if the |
| // caller can wait. |
| unsigned int GetLargestFreeOrPendingSize() { |
| return allocator_.GetLargestFreeOrPendingSize(); |
| } |
| |
| // Checks for consistency inside the book-keeping structures. Used for |
| // testing. |
| bool CheckConsistency() { |
| return allocator_.CheckConsistency(); |
| } |
| |
| // True if any memory is allocated. |
| bool InUse() { |
| return allocator_.InUse(); |
| } |
| |
| FencedAllocator &allocator() { return allocator_; } |
| |
| size_t bytes_in_use() const { return allocator_.bytes_in_use(); } |
| |
| private: |
| FencedAllocator allocator_; |
| void* base_; |
| DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper); |
| }; |
| |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_ |