gfx/layers/ImageContainer.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial