cmd_buffer_helper.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../client/cmd_buffer_helper.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../common/command_buffer.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../common/trace_event.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gpu {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCommandsPerFlushCheck = 100;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kFlushDelay = 1.0 / (5.0 * 60.0);
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : command_buffer_(command_buffer),
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ring_buffer_id_(-1),
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ring_buffer_size_(0),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries_(NULL),
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      total_entry_count_(0),
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usable_entry_count_(0),
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token_(0),
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      put_(0),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_put_sent_(0),
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      commands_issued_(0),
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usable_(true),
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context_lost_(false),
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flush_automatically_(true),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_flush_time_(0) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::SetAutomaticFlushes(bool enabled) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  flush_automatically_ = enabled;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::IsContextLost() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context_lost_) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_lost_ = error::IsError(command_buffer()->GetLastError());
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return context_lost_;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::AllocateRingBuffer() {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HaveRingBuffer()) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 id = command_buffer_->CreateTransferBuffer(ring_buffer_size_, -1);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id < 0) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUsable();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ring_buffer_ = command_buffer_->GetTransferBuffer(id);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ring_buffer_.ptr) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUsable();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ring_buffer_id_ = id;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_buffer_->SetGetBuffer(id);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(gman): Do we really need to call GetState here? We know get & put = 0
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Also do we need to check state.num_entries?
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer::State state = command_buffer_->GetState();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 num_ring_buffer_entries =
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ring_buffer_size_ / sizeof(CommandBufferEntry);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (num_ring_buffer_entries > state.num_entries) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearUsable();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int32 kJumpEntries =
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizeof(cmd::Jump) / sizeof(*entries_);  // NOLINT
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  total_entry_count_ = num_ring_buffer_entries;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usable_entry_count_ = total_entry_count_ - kJumpEntries;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  put_ = state.put_offset;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::FreeResources() {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HaveRingBuffer()) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_buffer_->DestroyTransferBuffer(ring_buffer_id_);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ring_buffer_id_ = -1;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::FreeRingBuffer() {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_CHECK_EQ(put_, get_offset());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreeResources();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::Initialize(int32 ring_buffer_size) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ring_buffer_size_ = ring_buffer_size;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return AllocateRingBuffer();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferHelper::~CommandBufferHelper() {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreeResources();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::FlushSync() {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_flush_time_ = clock();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_put_sent_ = put_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer::State state = command_buffer_->FlushSync(put_, get_offset());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state.error == error::kNoError;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::Flush() {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (usable()) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_flush_time_ = clock();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_put_sent_ = put_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_buffer_->Flush(put_);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls Flush() and then waits until the buffer is empty. Break early if the
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error is set.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandBufferHelper::Finish() {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("gpu", "CommandBufferHelper::Finish");
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is no work just exit.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (put_ == get_offset()) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK(HaveRingBuffer());
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Do not loop forever if the flush fails, meaning the command buffer reader
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has shutdown.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!FlushSync())
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (put_ != get_offset());
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Inserts a new token into the command stream. It uses an increasing value
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// scheme so that we don't lose tokens (a token has passed if the current token
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value is higher than that token). Calls Finish() if the token value wraps,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which will be rare.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32 CommandBufferHelper::InsertToken() {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocateRingBuffer();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return token_;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK(HaveRingBuffer());
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Increment token as 31-bit integer. Negative values are used to signal an
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // error.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  token_ = (token_ + 1) & 0x7FFFFFFF;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cmd) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd->Init(token_);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (token_ == 0) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TRACE_EVENT0("gpu", "CommandBufferHelper::InsertToken(wrapped)");
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we wrapped
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Finish();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GPU_DCHECK_EQ(token_, last_token_read());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return token_;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Waits until the current token value is greater or equal to the value passed
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in argument.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::WaitForToken(int32 token) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT_IF_LONGER_THAN0(50, "gpu", "CommandBufferHelper::WaitForToken");
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK(HaveRingBuffer());
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return immediately if corresponding InsertToken failed.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (token < 0)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (token > token_) return;  // we wrapped
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (last_token_read() < token) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (get_offset() == put_) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GPU_LOG(FATAL) << "Empty command buffer while waiting on a token.";
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Do not loop forever if the flush fails, meaning the command buffer reader
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has shutdown.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!FlushSync())
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Waits for available entries, basically waiting until get >= put + count + 1.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It actually waits for contiguous entries, so it may need to wrap the buffer
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// around, adding a jump. Thus this function may change the value of put_. The
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function will return early if an error occurs, in which case the available
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// space may not be available.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocateRingBuffer();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK(HaveRingBuffer());
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK(count < usable_entry_count_);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (put_ + count > usable_entry_count_) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There's not enough room between the current put and the end of the
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // buffer, so we need to wrap. We will add a jump back to the start, but we
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // need to make sure get wraps first, actually that get is 1 or more (since
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // put will wrap to 0 after we add the jump).
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GPU_DCHECK_LE(1, put_);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (get_offset() > put_ || get_offset() == 0) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries");
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (get_offset() > put_ || get_offset() == 0) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Do not loop forever if the flush fails, meaning the command buffer
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // reader has shutdown.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!FlushSync())
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Insert a jump back to the beginning.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::Jump::Set(&entries_[put_], 0);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    put_ = 0;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AvailableEntries() < count) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1");
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (AvailableEntries() < count) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Do not loop forever if the flush fails, meaning the command buffer
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // reader has shutdown.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!FlushSync())
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force a flush if the buffer is getting half full, or even earlier if the
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reader is known to be idle.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 pending =
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (put_ + usable_entry_count_ - last_put_sent_) % usable_entry_count_;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 limit = usable_entry_count_ /
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((get_offset() == last_put_sent_) ? 16 : 2);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending > limit) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Flush();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (flush_automatically_ &&
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (commands_issued_ % kCommandsPerFlushCheck == 0)) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Allow this command buffer to be pre-empted by another if a "reasonable"
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // amount of work has been done. On highend machines, this reduces the
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // latency of GPU commands. However, on Android, this can cause the
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // kernel to thrash between generating GPU commands and executing them.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clock_t current_time = clock();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_time - last_flush_time_ > kFlushDelay * CLOCKS_PER_SEC)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Flush();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocateRingBuffer();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usable()) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK(HaveRingBuffer());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++commands_issued_;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitForAvailableEntries(entries);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBufferEntry* space = &entries_[put_];
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  put_ += entries;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GPU_DCHECK_LE(put_, usable_entry_count_);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (put_ == usable_entry_count_) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::Jump::Set(&entries_[put_], 0);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    put_ = 0;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return space;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)error::Error CommandBufferHelper::GetError() {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer::State state = command_buffer_->GetState();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<error::Error>(state.error);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gpu
287