// 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.
#ifndef GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_
#define GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/client/ring_buffer.h"
#include "gpu/command_buffer/common/buffer.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/gpu_export.h"
namespace gpu {
class CommandBufferHelper;
// Wraps RingBufferWrapper to provide aligned allocations.
class AlignedRingBuffer : public RingBufferWrapper {
public:
AlignedRingBuffer(
unsigned int alignment,
int32 shm_id,
RingBuffer::Offset base_offset,
unsigned int size,
CommandBufferHelper* helper,
void* base)
: RingBufferWrapper(base_offset, size, helper, base),
alignment_(alignment),
shm_id_(shm_id) {
}
~AlignedRingBuffer();
// Hiding Alloc from RingBufferWrapper
void* Alloc(unsigned int size) {
return RingBufferWrapper::Alloc(RoundToAlignment(size));
}
int32 GetShmId() const {
return shm_id_;
}
private:
unsigned int RoundToAlignment(unsigned int size) {
return (size + alignment_ - 1) & ~(alignment_ - 1);
}
unsigned int alignment_;
int32 shm_id_;
};
// Interface for managing the transfer buffer.
class GPU_EXPORT TransferBufferInterface {
public:
TransferBufferInterface() { }
virtual ~TransferBufferInterface() { }
virtual bool Initialize(
unsigned int buffer_size,
unsigned int result_size,
unsigned int min_buffer_size,
unsigned int max_buffer_size,
unsigned int alignment,
unsigned int size_to_flush) = 0;
virtual int GetShmId() = 0;
virtual void* GetResultBuffer() = 0;
virtual int GetResultOffset() = 0;
virtual void Free() = 0;
virtual bool HaveBuffer() const = 0;
// Allocates up to size bytes.
virtual void* AllocUpTo(unsigned int size, unsigned int* size_allocated) = 0;
// Allocates size bytes.
// Note: Alloc will fail if it can not return size bytes.
virtual void* Alloc(unsigned int size) = 0;
virtual RingBuffer::Offset GetOffset(void* pointer) const = 0;
virtual void FreePendingToken(void* p, unsigned int token) = 0;
};
// Class that manages the transfer buffer.
class GPU_EXPORT TransferBuffer : public TransferBufferInterface {
public:
TransferBuffer(CommandBufferHelper* helper);
virtual ~TransferBuffer();
// Overridden from TransferBufferInterface.
virtual bool 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) OVERRIDE;
virtual int GetShmId() OVERRIDE;
virtual void* GetResultBuffer() OVERRIDE;
virtual int GetResultOffset() OVERRIDE;
virtual void Free() OVERRIDE;
virtual bool HaveBuffer() const OVERRIDE;
virtual void* AllocUpTo(
unsigned int size, unsigned int* size_allocated) OVERRIDE;
virtual void* Alloc(unsigned int size) OVERRIDE;
virtual RingBuffer::Offset GetOffset(void* pointer) const OVERRIDE;
virtual void FreePendingToken(void* p, unsigned int token) OVERRIDE;
// These are for testing.
unsigned int GetCurrentMaxAllocationWithoutRealloc() const;
unsigned int GetMaxAllocation() const;
private:
// Tries to reallocate the ring buffer if it's not large enough for size.
void ReallocateRingBuffer(unsigned int size);
void AllocateRingBuffer(unsigned int size);
CommandBufferHelper* helper_;
scoped_ptr<AlignedRingBuffer> ring_buffer_;
// size reserved for results
unsigned int result_size_;
// default size. Size we want when starting or re-allocating
unsigned int default_buffer_size_;
// min size we'll consider successful
unsigned int min_buffer_size_;
// max size we'll let the buffer grow
unsigned int max_buffer_size_;
// alignment for allocations
unsigned int alignment_;
// Size at which to do an async flush. 0 = never.
unsigned int size_to_flush_;
// Number of bytes since we last flushed.
unsigned int bytes_since_last_flush_;
// the current buffer.
gpu::Buffer buffer_;
// id of buffer. -1 = no buffer
int32 buffer_id_;
// address of result area
void* result_buffer_;
// offset to result area
uint32 result_shm_offset_;
// false if we failed to allocate min_buffer_size
bool usable_;
};
// A class that will manage the lifetime of a transferbuffer allocation.
class GPU_EXPORT ScopedTransferBufferPtr {
public:
ScopedTransferBufferPtr(
unsigned int size,
CommandBufferHelper* helper,
TransferBufferInterface* transfer_buffer)
: buffer_(NULL),
size_(0),
helper_(helper),
transfer_buffer_(transfer_buffer) {
Reset(size);
}
~ScopedTransferBufferPtr() {
Release();
}
bool valid() const {
return buffer_ != NULL;
}
unsigned int size() const {
return size_;
}
int shm_id() const {
return transfer_buffer_->GetShmId();
}
RingBuffer::Offset offset() const {
return transfer_buffer_->GetOffset(buffer_);
}
void* address() const {
return buffer_;
}
void Release();
void Reset(unsigned int new_size);
private:
void* buffer_;
unsigned int size_;
CommandBufferHelper* helper_;
TransferBufferInterface* transfer_buffer_;
DISALLOW_COPY_AND_ASSIGN(ScopedTransferBufferPtr);
};
template <typename T>
class ScopedTransferBufferArray : public ScopedTransferBufferPtr {
public:
ScopedTransferBufferArray(
unsigned int num_elements,
CommandBufferHelper* helper, TransferBufferInterface* transfer_buffer)
: ScopedTransferBufferPtr(
num_elements * sizeof(T), helper, transfer_buffer) {
}
T* elements() {
return static_cast<T*>(address());
}
unsigned int num_elements() const {
return size() / sizeof(T);
}
};
} // namespace gpu
#endif // GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_