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