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