// 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 RingBuffer class. #ifndef GPU_COMMAND_BUFFER_CLIENT_RING_BUFFER_H_ #define GPU_COMMAND_BUFFER_CLIENT_RING_BUFFER_H_ #include <deque> #include "base/logging.h" #include "gpu/command_buffer/common/types.h" #include "gpu/gpu_export.h" namespace gpu { class CommandBufferHelper; // RingBuffer manages a piece of memory as a ring buffer. Memory is allocated // with Alloc and then a is freed pending a token with FreePendingToken. Old // allocations must not be kept past new allocations. class GPU_EXPORT RingBuffer { public: typedef unsigned int Offset; // Creates a RingBuffer. // Parameters: // base_offset: The offset of the start of the buffer. // size: The size of the buffer in bytes. // helper: A CommandBufferHelper for dealing with tokens. RingBuffer( Offset base_offset, unsigned int size, CommandBufferHelper* helper); ~RingBuffer(); // 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. Offset Alloc(unsigned int size); // 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, unsigned int token); // Gets the size of the largest free block that is available without waiting. unsigned int GetLargestFreeSizeNoWaiting(); // 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() { return size_; } private: enum State { IN_USE, PADDING, FREE_PENDING_TOKEN }; // Book-keeping sturcture that describes a block of memory. struct Block { Block(Offset _offset, unsigned int _size, State _state) : offset(_offset), size(_size), token(0), state(_state) { } Offset offset; unsigned int size; unsigned int token; // token to wait for. State state; }; typedef std::deque<Block> Container; typedef unsigned int BlockIndex; void FreeOldestBlock(); CommandBufferHelper* helper_; // Used blocks are added to the end, blocks are freed from the beginning. Container blocks_; // The base offset of the ring buffer. Offset base_offset_; // The size of the ring buffer. Offset size_; // Offset of first free byte. Offset free_offset_; // Offset of first used byte. // Range between in_use_mark and free_mark is in use. Offset in_use_offset_; DISALLOW_IMPLICIT_CONSTRUCTORS(RingBuffer); }; // This class functions just like RingBuffer, but its API uses pointers // instead of offsets. class RingBufferWrapper { public: // Parameters: // base_offset: The offset to the start of the buffer // size: The size of the buffer in bytes. // helper: A CommandBufferHelper for dealing with tokens. // base: The physical address that corresponds to base_offset. RingBufferWrapper(RingBuffer::Offset base_offset, unsigned int size, CommandBufferHelper* helper, void* base) : allocator_(base_offset, size, helper), base_(static_cast<int8*>(base) - base_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. // // 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) { RingBuffer::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, 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, unsigned int token) { DCHECK(pointer); allocator_.FreePendingToken(GetOffset(pointer), token); } // Gets a pointer to a memory block given the base memory and the offset. void* GetPointer(RingBuffer::Offset offset) const { return static_cast<int8*>(base_) + offset; } // Gets the offset to a memory block given the base memory and the address. RingBuffer::Offset GetOffset(void* pointer) const { return static_cast<int8*>(pointer) - static_cast<int8*>(base_); } // Gets the size of the largest free block that is available without waiting. unsigned int GetLargestFreeSizeNoWaiting() { return allocator_.GetLargestFreeSizeNoWaiting(); } // Gets the size of the largest free block that can be allocated if the // caller can wait. unsigned int GetLargestFreeOrPendingSize() { return allocator_.GetLargestFreeOrPendingSize(); } private: RingBuffer allocator_; void* base_; DISALLOW_IMPLICIT_CONSTRUCTORS(RingBufferWrapper); }; } // namespace gpu #endif // GPU_COMMAND_BUFFER_CLIENT_RING_BUFFER_H_