// Copyright (c) 2009 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 #include "../common/logging.h" #include "../common/constants.h" #include "../common/cmd_buffer_common.h" #include "../common/command_buffer.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 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); // 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); // 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 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(data); } // Typed version of GetSpace for immediate commands. template 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(data); } // Typed version of GetSpace for immediate commands. template 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(data); } int32 last_token_read() const { return last_token_read_; } error::Error GetError(); // Common Commands void Noop(uint32 skip_count) { cmd::Noop& cmd = GetImmediateCmdSpace( skip_count * sizeof(CommandBufferEntry)); cmd.Init(skip_count); } void SetToken(uint32 token) { cmd::SetToken& cmd = GetCmdSpace(); cmd.Init(token); } void Jump(uint32 offset) { cmd::Jump& cmd = GetCmdSpace(); cmd.Init(offset); } void JumpRelative(int32 offset) { cmd::JumpRelative& cmd = GetCmdSpace(); cmd.Init(offset); } void Call(uint32 offset) { cmd::Call& cmd = GetCmdSpace(); cmd.Init(offset); } void CallRelative(int32 offset) { cmd::CallRelative& cmd = GetCmdSpace(); cmd.Init(offset); } void Return() { cmd::Return& cmd = GetCmdSpace(); cmd.Init(); } void SetBucketSize(uint32 bucket_id, uint32 size) { cmd::SetBucketSize& cmd = GetCmdSpace(); 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.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(size); cmd.Init(bucket_id, offset, size); memcpy(ImmediateDataAddress(&cmd), data, size); } void GetBucketSize(uint32 bucket_id, uint32 shared_memory_id, uint32 shared_memory_offset) { cmd::GetBucketSize& cmd = GetCmdSpace(); cmd.Init(bucket_id, shared_memory_id, shared_memory_offset); } void GetBucketData(uint32 bucket_id, uint32 offset, uint32 size, uint32 shared_memory_id, uint32 shared_memory_offset) { cmd::GetBucketData& cmd = GetCmdSpace(); cmd.Init(bucket_id, offset, size, shared_memory_id, shared_memory_offset); } CommandBuffer* command_buffer() const { return command_buffer_; } 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 + usable_entry_count_) % usable_entry_count_; } // Synchronize with current service state. void SynchronizeState(CommandBuffer::State state); CommandBuffer* command_buffer_; Buffer ring_buffer_; CommandBufferEntry *entries_; int32 total_entry_count_; // the total number of entries int32 usable_entry_count_; // the usable number (ie, minus space for jump) int32 token_; int32 last_token_read_; int32 get_; int32 put_; friend class CommandBufferHelperTest; DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper); }; } // namespace gpu #endif // GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_