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 command buffer helper class.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/time/time.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/common/cmd_buffer_common.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/common/command_buffer.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/common/constants.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/gpu_export.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gpu {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if !defined(OS_ANDROID)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define CMD_HELPER_PERIODIC_FLUSH_CHECK
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kCommandsPerFlushCheck = 100;
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kPeriodicFlushDelayInMicroseconds =
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::Time::kMicrosecondsPerSecond / (5 * 60);
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kAutoFlushSmall = 16;  // 1/16 of the buffer
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kAutoFlushBig = 2;     // 1/2 of the buffer
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Command buffer helper class. This class simplifies ring buffer management:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it will allocate the buffer, give it to the buffer interface, and let the
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// user add commands to it, while taking care of the synchronization (put and
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// get). It also provides a way to ensure commands have been executed, through
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the token mechanism:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// helper.AddCommand(...);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// helper.AddCommand(...);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// int32 token = helper.InsertToken();
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// helper.AddCommand(...);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// helper.AddCommand(...);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [...]
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// helper.WaitForToken(token);  // this doesn't return until the first two
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                              // commands have been executed.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GPU_EXPORT CommandBufferHelper {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommandBufferHelper(CommandBuffer* command_buffer);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~CommandBufferHelper();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initializes the CommandBufferHelper.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parameters:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   ring_buffer_size: The size of the ring buffer portion of the command
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //       buffer.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Initialize(int32 ring_buffer_size);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets whether the command buffer should automatically flush periodically
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to try to increase performance. Defaults to true.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetAutomaticFlushes(bool enabled);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True if the context is lost.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsContextLost();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Asynchronously flushes the commands, setting the put pointer to let the
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // buffer interface know that new commands have been added. After a flush
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returns, the command buffer service is aware of all pending commands.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Flush();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Waits until all the commands have been executed. Returns whether it
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // was successful. The function will fail if the command buffer service has
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // disconnected.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Finish();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Waits until a given number of available entries are available.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parameters:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   count: number of entries needed. This value must be at most
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     the size of the buffer minus one.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void WaitForAvailableEntries(int32 count);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inserts a new token into the command buffer. This token either has a value
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // different from previously inserted tokens, or ensures that previously
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // inserted tokens with that value have already passed through the command
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stream.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   the value of the new token or -1 if the command buffer reader has
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   shutdown.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 InsertToken();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
894ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  // Returns true if the token has passed.
904ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  // Parameters:
914ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  //   the value of the token to check whether it has passed
924ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  bool HasTokenPassed(int32 token) const {
934ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch    if (token > token_)
944ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch      return true;  // we wrapped
954ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch    return last_token_read() >= token;
964ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  }
974ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Waits until the token of a particular value has passed through the command
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stream (i.e. commands inserted before that token have been executed).
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: This will call Flush if it needs to block.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parameters:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   the value of the token to wait for.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void WaitForToken(int32 token);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called prior to each command being issued. Waits for a certain amount of
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // space to be available. Returns address of space.
107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  void* GetSpace(int32 entries) {
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Allow this command buffer to be pre-empted by another if a "reasonable"
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // amount of work has been done. On highend machines, this reduces the
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // latency of GPU commands. However, on Android, this can cause the
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // kernel to thrash between generating GPU commands and executing them.
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++commands_issued_;
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (flush_automatically_ &&
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (commands_issued_ % kCommandsPerFlushCheck == 0)) {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PeriodicFlushCheck();
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Test for immediate entries.
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (entries > immediate_entry_count_) {
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WaitForAvailableEntries(entries);
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (entries > immediate_entry_count_)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return NULL;
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_LE(entries, immediate_entry_count_);
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Allocate space and advance put_.
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CommandBufferEntry* space = &entries_[put_];
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    put_ += entries;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    immediate_entry_count_ -= entries;
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_LE(put_, total_entry_count_);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return space;
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  template <typename T>
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void ForceNullCheck(T* data) {
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // 64-bit MSVC's alias analysis was determining that the command buffer
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // entry couldn't be NULL, so it optimized out the NULL check.
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Dereferencing the same datatype through a volatile pointer seems to
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // prevent that from happening. http://crbug.com/361936
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (data)
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      static_cast<volatile T*>(data)->header;
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#endif
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Typed version of GetSpace. Gets enough room for the given type and returns
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a reference to it.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <typename T>
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* GetCmdSpace() {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32 space_needed = ComputeNumEntries(sizeof(T));
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    T* data = static_cast<T*>(GetSpace(space_needed));
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ForceNullCheck(data);
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return data;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Typed version of GetSpace for immediate commands.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <typename T>
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* GetImmediateCmdSpace(size_t data_space) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32 space_needed = ComputeNumEntries(sizeof(T) + data_space);
1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    T* data = static_cast<T*>(GetSpace(space_needed));
1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ForceNullCheck(data);
1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return data;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Typed version of GetSpace for immediate commands.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <typename T>
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* GetImmediateCmdSpaceTotalSize(size_t total_space) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32 space_needed = ComputeNumEntries(total_space);
1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    T* data = static_cast<T*>(GetSpace(space_needed));
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ForceNullCheck(data);
1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return data;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 last_token_read() const {
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return command_buffer_->GetLastToken();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 get_offset() const {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return command_buffer_->GetLastState().get_offset;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Common Commands
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Noop(uint32 skip_count) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::Noop* cmd = GetImmediateCmdSpace<cmd::Noop>(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (skip_count - 1) * sizeof(CommandBufferEntry));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(skip_count);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetToken(uint32 token) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(token);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetBucketSize(uint32 bucket_id, uint32 size) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::SetBucketSize* cmd = GetCmdSpace<cmd::SetBucketSize>();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(bucket_id, size);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetBucketData(uint32 bucket_id,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 offset,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 size,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 shared_memory_id,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 shared_memory_offset) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::SetBucketData* cmd = GetCmdSpace<cmd::SetBucketData>();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(bucket_id,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                offset,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                size,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                shared_memory_id,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                shared_memory_offset);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetBucketDataImmediate(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32 bucket_id, uint32 offset, const void* data, uint32 size) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::SetBucketDataImmediate* cmd =
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetImmediateCmdSpace<cmd::SetBucketDataImmediate>(size);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(bucket_id, offset, size);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(ImmediateDataAddress(cmd), data, size);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GetBucketStart(uint32 bucket_id,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      uint32 result_memory_id,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      uint32 result_memory_offset,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      uint32 data_memory_size,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      uint32 data_memory_id,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      uint32 data_memory_offset) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::GetBucketStart* cmd = GetCmdSpace<cmd::GetBucketStart>();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(bucket_id,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result_memory_id,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result_memory_offset,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                data_memory_size,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                data_memory_id,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                data_memory_offset);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GetBucketData(uint32 bucket_id,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 offset,
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 size,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 shared_memory_id,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32 shared_memory_offset) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd::GetBucketData* cmd = GetCmdSpace<cmd::GetBucketData>();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cmd) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd->Init(bucket_id,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                offset,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                size,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                shared_memory_id,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                shared_memory_offset);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer* command_buffer() const {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return command_buffer_;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_refptr<Buffer> get_ring_buffer() const { return ring_buffer_; }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  uint32 flush_generation() const { return flush_generation_; }
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FreeRingBuffer();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HaveRingBuffer() const {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ring_buffer_id_ != -1;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool usable () const {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return usable_;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ClearUsable() {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usable_ = false;
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CalcImmediateEntries(0);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the number of available entries (they may not be contiguous).
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 AvailableEntries() {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (get_offset() - put_ - 1 + total_entry_count_) % total_entry_count_;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CalcImmediateEntries(int waiting_count);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool AllocateRingBuffer();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FreeResources();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Waits for the get offset to be in a specific range, inclusive. Returns
30323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // false if there was an error.
30423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  bool WaitForGetOffsetInRange(int32 start, int32 end);
30523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK)
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Calls Flush if automatic flush conditions are met.
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void PeriodicFlushCheck();
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer* command_buffer_;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 ring_buffer_id_;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 ring_buffer_size_;
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_refptr<gpu::Buffer> ring_buffer_;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBufferEntry* entries_;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 total_entry_count_;  // the total number of entries
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32 immediate_entry_count_;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 token_;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 put_;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 last_put_sent_;
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int commands_issued_;
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool usable_;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool context_lost_;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool flush_automatically_;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeTicks last_flush_time_;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Incremented every time the helper flushes the command buffer.
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Can be used to track when prior commands have been flushed.
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  uint32 flush_generation_;
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class CommandBufferHelperTest;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gpu
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
343