Coverage Report

Created: 2018-09-25 14:53

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