diff options
Diffstat (limited to 'chromium/gpu/command_buffer/client/cmd_buffer_helper.cc')
-rw-r--r-- | chromium/gpu/command_buffer/client/cmd_buffer_helper.cc | 196 |
1 files changed, 104 insertions, 92 deletions
diff --git a/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc b/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc index 11219ede664..b50527a8dce 100644 --- a/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc +++ b/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc @@ -12,30 +12,29 @@ namespace gpu { -const int kCommandsPerFlushCheck = 100; - -#if !defined(OS_ANDROID) -const double kFlushDelay = 1.0 / (5.0 * 60.0); -#endif - CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer) : command_buffer_(command_buffer), ring_buffer_id_(-1), ring_buffer_size_(0), entries_(NULL), total_entry_count_(0), + immediate_entry_count_(0), token_(0), put_(0), last_put_sent_(0), +#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK) commands_issued_(0), +#endif usable_(true), context_lost_(false), flush_automatically_(true), - last_flush_time_(0) { + last_flush_time_(0), + flush_generation_(0) { } void CommandBufferHelper::SetAutomaticFlushes(bool enabled) { flush_automatically_ = enabled; + CalcImmediateEntries(0); } bool CommandBufferHelper::IsContextLost() { @@ -45,6 +44,47 @@ bool CommandBufferHelper::IsContextLost() { return context_lost_; } +void CommandBufferHelper::CalcImmediateEntries(int waiting_count) { + DCHECK_GE(waiting_count, 0); + + // Check if usable & allocated. + if (!usable() || !HaveRingBuffer()) { + immediate_entry_count_ = 0; + return; + } + + // Get maximum safe contiguous entries. + const int32 curr_get = get_offset(); + if (curr_get > put_) { + immediate_entry_count_ = curr_get - put_ - 1; + } else { + immediate_entry_count_ = + total_entry_count_ - put_ - (curr_get == 0 ? 1 : 0); + } + + // Limit entry count to force early flushing. + if (flush_automatically_) { + int32 limit = + total_entry_count_ / + ((curr_get == last_put_sent_) ? kAutoFlushSmall : kAutoFlushBig); + + int32 pending = + (put_ + total_entry_count_ - last_put_sent_) % total_entry_count_; + + if (pending > 0 && pending >= limit) { + // Time to force flush. + immediate_entry_count_ = 0; + } else { + // Limit remaining entries, but not lower than waiting_count entries to + // prevent deadlock when command size is greater than the flush limit. + limit -= pending; + limit = limit < waiting_count ? waiting_count : limit; + immediate_entry_count_ = + immediate_entry_count_ > limit ? limit : immediate_entry_count_; + } + } +} + bool CommandBufferHelper::AllocateRingBuffer() { if (!usable()) { return false; @@ -55,7 +95,8 @@ bool CommandBufferHelper::AllocateRingBuffer() { } int32 id = -1; - Buffer buffer = command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id); + scoped_refptr<Buffer> buffer = + command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id); if (id < 0) { ClearUsable(); return false; @@ -64,20 +105,12 @@ bool CommandBufferHelper::AllocateRingBuffer() { ring_buffer_ = buffer; ring_buffer_id_ = id; command_buffer_->SetGetBuffer(id); - - // TODO(gman): Do we really need to call GetState here? We know get & put = 0 - // Also do we need to check state.num_entries? - CommandBuffer::State state = command_buffer_->GetState(); - entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr); - int32 num_ring_buffer_entries = - ring_buffer_size_ / sizeof(CommandBufferEntry); - if (num_ring_buffer_entries > state.num_entries) { - ClearUsable(); - return false; - } - - total_entry_count_ = num_ring_buffer_entries; - put_ = state.put_offset; + entries_ = static_cast<CommandBufferEntry*>(ring_buffer_->memory()); + total_entry_count_ = ring_buffer_size_ / sizeof(CommandBufferEntry); + // Call to SetGetBuffer(id) above resets get and put offsets to 0. + // No need to query it through IPC. + put_ = 0; + CalcImmediateEntries(0); return true; } @@ -85,6 +118,7 @@ void CommandBufferHelper::FreeResources() { if (HaveRingBuffer()) { command_buffer_->DestroyTransferBuffer(ring_buffer_id_); ring_buffer_id_ = -1; + CalcImmediateEntries(0); } } @@ -103,24 +137,36 @@ CommandBufferHelper::~CommandBufferHelper() { FreeResources(); } -bool CommandBufferHelper::FlushSync() { +bool CommandBufferHelper::WaitForGetOffsetInRange(int32 start, int32 end) { if (!usable()) { return false; } - last_flush_time_ = clock(); - last_put_sent_ = put_; - CommandBuffer::State state = command_buffer_->FlushSync(put_, get_offset()); - return state.error == error::kNoError; + command_buffer_->WaitForGetOffsetInRange(start, end); + return command_buffer_->GetLastError() == gpu::error::kNoError; } void CommandBufferHelper::Flush() { + // Wrap put_ before flush. + if (put_ == total_entry_count_) + put_ = 0; + if (usable() && last_put_sent_ != put_) { last_flush_time_ = clock(); last_put_sent_ = put_; command_buffer_->Flush(put_); + ++flush_generation_; + CalcImmediateEntries(0); } } +#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK) +void CommandBufferHelper::PeriodicFlushCheck() { + clock_t current_time = clock(); + if (current_time - last_flush_time_ > kPeriodicFlushDelay * CLOCKS_PER_SEC) + Flush(); +} +#endif + // Calls Flush() and then waits until the buffer is empty. Break early if the // error is set. bool CommandBufferHelper::Finish() { @@ -133,12 +179,12 @@ bool CommandBufferHelper::Finish() { return true; } DCHECK(HaveRingBuffer()); - do { - // Do not loop forever if the flush fails, meaning the command buffer reader - // has shutdown. - if (!FlushSync()) - return false; - } while (put_ != get_offset()); + Flush(); + if (!WaitForGetOffsetInRange(put_, put_)) + return false; + DCHECK_EQ(get_offset(), put_); + + CalcImmediateEntries(0); return true; } @@ -179,16 +225,10 @@ void CommandBufferHelper::WaitForToken(int32 token) { if (token < 0) return; if (token > token_) return; // we wrapped - while (last_token_read() < token) { - if (get_offset() == put_) { - LOG(FATAL) << "Empty command buffer while waiting on a token."; - return; - } - // Do not loop forever if the flush fails, meaning the command buffer reader - // has shutdown. - if (!FlushSync()) - return; - } + if (last_token_read() >= token) + return; + Flush(); + command_buffer_->WaitForTokenInRange(token, token_); } // Waits for available entries, basically waiting until get >= put + count + 1. @@ -209,14 +249,15 @@ void CommandBufferHelper::WaitForAvailableEntries(int32 count) { // but we need to make sure get wraps first, actually that get is 1 or // more (since put will wrap to 0 after we add the noops). DCHECK_LE(1, put_); - if (get_offset() > put_ || get_offset() == 0) { + int32 curr_get = get_offset(); + if (curr_get > put_ || curr_get == 0) { TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries"); - while (get_offset() > put_ || get_offset() == 0) { - // Do not loop forever if the flush fails, meaning the command buffer - // reader has shutdown. - if (!FlushSync()) - return; - } + Flush(); + if (!WaitForGetOffsetInRange(1, put_)) + return; + curr_get = get_offset(); + DCHECK_LE(curr_get, put_); + DCHECK_NE(0, curr_get); } // Insert Noops to fill out the buffer. int32 num_entries = total_entry_count_ - put_; @@ -228,52 +269,23 @@ void CommandBufferHelper::WaitForAvailableEntries(int32 count) { } put_ = 0; } - if (AvailableEntries() < count) { - TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1"); - while (AvailableEntries() < count) { - // Do not loop forever if the flush fails, meaning the command buffer - // reader has shutdown. - if (!FlushSync()) + + // Try to get 'count' entries without flushing. + CalcImmediateEntries(count); + if (immediate_entry_count_ < count) { + // Try again with a shallow Flush(). + Flush(); + CalcImmediateEntries(count); + if (immediate_entry_count_ < count) { + // Buffer is full. Need to wait for entries. + TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1"); + if (!WaitForGetOffsetInRange(put_ + count + 1, put_)) return; + CalcImmediateEntries(count); + DCHECK_GE(immediate_entry_count_, count); } } - // Force a flush if the buffer is getting half full, or even earlier if the - // reader is known to be idle. - int32 pending = - (put_ + total_entry_count_ - last_put_sent_) % total_entry_count_; - int32 limit = total_entry_count_ / - ((get_offset() == last_put_sent_) ? 16 : 2); - if (pending > limit) { - Flush(); - } else if (flush_automatically_ && - (commands_issued_ % kCommandsPerFlushCheck == 0)) { -#if !defined(OS_ANDROID) - // Allow this command buffer to be pre-empted by another if a "reasonable" - // amount of work has been done. On highend machines, this reduces the - // latency of GPU commands. However, on Android, this can cause the - // kernel to thrash between generating GPU commands and executing them. - clock_t current_time = clock(); - if (current_time - last_flush_time_ > kFlushDelay * CLOCKS_PER_SEC) - Flush(); -#endif - } } -CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) { - AllocateRingBuffer(); - if (!usable()) { - return NULL; - } - DCHECK(HaveRingBuffer()); - ++commands_issued_; - WaitForAvailableEntries(entries); - CommandBufferEntry* space = &entries_[put_]; - put_ += entries; - DCHECK_LE(put_, total_entry_count_); - if (put_ == total_entry_count_) { - put_ = 0; - } - return space; -} } // namespace gpu |