This source file includes following definitions.
- usable_
- Initialize
- Free
- HaveBuffer
- GetOffset
- FreePendingToken
- AllocateRingBuffer
- Log2Floor
- Log2Ceiling
- ComputePOTSize
- ReallocateRingBuffer
- AllocUpTo
- Alloc
- GetResultBuffer
- GetResultOffset
- GetShmId
- GetCurrentMaxAllocationWithoutRealloc
- GetMaxAllocation
- Release
- Reset
#include "gpu/command_buffer/client/transfer_buffer.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"
namespace gpu {
AlignedRingBuffer::~AlignedRingBuffer() {
}
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_);
return buffer_id_ != -1;
}
RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
return ring_buffer_->GetOffset(pointer);
}
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;
}
}
void TransferBuffer::AllocateRingBuffer(unsigned int size) {
for (;size >= min_buffer_size_; size /= 2) {
int32 id = -1;
scoped_refptr<gpu::Buffer> buffer =
helper_->command_buffer()->CreateTransferBuffer(size, &id);
if (id != -1) {
DCHECK(buffer);
buffer_ = buffer;
ring_buffer_.reset(new AlignedRingBuffer(
alignment_,
id,
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;
}
max_buffer_size_ = size / 2;
}
usable_ = false;
}
static int Log2Floor(uint32 n) {
if (n == 0)
return -1;
int log = 0;
uint32 value = n;
for (int i = 4; i >= 0; --i) {
int shift = (1 << i);
uint32 x = value >> shift;
if (x != 0) {
value = x;
log += shift;
}
}
DCHECK_EQ(value, 1u);
return log;
}
static int Log2Ceiling(uint32 n) {
if (n == 0) {
return -1;
} else {
return 1 + Log2Floor(n - 1);
}
}
static unsigned int ComputePOTSize(unsigned int dimension) {
return (dimension == 0) ? 0 : 1 << Log2Ceiling(dimension);
}
void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
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::Reset(unsigned int new_size) {
Release();
buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
}
}