text: // 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 "gpu/command_buffer/common/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) {
      GPU_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_
  