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