| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This file contains the implementation of the command buffer helper class. | 5 // This file contains the implementation of the command buffer helper class. |
| 6 | 6 |
| 7 #include "gpu/command_buffer/client/cmd_buffer_helper.h" | 7 #include "gpu/command_buffer/client/cmd_buffer_helper.h" |
| 8 | 8 |
| 9 #include <stdint.h> |
| 10 |
| 9 #include <algorithm> | 11 #include <algorithm> |
| 10 #include "base/logging.h" | 12 #include "base/logging.h" |
| 11 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 12 #include "base/thread_task_runner_handle.h" | 14 #include "base/thread_task_runner_handle.h" |
| 13 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 14 #include "base/trace_event/memory_allocator_dump.h" | 16 #include "base/trace_event/memory_allocator_dump.h" |
| 15 #include "base/trace_event/memory_dump_manager.h" | 17 #include "base/trace_event/memory_dump_manager.h" |
| 16 #include "base/trace_event/process_memory_dump.h" | 18 #include "base/trace_event/process_memory_dump.h" |
| 17 #include "gpu/command_buffer/common/buffer.h" | 19 #include "gpu/command_buffer/common/buffer.h" |
| 18 #include "gpu/command_buffer/common/command_buffer.h" | 20 #include "gpu/command_buffer/common/command_buffer.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 void CommandBufferHelper::CalcImmediateEntries(int waiting_count) { | 64 void CommandBufferHelper::CalcImmediateEntries(int waiting_count) { |
| 63 DCHECK_GE(waiting_count, 0); | 65 DCHECK_GE(waiting_count, 0); |
| 64 | 66 |
| 65 // Check if usable & allocated. | 67 // Check if usable & allocated. |
| 66 if (!usable() || !HaveRingBuffer()) { | 68 if (!usable() || !HaveRingBuffer()) { |
| 67 immediate_entry_count_ = 0; | 69 immediate_entry_count_ = 0; |
| 68 return; | 70 return; |
| 69 } | 71 } |
| 70 | 72 |
| 71 // Get maximum safe contiguous entries. | 73 // Get maximum safe contiguous entries. |
| 72 const int32 curr_get = get_offset(); | 74 const int32_t curr_get = get_offset(); |
| 73 if (curr_get > put_) { | 75 if (curr_get > put_) { |
| 74 immediate_entry_count_ = curr_get - put_ - 1; | 76 immediate_entry_count_ = curr_get - put_ - 1; |
| 75 } else { | 77 } else { |
| 76 immediate_entry_count_ = | 78 immediate_entry_count_ = |
| 77 total_entry_count_ - put_ - (curr_get == 0 ? 1 : 0); | 79 total_entry_count_ - put_ - (curr_get == 0 ? 1 : 0); |
| 78 } | 80 } |
| 79 | 81 |
| 80 // Limit entry count to force early flushing. | 82 // Limit entry count to force early flushing. |
| 81 if (flush_automatically_) { | 83 if (flush_automatically_) { |
| 82 int32 limit = | 84 int32_t limit = |
| 83 total_entry_count_ / | 85 total_entry_count_ / |
| 84 ((curr_get == last_put_sent_) ? kAutoFlushSmall : kAutoFlushBig); | 86 ((curr_get == last_put_sent_) ? kAutoFlushSmall : kAutoFlushBig); |
| 85 | 87 |
| 86 int32 pending = | 88 int32_t pending = |
| 87 (put_ + total_entry_count_ - last_put_sent_) % total_entry_count_; | 89 (put_ + total_entry_count_ - last_put_sent_) % total_entry_count_; |
| 88 | 90 |
| 89 if (pending > 0 && pending >= limit) { | 91 if (pending > 0 && pending >= limit) { |
| 90 // Time to force flush. | 92 // Time to force flush. |
| 91 immediate_entry_count_ = 0; | 93 immediate_entry_count_ = 0; |
| 92 } else { | 94 } else { |
| 93 // Limit remaining entries, but not lower than waiting_count entries to | 95 // Limit remaining entries, but not lower than waiting_count entries to |
| 94 // prevent deadlock when command size is greater than the flush limit. | 96 // prevent deadlock when command size is greater than the flush limit. |
| 95 limit -= pending; | 97 limit -= pending; |
| 96 limit = limit < waiting_count ? waiting_count : limit; | 98 limit = limit < waiting_count ? waiting_count : limit; |
| 97 immediate_entry_count_ = | 99 immediate_entry_count_ = |
| 98 immediate_entry_count_ > limit ? limit : immediate_entry_count_; | 100 immediate_entry_count_ > limit ? limit : immediate_entry_count_; |
| 99 } | 101 } |
| 100 } | 102 } |
| 101 } | 103 } |
| 102 | 104 |
| 103 bool CommandBufferHelper::AllocateRingBuffer() { | 105 bool CommandBufferHelper::AllocateRingBuffer() { |
| 104 if (!usable()) { | 106 if (!usable()) { |
| 105 return false; | 107 return false; |
| 106 } | 108 } |
| 107 | 109 |
| 108 if (HaveRingBuffer()) { | 110 if (HaveRingBuffer()) { |
| 109 return true; | 111 return true; |
| 110 } | 112 } |
| 111 | 113 |
| 112 int32 id = -1; | 114 int32_t id = -1; |
| 113 scoped_refptr<Buffer> buffer = | 115 scoped_refptr<Buffer> buffer = |
| 114 command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id); | 116 command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id); |
| 115 if (id < 0) { | 117 if (id < 0) { |
| 116 ClearUsable(); | 118 ClearUsable(); |
| 117 DCHECK(error::IsError(command_buffer()->GetLastError())); | 119 DCHECK(error::IsError(command_buffer()->GetLastError())); |
| 118 return false; | 120 return false; |
| 119 } | 121 } |
| 120 | 122 |
| 121 ring_buffer_ = buffer; | 123 ring_buffer_ = buffer; |
| 122 ring_buffer_id_ = id; | 124 ring_buffer_id_ = id; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 139 ring_buffer_ = nullptr; | 141 ring_buffer_ = nullptr; |
| 140 } | 142 } |
| 141 } | 143 } |
| 142 | 144 |
| 143 void CommandBufferHelper::FreeRingBuffer() { | 145 void CommandBufferHelper::FreeRingBuffer() { |
| 144 CHECK((put_ == get_offset()) || | 146 CHECK((put_ == get_offset()) || |
| 145 error::IsError(command_buffer_->GetLastState().error)); | 147 error::IsError(command_buffer_->GetLastState().error)); |
| 146 FreeResources(); | 148 FreeResources(); |
| 147 } | 149 } |
| 148 | 150 |
| 149 bool CommandBufferHelper::Initialize(int32 ring_buffer_size) { | 151 bool CommandBufferHelper::Initialize(int32_t ring_buffer_size) { |
| 150 ring_buffer_size_ = ring_buffer_size; | 152 ring_buffer_size_ = ring_buffer_size; |
| 151 return AllocateRingBuffer(); | 153 return AllocateRingBuffer(); |
| 152 } | 154 } |
| 153 | 155 |
| 154 CommandBufferHelper::~CommandBufferHelper() { | 156 CommandBufferHelper::~CommandBufferHelper() { |
| 155 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | 157 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
| 156 this); | 158 this); |
| 157 FreeResources(); | 159 FreeResources(); |
| 158 } | 160 } |
| 159 | 161 |
| 160 bool CommandBufferHelper::WaitForGetOffsetInRange(int32 start, int32 end) { | 162 bool CommandBufferHelper::WaitForGetOffsetInRange(int32_t start, int32_t end) { |
| 161 DCHECK(start >= 0 && start <= total_entry_count_); | 163 DCHECK(start >= 0 && start <= total_entry_count_); |
| 162 DCHECK(end >= 0 && end <= total_entry_count_); | 164 DCHECK(end >= 0 && end <= total_entry_count_); |
| 163 if (!usable()) { | 165 if (!usable()) { |
| 164 return false; | 166 return false; |
| 165 } | 167 } |
| 166 command_buffer_->WaitForGetOffsetInRange(start, end); | 168 command_buffer_->WaitForGetOffsetInRange(start, end); |
| 167 return command_buffer_->GetLastError() == gpu::error::kNoError; | 169 return command_buffer_->GetLastError() == gpu::error::kNoError; |
| 168 } | 170 } |
| 169 | 171 |
| 170 void CommandBufferHelper::Flush() { | 172 void CommandBufferHelper::Flush() { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 | 225 |
| 224 CalcImmediateEntries(0); | 226 CalcImmediateEntries(0); |
| 225 | 227 |
| 226 return true; | 228 return true; |
| 227 } | 229 } |
| 228 | 230 |
| 229 // Inserts a new token into the command stream. It uses an increasing value | 231 // Inserts a new token into the command stream. It uses an increasing value |
| 230 // scheme so that we don't lose tokens (a token has passed if the current token | 232 // scheme so that we don't lose tokens (a token has passed if the current token |
| 231 // value is higher than that token). Calls Finish() if the token value wraps, | 233 // value is higher than that token). Calls Finish() if the token value wraps, |
| 232 // which will be rare. | 234 // which will be rare. |
| 233 int32 CommandBufferHelper::InsertToken() { | 235 int32_t CommandBufferHelper::InsertToken() { |
| 234 AllocateRingBuffer(); | 236 AllocateRingBuffer(); |
| 235 if (!usable()) { | 237 if (!usable()) { |
| 236 return token_; | 238 return token_; |
| 237 } | 239 } |
| 238 DCHECK(HaveRingBuffer()); | 240 DCHECK(HaveRingBuffer()); |
| 239 // Increment token as 31-bit integer. Negative values are used to signal an | 241 // Increment token as 31-bit integer. Negative values are used to signal an |
| 240 // error. | 242 // error. |
| 241 token_ = (token_ + 1) & 0x7FFFFFFF; | 243 token_ = (token_ + 1) & 0x7FFFFFFF; |
| 242 cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>(); | 244 cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>(); |
| 243 if (cmd) { | 245 if (cmd) { |
| 244 cmd->Init(token_); | 246 cmd->Init(token_); |
| 245 if (token_ == 0) { | 247 if (token_ == 0) { |
| 246 TRACE_EVENT0("gpu", "CommandBufferHelper::InsertToken(wrapped)"); | 248 TRACE_EVENT0("gpu", "CommandBufferHelper::InsertToken(wrapped)"); |
| 247 // we wrapped | 249 // we wrapped |
| 248 Finish(); | 250 Finish(); |
| 249 DCHECK_EQ(token_, last_token_read()); | 251 DCHECK_EQ(token_, last_token_read()); |
| 250 } | 252 } |
| 251 } | 253 } |
| 252 return token_; | 254 return token_; |
| 253 } | 255 } |
| 254 | 256 |
| 255 // Waits until the current token value is greater or equal to the value passed | 257 // Waits until the current token value is greater or equal to the value passed |
| 256 // in argument. | 258 // in argument. |
| 257 void CommandBufferHelper::WaitForToken(int32 token) { | 259 void CommandBufferHelper::WaitForToken(int32_t token) { |
| 258 if (!usable() || !HaveRingBuffer()) { | 260 if (!usable() || !HaveRingBuffer()) { |
| 259 return; | 261 return; |
| 260 } | 262 } |
| 261 // Return immediately if corresponding InsertToken failed. | 263 // Return immediately if corresponding InsertToken failed. |
| 262 if (token < 0) | 264 if (token < 0) |
| 263 return; | 265 return; |
| 264 if (token > token_) return; // we wrapped | 266 if (token > token_) return; // we wrapped |
| 265 if (last_token_read() >= token) | 267 if (last_token_read() >= token) |
| 266 return; | 268 return; |
| 267 Flush(); | 269 Flush(); |
| 268 command_buffer_->WaitForTokenInRange(token, token_); | 270 command_buffer_->WaitForTokenInRange(token, token_); |
| 269 } | 271 } |
| 270 | 272 |
| 271 // Waits for available entries, basically waiting until get >= put + count + 1. | 273 // Waits for available entries, basically waiting until get >= put + count + 1. |
| 272 // It actually waits for contiguous entries, so it may need to wrap the buffer | 274 // It actually waits for contiguous entries, so it may need to wrap the buffer |
| 273 // around, adding a noops. Thus this function may change the value of put_. The | 275 // around, adding a noops. Thus this function may change the value of put_. The |
| 274 // function will return early if an error occurs, in which case the available | 276 // function will return early if an error occurs, in which case the available |
| 275 // space may not be available. | 277 // space may not be available. |
| 276 void CommandBufferHelper::WaitForAvailableEntries(int32 count) { | 278 void CommandBufferHelper::WaitForAvailableEntries(int32_t count) { |
| 277 AllocateRingBuffer(); | 279 AllocateRingBuffer(); |
| 278 if (!usable()) { | 280 if (!usable()) { |
| 279 return; | 281 return; |
| 280 } | 282 } |
| 281 DCHECK(HaveRingBuffer()); | 283 DCHECK(HaveRingBuffer()); |
| 282 DCHECK(count < total_entry_count_); | 284 DCHECK(count < total_entry_count_); |
| 283 if (put_ + count > total_entry_count_) { | 285 if (put_ + count > total_entry_count_) { |
| 284 // There's not enough room between the current put and the end of the | 286 // There's not enough room between the current put and the end of the |
| 285 // buffer, so we need to wrap. We will add noops all the way to the end, | 287 // buffer, so we need to wrap. We will add noops all the way to the end, |
| 286 // but we need to make sure get wraps first, actually that get is 1 or | 288 // but we need to make sure get wraps first, actually that get is 1 or |
| 287 // more (since put will wrap to 0 after we add the noops). | 289 // more (since put will wrap to 0 after we add the noops). |
| 288 DCHECK_LE(1, put_); | 290 DCHECK_LE(1, put_); |
| 289 int32 curr_get = get_offset(); | 291 int32_t curr_get = get_offset(); |
| 290 if (curr_get > put_ || curr_get == 0) { | 292 if (curr_get > put_ || curr_get == 0) { |
| 291 TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries"); | 293 TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries"); |
| 292 Flush(); | 294 Flush(); |
| 293 if (!WaitForGetOffsetInRange(1, put_)) | 295 if (!WaitForGetOffsetInRange(1, put_)) |
| 294 return; | 296 return; |
| 295 curr_get = get_offset(); | 297 curr_get = get_offset(); |
| 296 DCHECK_LE(curr_get, put_); | 298 DCHECK_LE(curr_get, put_); |
| 297 DCHECK_NE(0, curr_get); | 299 DCHECK_NE(0, curr_get); |
| 298 } | 300 } |
| 299 // Insert Noops to fill out the buffer. | 301 // Insert Noops to fill out the buffer. |
| 300 int32 num_entries = total_entry_count_ - put_; | 302 int32_t num_entries = total_entry_count_ - put_; |
| 301 while (num_entries > 0) { | 303 while (num_entries > 0) { |
| 302 int32 num_to_skip = std::min(CommandHeader::kMaxSize, num_entries); | 304 int32_t num_to_skip = std::min(CommandHeader::kMaxSize, num_entries); |
| 303 cmd::Noop::Set(&entries_[put_], num_to_skip); | 305 cmd::Noop::Set(&entries_[put_], num_to_skip); |
| 304 put_ += num_to_skip; | 306 put_ += num_to_skip; |
| 305 num_entries -= num_to_skip; | 307 num_entries -= num_to_skip; |
| 306 } | 308 } |
| 307 put_ = 0; | 309 put_ = 0; |
| 308 } | 310 } |
| 309 | 311 |
| 310 // Try to get 'count' entries without flushing. | 312 // Try to get 'count' entries without flushing. |
| 311 CalcImmediateEntries(count); | 313 CalcImmediateEntries(count); |
| 312 if (immediate_entry_count_ < count) { | 314 if (immediate_entry_count_ < count) { |
| 313 // Try again with a shallow Flush(). | 315 // Try again with a shallow Flush(). |
| 314 Flush(); | 316 Flush(); |
| 315 CalcImmediateEntries(count); | 317 CalcImmediateEntries(count); |
| 316 if (immediate_entry_count_ < count) { | 318 if (immediate_entry_count_ < count) { |
| 317 // Buffer is full. Need to wait for entries. | 319 // Buffer is full. Need to wait for entries. |
| 318 TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1"); | 320 TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1"); |
| 319 if (!WaitForGetOffsetInRange((put_ + count + 1) % total_entry_count_, | 321 if (!WaitForGetOffsetInRange((put_ + count + 1) % total_entry_count_, |
| 320 put_)) | 322 put_)) |
| 321 return; | 323 return; |
| 322 CalcImmediateEntries(count); | 324 CalcImmediateEntries(count); |
| 323 DCHECK_GE(immediate_entry_count_, count); | 325 DCHECK_GE(immediate_entry_count_, count); |
| 324 } | 326 } |
| 325 } | 327 } |
| 326 } | 328 } |
| 327 | 329 |
| 328 int32 CommandBufferHelper::GetTotalFreeEntriesNoWaiting() const { | 330 int32_t CommandBufferHelper::GetTotalFreeEntriesNoWaiting() const { |
| 329 int32 current_get_offset = get_offset(); | 331 int32_t current_get_offset = get_offset(); |
| 330 if (current_get_offset > put_) { | 332 if (current_get_offset > put_) { |
| 331 return current_get_offset - put_ - 1; | 333 return current_get_offset - put_ - 1; |
| 332 } else { | 334 } else { |
| 333 return current_get_offset + total_entry_count_ - put_ - | 335 return current_get_offset + total_entry_count_ - put_ - |
| 334 (current_get_offset == 0 ? 1 : 0); | 336 (current_get_offset == 0 ? 1 : 0); |
| 335 } | 337 } |
| 336 } | 338 } |
| 337 | 339 |
| 338 bool CommandBufferHelper::OnMemoryDump( | 340 bool CommandBufferHelper::OnMemoryDump( |
| 339 const base::trace_event::MemoryDumpArgs& args, | 341 const base::trace_event::MemoryDumpArgs& args, |
| 340 base::trace_event::ProcessMemoryDump* pmd) { | 342 base::trace_event::ProcessMemoryDump* pmd) { |
| 341 if (!HaveRingBuffer()) | 343 if (!HaveRingBuffer()) |
| 342 return true; | 344 return true; |
| 343 | 345 |
| 344 const uint64 tracing_process_id = | 346 const uint64_t tracing_process_id = |
| 345 base::trace_event::MemoryDumpManager::GetInstance() | 347 base::trace_event::MemoryDumpManager::GetInstance() |
| 346 ->GetTracingProcessId(); | 348 ->GetTracingProcessId(); |
| 347 | 349 |
| 348 base::trace_event::MemoryAllocatorDump* dump = | 350 base::trace_event::MemoryAllocatorDump* dump = |
| 349 pmd->CreateAllocatorDump(base::StringPrintf( | 351 pmd->CreateAllocatorDump(base::StringPrintf( |
| 350 "gpu/command_buffer_memory/buffer_%d", ring_buffer_id_)); | 352 "gpu/command_buffer_memory/buffer_%d", ring_buffer_id_)); |
| 351 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | 353 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| 352 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 354 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 353 ring_buffer_size_); | 355 ring_buffer_size_); |
| 354 dump->AddScalar("free_size", | 356 dump->AddScalar("free_size", |
| 355 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 357 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 356 GetTotalFreeEntriesNoWaiting() * sizeof(CommandBufferEntry)); | 358 GetTotalFreeEntriesNoWaiting() * sizeof(CommandBufferEntry)); |
| 357 auto guid = GetBufferGUIDForTracing(tracing_process_id, ring_buffer_id_); | 359 auto guid = GetBufferGUIDForTracing(tracing_process_id, ring_buffer_id_); |
| 358 const int kImportance = 2; | 360 const int kImportance = 2; |
| 359 pmd->CreateSharedGlobalAllocatorDump(guid); | 361 pmd->CreateSharedGlobalAllocatorDump(guid); |
| 360 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance); | 362 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance); |
| 361 | 363 |
| 362 return true; | 364 return true; |
| 363 } | 365 } |
| 364 | 366 |
| 365 } // namespace gpu | 367 } // namespace gpu |
| OLD | NEW |