1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/ImageContainer.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,919 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_IMAGECONTAINER_H 1.10 +#define GFX_IMAGECONTAINER_H 1.11 + 1.12 +#include <stdint.h> // for uint32_t, uint8_t, uint64_t 1.13 +#include <sys/types.h> // for int32_t 1.14 +#include "gfxTypes.h" 1.15 +#include "ImageTypes.h" // for ImageFormat, etc 1.16 +#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 1.17 +#include "mozilla/Mutex.h" // for Mutex 1.18 +#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitorAutoEnter, etc 1.19 +#include "mozilla/TimeStamp.h" // for TimeStamp 1.20 +#include "mozilla/gfx/Point.h" // For IntSize 1.21 +#include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc 1.22 +#include "mozilla/mozalloc.h" // for operator delete, etc 1.23 +#include "nsAutoPtr.h" // for nsRefPtr, nsAutoArrayPtr, etc 1.24 +#include "nsAutoRef.h" // for nsCountedRef 1.25 +#include "nsCOMPtr.h" // for already_AddRefed 1.26 +#include "nsDebug.h" // for NS_ASSERTION 1.27 +#include "nsISupportsImpl.h" // for Image::Release, etc 1.28 +#include "nsRect.h" // for nsIntRect 1.29 +#include "nsSize.h" // for nsIntSize 1.30 +#include "nsTArray.h" // for nsTArray 1.31 +#include "mozilla/Atomics.h" 1.32 +#include "mozilla/WeakPtr.h" 1.33 +#include "nsThreadUtils.h" 1.34 +#include "mozilla/gfx/2D.h" 1.35 +#include "nsDataHashtable.h" 1.36 +#include "mozilla/EnumeratedArray.h" 1.37 + 1.38 +#ifndef XPCOM_GLUE_AVOID_NSPR 1.39 +/** 1.40 + * We need to be able to hold a reference to a Moz2D SourceSurface from Image 1.41 + * subclasses. This is potentially a problem since Images can be addrefed 1.42 + * or released off the main thread. We can ensure that we never AddRef 1.43 + * a SourceSurface off the main thread, but we might want to Release due 1.44 + * to an Image being destroyed off the main thread. 1.45 + * 1.46 + * We use nsCountedRef<nsMainThreadSourceSurfaceRef> to reference the 1.47 + * SourceSurface. When AddRefing, we assert that we're on the main thread. 1.48 + * When Releasing, if we're not on the main thread, we post an event to 1.49 + * the main thread to do the actual release. 1.50 + */ 1.51 +class nsMainThreadSourceSurfaceRef; 1.52 + 1.53 +template <> 1.54 +class nsAutoRefTraits<nsMainThreadSourceSurfaceRef> { 1.55 +public: 1.56 + typedef mozilla::gfx::SourceSurface* RawRef; 1.57 + 1.58 + /** 1.59 + * The XPCOM event that will do the actual release on the main thread. 1.60 + */ 1.61 + class SurfaceReleaser : public nsRunnable { 1.62 + public: 1.63 + SurfaceReleaser(RawRef aRef) : mRef(aRef) {} 1.64 + NS_IMETHOD Run() { 1.65 + mRef->Release(); 1.66 + return NS_OK; 1.67 + } 1.68 + RawRef mRef; 1.69 + }; 1.70 + 1.71 + static RawRef Void() { return nullptr; } 1.72 + static void Release(RawRef aRawRef) 1.73 + { 1.74 + if (NS_IsMainThread()) { 1.75 + aRawRef->Release(); 1.76 + return; 1.77 + } 1.78 + nsCOMPtr<nsIRunnable> runnable = new SurfaceReleaser(aRawRef); 1.79 + NS_DispatchToMainThread(runnable); 1.80 + } 1.81 + static void AddRef(RawRef aRawRef) 1.82 + { 1.83 + NS_ASSERTION(NS_IsMainThread(), 1.84 + "Can only add a reference on the main thread"); 1.85 + aRawRef->AddRef(); 1.86 + } 1.87 +}; 1.88 + 1.89 +#endif 1.90 + 1.91 +#ifdef XP_WIN 1.92 +struct ID3D10Texture2D; 1.93 +struct ID3D10Device; 1.94 +struct ID3D10ShaderResourceView; 1.95 +#endif 1.96 + 1.97 +typedef void* HANDLE; 1.98 + 1.99 +namespace mozilla { 1.100 + 1.101 +class CrossProcessMutex; 1.102 + 1.103 +namespace layers { 1.104 + 1.105 +class ImageClient; 1.106 +class SharedPlanarYCbCrImage; 1.107 +class TextureClient; 1.108 +class CompositableClient; 1.109 +class CompositableForwarder; 1.110 +class SurfaceDescriptor; 1.111 + 1.112 +struct ImageBackendData 1.113 +{ 1.114 + virtual ~ImageBackendData() {} 1.115 + 1.116 +protected: 1.117 + ImageBackendData() {} 1.118 +}; 1.119 + 1.120 +// sadly we'll need this until we get rid of Deprected image classes 1.121 +class ISharedImage { 1.122 +public: 1.123 + virtual uint8_t* GetBuffer() = 0; 1.124 + 1.125 + /** 1.126 + * For use with the CompositableClient only (so that the later can 1.127 + * synchronize the TextureClient with the TextureHost). 1.128 + */ 1.129 + virtual TextureClient* GetTextureClient(CompositableClient* aClient) = 0; 1.130 +}; 1.131 + 1.132 +/** 1.133 + * A class representing a buffer of pixel data. The data can be in one 1.134 + * of various formats including YCbCr. 1.135 + * 1.136 + * Create an image using an ImageContainer. Fill the image with data, and 1.137 + * then call ImageContainer::SetImage to display it. An image must not be 1.138 + * modified after calling SetImage. Image implementations do not need to 1.139 + * perform locking; when filling an Image, the Image client is responsible 1.140 + * for ensuring only one thread accesses the Image at a time, and after 1.141 + * SetImage the image is immutable. 1.142 + * 1.143 + * When resampling an Image, only pixels within the buffer should be 1.144 + * sampled. For example, cairo images should be sampled in EXTEND_PAD mode. 1.145 + */ 1.146 +class Image { 1.147 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image) 1.148 + 1.149 +public: 1.150 + virtual ISharedImage* AsSharedImage() { return nullptr; } 1.151 + 1.152 + ImageFormat GetFormat() { return mFormat; } 1.153 + void* GetImplData() { return mImplData; } 1.154 + 1.155 + virtual gfx::IntSize GetSize() = 0; 1.156 + virtual nsIntRect GetPictureRect() 1.157 + { 1.158 + return nsIntRect(0, 0, GetSize().width, GetSize().height); 1.159 + } 1.160 + 1.161 + ImageBackendData* GetBackendData(LayersBackend aBackend) 1.162 + { return mBackendData[aBackend]; } 1.163 + void SetBackendData(LayersBackend aBackend, ImageBackendData* aData) 1.164 + { mBackendData[aBackend] = aData; } 1.165 + 1.166 + int32_t GetSerial() { return mSerial; } 1.167 + 1.168 + void MarkSent() { mSent = true; } 1.169 + bool IsSentToCompositor() { return mSent; } 1.170 + 1.171 + virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0; 1.172 + 1.173 +protected: 1.174 + Image(void* aImplData, ImageFormat aFormat) : 1.175 + mImplData(aImplData), 1.176 + mSerial(++sSerialCounter), 1.177 + mFormat(aFormat), 1.178 + mSent(false) 1.179 + {} 1.180 + 1.181 + // Protected destructor, to discourage deletion outside of Release(): 1.182 + virtual ~Image() {} 1.183 + 1.184 + mozilla::EnumeratedArray<mozilla::layers::LayersBackend, 1.185 + mozilla::layers::LayersBackend::LAYERS_LAST, 1.186 + nsAutoPtr<ImageBackendData>> 1.187 + mBackendData; 1.188 + 1.189 + void* mImplData; 1.190 + int32_t mSerial; 1.191 + ImageFormat mFormat; 1.192 + static mozilla::Atomic<int32_t> sSerialCounter; 1.193 + bool mSent; 1.194 +}; 1.195 + 1.196 +/** 1.197 + * A RecycleBin is owned by an ImageContainer. We store buffers in it that we 1.198 + * want to recycle from one image to the next.It's a separate object from 1.199 + * ImageContainer because images need to store a strong ref to their RecycleBin 1.200 + * and we must avoid creating a reference loop between an ImageContainer and 1.201 + * its active image. 1.202 + */ 1.203 +class BufferRecycleBin MOZ_FINAL { 1.204 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin) 1.205 + 1.206 + //typedef mozilla::gl::GLContext GLContext; 1.207 + 1.208 +public: 1.209 + BufferRecycleBin(); 1.210 + 1.211 + void RecycleBuffer(uint8_t* aBuffer, uint32_t aSize); 1.212 + // Returns a recycled buffer of the right size, or allocates a new buffer. 1.213 + uint8_t* GetBuffer(uint32_t aSize); 1.214 + 1.215 +private: 1.216 + typedef mozilla::Mutex Mutex; 1.217 + 1.218 + // Private destructor, to discourage deletion outside of Release(): 1.219 + ~BufferRecycleBin() 1.220 + { 1.221 + } 1.222 + 1.223 + // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures 1.224 + // and mRecycledTextureSizes 1.225 + Mutex mLock; 1.226 + 1.227 + // We should probably do something to prune this list on a timer so we don't 1.228 + // eat excess memory while video is paused... 1.229 + nsTArray<nsAutoArrayPtr<uint8_t> > mRecycledBuffers; 1.230 + // This is only valid if mRecycledBuffers is non-empty 1.231 + uint32_t mRecycledBufferSize; 1.232 +}; 1.233 + 1.234 +class CompositionNotifySink 1.235 +{ 1.236 +public: 1.237 + virtual void DidComposite() = 0; 1.238 + virtual ~CompositionNotifySink() {} 1.239 +}; 1.240 + 1.241 +/** 1.242 + * A class that manages Image creation for a LayerManager. The only reason 1.243 + * we need a separate class here is that LayerManagers aren't threadsafe 1.244 + * (because layers can only be used on the main thread) and we want to 1.245 + * be able to create images from any thread, to facilitate video playback 1.246 + * without involving the main thread, for example. 1.247 + * Different layer managers can implement child classes of this making it 1.248 + * possible to create layer manager specific images. 1.249 + * This class is not meant to be used directly but rather can be set on an 1.250 + * image container. This is usually done by the layer system internally and 1.251 + * not explicitly by users. For PlanarYCbCr or Cairo images the default 1.252 + * implementation will creates images whose data lives in system memory, for 1.253 + * MacIOSurfaces the default implementation will be a simple MacIOSurface 1.254 + * wrapper. 1.255 + */ 1.256 + 1.257 +class ImageFactory 1.258 +{ 1.259 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory) 1.260 +protected: 1.261 + friend class ImageContainer; 1.262 + 1.263 + ImageFactory() {} 1.264 + virtual ~ImageFactory() {} 1.265 + 1.266 + virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat, 1.267 + const gfx::IntSize &aScaleHint, 1.268 + BufferRecycleBin *aRecycleBin); 1.269 + 1.270 +}; 1.271 + 1.272 +/** 1.273 + * This struct is used to store RemoteImages, it is meant to be able to live in 1.274 + * shared memory. Therefor it should not contain a vtable pointer. Remote 1.275 + * users can manipulate the data in this structure to specify what image is to 1.276 + * be drawn by the container. When accessing this data users should make sure 1.277 + * the mutex synchronizing access to the structure is held! 1.278 + */ 1.279 +struct RemoteImageData { 1.280 + enum Type { 1.281 + /** 1.282 + * This is a format that uses raw bitmap data. 1.283 + */ 1.284 + RAW_BITMAP, 1.285 + 1.286 + /** 1.287 + * This is a format that uses a pointer to a texture do draw directly 1.288 + * from a shared texture. Any process may have created this texture handle, 1.289 + * the process creating the texture handle is responsible for managing it's 1.290 + * lifetime by managing the lifetime of the first D3D texture object this 1.291 + * handle was created for. It must also ensure the handle is not set 1.292 + * current anywhere when the last reference to this object is released. 1.293 + */ 1.294 + DXGI_TEXTURE_HANDLE 1.295 + }; 1.296 + /* These formats describe the format in the memory byte-order */ 1.297 + enum Format { 1.298 + /* 8 bits per channel */ 1.299 + BGRA32, 1.300 + /* 8 bits per channel, alpha channel is ignored */ 1.301 + BGRX32 1.302 + }; 1.303 + 1.304 + // This should be set to true if a change was made so that the ImageContainer 1.305 + // knows to throw out any cached RemoteImage objects. 1.306 + bool mWasUpdated; 1.307 + Type mType; 1.308 + Format mFormat; 1.309 + gfx::IntSize mSize; 1.310 + union { 1.311 + struct { 1.312 + /* This pointer is set by a remote process, however it will be set to 1.313 + * the container process' address the memory of the raw bitmap resides 1.314 + * at. 1.315 + */ 1.316 + unsigned char *mData; 1.317 + int mStride; 1.318 + } mBitmap; 1.319 +#ifdef XP_WIN 1.320 + HANDLE mTextureHandle; 1.321 +#endif 1.322 + }; 1.323 +}; 1.324 + 1.325 +/** 1.326 + * A class that manages Images for an ImageLayer. The only reason 1.327 + * we need a separate class here is that ImageLayers aren't threadsafe 1.328 + * (because layers can only be used on the main thread) and we want to 1.329 + * be able to set the current Image from any thread, to facilitate 1.330 + * video playback without involving the main thread, for example. 1.331 + * 1.332 + * An ImageContainer can operate in one of three modes: 1.333 + * 1) Normal. Triggered by constructing the ImageContainer with 1.334 + * DISABLE_ASYNC or when compositing is happening on the main thread. 1.335 + * SetCurrentImage changes ImageContainer state but nothing is sent to the 1.336 + * compositor until the next layer transaction. 1.337 + * 2) Asynchronous. Initiated by constructing the ImageContainer with 1.338 + * ENABLE_ASYNC when compositing is happening on the main thread. 1.339 + * SetCurrentImage sends a message through the ImageBridge to the compositor 1.340 + * thread to update the image, without going through the main thread or 1.341 + * a layer transaction. 1.342 + * 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer 1.343 + * before any other activity. 1.344 + * The ImageContainer uses a shared memory block containing a cross-process mutex 1.345 + * to communicate with the compositor thread. SetCurrentImage synchronously 1.346 + * updates the shared state to point to the new image and the old image 1.347 + * is immediately released (not true in Normal or Asynchronous modes). 1.348 + */ 1.349 +class ImageContainer MOZ_FINAL : public SupportsWeakPtr<ImageContainer> { 1.350 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer) 1.351 +public: 1.352 + MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer) 1.353 + 1.354 + enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 }; 1.355 + 1.356 + ImageContainer(int flag = 0); 1.357 + 1.358 + /** 1.359 + * Create an Image in one of the given formats. 1.360 + * Picks the "best" format from the list and creates an Image of that 1.361 + * format. 1.362 + * Returns null if this backend does not support any of the formats. 1.363 + * Can be called on any thread. This method takes mReentrantMonitor 1.364 + * when accessing thread-shared state. 1.365 + */ 1.366 + already_AddRefed<Image> CreateImage(ImageFormat aFormat); 1.367 + 1.368 + /** 1.369 + * Set an Image as the current image to display. The Image must have 1.370 + * been created by this ImageContainer. 1.371 + * Can be called on any thread. This method takes mReentrantMonitor 1.372 + * when accessing thread-shared state. 1.373 + * aImage can be null. While it's null, nothing will be painted. 1.374 + * 1.375 + * The Image data must not be modified after this method is called! 1.376 + * Note that this must not be called if ENABLE_ASYNC has not been set. 1.377 + * 1.378 + * Implementations must call CurrentImageChanged() while holding 1.379 + * mReentrantMonitor. 1.380 + * 1.381 + * If this ImageContainer has an ImageClient for async video: 1.382 + * Schelude a task to send the image to the compositor using the 1.383 + * PImageBridge protcol without using the main thread. 1.384 + */ 1.385 + void SetCurrentImage(Image* aImage); 1.386 + 1.387 + /** 1.388 + * Clear all images. Let ImageClient release all TextureClients. 1.389 + */ 1.390 + void ClearAllImages(); 1.391 + 1.392 + /** 1.393 + * Clear all images except current one. 1.394 + * Let ImageClient release all TextureClients except front one. 1.395 + */ 1.396 + void ClearAllImagesExceptFront(); 1.397 + 1.398 + /** 1.399 + * Clear the current image. 1.400 + * This function is expect to be called only from a CompositableClient 1.401 + * that belongs to ImageBridgeChild. Created to prevent dead lock. 1.402 + * See Bug 901224. 1.403 + */ 1.404 + void ClearCurrentImage(); 1.405 + 1.406 + /** 1.407 + * Set an Image as the current image to display. The Image must have 1.408 + * been created by this ImageContainer. 1.409 + * Must be called on the main thread, within a layers transaction. 1.410 + * 1.411 + * This method takes mReentrantMonitor 1.412 + * when accessing thread-shared state. 1.413 + * aImage can be null. While it's null, nothing will be painted. 1.414 + * 1.415 + * The Image data must not be modified after this method is called! 1.416 + * Note that this must not be called if ENABLE_ASYNC been set. 1.417 + * 1.418 + * Implementations must call CurrentImageChanged() while holding 1.419 + * mReentrantMonitor. 1.420 + */ 1.421 + void SetCurrentImageInTransaction(Image* aImage); 1.422 + 1.423 + /** 1.424 + * Returns true if this ImageContainer uses the ImageBridge IPDL protocol. 1.425 + * 1.426 + * Can be called from any thread. 1.427 + */ 1.428 + bool IsAsync() const; 1.429 + 1.430 + /** 1.431 + * If this ImageContainer uses ImageBridge, returns the ID associated to 1.432 + * this container, for use in the ImageBridge protocol. 1.433 + * Returns 0 if this ImageContainer does not use ImageBridge. Note that 1.434 + * 0 is always an invalid ID for asynchronous image containers. 1.435 + * 1.436 + * Can be called from any thread. 1.437 + */ 1.438 + uint64_t GetAsyncContainerID() const; 1.439 + 1.440 + /** 1.441 + * Returns if the container currently has an image. 1.442 + * Can be called on any thread. This method takes mReentrantMonitor 1.443 + * when accessing thread-shared state. 1.444 + */ 1.445 + bool HasCurrentImage(); 1.446 + 1.447 + /** 1.448 + * Lock the current Image. 1.449 + * This has to add a reference since otherwise there are race conditions 1.450 + * where the current image is destroyed before the caller can add 1.451 + * a reference. This lock strictly guarantees the underlying image remains 1.452 + * valid, it does not mean the current image cannot change. 1.453 + * Can be called on any thread. This method will lock the cross-process 1.454 + * mutex to ensure remote processes cannot alter underlying data. This call 1.455 + * -must- be balanced by a call to UnlockCurrentImage and users should avoid 1.456 + * holding the image locked for a long time. 1.457 + */ 1.458 + already_AddRefed<Image> LockCurrentImage(); 1.459 + 1.460 + /** 1.461 + * This call unlocks the image. For remote images releasing the cross-process 1.462 + * mutex. 1.463 + */ 1.464 + void UnlockCurrentImage(); 1.465 + 1.466 + /** 1.467 + * Get the current image as a SourceSurface. This is useful for fallback 1.468 + * rendering. 1.469 + * This can only be called from the main thread, since cairo objects 1.470 + * can only be used from the main thread. 1.471 + * This is defined here and not on Image because it's possible (likely) 1.472 + * that some backends will make an Image "ready to draw" only when it 1.473 + * becomes the current image for an image container. 1.474 + * Returns null if there is no current image. 1.475 + * Returns the size in aSize. 1.476 + * The returned surface will never be modified. The caller must not 1.477 + * modify it. 1.478 + * Can be called on any thread. This method takes mReentrantMonitor 1.479 + * when accessing thread-shared state. 1.480 + * If the current image is a remote image, that is, if it is an image that 1.481 + * may be shared accross processes, calling this function will make 1.482 + * a copy of the image data while holding the mRemoteDataMutex. If possible, 1.483 + * the lock methods should be used to avoid the copy, however this should be 1.484 + * avoided if the surface is required for a long period of time. 1.485 + */ 1.486 + TemporaryRef<gfx::SourceSurface> GetCurrentAsSourceSurface(gfx::IntSize* aSizeResult); 1.487 + 1.488 + /** 1.489 + * Same as LockCurrentAsSurface but for Moz2D 1.490 + */ 1.491 + TemporaryRef<gfx::SourceSurface> LockCurrentAsSourceSurface(gfx::IntSize* aSizeResult, 1.492 + Image** aCurrentImage = nullptr); 1.493 + 1.494 + /** 1.495 + * Returns the size of the image in pixels. 1.496 + * Can be called on any thread. This method takes mReentrantMonitor when accessing 1.497 + * thread-shared state. 1.498 + */ 1.499 + gfx::IntSize GetCurrentSize(); 1.500 + 1.501 + /** 1.502 + * Sets a size that the image is expected to be rendered at. 1.503 + * This is a hint for image backends to optimize scaling. 1.504 + * Default implementation in this class is to ignore the hint. 1.505 + * Can be called on any thread. This method takes mReentrantMonitor 1.506 + * when accessing thread-shared state. 1.507 + */ 1.508 + void SetScaleHint(const gfx::IntSize& aScaleHint) 1.509 + { mScaleHint = aScaleHint; } 1.510 + 1.511 + void SetImageFactory(ImageFactory *aFactory) 1.512 + { 1.513 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.514 + mImageFactory = aFactory ? aFactory : new ImageFactory(); 1.515 + } 1.516 + 1.517 + /** 1.518 + * Returns the time at which the currently contained image was first 1.519 + * painted. This is reset every time a new image is set as the current 1.520 + * image. Note this may return a null timestamp if the current image 1.521 + * has not yet been painted. Can be called from any thread. 1.522 + */ 1.523 + TimeStamp GetPaintTime() { 1.524 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.525 + return mPaintTime; 1.526 + } 1.527 + 1.528 + /** 1.529 + * Returns the number of images which have been contained in this container 1.530 + * and painted at least once. Can be called from any thread. 1.531 + */ 1.532 + uint32_t GetPaintCount() { 1.533 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.534 + return mPaintCount; 1.535 + } 1.536 + 1.537 + /** 1.538 + * Resets the paint count to zero. 1.539 + * Can be called from any thread. 1.540 + */ 1.541 + void ResetPaintCount() { 1.542 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.543 + mPaintCount = 0; 1.544 + } 1.545 + 1.546 + /** 1.547 + * Increments mPaintCount if this is the first time aPainted has been 1.548 + * painted, and sets mPaintTime if the painted image is the current image. 1.549 + * current image. Can be called from any thread. 1.550 + */ 1.551 + void NotifyPaintedImage(Image* aPainted) { 1.552 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.553 + 1.554 + nsRefPtr<Image> current = mActiveImage; 1.555 + if (aPainted == current) { 1.556 + if (mPaintTime.IsNull()) { 1.557 + mPaintTime = TimeStamp::Now(); 1.558 + mPaintCount++; 1.559 + } 1.560 + } else if (!mPreviousImagePainted) { 1.561 + // While we were painting this image, the current image changed. We 1.562 + // still must count it as painted, but can't set mPaintTime, since we're 1.563 + // no longer the current image. 1.564 + mPaintCount++; 1.565 + mPreviousImagePainted = true; 1.566 + } 1.567 + 1.568 + if (mCompositionNotifySink) { 1.569 + mCompositionNotifySink->DidComposite(); 1.570 + } 1.571 + } 1.572 + 1.573 + void SetCompositionNotifySink(CompositionNotifySink *aSink) { 1.574 + mCompositionNotifySink = aSink; 1.575 + } 1.576 + 1.577 + /** 1.578 + * This function is called to tell the ImageContainer where the 1.579 + * (cross-process) segment lives where the shared data about possible 1.580 + * remote images are stored. In addition to this a CrossProcessMutex object 1.581 + * is passed telling the container how to synchronize access to this data. 1.582 + * NOTE: This should be called during setup of the container and not after 1.583 + * usage has started. 1.584 + */ 1.585 + void SetRemoteImageData(RemoteImageData *aRemoteData, 1.586 + CrossProcessMutex *aRemoteDataMutex); 1.587 + /** 1.588 + * This can be used to check if the container has RemoteData set. 1.589 + */ 1.590 + RemoteImageData *GetRemoteImageData() { return mRemoteData; } 1.591 + 1.592 +private: 1.593 + typedef mozilla::ReentrantMonitor ReentrantMonitor; 1.594 + 1.595 + // Private destructor, to discourage deletion outside of Release(): 1.596 + ~ImageContainer(); 1.597 + 1.598 + void SetCurrentImageInternal(Image* aImage); 1.599 + 1.600 + // This is called to ensure we have an active image, this may not be true 1.601 + // when we're storing image information in a RemoteImageData structure. 1.602 + // NOTE: If we have remote data mRemoteDataMutex should be locked when 1.603 + // calling this function! 1.604 + void EnsureActiveImage(); 1.605 + 1.606 + // ReentrantMonitor to protect thread safe access to the "current 1.607 + // image", and any other state which is shared between threads. 1.608 + ReentrantMonitor mReentrantMonitor; 1.609 + 1.610 + // Performs necessary housekeeping to ensure the painted frame statistics 1.611 + // are accurate. Must be called by SetCurrentImage() implementations with 1.612 + // mReentrantMonitor held. 1.613 + void CurrentImageChanged() { 1.614 + mReentrantMonitor.AssertCurrentThreadIn(); 1.615 + mPreviousImagePainted = !mPaintTime.IsNull(); 1.616 + mPaintTime = TimeStamp(); 1.617 + } 1.618 + 1.619 + nsRefPtr<Image> mActiveImage; 1.620 + 1.621 + // Number of contained images that have been painted at least once. It's up 1.622 + // to the ImageContainer implementation to ensure accesses to this are 1.623 + // threadsafe. 1.624 + uint32_t mPaintCount; 1.625 + 1.626 + // Time stamp at which the current image was first painted. It's up to the 1.627 + // ImageContainer implementation to ensure accesses to this are threadsafe. 1.628 + TimeStamp mPaintTime; 1.629 + 1.630 + // Denotes whether the previous image was painted. 1.631 + bool mPreviousImagePainted; 1.632 + 1.633 + // This is the image factory used by this container, layer managers using 1.634 + // this container can set an alternative image factory that will be used to 1.635 + // create images for this container. 1.636 + nsRefPtr<ImageFactory> mImageFactory; 1.637 + 1.638 + gfx::IntSize mScaleHint; 1.639 + 1.640 + nsRefPtr<BufferRecycleBin> mRecycleBin; 1.641 + 1.642 + // This contains the remote image data for this container, if this is nullptr 1.643 + // that means the container has no other process that may control its active 1.644 + // image. 1.645 + RemoteImageData *mRemoteData; 1.646 + 1.647 + // This cross-process mutex is used to synchronise access to mRemoteData. 1.648 + // When this mutex is held, we will always be inside the mReentrantMonitor 1.649 + // however the same is not true vice versa. 1.650 + CrossProcessMutex *mRemoteDataMutex; 1.651 + 1.652 + CompositionNotifySink *mCompositionNotifySink; 1.653 + 1.654 + // This member points to an ImageClient if this ImageContainer was 1.655 + // sucessfully created with ENABLE_ASYNC, or points to null otherwise. 1.656 + // 'unsuccessful' in this case only means that the ImageClient could not 1.657 + // be created, most likely because off-main-thread compositing is not enabled. 1.658 + // In this case the ImageContainer is perfectly usable, but it will forward 1.659 + // frames to the compositor through transactions in the main thread rather than 1.660 + // asynchronusly using the ImageBridge IPDL protocol. 1.661 + ImageClient* mImageClient; 1.662 +}; 1.663 + 1.664 +class AutoLockImage 1.665 +{ 1.666 +public: 1.667 + AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); } 1.668 + AutoLockImage(ImageContainer *aContainer, RefPtr<gfx::SourceSurface> *aSurface) : mContainer(aContainer) { 1.669 + *aSurface = mContainer->LockCurrentAsSourceSurface(&mSize, getter_AddRefs(mImage)); 1.670 + } 1.671 + ~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } } 1.672 + 1.673 + Image* GetImage() { return mImage; } 1.674 + const gfx::IntSize &GetSize() { return mSize; } 1.675 + 1.676 + void Unlock() { 1.677 + if (mContainer) { 1.678 + mImage = nullptr; 1.679 + mContainer->UnlockCurrentImage(); 1.680 + mContainer = nullptr; 1.681 + } 1.682 + } 1.683 + 1.684 + /** Things get a little tricky here, because our underlying image can -still- 1.685 + * change, and OS X requires a complicated callback mechanism to update this 1.686 + * we need to support staying the lock and getting the new image in a proper 1.687 + * way. This method makes any images retrieved with GetImage invalid! 1.688 + */ 1.689 + void Refresh() { 1.690 + if (mContainer) { 1.691 + mContainer->UnlockCurrentImage(); 1.692 + mImage = mContainer->LockCurrentImage(); 1.693 + } 1.694 + } 1.695 + 1.696 +private: 1.697 + ImageContainer *mContainer; 1.698 + nsRefPtr<Image> mImage; 1.699 + gfx::IntSize mSize; 1.700 +}; 1.701 + 1.702 +struct PlanarYCbCrData { 1.703 + // Luminance buffer 1.704 + uint8_t* mYChannel; 1.705 + int32_t mYStride; 1.706 + gfx::IntSize mYSize; 1.707 + int32_t mYSkip; 1.708 + // Chroma buffers 1.709 + uint8_t* mCbChannel; 1.710 + uint8_t* mCrChannel; 1.711 + int32_t mCbCrStride; 1.712 + gfx::IntSize mCbCrSize; 1.713 + int32_t mCbSkip; 1.714 + int32_t mCrSkip; 1.715 + // Picture region 1.716 + uint32_t mPicX; 1.717 + uint32_t mPicY; 1.718 + gfx::IntSize mPicSize; 1.719 + StereoMode mStereoMode; 1.720 + 1.721 + nsIntRect GetPictureRect() const { 1.722 + return nsIntRect(mPicX, mPicY, 1.723 + mPicSize.width, 1.724 + mPicSize.height); 1.725 + } 1.726 + 1.727 + PlanarYCbCrData() 1.728 + : mYChannel(nullptr), mYStride(0), mYSize(0, 0), mYSkip(0) 1.729 + , mCbChannel(nullptr), mCrChannel(nullptr) 1.730 + , mCbCrStride(0), mCbCrSize(0, 0) , mCbSkip(0), mCrSkip(0) 1.731 + , mPicX(0), mPicY(0), mPicSize(0, 0), mStereoMode(StereoMode::MONO) 1.732 + {} 1.733 +}; 1.734 + 1.735 +/****** Image subtypes for the different formats ******/ 1.736 + 1.737 +/** 1.738 + * We assume that the image data is in the REC 470M color space (see 1.739 + * Theora specification, section 4.3.1). 1.740 + * 1.741 + * The YCbCr format can be: 1.742 + * 1.743 + * 4:4:4 - CbCr width/height are the same as Y. 1.744 + * 4:2:2 - CbCr width is half that of Y. Height is the same. 1.745 + * 4:2:0 - CbCr width and height is half that of Y. 1.746 + * 1.747 + * The color format is detected based on the height/width ratios 1.748 + * defined above. 1.749 + * 1.750 + * The Image that is rendered is the picture region defined by 1.751 + * mPicX, mPicY and mPicSize. The size of the rendered image is 1.752 + * mPicSize, not mYSize or mCbCrSize. 1.753 + * 1.754 + * mYSkip, mCbSkip, mCrSkip are added to support various output 1.755 + * formats from hardware decoder. They are per-pixel skips in the 1.756 + * source image. 1.757 + * 1.758 + * For example when image width is 640, mYStride is 670, mYSkip is 3, 1.759 + * the mYChannel buffer looks like: 1.760 + * 1.761 + * |<----------------------- mYStride ----------------------------->| 1.762 + * |<----------------- mYSize.width --------------->| 1.763 + * 0 3 6 9 12 15 18 21 659 669 1.764 + * |----------------------------------------------------------------| 1.765 + * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%| 1.766 + * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%| 1.767 + * |Y___Y___Y___Y___Y___Y___Y___Y... |%%%%%%%%%| 1.768 + * | |<->| 1.769 + * mYSkip 1.770 + */ 1.771 +class PlanarYCbCrImage : public Image { 1.772 +public: 1.773 + typedef PlanarYCbCrData Data; 1.774 + 1.775 + enum { 1.776 + MAX_DIMENSION = 16384 1.777 + }; 1.778 + 1.779 + virtual ~PlanarYCbCrImage(); 1.780 + 1.781 + /** 1.782 + * This makes a copy of the data buffers, in order to support functioning 1.783 + * in all different layer managers. 1.784 + */ 1.785 + virtual void SetData(const Data& aData); 1.786 + 1.787 + /** 1.788 + * This doesn't make a copy of the data buffers. Can be used when mBuffer is 1.789 + * pre allocated with AllocateAndGetNewBuffer(size) and then SetDataNoCopy is 1.790 + * called to only update the picture size, planes etc. fields in mData. 1.791 + * The GStreamer media backend uses this to decode into PlanarYCbCrImage(s) 1.792 + * directly. 1.793 + */ 1.794 + virtual void SetDataNoCopy(const Data &aData); 1.795 + 1.796 + /** 1.797 + * This allocates and returns a new buffer 1.798 + */ 1.799 + virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize); 1.800 + 1.801 + /** 1.802 + * Ask this Image to not convert YUV to RGB during SetData, and make 1.803 + * the original data available through GetData. This is optional, 1.804 + * and not all PlanarYCbCrImages will support it. 1.805 + */ 1.806 + virtual void SetDelayedConversion(bool aDelayed) { } 1.807 + 1.808 + /** 1.809 + * Grab the original YUV data. This is optional. 1.810 + */ 1.811 + virtual const Data* GetData() { return &mData; } 1.812 + 1.813 + /** 1.814 + * Return the number of bytes of heap memory used to store this image. 1.815 + */ 1.816 + virtual uint32_t GetDataSize() { return mBufferSize; } 1.817 + 1.818 + virtual bool IsValid() { return !!mBufferSize; } 1.819 + 1.820 + virtual gfx::IntSize GetSize() { return mSize; } 1.821 + 1.822 + PlanarYCbCrImage(BufferRecycleBin *aRecycleBin); 1.823 + 1.824 + virtual SharedPlanarYCbCrImage *AsSharedPlanarYCbCrImage() { return nullptr; } 1.825 + 1.826 + virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { 1.827 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.828 + } 1.829 + 1.830 + virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; 1.831 + 1.832 +protected: 1.833 + /** 1.834 + * Make a copy of the YCbCr data into local storage. 1.835 + * 1.836 + * @param aData Input image data. 1.837 + */ 1.838 + void CopyData(const Data& aData); 1.839 + 1.840 + /** 1.841 + * Return a buffer to store image data in. 1.842 + * The default implementation returns memory that can 1.843 + * be freed wit delete[] 1.844 + */ 1.845 + virtual uint8_t* AllocateBuffer(uint32_t aSize); 1.846 + 1.847 + TemporaryRef<gfx::SourceSurface> GetAsSourceSurface(); 1.848 + 1.849 + void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; } 1.850 + gfxImageFormat GetOffscreenFormat(); 1.851 + 1.852 + nsAutoArrayPtr<uint8_t> mBuffer; 1.853 + uint32_t mBufferSize; 1.854 + Data mData; 1.855 + gfx::IntSize mSize; 1.856 + gfxImageFormat mOffscreenFormat; 1.857 + nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface; 1.858 + nsRefPtr<BufferRecycleBin> mRecycleBin; 1.859 +}; 1.860 + 1.861 +/** 1.862 + * Currently, the data in a CairoImage surface is treated as being in the 1.863 + * device output color space. This class is very simple as all backends 1.864 + * have to know about how to deal with drawing a cairo image. 1.865 + */ 1.866 +class CairoImage : public Image, 1.867 + public ISharedImage { 1.868 +public: 1.869 + struct Data { 1.870 + gfx::IntSize mSize; 1.871 + RefPtr<gfx::SourceSurface> mSourceSurface; 1.872 + }; 1.873 + 1.874 + /** 1.875 + * This can only be called on the main thread. It may add a reference 1.876 + * to the surface (which will eventually be released on the main thread). 1.877 + * The surface must not be modified after this call!!! 1.878 + */ 1.879 + void SetData(const Data& aData) 1.880 + { 1.881 + mSize = aData.mSize; 1.882 + mSourceSurface = aData.mSourceSurface; 1.883 + } 1.884 + 1.885 + virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() 1.886 + { 1.887 + return mSourceSurface.get(); 1.888 + } 1.889 + 1.890 + virtual ISharedImage* AsSharedImage() { return this; } 1.891 + virtual uint8_t* GetBuffer() { return nullptr; } 1.892 + virtual TextureClient* GetTextureClient(CompositableClient* aClient); 1.893 + 1.894 + gfx::IntSize GetSize() { return mSize; } 1.895 + 1.896 + CairoImage(); 1.897 + ~CairoImage(); 1.898 + 1.899 + gfx::IntSize mSize; 1.900 + 1.901 + nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface; 1.902 + nsDataHashtable<nsUint32HashKey, RefPtr<TextureClient> > mTextureClients; 1.903 +}; 1.904 + 1.905 +class RemoteBitmapImage : public Image { 1.906 +public: 1.907 + RemoteBitmapImage() : Image(nullptr, ImageFormat::REMOTE_IMAGE_BITMAP) {} 1.908 + 1.909 + TemporaryRef<gfx::SourceSurface> GetAsSourceSurface(); 1.910 + 1.911 + gfx::IntSize GetSize() { return mSize; } 1.912 + 1.913 + unsigned char *mData; 1.914 + int mStride; 1.915 + gfx::IntSize mSize; 1.916 + RemoteImageData::Format mFormat; 1.917 +}; 1.918 + 1.919 +} //namespace 1.920 +} //namespace 1.921 + 1.922 +#endif