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