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