ImageContainer.h (35027B)
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 GFX_IMAGECONTAINER_H 8 #define GFX_IMAGECONTAINER_H 9 10 #include <stdint.h> // for int32_t, uint32_t, uint8_t, uint64_t 11 #include "ImageTypes.h" // for ImageFormat, etc 12 #include "mozilla/AlreadyAddRefed.h" 13 #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 14 #include "mozilla/Mutex.h" // for Mutex 15 #include "mozilla/RecursiveMutex.h" // for RecursiveMutex, etc 16 #include "mozilla/ThreadSafeWeakPtr.h" 17 #include "mozilla/TimeStamp.h" // for TimeStamp 18 #include "mozilla/gfx/Point.h" // For IntSize 19 #include "mozilla/gfx/Rect.h" 20 #include "mozilla/gfx/Types.h" // For ColorDepth 21 #include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc 22 #include "mozilla/layers/CompositorTypes.h" 23 #include "mozilla/mozalloc.h" // for operator delete, etc 24 #include "mozilla/TypedEnumBits.h" 25 #include "nsDebug.h" // for NS_ASSERTION 26 #include "nsISupportsImpl.h" // for Image::Release, etc 27 #include "nsTArray.h" // for nsTArray 28 #include "nsThreadUtils.h" // for NS_IsMainThread 29 #include "mozilla/Atomics.h" 30 #include "mozilla/gfx/2D.h" 31 #include "mozilla/EnumeratedArray.h" 32 #include "mozilla/UniquePtr.h" 33 #include "nsTHashMap.h" 34 #include "TimeUnits.h" 35 #include "MediaData.h" 36 37 #ifdef XP_WIN 38 struct ID3D10Texture2D; 39 struct ID3D10Device; 40 struct ID3D10ShaderResourceView; 41 #endif 42 43 typedef void* HANDLE; 44 45 namespace mozilla { 46 47 enum class VideoRotation; 48 49 namespace layers { 50 51 class GPUVideoImage; 52 class ImageClient; 53 class ImageCompositeNotification; 54 class ImageContainer; 55 class ImageContainerChild; 56 class SharedPlanarYCbCrImage; 57 class SurfaceDescriptor; 58 class PlanarYCbCrImage; 59 class TextureClient; 60 class TextureClientRecycleAllocator; 61 class KnowsCompositor; 62 class NVImage; 63 class MemoryOrShmem; 64 #ifdef XP_WIN 65 class D3D11RecycleAllocator; 66 class D3D11YCbCrRecycleAllocator; 67 #endif 68 #ifdef XP_DARWIN 69 class MacIOSurfaceRecycleAllocator; 70 #endif 71 class SurfaceDescriptorBuffer; 72 enum class VideoBridgeSource : uint8_t; 73 74 struct ImageBackendData { 75 virtual ~ImageBackendData() = default; 76 77 protected: 78 ImageBackendData() = default; 79 }; 80 81 /* Forward declarations for Image derivatives. */ 82 class GLImage; 83 class SharedRGBImage; 84 #ifdef MOZ_WIDGET_ANDROID 85 class SurfaceTextureImage; 86 #elif defined(XP_DARWIN) 87 class MacIOSurfaceImage; 88 #elif MOZ_WIDGET_GTK 89 class DMABUFSurfaceImage; 90 #endif 91 92 /** 93 * A class representing a buffer of pixel data. The data can be in one 94 * of various formats including YCbCr. 95 * 96 * Create an image using an ImageContainer. Fill the image with data, and 97 * then call ImageContainer::SetImage to display it. An image must not be 98 * modified after calling SetImage. Image implementations do not need to 99 * perform locking; when filling an Image, the Image client is responsible 100 * for ensuring only one thread accesses the Image at a time, and after 101 * SetImage the image is immutable. 102 * 103 * When resampling an Image, only pixels within the buffer should be 104 * sampled. For example, cairo images should be sampled in EXTEND_PAD mode. 105 */ 106 class Image { 107 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image) 108 109 public: 110 ImageFormat GetFormat() const { return mFormat; } 111 void* GetImplData() const { return mImplData; } 112 113 virtual gfx::IntSize GetSize() const = 0; 114 virtual gfx::IntPoint GetOrigin() const { return gfx::IntPoint(0, 0); } 115 virtual gfx::IntRect GetPictureRect() const { 116 return gfx::IntRect(GetOrigin().x, GetOrigin().y, GetSize().width, 117 GetSize().height); 118 } 119 virtual gfx::ColorDepth GetColorDepth() const { 120 return gfx::ColorDepth::COLOR_8; 121 } 122 123 ImageBackendData* GetBackendData(LayersBackend aBackend) { 124 return mBackendData[aBackend].get(); 125 } 126 void SetBackendData(LayersBackend aBackend, ImageBackendData* aData) { 127 mBackendData[aBackend] = mozilla::WrapUnique(aData); 128 } 129 130 int32_t GetSerial() const { return mSerial; } 131 132 bool IsDRM() const { return mIsDRM; } 133 virtual void SetIsDRM(bool aIsDRM) { mIsDRM = aIsDRM; } 134 135 virtual void OnPrepareForwardToHost() {} 136 virtual void OnAbandonForwardToHost() {} 137 virtual void OnSetCurrent() {} 138 139 virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() = 0; 140 141 enum class BuildSdbFlags : uint8_t { 142 Default = 0, 143 RgbOnly = 1 << 0, 144 }; 145 146 virtual nsresult BuildSurfaceDescriptorBuffer( 147 SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags, 148 const std::function<MemoryOrShmem(uint32_t)>& aAllocate); 149 150 /** 151 * Get a SurfaceDescriptorGPUVideo if possible, with the source matching aDest 152 * if given. Otherwise copy the data into a SurfaceDescriptorBuffer. 153 */ 154 nsresult BuildSurfaceDescriptorGPUVideoOrBuffer( 155 SurfaceDescriptor& aSd, BuildSdbFlags aFlags, 156 const Maybe<VideoBridgeSource>& aDest, 157 const std::function<MemoryOrShmem(uint32_t)>& aAllocate, 158 const std::function<void(MemoryOrShmem&&)>& aFree); 159 160 virtual bool IsValid() const { return true; } 161 162 /** 163 * For use with the TextureForwarder only (so that the later can 164 * synchronize the TextureClient with the TextureHost). 165 */ 166 virtual TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) { 167 return nullptr; 168 } 169 170 /* Access to derived classes. */ 171 virtual GLImage* AsGLImage() { return nullptr; } 172 virtual GPUVideoImage* AsGPUVideoImage() { return nullptr; } 173 #ifdef MOZ_WIDGET_ANDROID 174 virtual SurfaceTextureImage* AsSurfaceTextureImage() { return nullptr; } 175 #endif 176 #ifdef XP_DARWIN 177 virtual MacIOSurfaceImage* AsMacIOSurfaceImage() { return nullptr; } 178 #endif 179 virtual PlanarYCbCrImage* AsPlanarYCbCrImage() { return nullptr; } 180 #ifdef MOZ_WIDGET_GTK 181 virtual DMABUFSurfaceImage* AsDMABUFSurfaceImage() { return nullptr; } 182 #endif 183 184 virtual NVImage* AsNVImage() { return nullptr; } 185 186 virtual Maybe<SurfaceDescriptor> GetDesc(); 187 188 static nsresult AllocateSurfaceDescriptorBufferRgb( 189 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, 190 uint8_t*& aOutBuffer, SurfaceDescriptorBuffer& aSdBuffer, 191 int32_t& aStride, 192 const std::function<layers::MemoryOrShmem(uint32_t)>& aAllocate); 193 194 protected: 195 Maybe<SurfaceDescriptor> GetDescFromTexClient( 196 TextureClient* tcOverride = nullptr); 197 198 Image(void* aImplData, ImageFormat aFormat) 199 : mImplData(aImplData), 200 mSerial(++sSerialCounter), 201 mFormat(aFormat), 202 mIsDRM(false) {} 203 204 // Protected destructor, to discourage deletion outside of Release(): 205 virtual ~Image() = default; 206 207 mozilla::EnumeratedArray<mozilla::layers::LayersBackend, 208 UniquePtr<ImageBackendData>, 209 size_t(mozilla::layers::LayersBackend::LAYERS_LAST)> 210 mBackendData; 211 212 void* mImplData; 213 int32_t mSerial; 214 ImageFormat mFormat; 215 bool mIsDRM; 216 217 static mozilla::Atomic<int32_t> sSerialCounter; 218 }; 219 220 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Image::BuildSdbFlags) 221 222 /** 223 * A RecycleBin is owned by an ImageContainer. We store buffers in it that we 224 * want to recycle from one image to the next.It's a separate object from 225 * ImageContainer because images need to store a strong ref to their RecycleBin 226 * and we must avoid creating a reference loop between an ImageContainer and 227 * its active image. 228 */ 229 class BufferRecycleBin final { 230 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BufferRecycleBin) 231 232 // typedef mozilla::gl::GLContext GLContext; 233 234 public: 235 BufferRecycleBin(); 236 237 void RecycleBuffer(mozilla::UniquePtr<uint8_t[]> aBuffer, uint32_t aSize); 238 // Returns a recycled buffer of the right size, or allocates a new buffer. 239 mozilla::UniquePtr<uint8_t[]> GetBuffer(uint32_t aSize); 240 void ClearRecycledBuffers(); 241 242 private: 243 typedef mozilla::Mutex Mutex; 244 245 // Private destructor, to discourage deletion outside of Release(): 246 ~BufferRecycleBin() = default; 247 248 // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures 249 // and mRecycledTextureSizes 250 Mutex mLock; 251 252 // We should probably do something to prune this list on a timer so we don't 253 // eat excess memory while video is paused... 254 nsTArray<mozilla::UniquePtr<uint8_t[]>> mRecycledBuffers 255 MOZ_GUARDED_BY(mLock); 256 // This is only valid if mRecycledBuffers is non-empty 257 uint32_t mRecycledBufferSize MOZ_GUARDED_BY(mLock); 258 }; 259 260 /** 261 * A class that manages Image creation for a LayerManager. The only reason 262 * we need a separate class here is that LayerManagers aren't threadsafe 263 * (because layers can only be used on the main thread) and we want to 264 * be able to create images from any thread, to facilitate video playback 265 * without involving the main thread, for example. 266 * Different layer managers can implement child classes of this making it 267 * possible to create layer manager specific images. 268 * This class is not meant to be used directly but rather can be set on an 269 * image container. This is usually done by the layer system internally and 270 * not explicitly by users. For PlanarYCbCr or Cairo images the default 271 * implementation will creates images whose data lives in system memory, for 272 * MacIOSurfaces the default implementation will be a simple MacIOSurface 273 * wrapper. 274 */ 275 276 class ImageFactory { 277 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory) 278 protected: 279 friend class ImageContainer; 280 281 ImageFactory() = default; 282 virtual ~ImageFactory() = default; 283 284 virtual RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage( 285 const gfx::IntSize& aScaleHint, BufferRecycleBin* aRecycleBin); 286 }; 287 288 // Used to notify ImageContainer::NotifyComposite() 289 class ImageContainerListener final { 290 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainerListener) 291 292 public: 293 explicit ImageContainerListener(ImageContainer* aImageContainer); 294 295 void NotifyComposite(const ImageCompositeNotification& aNotification); 296 void NotifyDropped(uint32_t aDropped); 297 void ClearImageContainer(); 298 void DropImageClient(); 299 300 private: 301 typedef mozilla::Mutex Mutex; 302 303 ~ImageContainerListener(); 304 305 Mutex mLock; 306 ImageContainer* mImageContainer MOZ_GUARDED_BY(mLock); 307 }; 308 309 enum class ClearImagesType { All, CacheOnly }; 310 311 /** 312 * A class that manages Images for an ImageLayer. The only reason 313 * we need a separate class here is that ImageLayers aren't threadsafe 314 * (because layers can only be used on the main thread) and we want to 315 * be able to set the current Image from any thread, to facilitate 316 * video playback without involving the main thread, for example. 317 * 318 * An ImageContainer can operate in one of these modes: 319 * 1) Normal. Triggered by constructing the ImageContainer with 320 * DISABLE_ASYNC or when compositing is happening on the main thread. 321 * SetCurrentImages changes ImageContainer state but nothing is sent to the 322 * compositor until the next layer transaction. 323 * 2) Asynchronous. Initiated by constructing the ImageContainer with 324 * ENABLE_ASYNC when compositing is happening on the main thread. 325 * SetCurrentImages sends a message through the ImageBridge to the compositor 326 * thread to update the image, without going through the main thread or 327 * a layer transaction. 328 * The ImageContainer uses a shared memory block containing a cross-process 329 * mutex to communicate with the compositor thread. SetCurrentImage 330 * synchronously updates the shared state to point to the new image and the old 331 * image is immediately released (not true in Normal or Asynchronous modes). 332 */ 333 class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> { 334 friend class ImageContainerChild; 335 336 public: 337 MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer) 338 339 enum Mode { SYNCHRONOUS = 0x0, ASYNCHRONOUS = 0x01 }; 340 341 static const uint64_t sInvalidAsyncContainerId = 0; 342 343 ImageContainer(ImageUsageType aUsageType, ImageContainer::Mode aFlag); 344 345 ~ImageContainer(); 346 347 using FrameID = ContainerFrameID; 348 using ProducerID = ContainerProducerID; 349 using CaptureTime = ContainerCaptureTime; 350 using ReceiveTime = ContainerReceiveTime; 351 using RtpTimestamp = ContainerRtpTimestamp; 352 353 RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage(); 354 355 // Factory methods for shared image types. 356 RefPtr<SharedRGBImage> CreateSharedRGBImage(); 357 358 struct NonOwningImage { 359 explicit NonOwningImage( 360 Image* aImage = nullptr, TimeStamp aTimeStamp = TimeStamp(), 361 FrameID aFrameID = 0, ProducerID aProducerID = 0, 362 media::TimeUnit aProcessingDuration = media::TimeUnit::Invalid(), 363 media::TimeUnit aMediaTime = media::TimeUnit::Invalid(), 364 const CaptureTime& aWebrtcCaptureTime = AsVariant(Nothing()), 365 const ReceiveTime& aWebrtcReceiveTime = Nothing(), 366 const RtpTimestamp& aRtpTimestamp = Nothing()) 367 : mImage(aImage), 368 mTimeStamp(aTimeStamp), 369 mFrameID(aFrameID), 370 mProducerID(aProducerID), 371 mProcessingDuration(aProcessingDuration), 372 mMediaTime(aMediaTime), 373 mWebrtcCaptureTime(aWebrtcCaptureTime), 374 mWebrtcReceiveTime(aWebrtcReceiveTime), 375 mRtpTimestamp(aRtpTimestamp) {} 376 Image* mImage; 377 TimeStamp mTimeStamp; 378 FrameID mFrameID; 379 ProducerID mProducerID; 380 media::TimeUnit mProcessingDuration = media::TimeUnit::Invalid(); 381 media::TimeUnit mMediaTime = media::TimeUnit::Invalid(); 382 CaptureTime mWebrtcCaptureTime = AsVariant(Nothing()); 383 ReceiveTime mWebrtcReceiveTime; 384 RtpTimestamp mRtpTimestamp; 385 }; 386 /** 387 * Set aImages as the list of timestamped to display. The Images must have 388 * been created by this ImageContainer. 389 * Can be called on any thread. This method takes mRecursiveMutex 390 * when accessing thread-shared state. 391 * aImages must be non-empty. The first timestamp in the list may be 392 * null but the others must not be, and the timestamps must increase. 393 * Every element of aImages must have non-null mImage. 394 * mFrameID can be zero, in which case you won't get meaningful 395 * painted/dropped frame counts. Otherwise you should use a unique and 396 * increasing ID for each decoded and submitted frame (but it's OK to 397 * pass the same frame to SetCurrentImages). 398 * mProducerID is a unique ID for the stream of images. A change in the 399 * mProducerID means changing to a new mFrameID namespace. All frames in 400 * aImages must have the same mProducerID. 401 * 402 * The Image data must not be modified after this method is called! 403 * Note that this must not be called if ENABLE_ASYNC has not been set. 404 * 405 * The implementation calls CurrentImageChanged() while holding 406 * mRecursiveMutex. 407 * 408 * If this ImageContainer has an ImageClient for async video: 409 * Schedule a task to send the image to the compositor using the 410 * PImageBridge protcol without using the main thread. 411 */ 412 void SetCurrentImages(const nsTArray<NonOwningImage>& aImages); 413 414 /** 415 * Clear images in host. It could be used only with async ImageContainer. 416 * Because we may release the lock after acquiring it in this method, it 417 * cannot be called with the lock held. 418 */ 419 void ClearImagesInHost(ClearImagesType aType) MOZ_EXCLUDES(mRecursiveMutex); 420 421 /** 422 * Clear any resources that are not immediately necessary. This may be called 423 * in low-memory conditions. 424 */ 425 void ClearCachedResources(); 426 427 /** 428 * Clear the current images. 429 * This function is expect to be called only from a CompositableClient 430 * that belongs to ImageBridgeChild. Created to prevent dead lock. 431 * See Bug 901224. 432 */ 433 void ClearImagesFromImageBridge(); 434 435 /** 436 * Set an Image as the current image to display. The Image must have 437 * been created by this ImageContainer. 438 * Must be called on the main thread, within a layers transaction. 439 * 440 * This method takes mRecursiveMutex 441 * when accessing thread-shared state. 442 * aImage can be null. While it's null, nothing will be painted. 443 * 444 * The Image data must not be modified after this method is called! 445 * Note that this must not be called if ENABLE_ASYNC been set. 446 * 447 * You won't get meaningful painted/dropped counts when using this method. 448 */ 449 void SetCurrentImageInTransaction(Image* aImage); 450 void SetCurrentImagesInTransaction(const nsTArray<NonOwningImage>& aImages); 451 452 /** 453 * Returns true if this ImageContainer uses the ImageBridge IPDL protocol. 454 * 455 * Can be called from any thread. 456 */ 457 bool IsAsync() const; 458 459 /** 460 * If this ImageContainer uses ImageBridge, returns the ID associated to 461 * this container, for use in the ImageBridge protocol. 462 * Returns 0 if this ImageContainer does not use ImageBridge. Note that 463 * 0 is always an invalid ID for asynchronous image containers. 464 * 465 * Can be called from any thread. 466 */ 467 CompositableHandle GetAsyncContainerHandle(); 468 469 /** 470 * Returns if the container currently has an image. 471 * Can be called on any thread. This method takes mRecursiveMutex 472 * when accessing thread-shared state. 473 */ 474 bool HasCurrentImage(); 475 476 struct OwningImage { 477 RefPtr<Image> mImage; 478 TimeStamp mTimeStamp; 479 media::TimeUnit mProcessingDuration = media::TimeUnit::Invalid(); 480 media::TimeUnit mMediaTime = media::TimeUnit::Invalid(); 481 CaptureTime mWebrtcCaptureTime = AsVariant(Nothing()); 482 ReceiveTime mWebrtcReceiveTime; 483 RtpTimestamp mRtpTimestamp; 484 FrameID mFrameID = 0; 485 ProducerID mProducerID = 0; 486 bool mComposited = false; 487 }; 488 /** 489 * Copy the current Image list to aImages. 490 * This has to add references since otherwise there are race conditions 491 * where the current image is destroyed before the caller can add 492 * a reference. 493 * Can be called on any thread. 494 * May return an empty list to indicate there is no current image. 495 * If aGenerationCounter is non-null, sets *aGenerationCounter to a value 496 * that's unique for this ImageContainer state. 497 */ 498 void GetCurrentImages(nsTArray<OwningImage>* aImages, 499 uint32_t* aGenerationCounter = nullptr); 500 501 /** 502 * Returns the size of the image in pixels. 503 * Can be called on any thread. This method takes mRecursiveMutex when 504 * accessing thread-shared state. 505 */ 506 gfx::IntSize GetCurrentSize(); 507 508 /** 509 * Sets a size that the image is expected to be rendered at. 510 * This is a hint for image backends to optimize scaling. 511 * Default implementation in this class is to ignore the hint. 512 * Can be called on any thread. This method takes mRecursiveMutex 513 * when accessing thread-shared state. 514 */ 515 void SetScaleHint(const gfx::IntSize& aScaleHint) { 516 RecursiveMutexAutoLock lock(mRecursiveMutex); 517 mScaleHint = aScaleHint; 518 } 519 520 const gfx::IntSize GetScaleHint() const { 521 RecursiveMutexAutoLock lock(mRecursiveMutex); 522 return mScaleHint; 523 } 524 525 void SetTransformHint(const gfx::Matrix& aTransformHint) { 526 RecursiveMutexAutoLock lock(mRecursiveMutex); 527 mTransformHint = aTransformHint; 528 } 529 530 const gfx::Matrix GetTransformHint() const { 531 RecursiveMutexAutoLock lock(mRecursiveMutex); 532 return mTransformHint; 533 } 534 535 void SetRotation(VideoRotation aRotation) { 536 MOZ_ASSERT(NS_IsMainThread()); 537 mRotation = aRotation; 538 } 539 540 VideoRotation GetRotation() const { 541 MOZ_ASSERT(NS_IsMainThread()); 542 return mRotation; 543 } 544 545 void SetImageFactory(ImageFactory* aFactory) { 546 RecursiveMutexAutoLock lock(mRecursiveMutex); 547 mImageFactory = aFactory ? aFactory : new ImageFactory(); 548 } 549 550 already_AddRefed<ImageFactory> GetImageFactory() const { 551 RecursiveMutexAutoLock lock(mRecursiveMutex); 552 return do_AddRef(mImageFactory); 553 } 554 555 void EnsureRecycleAllocatorForRDD(KnowsCompositor* aKnowsCompositor); 556 557 #ifdef XP_WIN 558 already_AddRefed<D3D11RecycleAllocator> GetD3D11RecycleAllocator( 559 KnowsCompositor* aKnowsCompositor, gfx::SurfaceFormat aPreferredFormat); 560 already_AddRefed<D3D11YCbCrRecycleAllocator> GetD3D11YCbCrRecycleAllocator( 561 KnowsCompositor* aKnowsCompositor); 562 #endif 563 564 #ifdef XP_DARWIN 565 already_AddRefed<MacIOSurfaceRecycleAllocator> 566 GetMacIOSurfaceRecycleAllocator(); 567 #endif 568 569 /** 570 * Returns the delay between the last composited image's presentation 571 * timestamp and when it was first composited. It's possible for the delay 572 * to be negative if the first image in the list passed to SetCurrentImages 573 * has a presentation timestamp greater than "now". 574 * Returns 0 if the composited image had a null timestamp, or if no 575 * image has been composited yet. 576 */ 577 TimeDuration GetPaintDelay() { 578 RecursiveMutexAutoLock lock(mRecursiveMutex); 579 return mPaintDelay; 580 } 581 582 /** 583 * Returns the number of images which have been contained in this container 584 * and painted at least once. Can be called from any thread. 585 */ 586 uint32_t GetPaintCount() { 587 RecursiveMutexAutoLock lock(mRecursiveMutex); 588 return mPaintCount; 589 } 590 591 /** 592 * An entry in the current image list "expires" when the entry has an 593 * non-null timestamp, and in a SetCurrentImages call the new image list is 594 * non-empty, the timestamp of the first new image is non-null and greater 595 * than the timestamp associated with the image, and the first new image's 596 * frameID is not the same as the entry's. 597 * Every expired image that is never composited is counted as dropped. 598 */ 599 uint32_t GetDroppedImageCount() { return mDroppedImageCount; } 600 601 void NotifyComposite(const ImageCompositeNotification& aNotification); 602 void NotifyDropped(uint32_t aDropped); 603 604 already_AddRefed<ImageContainerListener> GetImageContainerListener() const; 605 606 /** 607 * Get the ImageClient associated with this container. Returns only after 608 * validating, and it will recreate the image client if that fails. 609 * Returns nullptr if not applicable. 610 */ 611 already_AddRefed<ImageClient> GetImageClient(); 612 613 /** 614 * Main thread only. 615 */ 616 static ProducerID AllocateProducerID(); 617 618 void DropImageClient(); 619 620 const ImageUsageType mUsageType; 621 const bool mIsAsync; 622 623 private: 624 typedef mozilla::RecursiveMutex RecursiveMutex; 625 626 void SetCurrentImageInternal(const nsTArray<NonOwningImage>& aImages); 627 628 // This is called to ensure we have an active image, this may not be true 629 // when we're storing image information in a RemoteImageData structure. 630 // NOTE: If we have remote data mRemoteDataMutex should be locked when 631 // calling this function! 632 void EnsureActiveImage(); 633 634 void EnsureImageClient() MOZ_REQUIRES(mRecursiveMutex); 635 636 bool HasImageClient() const { 637 RecursiveMutexAutoLock lock(mRecursiveMutex); 638 return !!mImageClient; 639 } 640 641 // RecursiveMutex to protect thread safe access to the "current 642 // image", and any other state which is shared between threads. 643 mutable RecursiveMutex mRecursiveMutex; 644 645 RefPtr<TextureClientRecycleAllocator> mRecycleAllocator 646 MOZ_GUARDED_BY(mRecursiveMutex); 647 648 #ifdef XP_WIN 649 RefPtr<D3D11RecycleAllocator> mD3D11RecycleAllocator 650 MOZ_GUARDED_BY(mRecursiveMutex); 651 652 RefPtr<D3D11YCbCrRecycleAllocator> mD3D11YCbCrRecycleAllocator 653 MOZ_GUARDED_BY(mRecursiveMutex); 654 #endif 655 #ifdef XP_DARWIN 656 RefPtr<MacIOSurfaceRecycleAllocator> mMacIOSurfaceRecycleAllocator 657 MOZ_GUARDED_BY(mRecursiveMutex); 658 #endif 659 660 nsTArray<OwningImage> mCurrentImages MOZ_GUARDED_BY(mRecursiveMutex); 661 662 // Updates every time mActiveImage changes 663 uint32_t mGenerationCounter MOZ_GUARDED_BY(mRecursiveMutex); 664 665 // Number of contained images that have been painted at least once. It's up 666 // to the ImageContainer implementation to ensure accesses to this are 667 // threadsafe. 668 uint32_t mPaintCount MOZ_GUARDED_BY(mRecursiveMutex); 669 670 // See GetPaintDelay. Accessed only with mRecursiveMutex held. 671 TimeDuration mPaintDelay MOZ_GUARDED_BY(mRecursiveMutex); 672 673 // See GetDroppedImageCount. 674 mozilla::Atomic<uint32_t> mDroppedImageCount; 675 676 // This is the image factory used by this container, layer managers using 677 // this container can set an alternative image factory that will be used to 678 // create images for this container. 679 RefPtr<ImageFactory> mImageFactory MOZ_GUARDED_BY(mRecursiveMutex); 680 681 gfx::IntSize mScaleHint MOZ_GUARDED_BY(mRecursiveMutex); 682 683 gfx::Matrix mTransformHint MOZ_GUARDED_BY(mRecursiveMutex); 684 685 // Main thread only. 686 VideoRotation mRotation; 687 688 RefPtr<BufferRecycleBin> mRecycleBin MOZ_GUARDED_BY(mRecursiveMutex); 689 690 // This member points to an ImageClient if this ImageContainer was 691 // sucessfully created with ENABLE_ASYNC, or points to null otherwise. 692 // 'unsuccessful' in this case only means that the ImageClient could not 693 // be created, most likely because off-main-thread compositing is not enabled. 694 // In this case the ImageContainer is perfectly usable, but it will forward 695 // frames to the compositor through transactions in the main thread rather 696 // than asynchronusly using the ImageBridge IPDL protocol. 697 RefPtr<ImageClient> mImageClient MOZ_GUARDED_BY(mRecursiveMutex); 698 699 CompositableHandle mAsyncContainerHandle MOZ_GUARDED_BY(mRecursiveMutex); 700 701 // ProducerID for last current image(s) 702 ProducerID mCurrentProducerID MOZ_GUARDED_BY(mRecursiveMutex); 703 704 RefPtr<ImageContainerListener> mNotifyCompositeListener; 705 706 static mozilla::Atomic<uint32_t> sGenerationCounter; 707 }; 708 709 class AutoLockImage { 710 public: 711 explicit AutoLockImage(ImageContainer* aContainer) { 712 aContainer->GetCurrentImages(&mImages); 713 } 714 715 bool HasImage() const { return !mImages.IsEmpty(); } 716 Image* GetImage() const { 717 return mImages.IsEmpty() ? nullptr : mImages[0].mImage.get(); 718 } 719 720 const ImageContainer::OwningImage* GetOwningImage( 721 TimeStamp aTimeStamp) const { 722 if (mImages.IsEmpty()) { 723 return nullptr; 724 } 725 726 MOZ_ASSERT(!aTimeStamp.IsNull()); 727 uint32_t chosenIndex = 0; 728 729 while (chosenIndex + 1 < mImages.Length() && 730 mImages[chosenIndex + 1].mTimeStamp <= aTimeStamp) { 731 ++chosenIndex; 732 } 733 734 return &mImages[chosenIndex]; 735 } 736 737 Image* GetImage(TimeStamp aTimeStamp) const { 738 if (const auto* owningImage = GetOwningImage(aTimeStamp)) { 739 return owningImage->mImage.get(); 740 } 741 return nullptr; 742 } 743 744 private: 745 AutoTArray<ImageContainer::OwningImage, 4> mImages; 746 }; 747 748 // This type is currently only used for AVIF and WebCodecs therefore makes some 749 // specific assumptions (e.g., Alpha's bpc and stride is equal to Y's one) 750 struct PlanarAlphaData { 751 uint8_t* mChannel = nullptr; 752 gfx::IntSize mSize = gfx::IntSize(0, 0); 753 gfx::ColorDepth mDepth = gfx::ColorDepth::COLOR_8; 754 bool mPremultiplied = false; 755 }; 756 struct PlanarYCbCrData { 757 // Luminance buffer 758 uint8_t* mYChannel = nullptr; 759 int32_t mYStride = 0; 760 int32_t mYSkip = 0; 761 // Chroma buffers 762 uint8_t* mCbChannel = nullptr; 763 uint8_t* mCrChannel = nullptr; 764 int32_t mCbCrStride = 0; 765 int32_t mCbSkip = 0; 766 int32_t mCrSkip = 0; 767 // Alpha buffer and its metadata 768 Maybe<PlanarAlphaData> mAlpha = Nothing(); 769 // Picture region 770 gfx::IntRect mPictureRect = gfx::IntRect(0, 0, 0, 0); 771 StereoMode mStereoMode = StereoMode::MONO; 772 gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8; 773 gfx::YUVColorSpace mYUVColorSpace = gfx::YUVColorSpace::Default; 774 gfx::ColorSpace2 mColorPrimaries = gfx::ColorSpace2::UNKNOWN; 775 gfx::TransferFunction mTransferFunction = gfx::TransferFunction::BT709; 776 gfx::ColorRange mColorRange = gfx::ColorRange::LIMITED; 777 gfx::ChromaSubsampling mChromaSubsampling = gfx::ChromaSubsampling::FULL; 778 779 // The cropped picture size of the Y channel. 780 gfx::IntSize YPictureSize() const { return mPictureRect.Size(); } 781 782 // The cropped picture size of the Cb/Cr channels. 783 gfx::IntSize CbCrPictureSize() const { 784 return mCbCrStride > 0 ? gfx::ChromaSize(YPictureSize(), mChromaSubsampling) 785 : gfx::IntSize(0, 0); 786 } 787 788 // The total uncropped size of data in the Y channel. 789 gfx::IntSize YDataSize() const { 790 return gfx::IntSize(mPictureRect.XMost(), mPictureRect.YMost()); 791 } 792 793 // The total uncropped size of data in the Cb/Cr channels. 794 gfx::IntSize CbCrDataSize() const { 795 return mCbCrStride > 0 ? gfx::ChromaSize(YDataSize(), mChromaSubsampling) 796 : gfx::IntSize(0, 0); 797 } 798 799 static Maybe<PlanarYCbCrData> From(const SurfaceDescriptorBuffer&); 800 static Maybe<PlanarYCbCrData> From(const VideoData::YCbCrBuffer&); 801 }; 802 803 /****** Image subtypes for the different formats ******/ 804 805 /** 806 * We assume that the image data is in the REC 470M color space (see 807 * Theora specification, section 4.3.1). 808 * 809 * The YCbCr format can be: 810 * 811 * 4:4:4 - CbCr width/height are the same as Y. 812 * 4:2:2 - CbCr width is half that of Y. Height is the same. 813 * 4:2:0 - CbCr width and height is half that of Y. 814 * 815 * mChromaSubsampling specifies which YCbCr subsampling scheme to use. 816 * 817 * The Image that is rendered is the picture region defined by mPictureRect. 818 * 819 * mYSkip, mCbSkip, mCrSkip are added to support various output 820 * formats from hardware decoder. They are per-pixel skips in the 821 * source image. 822 * 823 * For example when image width is 640, mYStride is 670, mYSkip is 2, 824 * the mYChannel buffer looks like: 825 * 826 * |<----------------------- mYStride ----------------------------->| 827 * |<----------------- YDataSize().width ---------->| 828 * 0 3 6 9 12 15 18 21 639 669 829 * |----------------------------------------------------------------| 830 * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%%%%%%%| 831 * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%%%%%%%| 832 * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%%%%%%%| 833 * | |<->| 834 * mYSkip 835 */ 836 class PlanarYCbCrImage : public Image { 837 public: 838 typedef PlanarYCbCrData Data; 839 840 enum { MAX_DIMENSION = 16384 }; 841 842 virtual ~PlanarYCbCrImage(); 843 844 /** 845 * This makes a copy of the data buffers, in order to support functioning 846 * in all different layer managers. 847 */ 848 virtual nsresult CopyData(const Data& aData) = 0; 849 850 /** 851 * This doesn't make a copy of the data buffers. 852 */ 853 virtual nsresult AdoptData(const Data& aData); 854 855 /** 856 * This will create an empty data buffers according to the input data's size. 857 */ 858 virtual nsresult CreateEmptyBuffer(const Data& aData, 859 const gfx::IntSize& aYSize, 860 const gfx::IntSize& aCbCrSize) { 861 return NS_ERROR_NOT_IMPLEMENTED; 862 } 863 864 /** 865 * Grab the original YUV data. This is optional. 866 */ 867 virtual const Data* GetData() const { return &mData; } 868 869 /** 870 * Return the number of bytes of heap memory used to store this image. 871 */ 872 uint32_t GetDataSize() const { return mBufferSize; } 873 874 bool IsValid() const override { return !!mBufferSize; } 875 876 gfx::IntSize GetSize() const override { return mSize; } 877 878 gfx::IntPoint GetOrigin() const override { return mOrigin; } 879 880 PlanarYCbCrImage(); 881 882 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { 883 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 884 } 885 886 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const = 0; 887 888 PlanarYCbCrImage* AsPlanarYCbCrImage() override { return this; } 889 890 /** 891 * Build a SurfaceDescriptorBuffer with this image. A function to allocate 892 * a MemoryOrShmem with the given capacity must be provided. 893 */ 894 nsresult BuildSurfaceDescriptorBuffer( 895 SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags, 896 const std::function<MemoryOrShmem(uint32_t)>& aAllocate) override; 897 898 void SetColorDepth(gfx::ColorDepth aColorDepth) { mColorDepth = aColorDepth; } 899 900 gfx::ColorDepth GetColorDepth() const override { return mColorDepth; } 901 902 protected: 903 already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override; 904 905 void SetOffscreenFormat(gfxImageFormat aFormat) { 906 mOffscreenFormat = aFormat; 907 } 908 gfxImageFormat GetOffscreenFormat() const; 909 910 Data mData; 911 gfx::IntPoint mOrigin; 912 gfx::IntSize mSize; 913 gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8; 914 gfxImageFormat mOffscreenFormat; 915 RefPtr<gfx::DataSourceSurface> mSourceSurface; 916 uint32_t mBufferSize; 917 }; 918 919 class RecyclingPlanarYCbCrImage : public PlanarYCbCrImage { 920 public: 921 explicit RecyclingPlanarYCbCrImage(BufferRecycleBin* aRecycleBin) 922 : mRecycleBin(aRecycleBin) {} 923 virtual ~RecyclingPlanarYCbCrImage(); 924 nsresult CopyData(const Data& aData) override; 925 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; 926 927 protected: 928 /** 929 * Return a buffer to store image data in. 930 */ 931 mozilla::UniquePtr<uint8_t[]> AllocateBuffer(uint32_t aSize); 932 933 RefPtr<BufferRecycleBin> mRecycleBin; 934 mozilla::UniquePtr<uint8_t[]> mBuffer; 935 }; 936 937 /** 938 * NVImage is used to store YUV420SP_NV12 and YUV420SP_NV21 data natively, which 939 * are not supported by PlanarYCbCrImage. (PlanarYCbCrImage only stores YUV444P, 940 * YUV422P and YUV420P, it converts YUV420SP_NV12 and YUV420SP_NV21 data into 941 * YUV420P in its PlanarYCbCrImage::SetData() method.) 942 * 943 * PlanarYCbCrData is able to express all the YUV family and so we keep use it 944 * in NVImage. 945 */ 946 class NVImage final : public Image { 947 typedef PlanarYCbCrData Data; 948 949 public: 950 NVImage(); 951 virtual ~NVImage(); 952 953 // Methods inherited from layers::Image. 954 gfx::IntSize GetSize() const override; 955 gfx::IntRect GetPictureRect() const override; 956 already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override; 957 nsresult BuildSurfaceDescriptorBuffer( 958 SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags, 959 const std::function<MemoryOrShmem(uint32_t)>& aAllocate) override; 960 bool IsValid() const override; 961 NVImage* AsNVImage() override; 962 963 // Methods mimic layers::PlanarYCbCrImage. 964 nsresult SetData(const Data& aData); 965 const Data* GetData() const; 966 uint32_t GetBufferSize() const; 967 968 protected: 969 /** 970 * Return a buffer to store image data in. 971 */ 972 mozilla::UniquePtr<uint8_t[]> AllocateBuffer(uint32_t aSize); 973 974 mozilla::UniquePtr<uint8_t[]> mBuffer; 975 uint32_t mBufferSize; 976 gfx::IntSize mSize; 977 Data mData; 978 RefPtr<gfx::DataSourceSurface> mSourceSurface; 979 }; 980 981 /** 982 * Currently, the data in a SourceSurfaceImage surface is treated as being in 983 * the device output color space. This class is very simple as all backends have 984 * to know about how to deal with drawing a cairo image. 985 */ 986 class SourceSurfaceImage final : public Image { 987 public: 988 already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override { 989 RefPtr<gfx::SourceSurface> surface(mSourceSurface); 990 return surface.forget(); 991 } 992 993 void SetTextureFlags(TextureFlags aTextureFlags) { 994 mTextureFlags = aTextureFlags; 995 } 996 TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) override; 997 998 gfx::IntSize GetSize() const override { return mSize; } 999 1000 SourceSurfaceImage(const gfx::IntSize& aSize, 1001 gfx::SourceSurface* aSourceSurface); 1002 explicit SourceSurfaceImage(gfx::SourceSurface* aSourceSurface); 1003 virtual ~SourceSurfaceImage(); 1004 1005 private: 1006 gfx::IntSize mSize; 1007 RefPtr<gfx::SourceSurface> mSourceSurface; 1008 nsTHashMap<uint32_t, RefPtr<TextureClient>> mTextureClients; 1009 TextureFlags mTextureFlags; 1010 }; 1011 1012 } // namespace layers 1013 } // namespace mozilla 1014 1015 #endif