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