1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef MOZILLA_GFX_PersistentBUFFERPROVIDER_H
8 #define MOZILLA_GFX_PersistentBUFFERPROVIDER_H
9 
10 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
11 #include "mozilla/RefPtr.h"      // for RefPtr, already_AddRefed, etc
12 #include "mozilla/layers/KnowsCompositor.h"
13 #include "mozilla/layers/LayersSurfaces.h"
14 #include "mozilla/layers/LayersTypes.h"
15 #include "mozilla/RefCounted.h"
16 #include "mozilla/gfx/Types.h"
17 #include "mozilla/Vector.h"
18 #include "mozilla/WeakPtr.h"
19 
20 namespace mozilla {
21 
22 class ClientWebGLContext;
23 
24 namespace gfx {
25 class SourceSurface;
26 class DrawTarget;
27 class DrawTargetWebgl;
28 }  // namespace gfx
29 
30 namespace layers {
31 
32 class TextureClient;
33 
34 /**
35  * A PersistentBufferProvider is for users which require the temporary use of
36  * a DrawTarget to draw into. When they're done drawing they return the
37  * DrawTarget, when they later need to continue drawing they get a DrawTarget
38  * from the provider again, the provider will guarantee the contents of the
39  * previously returned DrawTarget is persisted into the one newly returned.
40  */
41 class PersistentBufferProvider : public RefCounted<PersistentBufferProvider>,
42                                  public SupportsWeakPtr {
43  public:
44   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProvider)
45 
46   virtual ~PersistentBufferProvider() = default;
47 
IsShared()48   virtual bool IsShared() const { return false; }
IsAccelerated()49   virtual bool IsAccelerated() const { return false; }
50 
51   /**
52    * Get a DrawTarget from the PersistentBufferProvider.
53    *
54    * \param aPersistedRect This indicates the area of the DrawTarget that needs
55    *                       to have remained the same since the call to
56    *                       ReturnDrawTarget.
57    */
58   virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
59       const gfx::IntRect& aPersistedRect) = 0;
60 
61   /**
62    * Return a DrawTarget to the PersistentBufferProvider and indicate the
63    * contents of this DrawTarget is to be considered current by the
64    * BufferProvider. The caller should forget any references to the DrawTarget.
65    */
66   virtual bool ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) = 0;
67 
68   virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() = 0;
69 
70   /**
71    * Override this if it's possible to read data directly into the DT without
72    * copying to an intermediate snapshot.
73    */
CopySnapshotTo(gfx::DrawTarget * aDT)74   virtual bool CopySnapshotTo(gfx::DrawTarget* aDT) { return false; }
75 
76   virtual void ReturnSnapshot(
77       already_AddRefed<gfx::SourceSurface> aSnapshot) = 0;
78 
GetTextureClient()79   virtual TextureClient* GetTextureClient() { return nullptr; }
80 
OnShutdown()81   virtual void OnShutdown() {}
82 
SetKnowsCompositor(KnowsCompositor * aKnowsCompositor)83   virtual bool SetKnowsCompositor(KnowsCompositor* aKnowsCompositor) {
84     return true;
85   }
86 
ClearCachedResources()87   virtual void ClearCachedResources() {}
88 
89   /**
90    * Return true if this provider preserves the drawing state (clips,
91    * transforms, etc.) across frames. In practice this means users of the
92    * provider can skip popping all of the clips at the end of the frames and
93    * pushing them back at the beginning of the following frames, which can be
94    * costly (cf. bug 1294351).
95    */
96   virtual bool PreservesDrawingState() const = 0;
97 
98   /**
99    * Provide a WebGL front buffer for compositing, if available.
100    */
GetFrontBuffer()101   virtual Maybe<layers::SurfaceDescriptor> GetFrontBuffer() {
102     return Nothing();
103   }
104 };
105 
106 class PersistentBufferProviderBasic : public PersistentBufferProvider {
107  public:
108   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderBasic,
109                                           override)
110 
111   static already_AddRefed<PersistentBufferProviderBasic> Create(
112       gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
113       gfx::BackendType aBackend);
114 
115   explicit PersistentBufferProviderBasic(gfx::DrawTarget* aTarget);
116 
117   already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
118       const gfx::IntRect& aPersistedRect) override;
119 
120   bool ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) override;
121 
122   already_AddRefed<gfx::SourceSurface> BorrowSnapshot() override;
123 
124   void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) override;
125 
PreservesDrawingState()126   bool PreservesDrawingState() const override { return true; }
127 
OnShutdown()128   void OnShutdown() override { Destroy(); }
129 
130  protected:
131   void Destroy();
132 
133   ~PersistentBufferProviderBasic() override;
134 
135   RefPtr<gfx::DrawTarget> mDrawTarget;
136   RefPtr<gfx::SourceSurface> mSnapshot;
137 };
138 
139 class PersistentBufferProviderAccelerated
140     : public PersistentBufferProviderBasic {
141  public:
142   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderAccelerated,
143                                           override)
144 
145   explicit PersistentBufferProviderAccelerated(gfx::DrawTarget* aTarget);
146 
IsAccelerated()147   bool IsAccelerated() const override { return true; }
148 
149   Maybe<layers::SurfaceDescriptor> GetFrontBuffer() override;
150 
151   bool CopySnapshotTo(gfx::DrawTarget* aDT) override;
152 
153   already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
154       const gfx::IntRect& aPersistedRect) override;
155 
156   bool ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) override;
157 
158  protected:
159   ~PersistentBufferProviderAccelerated() override;
160 
161   gfx::DrawTargetWebgl* GetDrawTargetWebgl() const;
162 };
163 
164 /**
165  * Provides access to a buffer which can be sent to the compositor without
166  * requiring a copy.
167  */
168 class PersistentBufferProviderShared : public PersistentBufferProvider,
169                                        public ActiveResource {
170  public:
171   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderShared,
172                                           override)
173 
174   static already_AddRefed<PersistentBufferProviderShared> Create(
175       gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
176       KnowsCompositor* aKnowsCompositor);
177 
IsShared()178   bool IsShared() const override { return true; }
179 
180   already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
181       const gfx::IntRect& aPersistedRect) override;
182 
183   bool ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) override;
184 
185   already_AddRefed<gfx::SourceSurface> BorrowSnapshot() override;
186 
187   void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) override;
188 
189   TextureClient* GetTextureClient() override;
190 
191   void NotifyInactive() override;
192 
OnShutdown()193   void OnShutdown() override { Destroy(); }
194 
195   bool SetKnowsCompositor(KnowsCompositor* aKnowsCompositor) override;
196 
197   void ClearCachedResources() override;
198 
PreservesDrawingState()199   bool PreservesDrawingState() const override { return false; }
200 
201  protected:
202   PersistentBufferProviderShared(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
203                                  KnowsCompositor* aKnowsCompositor,
204                                  RefPtr<TextureClient>& aTexture);
205 
206   ~PersistentBufferProviderShared();
207 
208   TextureClient* GetTexture(const Maybe<uint32_t>& aIndex);
CheckIndex(uint32_t aIndex)209   bool CheckIndex(uint32_t aIndex) { return aIndex < mTextures.length(); }
210 
211   void Destroy();
212 
213   gfx::IntSize mSize;
214   gfx::SurfaceFormat mFormat;
215   RefPtr<KnowsCompositor> mKnowsCompositor;
216   // If the texture has its own synchronization then copying back from the
217   // previous texture can cause contention issues and even deadlocks. So we use
218   // a separate permanent back buffer and copy into the shared back buffer when
219   // the DrawTarget is returned, before making it the new front buffer.
220   RefPtr<TextureClient> mPermanentBackBuffer;
221   static const size_t kMaxTexturesAllowed = 5;
222   Vector<RefPtr<TextureClient>, kMaxTexturesAllowed + 2> mTextures;
223   // Offset of the texture in mTextures that the canvas uses.
224   Maybe<uint32_t> mBack;
225   // Offset of the texture in mTextures that is presented to the compositor.
226   Maybe<uint32_t> mFront;
227 
228   RefPtr<gfx::DrawTarget> mDrawTarget;
229   RefPtr<gfx::SourceSurface> mSnapshot;
230   size_t mMaxAllowedTextures = kMaxTexturesAllowed;
231 };
232 
233 struct AutoReturnSnapshot final {
234   PersistentBufferProvider* mBufferProvider;
235   RefPtr<gfx::SourceSurface>* mSnapshot;
236 
237   explicit AutoReturnSnapshot(PersistentBufferProvider* aProvider = nullptr)
mBufferProviderfinal238       : mBufferProvider(aProvider), mSnapshot(nullptr) {}
239 
~AutoReturnSnapshotfinal240   ~AutoReturnSnapshot() {
241     if (mBufferProvider) {
242       mBufferProvider->ReturnSnapshot(mSnapshot ? mSnapshot->forget()
243                                                 : nullptr);
244     }
245   }
246 };
247 
248 }  // namespace layers
249 }  // namespace mozilla
250 
251 #endif
252