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