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_WEBRENDERCOMPOSITABLE_HOLDER_H
8 #define MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
9 
10 #include <vector>
11 
12 #include "CompositableHost.h"
13 #include "mozilla/gfx/Point.h"
14 #include "mozilla/ipc/FileDescriptor.h"
15 #include "mozilla/layers/TextureHost.h"
16 #include "mozilla/Maybe.h"
17 #include "mozilla/webrender/WebRenderAPI.h"
18 #include "mozilla/webrender/WebRenderTypes.h"
19 #include "nsClassHashtable.h"
20 
21 namespace mozilla {
22 
23 namespace wr {
24 class DisplayListBuilder;
25 class WebRenderAPI;
26 class WebRenderPipelineInfo;
27 }  // namespace wr
28 
29 namespace layers {
30 
31 class CompositableHost;
32 class CompositorVsyncScheduler;
33 class WebRenderImageHost;
34 class WebRenderTextureHost;
35 
36 class AsyncImagePipelineManager final {
37  public:
38   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncImagePipelineManager)
39 
40   explicit AsyncImagePipelineManager(RefPtr<wr::WebRenderAPI>&& aApi,
41                                      bool aUseCompositorWnd);
42 
43  protected:
44   ~AsyncImagePipelineManager();
45 
46  public:
47   void Destroy();
48 
UseCompositorWnd()49   bool UseCompositorWnd() const { return mUseCompositorWnd; }
50 
51   void AddPipeline(const wr::PipelineId& aPipelineId,
52                    WebRenderBridgeParent* aWrBridge);
53   void RemovePipeline(const wr::PipelineId& aPipelineId,
54                       const wr::Epoch& aEpoch);
55   WebRenderBridgeParent* GetWrBridge(const wr::PipelineId& aPipelineId);
56 
57   void HoldExternalImage(const wr::PipelineId& aPipelineId,
58                          const wr::Epoch& aEpoch, TextureHost* aTexture);
59   void HoldExternalImage(const wr::PipelineId& aPipelineId,
60                          const wr::Epoch& aEpoch,
61                          const wr::ExternalImageId& aImageId);
62 
63   // This is called from the Renderer thread to notify this class about the
64   // pipelines in the most recently completed update.
65   // @param aInfo PipelineInfo for the update
66   // @param aLatestFrameId RenderedFrameId if a frame has been submitted for
67   //                       rendering, invalid if not
68   // @param aLastCompletedFrameId RenderedFrameId for the last completed frame
69   void NotifyPipelinesUpdated(RefPtr<const wr::WebRenderPipelineInfo> aInfo,
70                               wr::RenderedFrameId aLatestFrameId,
71                               wr::RenderedFrameId aLastCompletedFrameId,
72                               ipc::FileDescriptor&& aFenceFd);
73 
74   // This is run on the compositor thread to process mRenderSubmittedUpdates. We
75   // make this public because we need to invoke it from other places.
76   void ProcessPipelineUpdates();
77 
GetCompositionTime()78   TimeStamp GetCompositionTime() const { return mCompositionTime; }
GetCompositionOpportunityId()79   CompositionOpportunityId GetCompositionOpportunityId() const {
80     return mCompositionOpportunityId;
81   }
82 
SetCompositionInfo(TimeStamp aTimeStamp,CompositionOpportunityId aCompositionOpportunityId)83   void SetCompositionInfo(TimeStamp aTimeStamp,
84                           CompositionOpportunityId aCompositionOpportunityId) {
85     mCompositionTime = aTimeStamp;
86     mCompositionOpportunityId = aCompositionOpportunityId;
87     if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
88         mCompositionTime >= mCompositeUntilTime) {
89       mCompositeUntilTime = TimeStamp();
90     }
91   }
CompositeUntil(TimeStamp aTimeStamp)92   void CompositeUntil(TimeStamp aTimeStamp) {
93     if (mCompositeUntilTime.IsNull() || mCompositeUntilTime < aTimeStamp) {
94       mCompositeUntilTime = aTimeStamp;
95     }
96   }
GetCompositeUntilTime()97   TimeStamp GetCompositeUntilTime() const { return mCompositeUntilTime; }
98 
99   void AddAsyncImagePipeline(const wr::PipelineId& aPipelineId,
100                              WebRenderImageHost* aImageHost);
101   void RemoveAsyncImagePipeline(const wr::PipelineId& aPipelineId,
102                                 wr::TransactionBuilder& aTxn);
103 
104   void UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
105                                 const LayoutDeviceRect& aScBounds,
106                                 VideoInfo::Rotation aRotation,
107                                 const wr::ImageRendering& aFilter,
108                                 const wr::MixBlendMode& aMixBlendMode);
109   void ApplyAsyncImagesOfImageBridge(wr::TransactionBuilder& aSceneBuilderTxn,
110                                      wr::TransactionBuilder& aFastTxn);
111   void ApplyAsyncImageForPipeline(const wr::PipelineId& aPipelineId,
112                                   wr::TransactionBuilder& aTxn,
113                                   wr::TransactionBuilder& aTxnForImageBridge);
114 
115   void SetEmptyDisplayList(const wr::PipelineId& aPipelineId,
116                            wr::TransactionBuilder& aTxn,
117                            wr::TransactionBuilder& aTxnForImageBridge);
118 
AppendImageCompositeNotification(const ImageCompositeNotificationInfo & aNotification)119   void AppendImageCompositeNotification(
120       const ImageCompositeNotificationInfo& aNotification) {
121     mImageCompositeNotifications.AppendElement(aNotification);
122   }
123 
FlushImageNotifications(nsTArray<ImageCompositeNotificationInfo> * aNotifications)124   void FlushImageNotifications(
125       nsTArray<ImageCompositeNotificationInfo>* aNotifications) {
126     aNotifications->AppendElements(std::move(mImageCompositeNotifications));
127   }
128 
129   void SetWillGenerateFrame();
130   bool GetAndResetWillGenerateFrame();
131 
132   static wr::ExternalImageId GetNextExternalImageId();
133 
134  private:
135   void ProcessPipelineRendered(const wr::PipelineId& aPipelineId,
136                                const wr::Epoch& aEpoch,
137                                wr::RenderedFrameId aRenderedFrameId);
138   void ProcessPipelineRemoved(const wr::RemovedPipeline& aRemovedPipeline,
139                               wr::RenderedFrameId aRenderedFrameId);
140 
141   wr::Epoch GetNextImageEpoch();
GetNextResourceId()142   uint32_t GetNextResourceId() { return ++mResourceId; }
GetNamespace()143   wr::IdNamespace GetNamespace() { return mIdNamespace; }
GenerateImageKey()144   wr::ImageKey GenerateImageKey() {
145     wr::ImageKey key;
146     key.mNamespace = GetNamespace();
147     key.mHandle = GetNextResourceId();
148     return key;
149   }
150 
151   struct ForwardingTextureHost {
ForwardingTextureHostForwardingTextureHost152     ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
153         : mEpoch(aEpoch), mTexture(aTexture) {}
154     wr::Epoch mEpoch;
155     CompositableTextureHostRef mTexture;
156   };
157 
158   struct ForwardingExternalImage {
ForwardingExternalImageForwardingExternalImage159     ForwardingExternalImage(const wr::Epoch& aEpoch,
160                             const wr::ExternalImageId& aImageId)
161         : mEpoch(aEpoch), mImageId(aImageId) {}
162     ~ForwardingExternalImage();
163     wr::Epoch mEpoch;
164     wr::ExternalImageId mImageId;
165   };
166 
167   struct PipelineTexturesHolder {
168     // Holds forwarding WebRenderTextureHosts.
169     std::vector<ForwardingTextureHost> mTextureHostsUntilRenderSubmitted;
170     // TextureHosts that must be held until rendering has completed. UniquePtr
171     // is used to make the entries movable, ideally ForwardingTextureHost would
172     // be fully movable.
173     std::vector<UniquePtr<ForwardingTextureHost>>
174         mTextureHostsUntilRenderCompleted;
175     std::vector<UniquePtr<ForwardingExternalImage>> mExternalImages;
176     Maybe<wr::Epoch> mDestroyedEpoch;
177     WebRenderBridgeParent* MOZ_NON_OWNING_REF mWrBridge = nullptr;
178   };
179 
180   struct AsyncImagePipeline {
181     AsyncImagePipeline(wr::PipelineId aPipelineId,
182                        layers::WebRenderBackend aBackend);
UpdateAsyncImagePipeline183     void Update(const LayoutDeviceRect& aScBounds,
184                 VideoInfo::Rotation aRotation,
185                 const wr::ImageRendering& aFilter,
186                 const wr::MixBlendMode& aMixBlendMode) {
187       mIsChanged |= !mScBounds.IsEqualEdges(aScBounds) ||
188                     mRotation != aRotation || mFilter != aFilter ||
189                     mMixBlendMode != aMixBlendMode;
190       mScBounds = aScBounds;
191       mRotation = aRotation;
192       mFilter = aFilter;
193       mMixBlendMode = aMixBlendMode;
194     }
195 
196     bool mInitialised;
197     bool mIsChanged;
198     bool mUseExternalImage;
199     LayoutDeviceRect mScBounds;
200     VideoInfo::Rotation mRotation;
201     wr::ImageRendering mFilter;
202     wr::MixBlendMode mMixBlendMode;
203     RefPtr<WebRenderImageHost> mImageHost;
204     CompositableTextureHostRef mCurrentTexture;
205     nsTArray<wr::ImageKey> mKeys;
206     wr::DisplayListBuilder mDLBuilder;
207   };
208 
209   void ApplyAsyncImageForPipeline(const wr::Epoch& aEpoch,
210                                   const wr::PipelineId& aPipelineId,
211                                   AsyncImagePipeline* aPipeline,
212                                   wr::TransactionBuilder& aSceneBuilderTxn,
213                                   wr::TransactionBuilder& aMaybeFastTxn);
214   Maybe<TextureHost::ResourceUpdateOp> UpdateImageKeys(
215       const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId,
216       AsyncImagePipeline* aPipeline, nsTArray<wr::ImageKey>& aKeys,
217       wr::TransactionBuilder& aSceneBuilderTxn,
218       wr::TransactionBuilder& aMaybeFastTxn);
219   Maybe<TextureHost::ResourceUpdateOp> UpdateWithoutExternalImage(
220       TextureHost* aTexture, wr::ImageKey aKey, TextureHost::ResourceUpdateOp,
221       wr::TransactionBuilder& aTxn);
222 
223   void CheckForTextureHostsNotUsedByGPU();
224 
225   RefPtr<wr::WebRenderAPI> mApi;
226   bool mUseCompositorWnd;
227 
228   const wr::IdNamespace mIdNamespace;
229   const bool mUseTripleBuffering;
230   uint32_t mResourceId;
231 
232   nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder>
233       mPipelineTexturesHolders;
234   nsClassHashtable<nsUint64HashKey, AsyncImagePipeline> mAsyncImagePipelines;
235   wr::Epoch mAsyncImageEpoch;
236   bool mWillGenerateFrame;
237   bool mDestroyed;
238 
239 #ifdef XP_WIN
240   bool mUseWebRenderDCompVideoOverlayWin;
241 #endif
242 
243   // Render time for the current composition.
244   TimeStamp mCompositionTime;
245 
246   // CompositionOpportunityId of the current composition.
247   CompositionOpportunityId mCompositionOpportunityId;
248 
249   // When nonnull, during rendering, some compositable indicated that it will
250   // change its rendering at this time. In order not to miss it, we composite
251   // on every vsync until this time occurs (this is the latest such time).
252   TimeStamp mCompositeUntilTime;
253 
254   nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
255 
256   struct WebRenderPipelineInfoHolder {
257     WebRenderPipelineInfoHolder(RefPtr<const wr::WebRenderPipelineInfo>&& aInfo,
258                                 ipc::FileDescriptor&& aFenceFd);
259     ~WebRenderPipelineInfoHolder();
260     RefPtr<const wr::WebRenderPipelineInfo> mInfo;
261     ipc::FileDescriptor mFenceFd;
262   };
263 
264   std::vector<std::pair<wr::RenderedFrameId, WebRenderPipelineInfoHolder>>
265       mRenderSubmittedUpdates;
266   Mutex mRenderSubmittedUpdatesLock;
267 
268   Atomic<uint64_t> mLastCompletedFrameId;
269   std::vector<std::pair<wr::RenderedFrameId,
270                         std::vector<UniquePtr<ForwardingTextureHost>>>>
271       mTexturesInUseByGPU;
272   ipc::FileDescriptor mReleaseFenceFd;
273 };
274 
275 }  // namespace layers
276 }  // namespace mozilla
277 
278 #endif /* MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H */
279