// 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.

// A class to Manage a growing transfer buffer.

#include "gpu/command_buffer/client/transfer_buffer.h"

#include <stddef.h>
#include <stdint.h>

#include "base/bits.h"
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"

namespace gpu {

TransferBuffer::TransferBuffer(
    CommandBufferHelper* helper)
    : helper_(helper),
      result_size_(0),
      default_buffer_size_(0),
      min_buffer_size_(0),
      max_buffer_size_(0),
      alignment_(0),
      size_to_flush_(0),
      bytes_since_last_flush_(0),
      buffer_id_(-1),
      result_buffer_(NULL),
      result_shm_offset_(0),
      usable_(true) {
}

TransferBuffer::~TransferBuffer() {
  Free();
}

bool TransferBuffer::Initialize(
    unsigned int default_buffer_size,
    unsigned int result_size,
    unsigned int min_buffer_size,
    unsigned int max_buffer_size,
    unsigned int alignment,
    unsigned int size_to_flush) {
  result_size_ = result_size;
  default_buffer_size_ = default_buffer_size;
  min_buffer_size_ = min_buffer_size;
  max_buffer_size_ = max_buffer_size;
  alignment_ = alignment;
  size_to_flush_ = size_to_flush;
  ReallocateRingBuffer(default_buffer_size_ - result_size);
  return HaveBuffer();
}

void TransferBuffer::Free() {
  if (HaveBuffer()) {
    TRACE_EVENT0("gpu", "TransferBuffer::Free");
    helper_->Finish();
    helper_->command_buffer()->DestroyTransferBuffer(buffer_id_);
    buffer_id_ = -1;
    buffer_ = NULL;
    result_buffer_ = NULL;
    result_shm_offset_ = 0;
    ring_buffer_.reset();
    bytes_since_last_flush_ = 0;
  }
}

bool TransferBuffer::HaveBuffer() const {
  DCHECK(buffer_id_ == -1 || buffer_.get());
  return buffer_id_ != -1;
}

RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
  return ring_buffer_->GetOffset(pointer);
}

void TransferBuffer::DiscardBlock(void* p) {
  ring_buffer_->DiscardBlock(p);
}

void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
  ring_buffer_->FreePendingToken(p, token);
  if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
    helper_->Flush();
    bytes_since_last_flush_ = 0;
  }
}

unsigned int TransferBuffer::GetSize() const {
  return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
}

unsigned int TransferBuffer::GetFreeSize() const {
  return HaveBuffer() ? ring_buffer_->GetTotalFreeSizeNoWaiting() : 0;
}

void TransferBuffer::AllocateRingBuffer(unsigned int size) {
  for (;size >= min_buffer_size_; size /= 2) {
    int32_t id = -1;
    scoped_refptr<gpu::Buffer> buffer =
        helper_->command_buffer()->CreateTransferBuffer(size, &id);
    if (id != -1) {
      DCHECK(buffer.get());
      buffer_ = buffer;
      ring_buffer_.reset(new RingBuffer(
          alignment_,
          result_size_,
          buffer_->size() - result_size_,
          helper_,
          static_cast<char*>(buffer_->memory()) + result_size_));
      buffer_id_ = id;
      result_buffer_ = buffer_->memory();
      result_shm_offset_ = 0;
      return;
    }
    // we failed so don't try larger than this.
    max_buffer_size_ = size / 2;
  }
  usable_ = false;
}

static unsigned int ComputePOTSize(unsigned int dimension) {
  return (dimension == 0) ? 0 : 1 << base::bits::Log2Ceiling(dimension);
}

void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
  // What size buffer would we ask for if we needed a new one?
  unsigned int needed_buffer_size = ComputePOTSize(size + result_size_);
  needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_);
  needed_buffer_size = std::max(needed_buffer_size, default_buffer_size_);
  needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_);

  if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_->size())) {
    if (HaveBuffer()) {
      Free();
    }
    AllocateRingBuffer(needed_buffer_size);
  }
}

void* TransferBuffer::AllocUpTo(
    unsigned int size, unsigned int* size_allocated) {
  DCHECK(size_allocated);

  ReallocateRingBuffer(size);

  if (!HaveBuffer()) {
    return NULL;
  }

  unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
  *size_allocated = std::min(max_size, size);
  bytes_since_last_flush_ += *size_allocated;
  return ring_buffer_->Alloc(*size_allocated);
}

void* TransferBuffer::Alloc(unsigned int size) {
  ReallocateRingBuffer(size);

  if (!HaveBuffer()) {
    return NULL;
  }

  unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
  if (size > max_size) {
    return NULL;
  }

  bytes_since_last_flush_ += size;
  return ring_buffer_->Alloc(size);
}

void* TransferBuffer::GetResultBuffer() {
  ReallocateRingBuffer(result_size_);
  return result_buffer_;
}

int TransferBuffer::GetResultOffset() {
  ReallocateRingBuffer(result_size_);
  return result_shm_offset_;
}

int TransferBuffer::GetShmId() {
  ReallocateRingBuffer(result_size_);
  return buffer_id_;
}

unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const {
  return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
}

unsigned int TransferBuffer::GetMaxAllocation() const {
  return HaveBuffer() ? max_buffer_size_ - result_size_ : 0;
}

void ScopedTransferBufferPtr::Release() {
  if (buffer_) {
    transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken());
    buffer_ = NULL;
    size_ = 0;
  }
}

void ScopedTransferBufferPtr::Discard() {
  if (buffer_) {
    transfer_buffer_->DiscardBlock(buffer_);
    buffer_ = NULL;
    size_ = 0;
  }
}

void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
  Release();
  // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
  // that address will return a pointer just like malloc, and so that GetShmId
  // will be valid. That has the side effect that we'll insert a token on free.
  // We could add code skip the token for a zero size buffer but it doesn't seem
  // worth the complication.
  buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
}

}  // namespace gpu
