1 // Copyright 2014 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 COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_BUFFER_QUEUE_H_
6 #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_BUFFER_QUEUE_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <vector>
12 
13 #include "base/containers/circular_deque.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/optional.h"
18 #include "components/viz/service/viz_service_export.h"
19 #include "gpu/command_buffer/common/mailbox.h"
20 #include "gpu/ipc/common/surface_handle.h"
21 #include "ui/gfx/buffer_types.h"
22 #include "ui/gfx/color_space.h"
23 #include "ui/gfx/geometry/rect.h"
24 #include "ui/gfx/geometry/size.h"
25 
26 namespace gfx {
27 class GpuMemoryBuffer;
28 }
29 
30 namespace gpu {
31 class GpuMemoryBufferManager;
32 class SharedImageInterface;
33 struct SyncToken;
34 }  // namespace gpu
35 
36 namespace viz {
37 
38 // Encapsulates a queue of buffers for compositing backed by SharedImages (in
39 // turn backed by GpuMemoryBuffers). Double/triple buffering is implemented
40 // internally. Double buffering occurs if PageFlipComplete is called before the
41 // next BindFramebuffer call, otherwise it creates extra buffers.
42 //
43 // SetSyncTokenProvider() must be called prior to using the BufferQueue. The
44 // reason the SyncTokenProvider is not passed in the constructor is testing:
45 // this allows us to create a mock BufferQueue that can be injected into a
46 // GLOutputSurfaceBufferQueue. The surface can then set itself as the
47 // SyncTokenProvider and fully own the BufferQueue thus guaranteeing that the
48 // queue's SyncTokenProvider outlives the queue.
49 class VIZ_SERVICE_EXPORT BufferQueue {
50  public:
51   // A BufferQueue uses a SyncTokenProvider to get sync tokens that ensure
52   // operations on the buffers done by the BufferQueue client are synchronized
53   // with respect to other work.
54   //
55   // TODO(crbug.com/958670): extend this abstraction to allow both fences and
56   // sync tokens.
57   class SyncTokenProvider {
58    public:
59     SyncTokenProvider() = default;
60     virtual ~SyncTokenProvider() = default;
61     virtual gpu::SyncToken GenSyncToken() = 0;
62   };
63 
64   // Creates a BufferQueue that allocates buffers using
65   // |gpu_memory_buffer_manager| and associates them with SharedImages using
66   // |sii|.
67   BufferQueue(gpu::SharedImageInterface* sii,
68               gpu::SurfaceHandle surface_handle);
69   virtual ~BufferQueue();
70 
71   // Sets the provider of sync tokens that the BufferQueue needs to ensure
72   // operations on a SharedImage are ordered correctly with respect to the
73   // operations issued by the client of the BufferQueue. |sync_token_provider|
74   // is not used after the BufferQueue is destroyed.
75   virtual void SetSyncTokenProvider(SyncTokenProvider* sync_token_provider);
76 
77   // Returns the SharedImage backed by the current buffer (i.e., the render
78   // target for compositing). A zeroed mailbox is returned if there is no
79   // current buffer and one could not be created. The caller needs to wait on
80   // *|creation_sync_token| if non-empty before consuming the mailbox.
81   virtual gpu::Mailbox GetCurrentBuffer(gpu::SyncToken* creation_sync_token);
82 
83   // Returns a rectangle whose contents may have changed since the current
84   // buffer was last submitted and needs to be redrawn. For partial swap,
85   // only the contents outside this rectangle can be considered valid and do not
86   // need to be redrawn.
87   virtual gfx::Rect CurrentBufferDamage() const;
88 
89   // Called by the user of this object to indicate that the buffer currently
90   // marked for drawing should be moved to the list of in-flight buffers.
91   // |damage| represents the rectangle containing the damaged area since the
92   // last SwapBuffers.
93   virtual void SwapBuffers(const gfx::Rect& damage);
94 
95   // Called by the user of this object to indicate that a previous request to
96   // swap buffers has completed. This allows us to correctly keep track of the
97   // state of the buffers: the buffer currently marked as being displayed will
98   // now marked as available, and the next buffer marked as in-flight will now
99   // be marked as displayed.
100   virtual void PageFlipComplete();
101 
102   // Requests a sync token from the SyncTokenProvider passed in the constructor
103   // and frees all buffers after that sync token has passed.
104   virtual void FreeAllSurfaces();
105 
106   // If |size| or |color_space| correspond to a change of state, requests a sync
107   // token from the SyncTokenProvider passed in the constructor and frees all
108   // the buffers after that sync token passes. Otherwise, it's a no-op. Returns
109   // true if there was a change of state, false otherwise.
110   virtual bool Reshape(const gfx::Size& size,
111                        const gfx::ColorSpace& color_space,
112                        gfx::BufferFormat format);
113 
buffer_format()114   gfx::BufferFormat buffer_format() const { return *format_; }
115   void SetMaxBuffers(size_t max);
116 
117  private:
118   friend class BufferQueueTest;
119   friend class BufferQueueMockedSharedImageInterfaceTest;
120   FRIEND_TEST_ALL_PREFIXES(BufferQueueTest, AllocateFails);
121   FRIEND_TEST_ALL_PREFIXES(BufferQueueMockedSharedImageInterfaceTest,
122                            AllocateFails);
123 
124   // TODO(andrescj): consider renaming this to AllocatedBuffer because 'surface'
125   // is an overloaded term (also problematic in the unit tests).
126   struct VIZ_SERVICE_EXPORT AllocatedSurface {
127     AllocatedSurface(const gpu::Mailbox& mailbox, const gfx::Rect& rect);
128     ~AllocatedSurface();
129 
130     // TODO(crbug.com/958670): if we can have a CreateSharedImage() that takes a
131     // SurfaceHandle, we don't have to keep track of |buffer|.
132     gpu::Mailbox mailbox;
133     gfx::Rect damage;  // This is the damage for this frame from the previous.
134   };
135 
136   void FreeSurface(std::unique_ptr<AllocatedSurface> surface,
137                    const gpu::SyncToken& sync_token);
138 
139   void UpdateBufferDamage(const gfx::Rect& damage);
140 
141   // Return a buffer that is available to be drawn into or nullptr if there is
142   // no available buffer and one cannot be created. If a new buffer is created
143   // *|creation_sync_token| is set to a sync token that the client must wait on
144   // before using the buffer.
145   std::unique_ptr<AllocatedSurface> GetNextSurface(
146       gpu::SyncToken* creation_sync_token);
147 
148   gpu::SharedImageInterface* const sii_;
149   gfx::Size size_;
150   gfx::ColorSpace color_space_;
151 
152   // We don't want to allow anything more than triple buffering by default.
153   size_t max_buffers_ = 3U;
154   size_t allocated_count_;
155   // The |format_| is optional to prevent use of uninitialized values.
156   base::Optional<gfx::BufferFormat> format_;
157   // This surface is currently bound. This may be nullptr if no surface has
158   // been bound, or if allocation failed at bind.
159   std::unique_ptr<AllocatedSurface> current_surface_;
160   // The surface currently on the screen, if any.
161   std::unique_ptr<AllocatedSurface> displayed_surface_;
162   // These are free for use, and are not nullptr.
163   std::vector<std::unique_ptr<AllocatedSurface>> available_surfaces_;
164   // These have been swapped but are not displayed yet. Entries of this deque
165   // may be nullptr, if they represent frames that have been destroyed.
166   base::circular_deque<std::unique_ptr<AllocatedSurface>> in_flight_surfaces_;
167   gpu::SurfaceHandle surface_handle_;
168   SyncTokenProvider* sync_token_provider_ = nullptr;
169 
170   DISALLOW_COPY_AND_ASSIGN(BufferQueue);
171 };
172 
173 }  // namespace viz
174 
175 #endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_BUFFER_QUEUE_H_
176