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#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_
6#define GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_
7
8#include <queue>
9
10#include "base/atomic_ref_count.h"
11#include "base/atomicops.h"
12#include "base/callback.h"
13#include "base/memory/linked_ptr.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/memory/shared_memory.h"
17#include "base/memory/weak_ptr.h"
18#include "gpu/command_buffer/service/cmd_buffer_engine.h"
19#include "gpu/command_buffer/service/cmd_parser.h"
20#include "gpu/command_buffer/service/command_buffer_service.h"
21#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
22#include "gpu/gpu_export.h"
23
24namespace gfx {
25class GLFence;
26}
27
28namespace gpu {
29
30class PreemptionFlag
31    : public base::RefCountedThreadSafe<PreemptionFlag> {
32 public:
33  PreemptionFlag() : flag_(0) {}
34
35  bool IsSet() { return !base::AtomicRefCountIsZero(&flag_); }
36  void Set() { base::AtomicRefCountInc(&flag_); }
37  void Reset() { base::subtle::NoBarrier_Store(&flag_, 0); }
38
39 private:
40  base::AtomicRefCount flag_;
41
42  ~PreemptionFlag() {}
43
44  friend class base::RefCountedThreadSafe<PreemptionFlag>;
45};
46
47// This class schedules commands that have been flushed. They are received via
48// a command buffer and forwarded to a command parser. TODO(apatrick): This
49// class should not know about the decoder. Do not add additional dependencies
50// on it.
51class GPU_EXPORT GpuScheduler
52    : NON_EXPORTED_BASE(public CommandBufferEngine),
53      public base::SupportsWeakPtr<GpuScheduler> {
54 public:
55  GpuScheduler(CommandBufferServiceBase* command_buffer,
56               AsyncAPIInterface* handler,
57               gles2::GLES2Decoder* decoder);
58
59  virtual ~GpuScheduler();
60
61  void PutChanged();
62
63  void SetPreemptByFlag(scoped_refptr<PreemptionFlag> flag) {
64    preemption_flag_ = flag;
65  }
66
67  // Sets whether commands should be processed by this scheduler. Setting to
68  // false unschedules. Setting to true reschedules. Whether or not the
69  // scheduler is currently scheduled is "reference counted". Every call with
70  // false must eventually be paired by a call with true.
71  void SetScheduled(bool is_scheduled);
72
73  // Returns whether the scheduler is currently able to process more commands.
74  bool IsScheduled();
75
76  // Returns whether the scheduler needs to be polled again in the future.
77  bool HasMoreWork();
78
79  typedef base::Callback<void(bool /* scheduled */)> SchedulingChangedCallback;
80
81  // Sets a callback that is invoked just before scheduler is rescheduled
82  // or descheduled. Takes ownership of callback object.
83  void SetSchedulingChangedCallback(const SchedulingChangedCallback& callback);
84
85  // Implementation of CommandBufferEngine.
86  virtual scoped_refptr<Buffer> GetSharedMemoryBuffer(int32 shm_id) OVERRIDE;
87  virtual void set_token(int32 token) OVERRIDE;
88  virtual bool SetGetBuffer(int32 transfer_buffer_id) OVERRIDE;
89  virtual bool SetGetOffset(int32 offset) OVERRIDE;
90  virtual int32 GetGetOffset() OVERRIDE;
91
92  void SetCommandProcessedCallback(const base::Closure& callback);
93
94  void DeferToFence(base::Closure task);
95
96  // Polls the fences, invoking callbacks that were waiting to be triggered
97  // by them and returns whether all fences were complete.
98  bool PollUnscheduleFences();
99
100  bool HasMoreIdleWork();
101  void PerformIdleWork();
102
103  CommandParser* parser() const {
104    return parser_.get();
105  }
106
107  bool IsPreempted();
108
109 private:
110  // Artificially reschedule if the scheduler is still unscheduled after a
111  // timeout.
112  void RescheduleTimeOut();
113
114  // The GpuScheduler holds a weak reference to the CommandBuffer. The
115  // CommandBuffer owns the GpuScheduler and holds a strong reference to it
116  // through the ProcessCommands callback.
117  CommandBufferServiceBase* command_buffer_;
118
119  // The parser uses this to execute commands.
120  AsyncAPIInterface* handler_;
121
122  // Does not own decoder. TODO(apatrick): The GpuScheduler shouldn't need a
123  // pointer to the decoder, it is only used to initialize the CommandParser,
124  // which could be an argument to the constructor, and to determine the
125  // reason for context lost.
126  gles2::GLES2Decoder* decoder_;
127
128  // TODO(apatrick): The GpuScheduler currently creates and owns the parser.
129  // This should be an argument to the constructor.
130  scoped_ptr<CommandParser> parser_;
131
132  // Greater than zero if this is waiting to be rescheduled before continuing.
133  int unscheduled_count_;
134
135  // The number of times this scheduler has been artificially rescheduled on
136  // account of a timeout.
137  int rescheduled_count_;
138
139  // The GpuScheduler will unschedule itself in the event that further GL calls
140  // are issued to it before all these fences have been crossed by the GPU.
141  struct UnscheduleFence {
142    UnscheduleFence(gfx::GLFence* fence, base::Closure task);
143    ~UnscheduleFence();
144
145    scoped_ptr<gfx::GLFence> fence;
146    base::Time issue_time;
147    base::Closure task;
148  };
149  std::queue<linked_ptr<UnscheduleFence> > unschedule_fences_;
150
151  SchedulingChangedCallback scheduling_changed_callback_;
152  base::Closure descheduled_callback_;
153  base::Closure command_processed_callback_;
154
155  // If non-NULL and |preemption_flag_->IsSet()|, exit PutChanged early.
156  scoped_refptr<PreemptionFlag> preemption_flag_;
157  bool was_preempted_;
158
159  // A factory for outstanding rescheduling tasks that is invalidated whenever
160  // the scheduler is rescheduled.
161  base::WeakPtrFactory<GpuScheduler> reschedule_task_factory_;
162
163  DISALLOW_COPY_AND_ASSIGN(GpuScheduler);
164};
165
166}  // namespace gpu
167
168#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_
169