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