gfx/layers/ImageContainer.cpp

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.

     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/. */
     7 #include "ImageContainer.h"
     8 #include <string.h>                     // for memcpy, memset
     9 #include "SharedTextureImage.h"         // for SharedTextureImage
    10 #include "gfx2DGlue.h"
    11 #include "gfxPlatform.h"                // for gfxPlatform
    12 #include "gfxUtils.h"                   // for gfxUtils
    13 #include "mozilla/RefPtr.h"             // for TemporaryRef
    14 #include "mozilla/ipc/CrossProcessMutex.h"  // for CrossProcessMutex, etc
    15 #include "mozilla/layers/CompositorTypes.h"
    16 #include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
    17 #include "mozilla/layers/ImageClient.h"  // for ImageClient
    18 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF
    19 #include "YCbCrUtils.h"                 // for YCbCr conversions
    20 #ifdef MOZ_WIDGET_GONK
    21 #include "GrallocImages.h"
    22 #endif
    23 #include "gfx2DGlue.h"
    24 #include "mozilla/gfx/2D.h"
    26 #ifdef XP_MACOSX
    27 #include "mozilla/gfx/QuartzSupport.h"
    28 #include "MacIOSurfaceImage.h"
    29 #endif
    31 #ifdef XP_WIN
    32 #include "gfxD2DSurface.h"
    33 #include "gfxWindowsPlatform.h"
    34 #include <d3d10_1.h>
    35 #include "d3d10/ImageLayerD3D10.h"
    36 #include "D3D9SurfaceImage.h"
    37 #endif
    39 using namespace mozilla::ipc;
    40 using namespace android;
    41 using namespace mozilla::gfx;
    44 namespace mozilla {
    45 namespace layers {
    48 Atomic<int32_t> Image::sSerialCounter(0);
    50 already_AddRefed<Image>
    51 ImageFactory::CreateImage(ImageFormat aFormat,
    52                           const gfx::IntSize &,
    53                           BufferRecycleBin *aRecycleBin)
    54 {
    55   nsRefPtr<Image> img;
    56 #ifdef MOZ_WIDGET_GONK
    57   if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) {
    58     img = new GrallocImage();
    59     return img.forget();
    60   }
    61 #endif
    62   if (aFormat == ImageFormat::PLANAR_YCBCR) {
    63     img = new PlanarYCbCrImage(aRecycleBin);
    64     return img.forget();
    65   }
    66   if (aFormat == ImageFormat::CAIRO_SURFACE) {
    67     img = new CairoImage();
    68     return img.forget();
    69   }
    70   if (aFormat == ImageFormat::SHARED_TEXTURE) {
    71     img = new SharedTextureImage();
    72     return img.forget();
    73   }
    74 #ifdef XP_MACOSX
    75   if (aFormat == ImageFormat::MAC_IOSURFACE) {
    76     img = new MacIOSurfaceImage();
    77     return img.forget();
    78   }
    79 #endif
    80 #ifdef XP_WIN
    81   if (aFormat == ImageFormat::D3D9_RGB32_TEXTURE) {
    82     img = new D3D9SurfaceImage();
    83     return img.forget();
    84   }
    85 #endif
    86   return nullptr;
    87 }
    89 BufferRecycleBin::BufferRecycleBin()
    90   : mLock("mozilla.layers.BufferRecycleBin.mLock")
    91 {
    92 }
    94 void
    95 BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize)
    96 {
    97   MutexAutoLock lock(mLock);
    99   if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) {
   100     mRecycledBuffers.Clear();
   101   }
   102   mRecycledBufferSize = aSize;
   103   mRecycledBuffers.AppendElement(aBuffer);
   104 }
   106 uint8_t*
   107 BufferRecycleBin::GetBuffer(uint32_t aSize)
   108 {
   109   MutexAutoLock lock(mLock);
   111   if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize)
   112     return new uint8_t[aSize];
   114   uint32_t last = mRecycledBuffers.Length() - 1;
   115   uint8_t* result = mRecycledBuffers[last].forget();
   116   mRecycledBuffers.RemoveElementAt(last);
   117   return result;
   118 }
   120 ImageContainer::ImageContainer(int flag)
   121 : mReentrantMonitor("ImageContainer.mReentrantMonitor"),
   122   mPaintCount(0),
   123   mPreviousImagePainted(false),
   124   mImageFactory(new ImageFactory()),
   125   mRecycleBin(new BufferRecycleBin()),
   126   mRemoteData(nullptr),
   127   mRemoteDataMutex(nullptr),
   128   mCompositionNotifySink(nullptr),
   129   mImageClient(nullptr)
   130 {
   131   if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) {
   132     // the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount
   133     // of this class must be done on the ImageBridge thread.
   134     mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(BUFFER_IMAGE_SINGLE).drop();
   135     MOZ_ASSERT(mImageClient);
   136   }
   137 }
   139 ImageContainer::~ImageContainer()
   140 {
   141   if (IsAsync()) {
   142     ImageBridgeChild::DispatchReleaseImageClient(mImageClient);
   143   }
   144 }
   146 already_AddRefed<Image>
   147 ImageContainer::CreateImage(ImageFormat aFormat)
   148 {
   149   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   151   if (mImageClient) {
   152     nsRefPtr<Image> img = mImageClient->CreateImage(aFormat);
   153     if (img) {
   154       return img.forget();
   155     }
   156   }
   157   return mImageFactory->CreateImage(aFormat, mScaleHint, mRecycleBin);
   158 }
   160 void
   161 ImageContainer::SetCurrentImageInternal(Image *aImage)
   162 {
   163   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   165   if (mRemoteData) {
   166     NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   167     mRemoteDataMutex->Lock();
   168     // This is important since it ensures we won't change the active image
   169     // when we currently have a locked image that depends on mRemoteData.
   170   }
   172   mActiveImage = aImage;
   173   CurrentImageChanged();
   175   if (mRemoteData) {
   176     mRemoteDataMutex->Unlock();
   177   }
   178 }
   180 void
   181 ImageContainer::ClearCurrentImage()
   182 {
   183   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   184   SetCurrentImageInternal(nullptr);
   185 }
   187 void
   188 ImageContainer::SetCurrentImage(Image *aImage)
   189 {
   190   if (!aImage) {
   191     ClearAllImages();
   192     return;
   193   }
   195   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   196   if (IsAsync()) {
   197     ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this);
   198   }
   199   SetCurrentImageInternal(aImage);
   200 }
   202  void
   203 ImageContainer::ClearAllImages()
   204 {
   205   if (IsAsync()) {
   206     // Let ImageClient release all TextureClients.
   207     ImageBridgeChild::FlushAllImages(mImageClient, this, false);
   208     return;
   209   }
   211   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   212   SetCurrentImageInternal(nullptr);
   213 }
   215 void
   216 ImageContainer::ClearAllImagesExceptFront()
   217 {
   218   if (IsAsync()) {
   219     // Let ImageClient release all TextureClients except front one.
   220     ImageBridgeChild::FlushAllImages(mImageClient, this, true);
   221   }
   222 }
   224 void
   225 ImageContainer::SetCurrentImageInTransaction(Image *aImage)
   226 {
   227   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   228   NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge.");
   230   SetCurrentImageInternal(aImage);
   231 }
   233 bool ImageContainer::IsAsync() const {
   234   return mImageClient != nullptr;
   235 }
   237 uint64_t ImageContainer::GetAsyncContainerID() const
   238 {
   239   NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
   240   if (IsAsync()) {
   241     return mImageClient->GetAsyncID();
   242   } else {
   243     return 0; // zero is always an invalid AsyncID
   244   }
   245 }
   247 bool
   248 ImageContainer::HasCurrentImage()
   249 {
   250   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   252   if (mRemoteData) {
   253     CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
   255     EnsureActiveImage();
   257     return !!mActiveImage.get();
   258   }
   260   return !!mActiveImage.get();
   261 }
   263 already_AddRefed<Image>
   264 ImageContainer::LockCurrentImage()
   265 {
   266   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   268   if (mRemoteData) {
   269     NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   270     mRemoteDataMutex->Lock();
   271   }
   273   EnsureActiveImage();
   275   nsRefPtr<Image> retval = mActiveImage;
   276   return retval.forget();
   277 }
   279 TemporaryRef<gfx::SourceSurface>
   280 ImageContainer::LockCurrentAsSourceSurface(gfx::IntSize *aSize, Image** aCurrentImage)
   281 {
   282   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   284   if (mRemoteData) {
   285     NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   286     mRemoteDataMutex->Lock();
   288     EnsureActiveImage();
   290     if (aCurrentImage) {
   291       NS_IF_ADDREF(mActiveImage);
   292       *aCurrentImage = mActiveImage.get();
   293     }
   295     if (!mActiveImage) {
   296       return nullptr;
   297     }
   299     if (mActiveImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) {
   300       gfxImageFormat fmt = mRemoteData->mFormat == RemoteImageData::BGRX32
   301                            ? gfxImageFormat::ARGB32
   302                            : gfxImageFormat::RGB24;
   304       RefPtr<gfx::DataSourceSurface> newSurf
   305         = gfx::Factory::CreateWrappingDataSourceSurface(mRemoteData->mBitmap.mData,
   306                                                         mRemoteData->mBitmap.mStride,
   307                                                         mRemoteData->mSize,
   308                                                         gfx::ImageFormatToSurfaceFormat(fmt));
   309       *aSize = newSurf->GetSize();
   311       return newSurf;
   312     }
   314     *aSize = mActiveImage->GetSize();
   315     return mActiveImage->GetAsSourceSurface();
   316   }
   318   if (aCurrentImage) {
   319     NS_IF_ADDREF(mActiveImage);
   320     *aCurrentImage = mActiveImage.get();
   321   }
   323   if (!mActiveImage) {
   324     return nullptr;
   325   }
   327   *aSize = mActiveImage->GetSize();
   328   return mActiveImage->GetAsSourceSurface();
   329 }
   331 void
   332 ImageContainer::UnlockCurrentImage()
   333 {
   334   if (mRemoteData) {
   335     NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   336     mRemoteDataMutex->Unlock();
   337   }
   338 }
   340 TemporaryRef<gfx::SourceSurface>
   341 ImageContainer::GetCurrentAsSourceSurface(gfx::IntSize *aSize)
   342 {
   343   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   345   if (mRemoteData) {
   346     CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
   347     EnsureActiveImage();
   349     if (!mActiveImage)
   350       return nullptr;
   351     *aSize = mRemoteData->mSize;
   352   } else {
   353     if (!mActiveImage)
   354       return nullptr;
   355     *aSize = mActiveImage->GetSize();
   356   }
   357   return mActiveImage->GetAsSourceSurface();
   358 }
   360 gfx::IntSize
   361 ImageContainer::GetCurrentSize()
   362 {
   363   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   365   if (mRemoteData) {
   366     CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
   368     // We don't need to ensure we have an active image here, as we need to
   369     // be in the mutex anyway, and this is easiest to return from there.
   370     return mRemoteData->mSize;
   371   }
   373   if (!mActiveImage) {
   374     return gfx::IntSize(0, 0);
   375   }
   377   return mActiveImage->GetSize();
   378 }
   380 void
   381 ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex)
   382 {
   383   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   385   NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData.");
   386   NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData.");
   388   mRemoteData = aData;
   390   if (aData) {
   391     memset(aData, 0, sizeof(RemoteImageData));
   392   } else {
   393     mActiveImage = nullptr;
   394   }
   396   mRemoteDataMutex = aMutex;
   397 }
   399 void
   400 ImageContainer::EnsureActiveImage()
   401 {
   402   if (mRemoteData) {
   403     if (mRemoteData->mWasUpdated) {
   404       mActiveImage = nullptr;
   405     }
   407     if (mRemoteData->mType == RemoteImageData::RAW_BITMAP &&
   408         mRemoteData->mBitmap.mData && !mActiveImage) {
   409       nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage();
   411       newImg->mFormat = mRemoteData->mFormat;
   412       newImg->mData = mRemoteData->mBitmap.mData;
   413       newImg->mSize = mRemoteData->mSize;
   414       newImg->mStride = mRemoteData->mBitmap.mStride;
   415       mRemoteData->mWasUpdated = false;
   417       mActiveImage = newImg;
   418     }
   419 #ifdef XP_WIN
   420     else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE &&
   421              mRemoteData->mTextureHandle && !mActiveImage) {
   422       nsRefPtr<RemoteDXGITextureImage> newImg = new RemoteDXGITextureImage();
   423       newImg->mSize = mRemoteData->mSize;
   424       newImg->mHandle = mRemoteData->mTextureHandle;
   425       newImg->mFormat = mRemoteData->mFormat;
   426       mRemoteData->mWasUpdated = false;
   428       mActiveImage = newImg;
   429     }
   430 #endif
   431   }
   432 }
   435 PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
   436   : Image(nullptr, ImageFormat::PLANAR_YCBCR)
   437   , mBufferSize(0)
   438   , mOffscreenFormat(gfxImageFormat::Unknown)
   439   , mRecycleBin(aRecycleBin)
   440 {
   441 }
   443 PlanarYCbCrImage::~PlanarYCbCrImage()
   444 {
   445   if (mBuffer) {
   446     mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
   447   }
   448 }
   450 size_t
   451 PlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   452 {
   453   // Ignoring:
   454   // - mData - just wraps mBuffer
   455   // - Surfaces should be reported under gfx-surfaces-*:
   456   //   - mSourceSurface
   457   // - Base class:
   458   //   - mImplData is not used
   459   // Not owned:
   460   // - mRecycleBin
   461   size_t size = mBuffer.SizeOfExcludingThis(aMallocSizeOf);
   463   // Could add in the future:
   464   // - mBackendData (from base class)
   466   return size;
   467 }
   469 uint8_t* 
   470 PlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
   471 {
   472   return mRecycleBin->GetBuffer(aSize); 
   473 }
   475 static void
   476 CopyPlane(uint8_t *aDst, const uint8_t *aSrc,
   477           const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip)
   478 {
   479   if (!aSkip) {
   480     // Fast path: planar input.
   481     memcpy(aDst, aSrc, aSize.height * aStride);
   482   } else {
   483     int32_t height = aSize.height;
   484     int32_t width = aSize.width;
   485     for (int y = 0; y < height; ++y) {
   486       const uint8_t *src = aSrc;
   487       uint8_t *dst = aDst;
   488       // Slow path
   489       for (int x = 0; x < width; ++x) {
   490         *dst++ = *src++;
   491         src += aSkip;
   492       }
   493       aSrc += aStride;
   494       aDst += aStride;
   495     }
   496   }
   497 }
   499 void
   500 PlanarYCbCrImage::CopyData(const Data& aData)
   501 {
   502   mData = aData;
   504   // update buffer size
   505   size_t size = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
   506                 mData.mYStride * mData.mYSize.height;
   508   // get new buffer
   509   mBuffer = AllocateBuffer(size);
   510   if (!mBuffer)
   511     return;
   513   // update buffer size
   514   mBufferSize = size;
   516   mData.mYChannel = mBuffer;
   517   mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
   518   mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
   520   CopyPlane(mData.mYChannel, aData.mYChannel,
   521             mData.mYSize, mData.mYStride, mData.mYSkip);
   522   CopyPlane(mData.mCbChannel, aData.mCbChannel,
   523             mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip);
   524   CopyPlane(mData.mCrChannel, aData.mCrChannel,
   525             mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip);
   527   mSize = aData.mPicSize;
   528 }
   530 void
   531 PlanarYCbCrImage::SetData(const Data &aData)
   532 {
   533   CopyData(aData);
   534 }
   536 gfxImageFormat
   537 PlanarYCbCrImage::GetOffscreenFormat()
   538 {
   539   return mOffscreenFormat == gfxImageFormat::Unknown ?
   540     gfxPlatform::GetPlatform()->GetOffscreenFormat() :
   541     mOffscreenFormat;
   542 }
   544 void
   545 PlanarYCbCrImage::SetDataNoCopy(const Data &aData)
   546 {
   547   mData = aData;
   548   mSize = aData.mPicSize;
   549 }
   551 uint8_t*
   552 PlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
   553 {
   554   // get new buffer
   555   mBuffer = AllocateBuffer(aSize);
   556   if (mBuffer) {
   557     // update buffer size
   558     mBufferSize = aSize;
   559   }
   560   return mBuffer;
   561 }
   563 TemporaryRef<gfx::SourceSurface>
   564 PlanarYCbCrImage::GetAsSourceSurface()
   565 {
   566   if (mSourceSurface) {
   567     return mSourceSurface.get();
   568   }
   570   gfx::IntSize size(mSize);
   571   gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
   572   gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
   573   if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
   574       mSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
   575     NS_ERROR("Illegal image dest width or height");
   576     return nullptr;
   577   }
   579   RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format);
   581   gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride());
   583   mSourceSurface = surface;
   585   return surface.forget();
   586 }
   588 TemporaryRef<gfx::SourceSurface>
   589 RemoteBitmapImage::GetAsSourceSurface()
   590 {
   591   gfx::SurfaceFormat fmt = mFormat == RemoteImageData::BGRX32
   592                          ? gfx::SurfaceFormat::B8G8R8X8
   593                          : gfx::SurfaceFormat::B8G8R8A8;
   594   RefPtr<gfx::DataSourceSurface> newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt);
   596   for (int y = 0; y < mSize.height; y++) {
   597     memcpy(newSurf->GetData() + newSurf->Stride() * y,
   598            mData + mStride * y,
   599            mSize.width * 4);
   600   }
   602   return newSurf;
   603 }
   605 CairoImage::CairoImage()
   606   : Image(nullptr, ImageFormat::CAIRO_SURFACE)
   607 {}
   609 CairoImage::~CairoImage()
   610 {
   611 }
   613 TextureClient*
   614 CairoImage::GetTextureClient(CompositableClient *aClient)
   615 {
   616   CompositableForwarder* forwarder = aClient->GetForwarder();
   617   RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial());
   618   if (textureClient) {
   619     return textureClient;
   620   }
   622   RefPtr<SourceSurface> surface = GetAsSourceSurface();
   623   MOZ_ASSERT(surface);
   625   // gfx::BackendType::NONE means default to content backend
   626   textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
   627                                                          TEXTURE_FLAGS_DEFAULT,
   628                                                          gfx::BackendType::NONE,
   629                                                          surface->GetSize());
   630   MOZ_ASSERT(textureClient->CanExposeDrawTarget());
   631   if (!textureClient->AllocateForSurface(surface->GetSize()) ||
   632       !textureClient->Lock(OPEN_WRITE_ONLY)) {
   633     return nullptr;
   634   }
   636   {
   637     // We must not keep a reference to the DrawTarget after it has been unlocked.
   638     RefPtr<DrawTarget> dt = textureClient->GetAsDrawTarget();
   639     dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
   640   }
   642   textureClient->Unlock();
   644   mTextureClients.Put(forwarder->GetSerial(), textureClient);
   645   return textureClient;
   646 }
   648 } // namespace
   649 } // namespace

mercurial