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