cmd_buffer_helper.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file contains the implementation of the command buffer helper class.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/client/cmd_buffer_helper.h"
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/logging.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/common/command_buffer.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/common/trace_event.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gpu {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : command_buffer_(command_buffer),
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ring_buffer_id_(-1),
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ring_buffer_size_(0),
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries_(NULL),
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      total_entry_count_(0),
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      immediate_entry_count_(0),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token_(0),
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      put_(0),
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_put_sent_(0),
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      commands_issued_(0),
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usable_(true),
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context_lost_(false),
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flush_automatically_(true),
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      last_flush_time_(0),
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      flush_generation_(0) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::SetAutomaticFlushes(bool enabled) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  flush_automatically_ = enabled;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalcImmediateEntries(0);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::IsContextLost() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context_lost_) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_lost_ = error::IsError(command_buffer()->GetLastError());
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return context_lost_;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CommandBufferHelper::CalcImmediateEntries(int waiting_count) {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_GE(waiting_count, 0);
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check if usable & allocated.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!usable() || !HaveRingBuffer()) {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    immediate_entry_count_ = 0;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get maximum safe contiguous entries.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int32 curr_get = get_offset();
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (curr_get > put_) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    immediate_entry_count_ = curr_get - put_ - 1;
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    immediate_entry_count_ =
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        total_entry_count_ - put_ - (curr_get == 0 ? 1 : 0);
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Limit entry count to force early flushing.
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flush_automatically_) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32 limit =
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        total_entry_count_ /
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ((curr_get == last_put_sent_) ? kAutoFlushSmall : kAutoFlushBig);
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32 pending =
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (put_ + total_entry_count_ - last_put_sent_) % total_entry_count_;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (pending > 0 && pending >= limit) {
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Time to force flush.
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      immediate_entry_count_ = 0;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Limit remaining entries, but not lower than waiting_count entries to
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // prevent deadlock when command size is greater than the flush limit.
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      limit -= pending;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      limit = limit < waiting_count ? waiting_count : limit;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      immediate_entry_count_ =
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          immediate_entry_count_ > limit ? limit : immediate_entry_count_;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::AllocateRingBuffer() {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HaveRingBuffer()) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32 id = -1;
98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_refptr<Buffer> buffer =
99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id < 0) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUsable();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ring_buffer_ = buffer;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ring_buffer_id_ = id;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_buffer_->SetGetBuffer(id);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(gman): Do we really need to call GetState here? We know get & put = 0
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Also do we need to check state.num_entries?
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer::State state = command_buffer_->GetState();
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  entries_ = static_cast<CommandBufferEntry*>(ring_buffer_->memory());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 num_ring_buffer_entries =
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ring_buffer_size_ / sizeof(CommandBufferEntry);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (num_ring_buffer_entries > state.num_entries) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUsable();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  total_entry_count_ = num_ring_buffer_entries;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  put_ = state.put_offset;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalcImmediateEntries(0);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::FreeResources() {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HaveRingBuffer()) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_buffer_->DestroyTransferBuffer(ring_buffer_id_);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ring_buffer_id_ = -1;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CalcImmediateEntries(0);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::FreeRingBuffer() {
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CHECK((put_ == get_offset()) ||
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error::IsError(command_buffer_->GetLastState().error));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreeResources();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::Initialize(int32 ring_buffer_size) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ring_buffer_size_ = ring_buffer_size;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return AllocateRingBuffer();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferHelper::~CommandBufferHelper() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreeResources();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool CommandBufferHelper::WaitForGetOffsetInRange(int32 start, int32 end) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  command_buffer_->WaitForGetOffsetInRange(start, end);
15423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return command_buffer_->GetLastError() == gpu::error::kNoError;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::Flush() {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Wrap put_ before flush.
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (put_ == total_entry_count_)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    put_ = 0;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (usable() && last_put_sent_ != put_) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_flush_time_ = clock();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_put_sent_ = put_;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_buffer_->Flush(put_);
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ++flush_generation_;
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CalcImmediateEntries(0);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK)
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CommandBufferHelper::PeriodicFlushCheck() {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  clock_t current_time = clock();
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (current_time - last_flush_time_ > kPeriodicFlushDelay * CLOCKS_PER_SEC)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Flush();
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls Flush() and then waits until the buffer is empty. Break early if the
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error is set.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::Finish() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("gpu", "CommandBufferHelper::Finish");
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is no work just exit.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (put_ == get_offset()) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(HaveRingBuffer());
19123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  Flush();
19223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!WaitForGetOffsetInRange(put_, put_))
19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
19423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(get_offset(), put_);
19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  CalcImmediateEntries(0);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Inserts a new token into the command stream. It uses an increasing value
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// scheme so that we don't lose tokens (a token has passed if the current token
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value is higher than that token). Calls Finish() if the token value wraps,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which will be rare.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32 CommandBufferHelper::InsertToken() {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocateRingBuffer();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return token_;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(HaveRingBuffer());
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Increment token as 31-bit integer. Negative values are used to signal an
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // error.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  token_ = (token_ + 1) & 0x7FFFFFFF;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cmd) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd->Init(token_);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (token_ == 0) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TRACE_EVENT0("gpu", "CommandBufferHelper::InsertToken(wrapped)");
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we wrapped
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Finish();
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK_EQ(token_, last_token_read());
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return token_;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Waits until the current token value is greater or equal to the value passed
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in argument.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::WaitForToken(int32 token) {
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!usable() || !HaveRingBuffer()) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return immediately if corresponding InsertToken failed.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (token < 0)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (token > token_) return;  // we wrapped
23723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (last_token_read() > token)
23823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
23923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  Flush();
24023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  command_buffer_->WaitForTokenInRange(token, token_);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Waits for available entries, basically waiting until get >= put + count + 1.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It actually waits for contiguous entries, so it may need to wrap the buffer
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// around, adding a noops. Thus this function may change the value of put_. The
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function will return early if an error occurs, in which case the available
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// space may not be available.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocateRingBuffer();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(HaveRingBuffer());
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(count < total_entry_count_);
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (put_ + count > total_entry_count_) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There's not enough room between the current put and the end of the
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // buffer, so we need to wrap. We will add noops all the way to the end,
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // but we need to make sure get wraps first, actually that get is 1 or
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // more (since put will wrap to 0 after we add the noops).
260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK_LE(1, put_);
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32 curr_get = get_offset();
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (curr_get > put_ || curr_get == 0) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries");
26423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      Flush();
26523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (!WaitForGetOffsetInRange(1, put_))
26623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        return;
26723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      curr_get = get_offset();
26823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      DCHECK_LE(curr_get, put_);
26923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      DCHECK_NE(0, curr_get);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Insert Noops to fill out the buffer.
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int32 num_entries = total_entry_count_ - put_;
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (num_entries > 0) {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int32 num_to_skip = std::min(CommandHeader::kMaxSize, num_entries);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cmd::Noop::Set(&entries_[put_], num_to_skip);
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      put_ += num_to_skip;
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_entries -= num_to_skip;
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    put_ = 0;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try to get 'count' entries without flushing.
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalcImmediateEntries(count);
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (immediate_entry_count_ < count) {
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Try again with a shallow Flush().
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Flush();
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CalcImmediateEntries(count);
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (immediate_entry_count_ < count) {
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Buffer is full.  Need to wait for entries.
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1");
29123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (!WaitForGetOffsetInRange(put_ + count + 1, put_))
29223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        return;
29323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      CalcImmediateEntries(count);
29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      DCHECK_GE(immediate_entry_count_, count);
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gpu
301