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_IMAGEBRIDGECHILD_H
8 #define MOZILLA_GFX_IMAGEBRIDGECHILD_H
9 
10 #include <stddef.h>  // for size_t
11 #include <stdint.h>  // for uint32_t, uint64_t
12 #include <unordered_map>
13 
14 #include "mozilla/Attributes.h"  // for override
15 #include "mozilla/Atomics.h"
16 #include "mozilla/RefPtr.h"            // for already_AddRefed
17 #include "mozilla/ipc/SharedMemory.h"  // for SharedMemory, etc
18 #include "mozilla/layers/CompositableForwarder.h"
19 #include "mozilla/layers/CompositorTypes.h"
20 #include "mozilla/layers/PImageBridgeChild.h"
21 #include "mozilla/layers/TextureForwarder.h"
22 #include "mozilla/Mutex.h"
23 #include "mozilla/webrender/WebRenderTypes.h"
24 #include "nsRegion.h"  // for nsIntRegion
25 #include "mozilla/gfx/Rect.h"
26 #include "mozilla/ReentrantMonitor.h"  // for ReentrantMonitor, etc
27 
28 namespace mozilla {
29 namespace ipc {
30 class Shmem;
31 }  // namespace ipc
32 
33 namespace layers {
34 
35 class ImageClient;
36 class ImageContainer;
37 class ImageContainerListener;
38 class ImageBridgeParent;
39 class CompositableClient;
40 struct CompositableTransaction;
41 class Image;
42 class TextureClient;
43 class SynchronousTask;
44 
45 /**
46  * Returns true if the current thread is the ImageBrdigeChild's thread.
47  *
48  * Can be called from any thread.
49  */
50 bool InImageBridgeChildThread();
51 
52 /**
53  * The ImageBridge protocol is meant to allow ImageContainers to forward images
54  * directly to the compositor thread/process without using the main thread.
55  *
56  * ImageBridgeChild is a CompositableForwarder just like ShadowLayerForwarder.
57  * This means it also does transactions with the compositor thread/process,
58  * except that the transactions are restricted to operations on the
59  * Compositables and cannot contain messages affecting layers directly.
60  *
61  * ImageBridgeChild is also a ISurfaceAllocator. It can be used to allocate or
62  * deallocate data that is shared with the compositor. The main differerence
63  * with other ISurfaceAllocators is that some of its overriden methods can be
64  * invoked from any thread.
65  *
66  * There are three important phases in the ImageBridge protocol. These three
67  * steps can do different things depending if (A) the ImageContainer uses
68  * ImageBridge or (B) it does not use ImageBridge:
69  *
70  * - When an ImageContainer calls its method SetCurrentImage:
71  *   - (A) The image is sent directly to the compositor process through the
72  *   ImageBridge IPDL protocol.
73  *   On the compositor side the image is stored in a global table that
74  *   associates the image with an ID corresponding to the ImageContainer, and a
75  *   composition is triggered.
76  *   - (B) Since it does not have an ImageBridge, the image is not sent yet.
77  *   instead the will be sent to the compositor during the next layer
78  *   transaction (on the main thread).
79  *
80  * - During a Layer transaction:
81  *   - (A) The ImageContainer uses ImageBridge. The image is already available
82  *   to the compositor process because it has been sent with SetCurrentImage.
83  *   Yet, the CompositableHost on the compositor side will needs the ID
84  *   referring to the ImageContainer to access the Image. So during the Swap
85  *   operation that happens in the transaction, we swap the container ID rather
86  *   than the image data.
87  *   - (B) Since the ImageContainer does not use ImageBridge, the image data is
88  *   swaped.
89  *
90  * - During composition:
91  *   - (A) The CompositableHost has an AsyncID, it looks up the ID in the
92  *   global table to see if there is an image. If there is no image, nothing is
93  *   rendered.
94  *   - (B) The CompositableHost has image data rather than an ID (meaning it is
95  *   not using ImageBridge), then it just composites the image data normally.
96  *
97  * This means that there might be a possibility for the ImageBridge to send the
98  * first frame before the first layer transaction that will pass the container
99  * ID to the CompositableHost happens. In this (unlikely) case the layer is not
100  * composited until the layer transaction happens. This means this scenario is
101  * not harmful.
102  *
103  * Since sending an image through imageBridge triggers compositing, the main
104  * thread is not used at all (except for the very first transaction that
105  * provides the CompositableHost with an AsyncID).
106  */
107 class ImageBridgeChild final : public PImageBridgeChild,
108                                public CompositableForwarder,
109                                public TextureForwarder {
110   friend class ImageContainer;
111 
112   typedef nsTArray<AsyncParentMessageData> AsyncParentMessageArray;
113 
114  public:
115   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageBridgeChild, override);
116 
GetTextureForwarder()117   TextureForwarder* GetTextureForwarder() override { return this; }
GetLayersIPCActor()118   LayersIPCActor* GetLayersIPCActor() override { return this; }
119 
120   /**
121    * Creates the image bridge with a dedicated thread for ImageBridgeChild.
122    *
123    * We may want to use a specifi thread in the future. In this case, use
124    * CreateWithThread instead.
125    */
126   static void InitSameProcess(uint32_t aNamespace);
127 
128   static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint,
129                                  uint32_t aNamespace);
130   static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
131                              uint32_t aNamespace);
132   static bool ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
133                                uint32_t aNamespace);
134 
135   /**
136    * Destroys the image bridge by calling DestroyBridge, and destroys the
137    * ImageBridge's thread.
138    *
139    * If you don't want to destroy the thread, call DestroyBridge directly
140    * instead.
141    */
142   static void ShutDown();
143 
144   /**
145    * returns the singleton instance.
146    *
147    * can be called from any thread.
148    */
149   static RefPtr<ImageBridgeChild> GetSingleton();
150 
151   static void IdentifyCompositorTextureHost(
152       const TextureFactoryIdentifier& aIdentifier);
153 
154   void BeginTransaction();
155   void EndTransaction();
156 
157   /**
158    * Returns the ImageBridgeChild's thread.
159    *
160    * Can be called from any thread.
161    */
162   nsISerialEventTarget* GetThread() const override;
163 
GetParentPid()164   base::ProcessId GetParentPid() const override { return OtherPid(); }
165 
166   PTextureChild* AllocPTextureChild(
167       const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock,
168       const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
169       const uint64_t& aSerial,
170       const wr::MaybeExternalImageId& aExternalImageId);
171 
172   bool DeallocPTextureChild(PTextureChild* actor);
173 
174   PMediaSystemResourceManagerChild* AllocPMediaSystemResourceManagerChild();
175   bool DeallocPMediaSystemResourceManagerChild(
176       PMediaSystemResourceManagerChild* aActor);
177 
178   mozilla::ipc::IPCResult RecvParentAsyncMessages(
179       nsTArray<AsyncParentMessageData>&& aMessages);
180 
181   mozilla::ipc::IPCResult RecvDidComposite(
182       nsTArray<ImageCompositeNotification>&& aNotifications);
183 
184   mozilla::ipc::IPCResult RecvReportFramesDropped(
185       const CompositableHandle& aHandle, const uint32_t& aFrames);
186 
187   // Create an ImageClient from any thread.
188   RefPtr<ImageClient> CreateImageClient(CompositableType aType,
189                                         ImageContainer* aImageContainer);
190 
191   // Create an ImageClient from the ImageBridge thread.
192   RefPtr<ImageClient> CreateImageClientNow(CompositableType aType,
193                                            ImageContainer* aImageContainer);
194 
195   void UpdateImageClient(RefPtr<ImageContainer> aContainer);
196 
197   /**
198    * Flush all Images sent to CompositableHost.
199    */
200   void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer);
201 
IPCOpen()202   bool IPCOpen() const override { return mCanSend; }
203 
204  private:
205   /**
206    * This must be called by the static function DeleteImageBridgeSync defined
207    * in ImageBridgeChild.cpp ONLY.
208    */
209   virtual ~ImageBridgeChild();
210 
211   // Helpers for dispatching.
212   void CreateImageClientSync(SynchronousTask* aTask,
213                              RefPtr<ImageClient>* result,
214                              CompositableType aType,
215                              ImageContainer* aImageContainer);
216 
217   void FlushAllImagesSync(SynchronousTask* aTask, ImageClient* aClient,
218                           ImageContainer* aContainer);
219 
220   void ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize,
221                           SharedMemory::SharedMemoryType aType,
222                           mozilla::ipc::Shmem* aShmem, bool aUnsafe,
223                           bool* aSuccess);
224   void ProxyDeallocShmemNow(SynchronousTask* aTask, mozilla::ipc::Shmem* aShmem,
225                             bool* aResult);
226 
227   void UpdateTextureFactoryIdentifier(
228       const TextureFactoryIdentifier& aIdentifier);
229 
230  public:
231   // CompositableForwarder
232 
233   void Connect(CompositableClient* aCompositable,
234                ImageContainer* aImageContainer) override;
235 
UsesImageBridge()236   bool UsesImageBridge() const override { return true; }
237 
238   /**
239    * See CompositableForwarder::UseTextures
240    */
241   void UseTextures(CompositableClient* aCompositable,
242                    const nsTArray<TimedTextureClient>& aTextures) override;
243 
244   void ReleaseCompositable(const CompositableHandle& aHandle) override;
245 
246   void ForgetImageContainer(const CompositableHandle& aHandle);
247 
248   /**
249    * Hold TextureClient ref until end of usage on host side if
250    * TextureFlags::RECYCLE is set. Host side's usage is checked via
251    * CompositableRef.
252    */
253   void HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient);
254 
255   /**
256    * Notify id of Texture When host side end its use. Transaction id is used to
257    * make sure if there is no newer usage.
258    */
259   void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
260 
261   void CancelWaitForNotifyNotUsed(uint64_t aTextureId) override;
262 
263   bool DestroyInTransaction(PTextureChild* aTexture) override;
264   bool DestroyInTransaction(const CompositableHandle& aHandle);
265 
266   void RemoveTextureFromCompositable(CompositableClient* aCompositable,
267                                      TextureClient* aTexture) override;
268 
269   // ISurfaceAllocator
270 
271   /**
272    * See ISurfaceAllocator.h
273    * Can be used from any thread.
274    * If used outside the ImageBridgeChild thread, it will proxy a synchronous
275    * call on the ImageBridgeChild thread.
276    */
277   bool AllocUnsafeShmem(size_t aSize,
278                         mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
279                         mozilla::ipc::Shmem* aShmem) override;
280   bool AllocShmem(size_t aSize,
281                   mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
282                   mozilla::ipc::Shmem* aShmem) override;
283 
284   /**
285    * See ISurfaceAllocator.h
286    * Can be used from any thread.
287    * If used outside the ImageBridgeChild thread, it will proxy a synchronous
288    * call on the ImageBridgeChild thread.
289    */
290   bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
291 
292   PTextureChild* CreateTexture(
293       const SurfaceDescriptor& aSharedData, ReadLockDescriptor&& aReadLock,
294       LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial,
295       wr::MaybeExternalImageId& aExternalImageId) override;
296 
297   bool IsSameProcess() const override;
298 
UpdateFwdTransactionId()299   void UpdateFwdTransactionId() override { ++mFwdTransactionId; }
GetFwdTransactionId()300   uint64_t GetFwdTransactionId() override { return mFwdTransactionId; }
301 
InForwarderThread()302   bool InForwarderThread() override { return InImageBridgeChildThread(); }
303 
304   void HandleFatalError(const char* aMsg) const override;
305 
306   wr::MaybeExternalImageId GetNextExternalImageId() override;
307 
308  protected:
309   explicit ImageBridgeChild(uint32_t aNamespace);
310   bool DispatchAllocShmemInternal(size_t aSize,
311                                   SharedMemory::SharedMemoryType aType,
312                                   Shmem* aShmem, bool aUnsafe);
313 
314   void Bind(Endpoint<PImageBridgeChild>&& aEndpoint);
315   void BindSameProcess(RefPtr<ImageBridgeParent> aParent);
316 
317   void SendImageBridgeThreadId();
318 
319   void WillShutdown();
320   void ShutdownStep1(SynchronousTask* aTask);
321   void ShutdownStep2(SynchronousTask* aTask);
322   void MarkShutDown();
323 
324   void ActorDestroy(ActorDestroyReason aWhy) override;
325   void ActorDealloc() override;
326 
327   bool CanSend() const;
328   bool CanPostTask() const;
329 
330   static void ShutdownSingleton();
331 
332  private:
333   uint32_t mNamespace;
334 
335   CompositableTransaction* mTxn;
336 
337   bool mCanSend;
338   mozilla::Atomic<bool> mDestroyed;
339 
340   /**
341    * Transaction id of CompositableForwarder.
342    * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction()
343    * call.
344    */
345   uint64_t mFwdTransactionId;
346 
347   /**
348    * Hold TextureClients refs until end of their usages on host side.
349    * It defer calling of TextureClient recycle callback.
350    */
351   std::unordered_map<uint64_t, RefPtr<TextureClient>>
352       mTexturesWaitingNotifyNotUsed;
353 
354   /**
355    * Mapping from async compositable IDs to image containers.
356    */
357   Mutex mContainerMapLock;
358   std::unordered_map<uint64_t, RefPtr<ImageContainerListener>>
359       mImageContainerListeners;
360   RefPtr<ImageContainerListener> FindListener(
361       const CompositableHandle& aHandle);
362 };
363 
364 }  // namespace layers
365 }  // namespace mozilla
366 
367 #endif
368