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, const 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   void UseComponentAlphaTextures(CompositableClient* aCompositable,
244                                  TextureClient* aClientOnBlack,
245                                  TextureClient* aClientOnWhite) override;
246 
247   void ReleaseCompositable(const CompositableHandle& aHandle) override;
248 
249   void ForgetImageContainer(const CompositableHandle& aHandle);
250 
251   /**
252    * Hold TextureClient ref until end of usage on host side if
253    * TextureFlags::RECYCLE is set. Host side's usage is checked via
254    * CompositableRef.
255    */
256   void HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient);
257 
258   /**
259    * Notify id of Texture When host side end its use. Transaction id is used to
260    * make sure if there is no newer usage.
261    */
262   void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
263 
264   void CancelWaitForNotifyNotUsed(uint64_t aTextureId) override;
265 
266   bool DestroyInTransaction(PTextureChild* aTexture) override;
267   bool DestroyInTransaction(const CompositableHandle& aHandle);
268 
269   void RemoveTextureFromCompositable(CompositableClient* aCompositable,
270                                      TextureClient* aTexture) override;
271 
UseTiledLayerBuffer(CompositableClient * aCompositable,const SurfaceDescriptorTiles & aTileLayerDescriptor)272   void UseTiledLayerBuffer(
273       CompositableClient* aCompositable,
274       const SurfaceDescriptorTiles& aTileLayerDescriptor) override {
275     MOZ_CRASH("should not be called");
276   }
277 
UpdateTextureRegion(CompositableClient * aCompositable,const ThebesBufferData & aThebesBufferData,const nsIntRegion & aUpdatedRegion)278   void UpdateTextureRegion(CompositableClient* aCompositable,
279                            const ThebesBufferData& aThebesBufferData,
280                            const nsIntRegion& aUpdatedRegion) override {
281     MOZ_CRASH("should not be called");
282   }
283 
284   // ISurfaceAllocator
285 
286   /**
287    * See ISurfaceAllocator.h
288    * Can be used from any thread.
289    * If used outside the ImageBridgeChild thread, it will proxy a synchronous
290    * call on the ImageBridgeChild thread.
291    */
292   bool AllocUnsafeShmem(size_t aSize,
293                         mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
294                         mozilla::ipc::Shmem* aShmem) override;
295   bool AllocShmem(size_t aSize,
296                   mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
297                   mozilla::ipc::Shmem* aShmem) override;
298 
299   /**
300    * See ISurfaceAllocator.h
301    * Can be used from any thread.
302    * If used outside the ImageBridgeChild thread, it will proxy a synchronous
303    * call on the ImageBridgeChild thread.
304    */
305   bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
306 
307   PTextureChild* CreateTexture(
308       const SurfaceDescriptor& aSharedData, const ReadLockDescriptor& aReadLock,
309       LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial,
310       wr::MaybeExternalImageId& aExternalImageId,
311       nsISerialEventTarget* aTarget = nullptr) override;
312 
313   bool IsSameProcess() const override;
314 
UpdateFwdTransactionId()315   void UpdateFwdTransactionId() override { ++mFwdTransactionId; }
GetFwdTransactionId()316   uint64_t GetFwdTransactionId() override { return mFwdTransactionId; }
317 
InForwarderThread()318   bool InForwarderThread() override { return InImageBridgeChildThread(); }
319 
320   void HandleFatalError(const char* aMsg) const override;
321 
322   wr::MaybeExternalImageId GetNextExternalImageId() override;
323 
324  protected:
325   explicit ImageBridgeChild(uint32_t aNamespace);
326   bool DispatchAllocShmemInternal(size_t aSize,
327                                   SharedMemory::SharedMemoryType aType,
328                                   Shmem* aShmem, bool aUnsafe);
329 
330   void Bind(Endpoint<PImageBridgeChild>&& aEndpoint);
331   void BindSameProcess(RefPtr<ImageBridgeParent> aParent);
332 
333   void SendImageBridgeThreadId();
334 
335   void WillShutdown();
336   void ShutdownStep1(SynchronousTask* aTask);
337   void ShutdownStep2(SynchronousTask* aTask);
338   void MarkShutDown();
339 
340   void ActorDestroy(ActorDestroyReason aWhy) override;
341   void ActorDealloc() override;
342 
343   bool CanSend() const;
344   bool CanPostTask() const;
345 
346   static void ShutdownSingleton();
347 
348  private:
349   uint32_t mNamespace;
350 
351   CompositableTransaction* mTxn;
352 
353   bool mCanSend;
354   mozilla::Atomic<bool> mDestroyed;
355 
356   /**
357    * Transaction id of CompositableForwarder.
358    * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction()
359    * call.
360    */
361   uint64_t mFwdTransactionId;
362 
363   /**
364    * Hold TextureClients refs until end of their usages on host side.
365    * It defer calling of TextureClient recycle callback.
366    */
367   std::unordered_map<uint64_t, RefPtr<TextureClient>>
368       mTexturesWaitingNotifyNotUsed;
369 
370   /**
371    * Mapping from async compositable IDs to image containers.
372    */
373   Mutex mContainerMapLock;
374   std::unordered_map<uint64_t, RefPtr<ImageContainerListener>>
375       mImageContainerListeners;
376   RefPtr<ImageContainerListener> FindListener(
377       const CompositableHandle& aHandle);
378 
379 #if defined(XP_WIN)
380   /**
381    * Used for checking if D3D11Device is updated.
382    */
383   RefPtr<ID3D11Device> mImageDevice;
384 #endif
385 };
386 
387 }  // namespace layers
388 }  // namespace mozilla
389 
390 #endif
391