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