|
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 |