gfx/layers/ImageContainer.h

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:b4665e5f33db
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/mozalloc.h" // for operator delete, etc
20 #include "nsAutoPtr.h" // for nsRefPtr, nsAutoArrayPtr, etc
21 #include "nsAutoRef.h" // for nsCountedRef
22 #include "nsCOMPtr.h" // for already_AddRefed
23 #include "nsDebug.h" // for NS_ASSERTION
24 #include "nsISupportsImpl.h" // for Image::Release, etc
25 #include "nsRect.h" // for nsIntRect
26 #include "nsSize.h" // for nsIntSize
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
35 #ifndef XPCOM_GLUE_AVOID_NSPR
36 /**
37 * We need to be able to hold a reference to a Moz2D SourceSurface from Image
38 * subclasses. This is potentially a problem since Images can be addrefed
39 * or released off the main thread. We can ensure that we never AddRef
40 * a SourceSurface off the main thread, but we might want to Release due
41 * to an Image being destroyed off the main thread.
42 *
43 * We use nsCountedRef<nsMainThreadSourceSurfaceRef> to reference the
44 * SourceSurface. When AddRefing, we assert that we're on the main thread.
45 * When Releasing, if we're not on the main thread, we post an event to
46 * the main thread to do the actual release.
47 */
48 class nsMainThreadSourceSurfaceRef;
49
50 template <>
51 class nsAutoRefTraits<nsMainThreadSourceSurfaceRef> {
52 public:
53 typedef mozilla::gfx::SourceSurface* RawRef;
54
55 /**
56 * The XPCOM event that will do the actual release on the main thread.
57 */
58 class SurfaceReleaser : public nsRunnable {
59 public:
60 SurfaceReleaser(RawRef aRef) : mRef(aRef) {}
61 NS_IMETHOD Run() {
62 mRef->Release();
63 return NS_OK;
64 }
65 RawRef mRef;
66 };
67
68 static RawRef Void() { return nullptr; }
69 static void Release(RawRef aRawRef)
70 {
71 if (NS_IsMainThread()) {
72 aRawRef->Release();
73 return;
74 }
75 nsCOMPtr<nsIRunnable> runnable = new SurfaceReleaser(aRawRef);
76 NS_DispatchToMainThread(runnable);
77 }
78 static void AddRef(RawRef aRawRef)
79 {
80 NS_ASSERTION(NS_IsMainThread(),
81 "Can only add a reference on the main thread");
82 aRawRef->AddRef();
83 }
84 };
85
86 #endif
87
88 #ifdef XP_WIN
89 struct ID3D10Texture2D;
90 struct ID3D10Device;
91 struct ID3D10ShaderResourceView;
92 #endif
93
94 typedef void* HANDLE;
95
96 namespace mozilla {
97
98 class CrossProcessMutex;
99
100 namespace layers {
101
102 class ImageClient;
103 class SharedPlanarYCbCrImage;
104 class TextureClient;
105 class CompositableClient;
106 class CompositableForwarder;
107 class SurfaceDescriptor;
108
109 struct ImageBackendData
110 {
111 virtual ~ImageBackendData() {}
112
113 protected:
114 ImageBackendData() {}
115 };
116
117 // sadly we'll need this until we get rid of Deprected image classes
118 class ISharedImage {
119 public:
120 virtual uint8_t* GetBuffer() = 0;
121
122 /**
123 * For use with the CompositableClient only (so that the later can
124 * synchronize the TextureClient with the TextureHost).
125 */
126 virtual TextureClient* GetTextureClient(CompositableClient* aClient) = 0;
127 };
128
129 /**
130 * A class representing a buffer of pixel data. The data can be in one
131 * of various formats including YCbCr.
132 *
133 * Create an image using an ImageContainer. Fill the image with data, and
134 * then call ImageContainer::SetImage to display it. An image must not be
135 * modified after calling SetImage. Image implementations do not need to
136 * perform locking; when filling an Image, the Image client is responsible
137 * for ensuring only one thread accesses the Image at a time, and after
138 * SetImage the image is immutable.
139 *
140 * When resampling an Image, only pixels within the buffer should be
141 * sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
142 */
143 class Image {
144 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
145
146 public:
147 virtual ISharedImage* AsSharedImage() { return nullptr; }
148
149 ImageFormat GetFormat() { return mFormat; }
150 void* GetImplData() { return mImplData; }
151
152 virtual gfx::IntSize GetSize() = 0;
153 virtual nsIntRect GetPictureRect()
154 {
155 return nsIntRect(0, 0, GetSize().width, GetSize().height);
156 }
157
158 ImageBackendData* GetBackendData(LayersBackend aBackend)
159 { return mBackendData[aBackend]; }
160 void SetBackendData(LayersBackend aBackend, ImageBackendData* aData)
161 { mBackendData[aBackend] = aData; }
162
163 int32_t GetSerial() { return mSerial; }
164
165 void MarkSent() { mSent = true; }
166 bool IsSentToCompositor() { return mSent; }
167
168 virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
169
170 protected:
171 Image(void* aImplData, ImageFormat aFormat) :
172 mImplData(aImplData),
173 mSerial(++sSerialCounter),
174 mFormat(aFormat),
175 mSent(false)
176 {}
177
178 // Protected destructor, to discourage deletion outside of Release():
179 virtual ~Image() {}
180
181 mozilla::EnumeratedArray<mozilla::layers::LayersBackend,
182 mozilla::layers::LayersBackend::LAYERS_LAST,
183 nsAutoPtr<ImageBackendData>>
184 mBackendData;
185
186 void* mImplData;
187 int32_t mSerial;
188 ImageFormat mFormat;
189 static mozilla::Atomic<int32_t> sSerialCounter;
190 bool mSent;
191 };
192
193 /**
194 * A RecycleBin is owned by an ImageContainer. We store buffers in it that we
195 * want to recycle from one image to the next.It's a separate object from
196 * ImageContainer because images need to store a strong ref to their RecycleBin
197 * and we must avoid creating a reference loop between an ImageContainer and
198 * its active image.
199 */
200 class BufferRecycleBin MOZ_FINAL {
201 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
202
203 //typedef mozilla::gl::GLContext GLContext;
204
205 public:
206 BufferRecycleBin();
207
208 void RecycleBuffer(uint8_t* aBuffer, uint32_t aSize);
209 // Returns a recycled buffer of the right size, or allocates a new buffer.
210 uint8_t* GetBuffer(uint32_t aSize);
211
212 private:
213 typedef mozilla::Mutex Mutex;
214
215 // Private destructor, to discourage deletion outside of Release():
216 ~BufferRecycleBin()
217 {
218 }
219
220 // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
221 // and mRecycledTextureSizes
222 Mutex mLock;
223
224 // We should probably do something to prune this list on a timer so we don't
225 // eat excess memory while video is paused...
226 nsTArray<nsAutoArrayPtr<uint8_t> > mRecycledBuffers;
227 // This is only valid if mRecycledBuffers is non-empty
228 uint32_t mRecycledBufferSize;
229 };
230
231 class CompositionNotifySink
232 {
233 public:
234 virtual void DidComposite() = 0;
235 virtual ~CompositionNotifySink() {}
236 };
237
238 /**
239 * A class that manages Image creation for a LayerManager. The only reason
240 * we need a separate class here is that LayerManagers aren't threadsafe
241 * (because layers can only be used on the main thread) and we want to
242 * be able to create images from any thread, to facilitate video playback
243 * without involving the main thread, for example.
244 * Different layer managers can implement child classes of this making it
245 * possible to create layer manager specific images.
246 * This class is not meant to be used directly but rather can be set on an
247 * image container. This is usually done by the layer system internally and
248 * not explicitly by users. For PlanarYCbCr or Cairo images the default
249 * implementation will creates images whose data lives in system memory, for
250 * MacIOSurfaces the default implementation will be a simple MacIOSurface
251 * wrapper.
252 */
253
254 class ImageFactory
255 {
256 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
257 protected:
258 friend class ImageContainer;
259
260 ImageFactory() {}
261 virtual ~ImageFactory() {}
262
263 virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat,
264 const gfx::IntSize &aScaleHint,
265 BufferRecycleBin *aRecycleBin);
266
267 };
268
269 /**
270 * This struct is used to store RemoteImages, it is meant to be able to live in
271 * shared memory. Therefor it should not contain a vtable pointer. Remote
272 * users can manipulate the data in this structure to specify what image is to
273 * be drawn by the container. When accessing this data users should make sure
274 * the mutex synchronizing access to the structure is held!
275 */
276 struct RemoteImageData {
277 enum Type {
278 /**
279 * This is a format that uses raw bitmap data.
280 */
281 RAW_BITMAP,
282
283 /**
284 * This is a format that uses a pointer to a texture do draw directly
285 * from a shared texture. Any process may have created this texture handle,
286 * the process creating the texture handle is responsible for managing it's
287 * lifetime by managing the lifetime of the first D3D texture object this
288 * handle was created for. It must also ensure the handle is not set
289 * current anywhere when the last reference to this object is released.
290 */
291 DXGI_TEXTURE_HANDLE
292 };
293 /* These formats describe the format in the memory byte-order */
294 enum Format {
295 /* 8 bits per channel */
296 BGRA32,
297 /* 8 bits per channel, alpha channel is ignored */
298 BGRX32
299 };
300
301 // This should be set to true if a change was made so that the ImageContainer
302 // knows to throw out any cached RemoteImage objects.
303 bool mWasUpdated;
304 Type mType;
305 Format mFormat;
306 gfx::IntSize mSize;
307 union {
308 struct {
309 /* This pointer is set by a remote process, however it will be set to
310 * the container process' address the memory of the raw bitmap resides
311 * at.
312 */
313 unsigned char *mData;
314 int mStride;
315 } mBitmap;
316 #ifdef XP_WIN
317 HANDLE mTextureHandle;
318 #endif
319 };
320 };
321
322 /**
323 * A class that manages Images for an ImageLayer. The only reason
324 * we need a separate class here is that ImageLayers aren't threadsafe
325 * (because layers can only be used on the main thread) and we want to
326 * be able to set the current Image from any thread, to facilitate
327 * video playback without involving the main thread, for example.
328 *
329 * An ImageContainer can operate in one of three modes:
330 * 1) Normal. Triggered by constructing the ImageContainer with
331 * DISABLE_ASYNC or when compositing is happening on the main thread.
332 * SetCurrentImage changes ImageContainer state but nothing is sent to the
333 * compositor until the next layer transaction.
334 * 2) Asynchronous. Initiated by constructing the ImageContainer with
335 * ENABLE_ASYNC when compositing is happening on the main thread.
336 * SetCurrentImage sends a message through the ImageBridge to the compositor
337 * thread to update the image, without going through the main thread or
338 * a layer transaction.
339 * 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer
340 * before any other activity.
341 * The ImageContainer uses a shared memory block containing a cross-process mutex
342 * to communicate with the compositor thread. SetCurrentImage synchronously
343 * updates the shared state to point to the new image and the old image
344 * is immediately released (not true in Normal or Asynchronous modes).
345 */
346 class ImageContainer MOZ_FINAL : public SupportsWeakPtr<ImageContainer> {
347 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
348 public:
349 MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer)
350
351 enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
352
353 ImageContainer(int flag = 0);
354
355 /**
356 * Create an Image in one of the given formats.
357 * Picks the "best" format from the list and creates an Image of that
358 * format.
359 * Returns null if this backend does not support any of the formats.
360 * Can be called on any thread. This method takes mReentrantMonitor
361 * when accessing thread-shared state.
362 */
363 already_AddRefed<Image> CreateImage(ImageFormat aFormat);
364
365 /**
366 * Set an Image as the current image to display. The Image must have
367 * been created by this ImageContainer.
368 * Can be called on any thread. This method takes mReentrantMonitor
369 * when accessing thread-shared state.
370 * aImage can be null. While it's null, nothing will be painted.
371 *
372 * The Image data must not be modified after this method is called!
373 * Note that this must not be called if ENABLE_ASYNC has not been set.
374 *
375 * Implementations must call CurrentImageChanged() while holding
376 * mReentrantMonitor.
377 *
378 * If this ImageContainer has an ImageClient for async video:
379 * Schelude a task to send the image to the compositor using the
380 * PImageBridge protcol without using the main thread.
381 */
382 void SetCurrentImage(Image* aImage);
383
384 /**
385 * Clear all images. Let ImageClient release all TextureClients.
386 */
387 void ClearAllImages();
388
389 /**
390 * Clear all images except current one.
391 * Let ImageClient release all TextureClients except front one.
392 */
393 void ClearAllImagesExceptFront();
394
395 /**
396 * Clear the current image.
397 * This function is expect to be called only from a CompositableClient
398 * that belongs to ImageBridgeChild. Created to prevent dead lock.
399 * See Bug 901224.
400 */
401 void ClearCurrentImage();
402
403 /**
404 * Set an Image as the current image to display. The Image must have
405 * been created by this ImageContainer.
406 * Must be called on the main thread, within a layers transaction.
407 *
408 * This method takes mReentrantMonitor
409 * when accessing thread-shared state.
410 * aImage can be null. While it's null, nothing will be painted.
411 *
412 * The Image data must not be modified after this method is called!
413 * Note that this must not be called if ENABLE_ASYNC been set.
414 *
415 * Implementations must call CurrentImageChanged() while holding
416 * mReentrantMonitor.
417 */
418 void SetCurrentImageInTransaction(Image* aImage);
419
420 /**
421 * Returns true if this ImageContainer uses the ImageBridge IPDL protocol.
422 *
423 * Can be called from any thread.
424 */
425 bool IsAsync() const;
426
427 /**
428 * If this ImageContainer uses ImageBridge, returns the ID associated to
429 * this container, for use in the ImageBridge protocol.
430 * Returns 0 if this ImageContainer does not use ImageBridge. Note that
431 * 0 is always an invalid ID for asynchronous image containers.
432 *
433 * Can be called from any thread.
434 */
435 uint64_t GetAsyncContainerID() const;
436
437 /**
438 * Returns if the container currently has an image.
439 * Can be called on any thread. This method takes mReentrantMonitor
440 * when accessing thread-shared state.
441 */
442 bool HasCurrentImage();
443
444 /**
445 * Lock the current Image.
446 * This has to add a reference since otherwise there are race conditions
447 * where the current image is destroyed before the caller can add
448 * a reference. This lock strictly guarantees the underlying image remains
449 * valid, it does not mean the current image cannot change.
450 * Can be called on any thread. This method will lock the cross-process
451 * mutex to ensure remote processes cannot alter underlying data. This call
452 * -must- be balanced by a call to UnlockCurrentImage and users should avoid
453 * holding the image locked for a long time.
454 */
455 already_AddRefed<Image> LockCurrentImage();
456
457 /**
458 * This call unlocks the image. For remote images releasing the cross-process
459 * mutex.
460 */
461 void UnlockCurrentImage();
462
463 /**
464 * Get the current image as a SourceSurface. This is useful for fallback
465 * rendering.
466 * This can only be called from the main thread, since cairo objects
467 * can only be used from the main thread.
468 * This is defined here and not on Image because it's possible (likely)
469 * that some backends will make an Image "ready to draw" only when it
470 * becomes the current image for an image container.
471 * Returns null if there is no current image.
472 * Returns the size in aSize.
473 * The returned surface will never be modified. The caller must not
474 * modify it.
475 * Can be called on any thread. This method takes mReentrantMonitor
476 * when accessing thread-shared state.
477 * If the current image is a remote image, that is, if it is an image that
478 * may be shared accross processes, calling this function will make
479 * a copy of the image data while holding the mRemoteDataMutex. If possible,
480 * the lock methods should be used to avoid the copy, however this should be
481 * avoided if the surface is required for a long period of time.
482 */
483 TemporaryRef<gfx::SourceSurface> GetCurrentAsSourceSurface(gfx::IntSize* aSizeResult);
484
485 /**
486 * Same as LockCurrentAsSurface but for Moz2D
487 */
488 TemporaryRef<gfx::SourceSurface> LockCurrentAsSourceSurface(gfx::IntSize* aSizeResult,
489 Image** aCurrentImage = nullptr);
490
491 /**
492 * Returns the size of the image in pixels.
493 * Can be called on any thread. This method takes mReentrantMonitor when accessing
494 * thread-shared state.
495 */
496 gfx::IntSize GetCurrentSize();
497
498 /**
499 * Sets a size that the image is expected to be rendered at.
500 * This is a hint for image backends to optimize scaling.
501 * Default implementation in this class is to ignore the hint.
502 * Can be called on any thread. This method takes mReentrantMonitor
503 * when accessing thread-shared state.
504 */
505 void SetScaleHint(const gfx::IntSize& aScaleHint)
506 { mScaleHint = aScaleHint; }
507
508 void SetImageFactory(ImageFactory *aFactory)
509 {
510 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
511 mImageFactory = aFactory ? aFactory : new ImageFactory();
512 }
513
514 /**
515 * Returns the time at which the currently contained image was first
516 * painted. This is reset every time a new image is set as the current
517 * image. Note this may return a null timestamp if the current image
518 * has not yet been painted. Can be called from any thread.
519 */
520 TimeStamp GetPaintTime() {
521 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
522 return mPaintTime;
523 }
524
525 /**
526 * Returns the number of images which have been contained in this container
527 * and painted at least once. Can be called from any thread.
528 */
529 uint32_t GetPaintCount() {
530 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
531 return mPaintCount;
532 }
533
534 /**
535 * Resets the paint count to zero.
536 * Can be called from any thread.
537 */
538 void ResetPaintCount() {
539 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
540 mPaintCount = 0;
541 }
542
543 /**
544 * Increments mPaintCount if this is the first time aPainted has been
545 * painted, and sets mPaintTime if the painted image is the current image.
546 * current image. Can be called from any thread.
547 */
548 void NotifyPaintedImage(Image* aPainted) {
549 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
550
551 nsRefPtr<Image> current = mActiveImage;
552 if (aPainted == current) {
553 if (mPaintTime.IsNull()) {
554 mPaintTime = TimeStamp::Now();
555 mPaintCount++;
556 }
557 } else if (!mPreviousImagePainted) {
558 // While we were painting this image, the current image changed. We
559 // still must count it as painted, but can't set mPaintTime, since we're
560 // no longer the current image.
561 mPaintCount++;
562 mPreviousImagePainted = true;
563 }
564
565 if (mCompositionNotifySink) {
566 mCompositionNotifySink->DidComposite();
567 }
568 }
569
570 void SetCompositionNotifySink(CompositionNotifySink *aSink) {
571 mCompositionNotifySink = aSink;
572 }
573
574 /**
575 * This function is called to tell the ImageContainer where the
576 * (cross-process) segment lives where the shared data about possible
577 * remote images are stored. In addition to this a CrossProcessMutex object
578 * is passed telling the container how to synchronize access to this data.
579 * NOTE: This should be called during setup of the container and not after
580 * usage has started.
581 */
582 void SetRemoteImageData(RemoteImageData *aRemoteData,
583 CrossProcessMutex *aRemoteDataMutex);
584 /**
585 * This can be used to check if the container has RemoteData set.
586 */
587 RemoteImageData *GetRemoteImageData() { return mRemoteData; }
588
589 private:
590 typedef mozilla::ReentrantMonitor ReentrantMonitor;
591
592 // Private destructor, to discourage deletion outside of Release():
593 ~ImageContainer();
594
595 void SetCurrentImageInternal(Image* aImage);
596
597 // This is called to ensure we have an active image, this may not be true
598 // when we're storing image information in a RemoteImageData structure.
599 // NOTE: If we have remote data mRemoteDataMutex should be locked when
600 // calling this function!
601 void EnsureActiveImage();
602
603 // ReentrantMonitor to protect thread safe access to the "current
604 // image", and any other state which is shared between threads.
605 ReentrantMonitor mReentrantMonitor;
606
607 // Performs necessary housekeeping to ensure the painted frame statistics
608 // are accurate. Must be called by SetCurrentImage() implementations with
609 // mReentrantMonitor held.
610 void CurrentImageChanged() {
611 mReentrantMonitor.AssertCurrentThreadIn();
612 mPreviousImagePainted = !mPaintTime.IsNull();
613 mPaintTime = TimeStamp();
614 }
615
616 nsRefPtr<Image> mActiveImage;
617
618 // Number of contained images that have been painted at least once. It's up
619 // to the ImageContainer implementation to ensure accesses to this are
620 // threadsafe.
621 uint32_t mPaintCount;
622
623 // Time stamp at which the current image was first painted. It's up to the
624 // ImageContainer implementation to ensure accesses to this are threadsafe.
625 TimeStamp mPaintTime;
626
627 // Denotes whether the previous image was painted.
628 bool mPreviousImagePainted;
629
630 // This is the image factory used by this container, layer managers using
631 // this container can set an alternative image factory that will be used to
632 // create images for this container.
633 nsRefPtr<ImageFactory> mImageFactory;
634
635 gfx::IntSize mScaleHint;
636
637 nsRefPtr<BufferRecycleBin> mRecycleBin;
638
639 // This contains the remote image data for this container, if this is nullptr
640 // that means the container has no other process that may control its active
641 // image.
642 RemoteImageData *mRemoteData;
643
644 // This cross-process mutex is used to synchronise access to mRemoteData.
645 // When this mutex is held, we will always be inside the mReentrantMonitor
646 // however the same is not true vice versa.
647 CrossProcessMutex *mRemoteDataMutex;
648
649 CompositionNotifySink *mCompositionNotifySink;
650
651 // This member points to an ImageClient if this ImageContainer was
652 // sucessfully created with ENABLE_ASYNC, or points to null otherwise.
653 // 'unsuccessful' in this case only means that the ImageClient could not
654 // be created, most likely because off-main-thread compositing is not enabled.
655 // In this case the ImageContainer is perfectly usable, but it will forward
656 // frames to the compositor through transactions in the main thread rather than
657 // asynchronusly using the ImageBridge IPDL protocol.
658 ImageClient* mImageClient;
659 };
660
661 class AutoLockImage
662 {
663 public:
664 AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
665 AutoLockImage(ImageContainer *aContainer, RefPtr<gfx::SourceSurface> *aSurface) : mContainer(aContainer) {
666 *aSurface = mContainer->LockCurrentAsSourceSurface(&mSize, getter_AddRefs(mImage));
667 }
668 ~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
669
670 Image* GetImage() { return mImage; }
671 const gfx::IntSize &GetSize() { return mSize; }
672
673 void Unlock() {
674 if (mContainer) {
675 mImage = nullptr;
676 mContainer->UnlockCurrentImage();
677 mContainer = nullptr;
678 }
679 }
680
681 /** Things get a little tricky here, because our underlying image can -still-
682 * change, and OS X requires a complicated callback mechanism to update this
683 * we need to support staying the lock and getting the new image in a proper
684 * way. This method makes any images retrieved with GetImage invalid!
685 */
686 void Refresh() {
687 if (mContainer) {
688 mContainer->UnlockCurrentImage();
689 mImage = mContainer->LockCurrentImage();
690 }
691 }
692
693 private:
694 ImageContainer *mContainer;
695 nsRefPtr<Image> mImage;
696 gfx::IntSize mSize;
697 };
698
699 struct PlanarYCbCrData {
700 // Luminance buffer
701 uint8_t* mYChannel;
702 int32_t mYStride;
703 gfx::IntSize mYSize;
704 int32_t mYSkip;
705 // Chroma buffers
706 uint8_t* mCbChannel;
707 uint8_t* mCrChannel;
708 int32_t mCbCrStride;
709 gfx::IntSize mCbCrSize;
710 int32_t mCbSkip;
711 int32_t mCrSkip;
712 // Picture region
713 uint32_t mPicX;
714 uint32_t mPicY;
715 gfx::IntSize mPicSize;
716 StereoMode mStereoMode;
717
718 nsIntRect GetPictureRect() const {
719 return nsIntRect(mPicX, mPicY,
720 mPicSize.width,
721 mPicSize.height);
722 }
723
724 PlanarYCbCrData()
725 : mYChannel(nullptr), mYStride(0), mYSize(0, 0), mYSkip(0)
726 , mCbChannel(nullptr), mCrChannel(nullptr)
727 , mCbCrStride(0), mCbCrSize(0, 0) , mCbSkip(0), mCrSkip(0)
728 , mPicX(0), mPicY(0), mPicSize(0, 0), mStereoMode(StereoMode::MONO)
729 {}
730 };
731
732 /****** Image subtypes for the different formats ******/
733
734 /**
735 * We assume that the image data is in the REC 470M color space (see
736 * Theora specification, section 4.3.1).
737 *
738 * The YCbCr format can be:
739 *
740 * 4:4:4 - CbCr width/height are the same as Y.
741 * 4:2:2 - CbCr width is half that of Y. Height is the same.
742 * 4:2:0 - CbCr width and height is half that of Y.
743 *
744 * The color format is detected based on the height/width ratios
745 * defined above.
746 *
747 * The Image that is rendered is the picture region defined by
748 * mPicX, mPicY and mPicSize. The size of the rendered image is
749 * mPicSize, not mYSize or mCbCrSize.
750 *
751 * mYSkip, mCbSkip, mCrSkip are added to support various output
752 * formats from hardware decoder. They are per-pixel skips in the
753 * source image.
754 *
755 * For example when image width is 640, mYStride is 670, mYSkip is 3,
756 * the mYChannel buffer looks like:
757 *
758 * |<----------------------- mYStride ----------------------------->|
759 * |<----------------- mYSize.width --------------->|
760 * 0 3 6 9 12 15 18 21 659 669
761 * |----------------------------------------------------------------|
762 * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%|
763 * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%|
764 * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%|
765 * | |<->|
766 * mYSkip
767 */
768 class PlanarYCbCrImage : public Image {
769 public:
770 typedef PlanarYCbCrData Data;
771
772 enum {
773 MAX_DIMENSION = 16384
774 };
775
776 virtual ~PlanarYCbCrImage();
777
778 /**
779 * This makes a copy of the data buffers, in order to support functioning
780 * in all different layer managers.
781 */
782 virtual void SetData(const Data& aData);
783
784 /**
785 * This doesn't make a copy of the data buffers. Can be used when mBuffer is
786 * pre allocated with AllocateAndGetNewBuffer(size) and then SetDataNoCopy is
787 * called to only update the picture size, planes etc. fields in mData.
788 * The GStreamer media backend uses this to decode into PlanarYCbCrImage(s)
789 * directly.
790 */
791 virtual void SetDataNoCopy(const Data &aData);
792
793 /**
794 * This allocates and returns a new buffer
795 */
796 virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize);
797
798 /**
799 * Ask this Image to not convert YUV to RGB during SetData, and make
800 * the original data available through GetData. This is optional,
801 * and not all PlanarYCbCrImages will support it.
802 */
803 virtual void SetDelayedConversion(bool aDelayed) { }
804
805 /**
806 * Grab the original YUV data. This is optional.
807 */
808 virtual const Data* GetData() { return &mData; }
809
810 /**
811 * Return the number of bytes of heap memory used to store this image.
812 */
813 virtual uint32_t GetDataSize() { return mBufferSize; }
814
815 virtual bool IsValid() { return !!mBufferSize; }
816
817 virtual gfx::IntSize GetSize() { return mSize; }
818
819 PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
820
821 virtual SharedPlanarYCbCrImage *AsSharedPlanarYCbCrImage() { return nullptr; }
822
823 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
824 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
825 }
826
827 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
828
829 protected:
830 /**
831 * Make a copy of the YCbCr data into local storage.
832 *
833 * @param aData Input image data.
834 */
835 void CopyData(const Data& aData);
836
837 /**
838 * Return a buffer to store image data in.
839 * The default implementation returns memory that can
840 * be freed wit delete[]
841 */
842 virtual uint8_t* AllocateBuffer(uint32_t aSize);
843
844 TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
845
846 void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
847 gfxImageFormat GetOffscreenFormat();
848
849 nsAutoArrayPtr<uint8_t> mBuffer;
850 uint32_t mBufferSize;
851 Data mData;
852 gfx::IntSize mSize;
853 gfxImageFormat mOffscreenFormat;
854 nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
855 nsRefPtr<BufferRecycleBin> mRecycleBin;
856 };
857
858 /**
859 * Currently, the data in a CairoImage surface is treated as being in the
860 * device output color space. This class is very simple as all backends
861 * have to know about how to deal with drawing a cairo image.
862 */
863 class CairoImage : public Image,
864 public ISharedImage {
865 public:
866 struct Data {
867 gfx::IntSize mSize;
868 RefPtr<gfx::SourceSurface> mSourceSurface;
869 };
870
871 /**
872 * This can only be called on the main thread. It may add a reference
873 * to the surface (which will eventually be released on the main thread).
874 * The surface must not be modified after this call!!!
875 */
876 void SetData(const Data& aData)
877 {
878 mSize = aData.mSize;
879 mSourceSurface = aData.mSourceSurface;
880 }
881
882 virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface()
883 {
884 return mSourceSurface.get();
885 }
886
887 virtual ISharedImage* AsSharedImage() { return this; }
888 virtual uint8_t* GetBuffer() { return nullptr; }
889 virtual TextureClient* GetTextureClient(CompositableClient* aClient);
890
891 gfx::IntSize GetSize() { return mSize; }
892
893 CairoImage();
894 ~CairoImage();
895
896 gfx::IntSize mSize;
897
898 nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
899 nsDataHashtable<nsUint32HashKey, RefPtr<TextureClient> > mTextureClients;
900 };
901
902 class RemoteBitmapImage : public Image {
903 public:
904 RemoteBitmapImage() : Image(nullptr, ImageFormat::REMOTE_IMAGE_BITMAP) {}
905
906 TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
907
908 gfx::IntSize GetSize() { return mSize; }
909
910 unsigned char *mData;
911 int mStride;
912 gfx::IntSize mSize;
913 RemoteImageData::Format mFormat;
914 };
915
916 } //namespace
917 } //namespace
918
919 #endif

mercurial