1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This file contains the command buffer helper class. 6 7 #ifndef GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_ 8 #define GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_ 9 10 #include <string.h> 11 #include <time.h> 12 13 #include "gpu/command_buffer/common/cmd_buffer_common.h" 14 #include "gpu/command_buffer/common/command_buffer.h" 15 #include "gpu/command_buffer/common/constants.h" 16 #include "gpu/gpu_export.h" 17 18 namespace gpu { 19 20 // Command buffer helper class. This class simplifies ring buffer management: 21 // it will allocate the buffer, give it to the buffer interface, and let the 22 // user add commands to it, while taking care of the synchronization (put and 23 // get). It also provides a way to ensure commands have been executed, through 24 // the token mechanism: 25 // 26 // helper.AddCommand(...); 27 // helper.AddCommand(...); 28 // int32 token = helper.InsertToken(); 29 // helper.AddCommand(...); 30 // helper.AddCommand(...); 31 // [...] 32 // 33 // helper.WaitForToken(token); // this doesn't return until the first two 34 // // commands have been executed. 35 class GPU_EXPORT CommandBufferHelper { 36 public: 37 explicit CommandBufferHelper(CommandBuffer* command_buffer); 38 virtual ~CommandBufferHelper(); 39 40 // Initializes the CommandBufferHelper. 41 // Parameters: 42 // ring_buffer_size: The size of the ring buffer portion of the command 43 // buffer. 44 bool Initialize(int32 ring_buffer_size); 45 46 // Sets whether the command buffer should automatically flush periodically 47 // to try to increase performance. Defaults to true. 48 void SetAutomaticFlushes(bool enabled); 49 50 // True if the context is lost. 51 bool IsContextLost(); 52 53 // Asynchronously flushes the commands, setting the put pointer to let the 54 // buffer interface know that new commands have been added. After a flush 55 // returns, the command buffer service is aware of all pending commands. 56 void Flush(); 57 58 // Flushes the commands, setting the put pointer to let the buffer interface 59 // know that new commands have been added. After a flush returns, the command 60 // buffer service is aware of all pending commands and it is guaranteed to 61 // have made some progress in processing them. Returns whether the flush was 62 // successful. The flush will fail if the command buffer service has 63 // disconnected. 64 bool FlushSync(); 65 66 // Waits until all the commands have been executed. Returns whether it 67 // was successful. The function will fail if the command buffer service has 68 // disconnected. 69 bool Finish(); 70 71 // Waits until a given number of available entries are available. 72 // Parameters: 73 // count: number of entries needed. This value must be at most 74 // the size of the buffer minus one. 75 void WaitForAvailableEntries(int32 count); 76 77 // Inserts a new token into the command buffer. This token either has a value 78 // different from previously inserted tokens, or ensures that previously 79 // inserted tokens with that value have already passed through the command 80 // stream. 81 // Returns: 82 // the value of the new token or -1 if the command buffer reader has 83 // shutdown. 84 int32 InsertToken(); 85 86 // Waits until the token of a particular value has passed through the command 87 // stream (i.e. commands inserted before that token have been executed). 88 // NOTE: This will call Flush if it needs to block. 89 // Parameters: 90 // the value of the token to wait for. 91 void WaitForToken(int32 token); 92 93 // Called prior to each command being issued. Waits for a certain amount of 94 // space to be available. Returns address of space. 95 CommandBufferEntry* GetSpace(uint32 entries); 96 97 // Typed version of GetSpace. Gets enough room for the given type and returns 98 // a reference to it. 99 template <typename T> GetCmdSpace()100 T* GetCmdSpace() { 101 COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed); 102 uint32 space_needed = ComputeNumEntries(sizeof(T)); 103 void* data = GetSpace(space_needed); 104 return reinterpret_cast<T*>(data); 105 } 106 107 // Typed version of GetSpace for immediate commands. 108 template <typename T> GetImmediateCmdSpace(size_t data_space)109 T* GetImmediateCmdSpace(size_t data_space) { 110 COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN); 111 uint32 space_needed = ComputeNumEntries(sizeof(T) + data_space); 112 void* data = GetSpace(space_needed); 113 return reinterpret_cast<T*>(data); 114 } 115 116 // Typed version of GetSpace for immediate commands. 117 template <typename T> GetImmediateCmdSpaceTotalSize(size_t total_space)118 T* GetImmediateCmdSpaceTotalSize(size_t total_space) { 119 COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN); 120 uint32 space_needed = ComputeNumEntries(total_space); 121 void* data = GetSpace(space_needed); 122 return reinterpret_cast<T*>(data); 123 } 124 last_token_read()125 int32 last_token_read() const { 126 return command_buffer_->GetLastToken(); 127 } 128 get_offset()129 int32 get_offset() const { 130 return command_buffer_->GetLastState().get_offset; 131 } 132 133 // Common Commands Noop(uint32 skip_count)134 void Noop(uint32 skip_count) { 135 cmd::Noop* cmd = GetImmediateCmdSpace<cmd::Noop>( 136 (skip_count - 1) * sizeof(CommandBufferEntry)); 137 if (cmd) { 138 cmd->Init(skip_count); 139 } 140 } 141 SetToken(uint32 token)142 void SetToken(uint32 token) { 143 cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>(); 144 if (cmd) { 145 cmd->Init(token); 146 } 147 } 148 SetBucketSize(uint32 bucket_id,uint32 size)149 void SetBucketSize(uint32 bucket_id, uint32 size) { 150 cmd::SetBucketSize* cmd = GetCmdSpace<cmd::SetBucketSize>(); 151 if (cmd) { 152 cmd->Init(bucket_id, size); 153 } 154 } 155 SetBucketData(uint32 bucket_id,uint32 offset,uint32 size,uint32 shared_memory_id,uint32 shared_memory_offset)156 void SetBucketData(uint32 bucket_id, 157 uint32 offset, 158 uint32 size, 159 uint32 shared_memory_id, 160 uint32 shared_memory_offset) { 161 cmd::SetBucketData* cmd = GetCmdSpace<cmd::SetBucketData>(); 162 if (cmd) { 163 cmd->Init(bucket_id, 164 offset, 165 size, 166 shared_memory_id, 167 shared_memory_offset); 168 } 169 } 170 SetBucketDataImmediate(uint32 bucket_id,uint32 offset,const void * data,uint32 size)171 void SetBucketDataImmediate( 172 uint32 bucket_id, uint32 offset, const void* data, uint32 size) { 173 cmd::SetBucketDataImmediate* cmd = 174 GetImmediateCmdSpace<cmd::SetBucketDataImmediate>(size); 175 if (cmd) { 176 cmd->Init(bucket_id, offset, size); 177 memcpy(ImmediateDataAddress(cmd), data, size); 178 } 179 } 180 GetBucketStart(uint32 bucket_id,uint32 result_memory_id,uint32 result_memory_offset,uint32 data_memory_size,uint32 data_memory_id,uint32 data_memory_offset)181 void GetBucketStart(uint32 bucket_id, 182 uint32 result_memory_id, 183 uint32 result_memory_offset, 184 uint32 data_memory_size, 185 uint32 data_memory_id, 186 uint32 data_memory_offset) { 187 cmd::GetBucketStart* cmd = GetCmdSpace<cmd::GetBucketStart>(); 188 if (cmd) { 189 cmd->Init(bucket_id, 190 result_memory_id, 191 result_memory_offset, 192 data_memory_size, 193 data_memory_id, 194 data_memory_offset); 195 } 196 } 197 GetBucketData(uint32 bucket_id,uint32 offset,uint32 size,uint32 shared_memory_id,uint32 shared_memory_offset)198 void GetBucketData(uint32 bucket_id, 199 uint32 offset, 200 uint32 size, 201 uint32 shared_memory_id, 202 uint32 shared_memory_offset) { 203 cmd::GetBucketData* cmd = GetCmdSpace<cmd::GetBucketData>(); 204 if (cmd) { 205 cmd->Init(bucket_id, 206 offset, 207 size, 208 shared_memory_id, 209 shared_memory_offset); 210 } 211 } 212 command_buffer()213 CommandBuffer* command_buffer() const { 214 return command_buffer_; 215 } 216 get_ring_buffer()217 Buffer get_ring_buffer() const { 218 return ring_buffer_; 219 } 220 221 void FreeRingBuffer(); 222 HaveRingBuffer()223 bool HaveRingBuffer() const { 224 return ring_buffer_id_ != -1; 225 } 226 usable()227 bool usable () const { 228 return usable_; 229 } 230 ClearUsable()231 void ClearUsable() { 232 usable_ = false; 233 } 234 235 private: 236 // Waits until get changes, updating the value of get_. 237 void WaitForGetChange(); 238 239 // Returns the number of available entries (they may not be contiguous). AvailableEntries()240 int32 AvailableEntries() { 241 return (get_offset() - put_ - 1 + total_entry_count_) % total_entry_count_; 242 } 243 244 bool AllocateRingBuffer(); 245 void FreeResources(); 246 247 CommandBuffer* command_buffer_; 248 int32 ring_buffer_id_; 249 int32 ring_buffer_size_; 250 Buffer ring_buffer_; 251 CommandBufferEntry* entries_; 252 int32 total_entry_count_; // the total number of entries 253 int32 token_; 254 int32 put_; 255 int32 last_put_sent_; 256 int commands_issued_; 257 bool usable_; 258 bool context_lost_; 259 bool flush_automatically_; 260 261 // Using C runtime instead of base because this file cannot depend on base. 262 clock_t last_flush_time_; 263 264 friend class CommandBufferHelperTest; 265 DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper); 266 }; 267 268 } // namespace gpu 269 270 #endif // GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_ 271