blob: 7cac568bfe4ca175b3f0ec0d2637ed0c2e1780b0 [file] [log] [blame]
/*
* Copyright 2009, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file contains the command buffer helper class.
#ifndef GPU_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
#define GPU_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
#include "gpu/command_buffer/common/logging.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/cmd_buffer_common.h"
#include "gpu/command_buffer/common/command_buffer.h"
namespace command_buffer {
// 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 CommandBufferHelper {
public:
explicit CommandBufferHelper(command_buffer::CommandBuffer* command_buffer);
virtual ~CommandBufferHelper();
bool Initialize();
// 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 Flush();
// 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);
// Adds a command data to the command buffer. This may wait until sufficient
// space is available.
// Parameters:
// entries: The command entries to add.
// count: The number of entries.
void AddCommandData(const CommandBufferEntry* entries, int32 count) {
WaitForAvailableEntries(count);
for (; count > 0; --count) {
entries_[put_++] = *entries++;
}
DCHECK_LE(put_, entry_count_);
if (put_ == entry_count_) put_ = 0;
}
// A typed version of AddCommandData.
template <typename T>
void AddTypedCmdData(const T& cmd) {
AddCommandData(reinterpret_cast<const CommandBufferEntry*>(&cmd),
ComputeNumEntries(sizeof(cmd)));
}
// Adds a command to the command buffer. This may wait until sufficient space
// is available.
// Parameters:
// command: the command index.
// arg_count: the number of arguments for the command.
// args: the arguments for the command (these are copied before the
// function returns).
void AddCommand(int32 command,
int32 arg_count,
const CommandBufferEntry *args) {
CommandHeader header;
header.size = arg_count + 1;
header.command = command;
WaitForAvailableEntries(header.size);
entries_[put_++].value_header = header;
for (int i = 0; i < arg_count; ++i) {
entries_[put_++] = args[i];
}
DCHECK_LE(put_, entry_count_);
if (put_ == entry_count_) put_ = 0;
}
// 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);
// 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);
}
parse_error::ParseError GetParseError();
// Common Commands
void Noop(uint32 skip_count) {
cmd::Noop& cmd = GetImmediateCmdSpace<cmd::Noop>(
skip_count * sizeof(CommandBufferEntry));
cmd.Init(skip_count);
}
void SetToken(uint32 token) {
cmd::SetToken& cmd = GetCmdSpace<cmd::SetToken>();
cmd.Init(token);
}
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_ - put_ - 1 + entry_count_) % entry_count_;
}
command_buffer::CommandBuffer* command_buffer_;
::base::SharedMemory* ring_buffer_;
CommandBufferEntry *entries_;
int32 entry_count_;
int32 token_;
int32 last_token_read_;
int32 get_;
int32 put_;
friend class CommandBufferHelperTest;
DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper);
};
} // namespace command_buffer
#endif // GPU_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_