1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275

gpu / command_buffer / service / query_manager.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_
#define GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "base/atomicops.h"
#include "base/containers/circular_deque.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "gpu/command_buffer/common/buffer.h"
#include "gpu/command_buffer/common/common_cmd_format.h"
#include "gpu/command_buffer/common/gl2_types.h"
#include "gpu/gpu_gles2_export.h"

namespace gpu {

// This class keeps track of the queries and their state
// As Queries are not shared there is one QueryManager per context.
class GPU_GLES2_EXPORT QueryManager {
 public:
  class GPU_GLES2_EXPORT Query : public base::RefCounted<Query> {
   public:
    Query(QueryManager* manager,
          GLenum target,
          scoped_refptr<gpu::Buffer> buffer,
          QuerySync* sync);

    GLenum target() const {
      return target_;
    }

    bool IsDeleted() const {
      return deleted_;
    }

    bool IsValid() const {
      return target() && !IsDeleted();
    }

    bool IsActive() const {
      return query_state_ == kQueryState_Active;
    }

    bool IsPaused() const {
      return query_state_ == kQueryState_Paused;
    }

    bool IsPending() const {
      return query_state_ == kQueryState_Pending;
    }

    bool IsFinished() const {
      return query_state_ == kQueryState_Finished;
    }

    const QuerySync* sync() const { return sync_; }

    virtual void Begin() = 0;

    virtual void End(base::subtle::Atomic32 submit_count) = 0;

    virtual void QueryCounter(base::subtle::Atomic32 submit_count) = 0;

    virtual void Process(bool did_finish) = 0;

    // Pauses active query to be resumed later.
    virtual void Pause() = 0;

    // Resume from a paused active query.
    virtual void Resume() = 0;

    virtual void Destroy(bool have_context) = 0;

    virtual void BeginProcessingCommands() {}
    virtual void EndProcessingCommands() {}

    void AddCallback(base::OnceClosure callback);

   protected:
    virtual ~Query();

    QueryManager* manager() const {
      return manager_;
    }

    void MarkAsDeleted() {
      deleted_ = true;
    }

    void MarkAsActive() {
      DCHECK(query_state_ == kQueryState_Initialize ||
             query_state_ == kQueryState_Paused ||
             query_state_ == kQueryState_Finished);
      query_state_ = kQueryState_Active;
    }

    void MarkAsPaused() {
      DCHECK(query_state_ == kQueryState_Active);
      query_state_ = kQueryState_Paused;
    }

    void MarkAsPending(base::subtle::Atomic32 submit_count) {
      DCHECK(query_state_ == kQueryState_Active);
      query_state_ = kQueryState_Pending;
      submit_count_ = submit_count;
    }

    void MarkAsCompleted(uint64_t result);

    void UnmarkAsPending() {
      DCHECK(query_state_ == kQueryState_Pending);
      query_state_ = kQueryState_Finished;
    }

    void AddToPendingQueue(base::subtle::Atomic32 submit_count) {
      manager_->AddPendingQuery(this, submit_count);
    }

    void BeginQueryHelper(GLenum target, GLuint id) {
      manager_->BeginQueryHelper(target, id);
    }

    void EndQueryHelper(GLenum target) {
      manager_->EndQueryHelper(target);
    }

    base::subtle::Atomic32 submit_count() const { return submit_count_; }

   private:
    friend class QueryManager;
    friend class QueryManagerTest;
    friend class base::RefCounted<Query>;

    void RunCallbacks();

    // The manager that owns this Query.
    raw_ptr<QueryManager> manager_;

    // The type of query.
    GLenum target_;

    // The shared memory used with this Query. We keep a reference to the Buffer
    // to ensure it doesn't get released until we wrote results. sync_ points to
    // memory inside buffer_.
    scoped_refptr<gpu::Buffer> buffer_;
    raw_ptr<QuerySync> sync_;

    // Count to set process count do when completed.
    base::subtle::Atomic32 submit_count_;

    // Current state of the query.
    enum QueryState {
      kQueryState_Initialize, // Has not been queried yet.
      kQueryState_Active, // Query began but has not ended.
      kQueryState_Paused, // Query was active but is now paused.
      kQueryState_Pending, // Query ended, waiting for result.
      kQueryState_Finished, // Query received result.
    } query_state_;

    // True if deleted.
    bool deleted_;

    // List of callbacks to run when result is available.
    std::vector<base::OnceClosure> callbacks_;
  };

  QueryManager();

  QueryManager(const QueryManager&) = delete;
  QueryManager& operator=(const QueryManager&) = delete;

  virtual ~QueryManager();

  // Must call before destruction.
  void Destroy(bool have_context);

  // Creates a Query for the given query.
  virtual Query* CreateQuery(GLenum target,
                             GLuint client_id,
                             scoped_refptr<gpu::Buffer> buffer,
                             QuerySync* sync);

  // Gets the query info for the given query.
  Query* GetQuery(GLuint client_id);

  // Gets the currently active query for a target.
  Query* GetActiveQuery(GLenum target);

  // Removes a query info for the given query.
  void RemoveQuery(GLuint client_id);

  // Removes a query info for all pending queries.
  void RemoveAllQueries();

  // Returns false if any query is pointing to invalid shared memory.
  void BeginQuery(Query* query);

  // Returns false if any query is pointing to invalid shared memory.
  void EndQuery(Query* query, base::subtle::Atomic32 submit_count);

  // Returns false if any query is pointing to invalid shared memory.
  void QueryCounter(Query* query, base::subtle::Atomic32 submit_count);

  void PauseQueries();
  void ResumeQueries();

  void BeginProcessingCommands();
  void EndProcessingCommands();

  // Processes pending queries. Returns false if any queries are pointing
  // to invalid shared memory. |did_finish| is true if this is called as
  // a result of calling glFinish().
  void ProcessPendingQueries(bool did_finish);

  // True if there are pending queries.
  bool HavePendingQueries();

  void GenQueries(GLsizei n, const GLuint* queries);
  bool IsValidQuery(GLuint id);

 protected:
  void StartTracking(Query* query);
  void StopTracking(Query* query);

  // Wrappers for BeginQueryARB and EndQueryARB to hide differences between
  // ARB_occlusion_query2 and EXT_occlusion_query_boolean.
  void BeginQueryHelper(GLenum target, GLuint id);
  void EndQueryHelper(GLenum target);

  // Adds to queue of queries waiting for completion.
  // Returns false if any query is pointing to invalid shared memory.
  void AddPendingQuery(Query* query, base::subtle::Atomic32 submit_count);

  // Removes a query from the queue of pending queries.
  // Returns false if any query is pointing to invalid shared memory.
  void RemovePendingQuery(Query* query);

  // Returns a target used for the underlying GL extension
  // used to emulate a query.
  virtual GLenum AdjustTargetForEmulation(GLenum target);

  // Counts the number of Queries allocated with 'this' as their manager.
  // Allows checking no Query will outlive this.
  unsigned query_count_;

  // Info for each query in the system.
  using QueryMap = std::unordered_map<GLuint, scoped_refptr<Query>>;
  QueryMap queries_;

  using GeneratedQueryIds = std::unordered_set<GLuint>;
  GeneratedQueryIds generated_query_ids_;

  // A map of targets -> Query for current active queries.
  using ActiveQueryMap = std::map<GLenum, scoped_refptr<Query>>;
  ActiveQueryMap active_queries_;

  // Queries waiting for completion.
  using QueryQueue = base::circular_deque<scoped_refptr<Query>>;
  QueryQueue pending_queries_;
};

}  // namespace gpu

#endif  // GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_