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