Home | History | Annotate | Download | only in client
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // This file contains the command buffer helper class.
      6 
      7 #ifndef GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
      8 #define GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
      9 
     10 #include <string.h>
     11 #include <time.h>
     12 
     13 #include "gpu/command_buffer/common/cmd_buffer_common.h"
     14 #include "gpu/command_buffer/common/command_buffer.h"
     15 #include "gpu/command_buffer/common/constants.h"
     16 #include "gpu/gpu_export.h"
     17 
     18 namespace gpu {
     19 
     20 // Command buffer helper class. This class simplifies ring buffer management:
     21 // it will allocate the buffer, give it to the buffer interface, and let the
     22 // user add commands to it, while taking care of the synchronization (put and
     23 // get). It also provides a way to ensure commands have been executed, through
     24 // the token mechanism:
     25 //
     26 // helper.AddCommand(...);
     27 // helper.AddCommand(...);
     28 // int32 token = helper.InsertToken();
     29 // helper.AddCommand(...);
     30 // helper.AddCommand(...);
     31 // [...]
     32 //
     33 // helper.WaitForToken(token);  // this doesn't return until the first two
     34 //                              // commands have been executed.
     35 class GPU_EXPORT CommandBufferHelper {
     36  public:
     37   explicit CommandBufferHelper(CommandBuffer* command_buffer);
     38   virtual ~CommandBufferHelper();
     39 
     40   // Initializes the CommandBufferHelper.
     41   // Parameters:
     42   //   ring_buffer_size: The size of the ring buffer portion of the command
     43   //       buffer.
     44   bool Initialize(int32 ring_buffer_size);
     45 
     46   // Sets whether the command buffer should automatically flush periodically
     47   // to try to increase performance. Defaults to true.
     48   void SetAutomaticFlushes(bool enabled);
     49 
     50   // True if the context is lost.
     51   bool IsContextLost();
     52 
     53   // Asynchronously flushes the commands, setting the put pointer to let the
     54   // buffer interface know that new commands have been added. After a flush
     55   // returns, the command buffer service is aware of all pending commands.
     56   void Flush();
     57 
     58   // Flushes the commands, setting the put pointer to let the buffer interface
     59   // know that new commands have been added. After a flush returns, the command
     60   // buffer service is aware of all pending commands and it is guaranteed to
     61   // have made some progress in processing them. Returns whether the flush was
     62   // successful. The flush will fail if the command buffer service has
     63   // disconnected.
     64   bool FlushSync();
     65 
     66   // Waits until all the commands have been executed. Returns whether it
     67   // was successful. The function will fail if the command buffer service has
     68   // disconnected.
     69   bool Finish();
     70 
     71   // Waits until a given number of available entries are available.
     72   // Parameters:
     73   //   count: number of entries needed. This value must be at most
     74   //     the size of the buffer minus one.
     75   void WaitForAvailableEntries(int32 count);
     76 
     77   // Inserts a new token into the command buffer. This token either has a value
     78   // different from previously inserted tokens, or ensures that previously
     79   // inserted tokens with that value have already passed through the command
     80   // stream.
     81   // Returns:
     82   //   the value of the new token or -1 if the command buffer reader has
     83   //   shutdown.
     84   int32 InsertToken();
     85 
     86   // Waits until the token of a particular value has passed through the command
     87   // stream (i.e. commands inserted before that token have been executed).
     88   // NOTE: This will call Flush if it needs to block.
     89   // Parameters:
     90   //   the value of the token to wait for.
     91   void WaitForToken(int32 token);
     92 
     93   // Called prior to each command being issued. Waits for a certain amount of
     94   // space to be available. Returns address of space.
     95   CommandBufferEntry* GetSpace(uint32 entries);
     96 
     97   // Typed version of GetSpace. Gets enough room for the given type and returns
     98   // a reference to it.
     99   template <typename T>
    100   T* GetCmdSpace() {
    101     COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
    102     uint32 space_needed = ComputeNumEntries(sizeof(T));
    103     void* data = GetSpace(space_needed);
    104     return reinterpret_cast<T*>(data);
    105   }
    106 
    107   // Typed version of GetSpace for immediate commands.
    108   template <typename T>
    109   T* GetImmediateCmdSpace(size_t data_space) {
    110     COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
    111     uint32 space_needed = ComputeNumEntries(sizeof(T) + data_space);
    112     void* data = GetSpace(space_needed);
    113     return reinterpret_cast<T*>(data);
    114   }
    115 
    116   // Typed version of GetSpace for immediate commands.
    117   template <typename T>
    118   T* GetImmediateCmdSpaceTotalSize(size_t total_space) {
    119     COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
    120     uint32 space_needed = ComputeNumEntries(total_space);
    121     void* data = GetSpace(space_needed);
    122     return reinterpret_cast<T*>(data);
    123   }
    124 
    125   int32 last_token_read() const {
    126     return command_buffer_->GetLastToken();
    127   }
    128 
    129   int32 get_offset() const {
    130     return command_buffer_->GetLastState().get_offset;
    131   }
    132 
    133   // Common Commands
    134   void Noop(uint32 skip_count) {
    135     cmd::Noop* cmd = GetImmediateCmdSpace<cmd::Noop>(
    136         (skip_count - 1) * sizeof(CommandBufferEntry));
    137     if (cmd) {
    138       cmd->Init(skip_count);
    139     }
    140   }
    141 
    142   void SetToken(uint32 token) {
    143     cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
    144     if (cmd) {
    145       cmd->Init(token);
    146     }
    147   }
    148 
    149   void SetBucketSize(uint32 bucket_id, uint32 size) {
    150     cmd::SetBucketSize* cmd = GetCmdSpace<cmd::SetBucketSize>();
    151     if (cmd) {
    152       cmd->Init(bucket_id, size);
    153     }
    154   }
    155 
    156   void SetBucketData(uint32 bucket_id,
    157                      uint32 offset,
    158                      uint32 size,
    159                      uint32 shared_memory_id,
    160                      uint32 shared_memory_offset) {
    161     cmd::SetBucketData* cmd = GetCmdSpace<cmd::SetBucketData>();
    162     if (cmd) {
    163       cmd->Init(bucket_id,
    164                 offset,
    165                 size,
    166                 shared_memory_id,
    167                 shared_memory_offset);
    168     }
    169   }
    170 
    171   void SetBucketDataImmediate(
    172       uint32 bucket_id, uint32 offset, const void* data, uint32 size) {
    173     cmd::SetBucketDataImmediate* cmd =
    174         GetImmediateCmdSpace<cmd::SetBucketDataImmediate>(size);
    175     if (cmd) {
    176       cmd->Init(bucket_id, offset, size);
    177       memcpy(ImmediateDataAddress(cmd), data, size);
    178     }
    179   }
    180 
    181   void GetBucketStart(uint32 bucket_id,
    182                       uint32 result_memory_id,
    183                       uint32 result_memory_offset,
    184                       uint32 data_memory_size,
    185                       uint32 data_memory_id,
    186                       uint32 data_memory_offset) {
    187     cmd::GetBucketStart* cmd = GetCmdSpace<cmd::GetBucketStart>();
    188     if (cmd) {
    189       cmd->Init(bucket_id,
    190                 result_memory_id,
    191                 result_memory_offset,
    192                 data_memory_size,
    193                 data_memory_id,
    194                 data_memory_offset);
    195     }
    196   }
    197 
    198   void GetBucketData(uint32 bucket_id,
    199                      uint32 offset,
    200                      uint32 size,
    201                      uint32 shared_memory_id,
    202                      uint32 shared_memory_offset) {
    203     cmd::GetBucketData* cmd = GetCmdSpace<cmd::GetBucketData>();
    204     if (cmd) {
    205       cmd->Init(bucket_id,
    206                 offset,
    207                 size,
    208                 shared_memory_id,
    209                 shared_memory_offset);
    210     }
    211   }
    212 
    213   CommandBuffer* command_buffer() const {
    214     return command_buffer_;
    215   }
    216 
    217   Buffer get_ring_buffer() const {
    218     return ring_buffer_;
    219   }
    220 
    221   void FreeRingBuffer();
    222 
    223   bool HaveRingBuffer() const {
    224     return ring_buffer_id_ != -1;
    225   }
    226 
    227   bool usable () const {
    228     return usable_;
    229   }
    230 
    231   void ClearUsable() {
    232     usable_ = false;
    233   }
    234 
    235  private:
    236   // Waits until get changes, updating the value of get_.
    237   void WaitForGetChange();
    238 
    239   // Returns the number of available entries (they may not be contiguous).
    240   int32 AvailableEntries() {
    241     return (get_offset() - put_ - 1 + total_entry_count_) % total_entry_count_;
    242   }
    243 
    244   bool AllocateRingBuffer();
    245   void FreeResources();
    246 
    247   CommandBuffer* command_buffer_;
    248   int32 ring_buffer_id_;
    249   int32 ring_buffer_size_;
    250   Buffer ring_buffer_;
    251   CommandBufferEntry* entries_;
    252   int32 total_entry_count_;  // the total number of entries
    253   int32 token_;
    254   int32 put_;
    255   int32 last_put_sent_;
    256   int commands_issued_;
    257   bool usable_;
    258   bool context_lost_;
    259   bool flush_automatically_;
    260 
    261   // Using C runtime instead of base because this file cannot depend on base.
    262   clock_t last_flush_time_;
    263 
    264   friend class CommandBufferHelperTest;
    265   DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper);
    266 };
    267 
    268 }  // namespace gpu
    269 
    270 #endif  // GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
    271