blob: e2639b3a264a0805627c583b0ff0316bf630efd0 [file] [log] [blame]
// 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 command buffer helper class.
#ifndef GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
#define GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
#include <string.h>
#include <time.h>
#include "gpu/command_buffer/common/cmd_buffer_common.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/logging.h"
#include "gpu/gpu_export.h"
namespace gpu {
// Command buffer helper class. This class simplifies ring buffer management:
// it will allocate the buffer, give it to the buffer interface, and let the
// user add commands to it, while taking care of the synchronization (put and
// get). It also provides a way to ensure commands have been executed, through
// the token mechanism:
//
// helper.AddCommand(...);
// helper.AddCommand(...);
// int32 token = helper.InsertToken();
// helper.AddCommand(...);
// helper.AddCommand(...);
// [...]
//
// helper.WaitForToken(token); // this doesn't return until the first two
// // commands have been executed.
class GPU_EXPORT CommandBufferHelper {
public:
explicit CommandBufferHelper(CommandBuffer* command_buffer);
virtual ~CommandBufferHelper();
// Initializes the CommandBufferHelper.
// Parameters:
// ring_buffer_size: The size of the ring buffer portion of the command
// buffer.
bool Initialize(int32 ring_buffer_size);
// Sets whether the command buffer should automatically flush periodically
// to try to increase performance. Defaults to true.
void SetAutomaticFlushes(bool enabled);
// True if the context is lost.
bool IsContextLost();
// Asynchronously flushes the commands, setting the put pointer to let the
// buffer interface know that new commands have been added. After a flush
// returns, the command buffer service is aware of all pending commands.
void Flush();
// Flushes the commands, setting the put pointer to let the buffer interface
// know that new commands have been added. After a flush returns, the command
// buffer service is aware of all pending commands and it is guaranteed to
// have made some progress in processing them. Returns whether the flush was
// successful. The flush will fail if the command buffer service has
// disconnected.
bool FlushSync();
// Waits until all the commands have been executed. Returns whether it
// was successful. The function will fail if the command buffer service has
// disconnected.
bool Finish();
// Waits until a given number of available entries are available.
// Parameters:
// count: number of entries needed. This value must be at most
// the size of the buffer minus one.
void WaitForAvailableEntries(int32 count);
// Inserts a new token into the command buffer. This token either has a value
// different from previously inserted tokens, or ensures that previously
// inserted tokens with that value have already passed through the command
// stream.
// Returns:
// the value of the new token or -1 if the command buffer reader has
// shutdown.
int32 InsertToken();
// Waits until the token of a particular value has passed through the command
// stream (i.e. commands inserted before that token have been executed).
// NOTE: This will call Flush if it needs to block.
// Parameters:
// the value of the token to wait for.
void WaitForToken(int32 token);
// Called prior to each command being issued. Waits for a certain amount of
// space to be available. Returns address of space.
CommandBufferEntry* GetSpace(uint32 entries);
// Typed version of GetSpace. Gets enough room for the given type and returns
// a reference to it.
template <typename T>
T* GetCmdSpace() {
COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
uint32 space_needed = ComputeNumEntries(sizeof(T));
void* data = GetSpace(space_needed);
return reinterpret_cast<T*>(data);
}
// Typed version of GetSpace for immediate commands.
template <typename T>
T* GetImmediateCmdSpace(size_t data_space) {
COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
uint32 space_needed = ComputeNumEntries(sizeof(T) + data_space);
void* data = GetSpace(space_needed);
return reinterpret_cast<T*>(data);
}
// Typed version of GetSpace for immediate commands.
template <typename T>
T* GetImmediateCmdSpaceTotalSize(size_t total_space) {
COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
uint32 space_needed = ComputeNumEntries(total_space);
void* data = GetSpace(space_needed);
return reinterpret_cast<T*>(data);
}
int32 last_token_read() const {
return command_buffer_->GetLastToken();
}
int32 get_offset() const {
return command_buffer_->GetLastState().get_offset;
}
// Common Commands
void Noop(uint32 skip_count) {
cmd::Noop* cmd = GetImmediateCmdSpace<cmd::Noop>(
(skip_count - 1) * sizeof(CommandBufferEntry));
if (cmd) {
cmd->Init(skip_count);
}
}
void SetToken(uint32 token) {
cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
if (cmd) {
cmd->Init(token);
}
}
void SetBucketSize(uint32 bucket_id, uint32 size) {
cmd::SetBucketSize* cmd = GetCmdSpace<cmd::SetBucketSize>();
if (cmd) {
cmd->Init(bucket_id, size);
}
}
void SetBucketData(uint32 bucket_id,
uint32 offset,
uint32 size,
uint32 shared_memory_id,
uint32 shared_memory_offset) {
cmd::SetBucketData* cmd = GetCmdSpace<cmd::SetBucketData>();
if (cmd) {
cmd->Init(bucket_id,
offset,
size,
shared_memory_id,
shared_memory_offset);
}
}
void SetBucketDataImmediate(
uint32 bucket_id, uint32 offset, const void* data, uint32 size) {
cmd::SetBucketDataImmediate* cmd =
GetImmediateCmdSpace<cmd::SetBucketDataImmediate>(size);
if (cmd) {
cmd->Init(bucket_id, offset, size);
memcpy(ImmediateDataAddress(cmd), data, size);
}
}
void GetBucketStart(uint32 bucket_id,
uint32 result_memory_id,
uint32 result_memory_offset,
uint32 data_memory_size,
uint32 data_memory_id,
uint32 data_memory_offset) {
cmd::GetBucketStart* cmd = GetCmdSpace<cmd::GetBucketStart>();
if (cmd) {
cmd->Init(bucket_id,
result_memory_id,
result_memory_offset,
data_memory_size,
data_memory_id,
data_memory_offset);
}
}
void GetBucketData(uint32 bucket_id,
uint32 offset,
uint32 size,
uint32 shared_memory_id,
uint32 shared_memory_offset) {
cmd::GetBucketData* cmd = GetCmdSpace<cmd::GetBucketData>();
if (cmd) {
cmd->Init(bucket_id,
offset,
size,
shared_memory_id,
shared_memory_offset);
}
}
CommandBuffer* command_buffer() const {
return command_buffer_;
}
Buffer get_ring_buffer() const {
return ring_buffer_;
}
void FreeRingBuffer();
bool HaveRingBuffer() const {
return ring_buffer_id_ != -1;
}
bool usable () const {
return usable_;
}
void ClearUsable() {
usable_ = false;
}
private:
// Waits until get changes, updating the value of get_.
void WaitForGetChange();
// Returns the number of available entries (they may not be contiguous).
int32 AvailableEntries() {
return (get_offset() - put_ - 1 + total_entry_count_) % total_entry_count_;
}
bool AllocateRingBuffer();
void FreeResources();
CommandBuffer* command_buffer_;
int32 ring_buffer_id_;
int32 ring_buffer_size_;
Buffer ring_buffer_;
CommandBufferEntry* entries_;
int32 total_entry_count_; // the total number of entries
int32 token_;
int32 put_;
int32 last_put_sent_;
int commands_issued_;
bool usable_;
bool context_lost_;
bool flush_automatically_;
// Using C runtime instead of base because this file cannot depend on base.
clock_t last_flush_time_;
friend class CommandBufferHelperTest;
DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper);
};
} // namespace gpu
#endif // GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_