gfx/layers/ImageContainer.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/ImageContainer.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,649 @@
     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 +
    1.10 +#include "ImageContainer.h"
    1.11 +#include <string.h>                     // for memcpy, memset
    1.12 +#include "SharedTextureImage.h"         // for SharedTextureImage
    1.13 +#include "gfx2DGlue.h"
    1.14 +#include "gfxPlatform.h"                // for gfxPlatform
    1.15 +#include "gfxUtils.h"                   // for gfxUtils
    1.16 +#include "mozilla/RefPtr.h"             // for TemporaryRef
    1.17 +#include "mozilla/ipc/CrossProcessMutex.h"  // for CrossProcessMutex, etc
    1.18 +#include "mozilla/layers/CompositorTypes.h"
    1.19 +#include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
    1.20 +#include "mozilla/layers/ImageClient.h"  // for ImageClient
    1.21 +#include "nsISupportsUtils.h"           // for NS_IF_ADDREF
    1.22 +#include "YCbCrUtils.h"                 // for YCbCr conversions
    1.23 +#ifdef MOZ_WIDGET_GONK
    1.24 +#include "GrallocImages.h"
    1.25 +#endif
    1.26 +#include "gfx2DGlue.h"
    1.27 +#include "mozilla/gfx/2D.h"
    1.28 +
    1.29 +#ifdef XP_MACOSX
    1.30 +#include "mozilla/gfx/QuartzSupport.h"
    1.31 +#include "MacIOSurfaceImage.h"
    1.32 +#endif
    1.33 +
    1.34 +#ifdef XP_WIN
    1.35 +#include "gfxD2DSurface.h"
    1.36 +#include "gfxWindowsPlatform.h"
    1.37 +#include <d3d10_1.h>
    1.38 +#include "d3d10/ImageLayerD3D10.h"
    1.39 +#include "D3D9SurfaceImage.h"
    1.40 +#endif
    1.41 +
    1.42 +using namespace mozilla::ipc;
    1.43 +using namespace android;
    1.44 +using namespace mozilla::gfx;
    1.45 +
    1.46 +
    1.47 +namespace mozilla {
    1.48 +namespace layers {
    1.49 +
    1.50 +
    1.51 +Atomic<int32_t> Image::sSerialCounter(0);
    1.52 +
    1.53 +already_AddRefed<Image>
    1.54 +ImageFactory::CreateImage(ImageFormat aFormat,
    1.55 +                          const gfx::IntSize &,
    1.56 +                          BufferRecycleBin *aRecycleBin)
    1.57 +{
    1.58 +  nsRefPtr<Image> img;
    1.59 +#ifdef MOZ_WIDGET_GONK
    1.60 +  if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) {
    1.61 +    img = new GrallocImage();
    1.62 +    return img.forget();
    1.63 +  }
    1.64 +#endif
    1.65 +  if (aFormat == ImageFormat::PLANAR_YCBCR) {
    1.66 +    img = new PlanarYCbCrImage(aRecycleBin);
    1.67 +    return img.forget();
    1.68 +  }
    1.69 +  if (aFormat == ImageFormat::CAIRO_SURFACE) {
    1.70 +    img = new CairoImage();
    1.71 +    return img.forget();
    1.72 +  }
    1.73 +  if (aFormat == ImageFormat::SHARED_TEXTURE) {
    1.74 +    img = new SharedTextureImage();
    1.75 +    return img.forget();
    1.76 +  }
    1.77 +#ifdef XP_MACOSX
    1.78 +  if (aFormat == ImageFormat::MAC_IOSURFACE) {
    1.79 +    img = new MacIOSurfaceImage();
    1.80 +    return img.forget();
    1.81 +  }
    1.82 +#endif
    1.83 +#ifdef XP_WIN
    1.84 +  if (aFormat == ImageFormat::D3D9_RGB32_TEXTURE) {
    1.85 +    img = new D3D9SurfaceImage();
    1.86 +    return img.forget();
    1.87 +  }
    1.88 +#endif
    1.89 +  return nullptr;
    1.90 +}
    1.91 +
    1.92 +BufferRecycleBin::BufferRecycleBin()
    1.93 +  : mLock("mozilla.layers.BufferRecycleBin.mLock")
    1.94 +{
    1.95 +}
    1.96 +
    1.97 +void
    1.98 +BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize)
    1.99 +{
   1.100 +  MutexAutoLock lock(mLock);
   1.101 +
   1.102 +  if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) {
   1.103 +    mRecycledBuffers.Clear();
   1.104 +  }
   1.105 +  mRecycledBufferSize = aSize;
   1.106 +  mRecycledBuffers.AppendElement(aBuffer);
   1.107 +}
   1.108 +
   1.109 +uint8_t*
   1.110 +BufferRecycleBin::GetBuffer(uint32_t aSize)
   1.111 +{
   1.112 +  MutexAutoLock lock(mLock);
   1.113 +
   1.114 +  if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize)
   1.115 +    return new uint8_t[aSize];
   1.116 +
   1.117 +  uint32_t last = mRecycledBuffers.Length() - 1;
   1.118 +  uint8_t* result = mRecycledBuffers[last].forget();
   1.119 +  mRecycledBuffers.RemoveElementAt(last);
   1.120 +  return result;
   1.121 +}
   1.122 +
   1.123 +ImageContainer::ImageContainer(int flag)
   1.124 +: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
   1.125 +  mPaintCount(0),
   1.126 +  mPreviousImagePainted(false),
   1.127 +  mImageFactory(new ImageFactory()),
   1.128 +  mRecycleBin(new BufferRecycleBin()),
   1.129 +  mRemoteData(nullptr),
   1.130 +  mRemoteDataMutex(nullptr),
   1.131 +  mCompositionNotifySink(nullptr),
   1.132 +  mImageClient(nullptr)
   1.133 +{
   1.134 +  if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) {
   1.135 +    // the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount
   1.136 +    // of this class must be done on the ImageBridge thread.
   1.137 +    mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(BUFFER_IMAGE_SINGLE).drop();
   1.138 +    MOZ_ASSERT(mImageClient);
   1.139 +  }
   1.140 +}
   1.141 +
   1.142 +ImageContainer::~ImageContainer()
   1.143 +{
   1.144 +  if (IsAsync()) {
   1.145 +    ImageBridgeChild::DispatchReleaseImageClient(mImageClient);
   1.146 +  }
   1.147 +}
   1.148 +
   1.149 +already_AddRefed<Image>
   1.150 +ImageContainer::CreateImage(ImageFormat aFormat)
   1.151 +{
   1.152 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.153 +
   1.154 +  if (mImageClient) {
   1.155 +    nsRefPtr<Image> img = mImageClient->CreateImage(aFormat);
   1.156 +    if (img) {
   1.157 +      return img.forget();
   1.158 +    }
   1.159 +  }
   1.160 +  return mImageFactory->CreateImage(aFormat, mScaleHint, mRecycleBin);
   1.161 +}
   1.162 +
   1.163 +void
   1.164 +ImageContainer::SetCurrentImageInternal(Image *aImage)
   1.165 +{
   1.166 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.167 +
   1.168 +  if (mRemoteData) {
   1.169 +    NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   1.170 +    mRemoteDataMutex->Lock();
   1.171 +    // This is important since it ensures we won't change the active image
   1.172 +    // when we currently have a locked image that depends on mRemoteData.
   1.173 +  }
   1.174 +
   1.175 +  mActiveImage = aImage;
   1.176 +  CurrentImageChanged();
   1.177 +
   1.178 +  if (mRemoteData) {
   1.179 +    mRemoteDataMutex->Unlock();
   1.180 +  }
   1.181 +}
   1.182 +
   1.183 +void
   1.184 +ImageContainer::ClearCurrentImage()
   1.185 +{
   1.186 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.187 +  SetCurrentImageInternal(nullptr);
   1.188 +}
   1.189 +
   1.190 +void
   1.191 +ImageContainer::SetCurrentImage(Image *aImage)
   1.192 +{
   1.193 +  if (!aImage) {
   1.194 +    ClearAllImages();
   1.195 +    return;
   1.196 +  }
   1.197 +
   1.198 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.199 +  if (IsAsync()) {
   1.200 +    ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this);
   1.201 +  }
   1.202 +  SetCurrentImageInternal(aImage);
   1.203 +}
   1.204 +
   1.205 + void
   1.206 +ImageContainer::ClearAllImages()
   1.207 +{
   1.208 +  if (IsAsync()) {
   1.209 +    // Let ImageClient release all TextureClients.
   1.210 +    ImageBridgeChild::FlushAllImages(mImageClient, this, false);
   1.211 +    return;
   1.212 +  }
   1.213 +
   1.214 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.215 +  SetCurrentImageInternal(nullptr);
   1.216 +}
   1.217 +
   1.218 +void
   1.219 +ImageContainer::ClearAllImagesExceptFront()
   1.220 +{
   1.221 +  if (IsAsync()) {
   1.222 +    // Let ImageClient release all TextureClients except front one.
   1.223 +    ImageBridgeChild::FlushAllImages(mImageClient, this, true);
   1.224 +  }
   1.225 +}
   1.226 +
   1.227 +void
   1.228 +ImageContainer::SetCurrentImageInTransaction(Image *aImage)
   1.229 +{
   1.230 +  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   1.231 +  NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge.");
   1.232 +
   1.233 +  SetCurrentImageInternal(aImage);
   1.234 +}
   1.235 +
   1.236 +bool ImageContainer::IsAsync() const {
   1.237 +  return mImageClient != nullptr;
   1.238 +}
   1.239 +
   1.240 +uint64_t ImageContainer::GetAsyncContainerID() const
   1.241 +{
   1.242 +  NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
   1.243 +  if (IsAsync()) {
   1.244 +    return mImageClient->GetAsyncID();
   1.245 +  } else {
   1.246 +    return 0; // zero is always an invalid AsyncID
   1.247 +  }
   1.248 +}
   1.249 +
   1.250 +bool
   1.251 +ImageContainer::HasCurrentImage()
   1.252 +{
   1.253 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.254 +
   1.255 +  if (mRemoteData) {
   1.256 +    CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
   1.257 +    
   1.258 +    EnsureActiveImage();
   1.259 +
   1.260 +    return !!mActiveImage.get();
   1.261 +  }
   1.262 +
   1.263 +  return !!mActiveImage.get();
   1.264 +}
   1.265 +
   1.266 +already_AddRefed<Image>
   1.267 +ImageContainer::LockCurrentImage()
   1.268 +{
   1.269 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.270 +  
   1.271 +  if (mRemoteData) {
   1.272 +    NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   1.273 +    mRemoteDataMutex->Lock();
   1.274 +  }
   1.275 +
   1.276 +  EnsureActiveImage();
   1.277 +
   1.278 +  nsRefPtr<Image> retval = mActiveImage;
   1.279 +  return retval.forget();
   1.280 +}
   1.281 +
   1.282 +TemporaryRef<gfx::SourceSurface>
   1.283 +ImageContainer::LockCurrentAsSourceSurface(gfx::IntSize *aSize, Image** aCurrentImage)
   1.284 +{
   1.285 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.286 +
   1.287 +  if (mRemoteData) {
   1.288 +    NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   1.289 +    mRemoteDataMutex->Lock();
   1.290 +
   1.291 +    EnsureActiveImage();
   1.292 +
   1.293 +    if (aCurrentImage) {
   1.294 +      NS_IF_ADDREF(mActiveImage);
   1.295 +      *aCurrentImage = mActiveImage.get();
   1.296 +    }
   1.297 +
   1.298 +    if (!mActiveImage) {
   1.299 +      return nullptr;
   1.300 +    }
   1.301 +
   1.302 +    if (mActiveImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) {
   1.303 +      gfxImageFormat fmt = mRemoteData->mFormat == RemoteImageData::BGRX32
   1.304 +                           ? gfxImageFormat::ARGB32
   1.305 +                           : gfxImageFormat::RGB24;
   1.306 +
   1.307 +      RefPtr<gfx::DataSourceSurface> newSurf
   1.308 +        = gfx::Factory::CreateWrappingDataSourceSurface(mRemoteData->mBitmap.mData,
   1.309 +                                                        mRemoteData->mBitmap.mStride,
   1.310 +                                                        mRemoteData->mSize,
   1.311 +                                                        gfx::ImageFormatToSurfaceFormat(fmt));
   1.312 +      *aSize = newSurf->GetSize();
   1.313 +
   1.314 +      return newSurf;
   1.315 +    }
   1.316 +
   1.317 +    *aSize = mActiveImage->GetSize();
   1.318 +    return mActiveImage->GetAsSourceSurface();
   1.319 +  }
   1.320 +
   1.321 +  if (aCurrentImage) {
   1.322 +    NS_IF_ADDREF(mActiveImage);
   1.323 +    *aCurrentImage = mActiveImage.get();
   1.324 +  }
   1.325 +
   1.326 +  if (!mActiveImage) {
   1.327 +    return nullptr;
   1.328 +  }
   1.329 +
   1.330 +  *aSize = mActiveImage->GetSize();
   1.331 +  return mActiveImage->GetAsSourceSurface();
   1.332 +}
   1.333 +
   1.334 +void
   1.335 +ImageContainer::UnlockCurrentImage()
   1.336 +{
   1.337 +  if (mRemoteData) {
   1.338 +    NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
   1.339 +    mRemoteDataMutex->Unlock();
   1.340 +  }
   1.341 +}
   1.342 +
   1.343 +TemporaryRef<gfx::SourceSurface>
   1.344 +ImageContainer::GetCurrentAsSourceSurface(gfx::IntSize *aSize)
   1.345 +{
   1.346 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.347 +
   1.348 +  if (mRemoteData) {
   1.349 +    CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
   1.350 +    EnsureActiveImage();
   1.351 +
   1.352 +    if (!mActiveImage)
   1.353 +      return nullptr;
   1.354 +    *aSize = mRemoteData->mSize;
   1.355 +  } else {
   1.356 +    if (!mActiveImage)
   1.357 +      return nullptr;
   1.358 +    *aSize = mActiveImage->GetSize();
   1.359 +  }
   1.360 +  return mActiveImage->GetAsSourceSurface();
   1.361 +}
   1.362 +
   1.363 +gfx::IntSize
   1.364 +ImageContainer::GetCurrentSize()
   1.365 +{
   1.366 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.367 +
   1.368 +  if (mRemoteData) {
   1.369 +    CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
   1.370 +
   1.371 +    // We don't need to ensure we have an active image here, as we need to
   1.372 +    // be in the mutex anyway, and this is easiest to return from there.
   1.373 +    return mRemoteData->mSize;
   1.374 +  }
   1.375 +
   1.376 +  if (!mActiveImage) {
   1.377 +    return gfx::IntSize(0, 0);
   1.378 +  }
   1.379 +
   1.380 +  return mActiveImage->GetSize();
   1.381 +}
   1.382 +
   1.383 +void
   1.384 +ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex)
   1.385 +{
   1.386 +  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   1.387 +
   1.388 +  NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData.");
   1.389 +  NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData.");
   1.390 +
   1.391 +  mRemoteData = aData;
   1.392 +
   1.393 +  if (aData) {
   1.394 +    memset(aData, 0, sizeof(RemoteImageData));
   1.395 +  } else {
   1.396 +    mActiveImage = nullptr;
   1.397 +  }
   1.398 +
   1.399 +  mRemoteDataMutex = aMutex;
   1.400 +}
   1.401 +
   1.402 +void
   1.403 +ImageContainer::EnsureActiveImage()
   1.404 +{
   1.405 +  if (mRemoteData) {
   1.406 +    if (mRemoteData->mWasUpdated) {
   1.407 +      mActiveImage = nullptr;
   1.408 +    }
   1.409 +
   1.410 +    if (mRemoteData->mType == RemoteImageData::RAW_BITMAP &&
   1.411 +        mRemoteData->mBitmap.mData && !mActiveImage) {
   1.412 +      nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage();
   1.413 +      
   1.414 +      newImg->mFormat = mRemoteData->mFormat;
   1.415 +      newImg->mData = mRemoteData->mBitmap.mData;
   1.416 +      newImg->mSize = mRemoteData->mSize;
   1.417 +      newImg->mStride = mRemoteData->mBitmap.mStride;
   1.418 +      mRemoteData->mWasUpdated = false;
   1.419 +              
   1.420 +      mActiveImage = newImg;
   1.421 +    }
   1.422 +#ifdef XP_WIN
   1.423 +    else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE &&
   1.424 +             mRemoteData->mTextureHandle && !mActiveImage) {
   1.425 +      nsRefPtr<RemoteDXGITextureImage> newImg = new RemoteDXGITextureImage();
   1.426 +      newImg->mSize = mRemoteData->mSize;
   1.427 +      newImg->mHandle = mRemoteData->mTextureHandle;
   1.428 +      newImg->mFormat = mRemoteData->mFormat;
   1.429 +      mRemoteData->mWasUpdated = false;
   1.430 +
   1.431 +      mActiveImage = newImg;
   1.432 +    }
   1.433 +#endif
   1.434 +  }
   1.435 +}
   1.436 +
   1.437 +
   1.438 +PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
   1.439 +  : Image(nullptr, ImageFormat::PLANAR_YCBCR)
   1.440 +  , mBufferSize(0)
   1.441 +  , mOffscreenFormat(gfxImageFormat::Unknown)
   1.442 +  , mRecycleBin(aRecycleBin)
   1.443 +{
   1.444 +}
   1.445 +
   1.446 +PlanarYCbCrImage::~PlanarYCbCrImage()
   1.447 +{
   1.448 +  if (mBuffer) {
   1.449 +    mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
   1.450 +  }
   1.451 +}
   1.452 +
   1.453 +size_t
   1.454 +PlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   1.455 +{
   1.456 +  // Ignoring:
   1.457 +  // - mData - just wraps mBuffer
   1.458 +  // - Surfaces should be reported under gfx-surfaces-*:
   1.459 +  //   - mSourceSurface
   1.460 +  // - Base class:
   1.461 +  //   - mImplData is not used
   1.462 +  // Not owned:
   1.463 +  // - mRecycleBin
   1.464 +  size_t size = mBuffer.SizeOfExcludingThis(aMallocSizeOf);
   1.465 +
   1.466 +  // Could add in the future:
   1.467 +  // - mBackendData (from base class)
   1.468 +
   1.469 +  return size;
   1.470 +}
   1.471 +
   1.472 +uint8_t* 
   1.473 +PlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
   1.474 +{
   1.475 +  return mRecycleBin->GetBuffer(aSize); 
   1.476 +}
   1.477 +
   1.478 +static void
   1.479 +CopyPlane(uint8_t *aDst, const uint8_t *aSrc,
   1.480 +          const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip)
   1.481 +{
   1.482 +  if (!aSkip) {
   1.483 +    // Fast path: planar input.
   1.484 +    memcpy(aDst, aSrc, aSize.height * aStride);
   1.485 +  } else {
   1.486 +    int32_t height = aSize.height;
   1.487 +    int32_t width = aSize.width;
   1.488 +    for (int y = 0; y < height; ++y) {
   1.489 +      const uint8_t *src = aSrc;
   1.490 +      uint8_t *dst = aDst;
   1.491 +      // Slow path
   1.492 +      for (int x = 0; x < width; ++x) {
   1.493 +        *dst++ = *src++;
   1.494 +        src += aSkip;
   1.495 +      }
   1.496 +      aSrc += aStride;
   1.497 +      aDst += aStride;
   1.498 +    }
   1.499 +  }
   1.500 +}
   1.501 +
   1.502 +void
   1.503 +PlanarYCbCrImage::CopyData(const Data& aData)
   1.504 +{
   1.505 +  mData = aData;
   1.506 +
   1.507 +  // update buffer size
   1.508 +  size_t size = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
   1.509 +                mData.mYStride * mData.mYSize.height;
   1.510 +
   1.511 +  // get new buffer
   1.512 +  mBuffer = AllocateBuffer(size);
   1.513 +  if (!mBuffer)
   1.514 +    return;
   1.515 +
   1.516 +  // update buffer size
   1.517 +  mBufferSize = size;
   1.518 +
   1.519 +  mData.mYChannel = mBuffer;
   1.520 +  mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
   1.521 +  mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
   1.522 +
   1.523 +  CopyPlane(mData.mYChannel, aData.mYChannel,
   1.524 +            mData.mYSize, mData.mYStride, mData.mYSkip);
   1.525 +  CopyPlane(mData.mCbChannel, aData.mCbChannel,
   1.526 +            mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip);
   1.527 +  CopyPlane(mData.mCrChannel, aData.mCrChannel,
   1.528 +            mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip);
   1.529 +
   1.530 +  mSize = aData.mPicSize;
   1.531 +}
   1.532 +
   1.533 +void
   1.534 +PlanarYCbCrImage::SetData(const Data &aData)
   1.535 +{
   1.536 +  CopyData(aData);
   1.537 +}
   1.538 +
   1.539 +gfxImageFormat
   1.540 +PlanarYCbCrImage::GetOffscreenFormat()
   1.541 +{
   1.542 +  return mOffscreenFormat == gfxImageFormat::Unknown ?
   1.543 +    gfxPlatform::GetPlatform()->GetOffscreenFormat() :
   1.544 +    mOffscreenFormat;
   1.545 +}
   1.546 +
   1.547 +void
   1.548 +PlanarYCbCrImage::SetDataNoCopy(const Data &aData)
   1.549 +{
   1.550 +  mData = aData;
   1.551 +  mSize = aData.mPicSize;
   1.552 +}
   1.553 +
   1.554 +uint8_t*
   1.555 +PlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
   1.556 +{
   1.557 +  // get new buffer
   1.558 +  mBuffer = AllocateBuffer(aSize);
   1.559 +  if (mBuffer) {
   1.560 +    // update buffer size
   1.561 +    mBufferSize = aSize;
   1.562 +  }
   1.563 +  return mBuffer;
   1.564 +}
   1.565 +
   1.566 +TemporaryRef<gfx::SourceSurface>
   1.567 +PlanarYCbCrImage::GetAsSourceSurface()
   1.568 +{
   1.569 +  if (mSourceSurface) {
   1.570 +    return mSourceSurface.get();
   1.571 +  }
   1.572 +
   1.573 +  gfx::IntSize size(mSize);
   1.574 +  gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
   1.575 +  gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
   1.576 +  if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
   1.577 +      mSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
   1.578 +    NS_ERROR("Illegal image dest width or height");
   1.579 +    return nullptr;
   1.580 +  }
   1.581 +
   1.582 +  RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format);
   1.583 +
   1.584 +  gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride());
   1.585 +
   1.586 +  mSourceSurface = surface;
   1.587 +
   1.588 +  return surface.forget();
   1.589 +}
   1.590 +
   1.591 +TemporaryRef<gfx::SourceSurface>
   1.592 +RemoteBitmapImage::GetAsSourceSurface()
   1.593 +{
   1.594 +  gfx::SurfaceFormat fmt = mFormat == RemoteImageData::BGRX32
   1.595 +                         ? gfx::SurfaceFormat::B8G8R8X8
   1.596 +                         : gfx::SurfaceFormat::B8G8R8A8;
   1.597 +  RefPtr<gfx::DataSourceSurface> newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt);
   1.598 +
   1.599 +  for (int y = 0; y < mSize.height; y++) {
   1.600 +    memcpy(newSurf->GetData() + newSurf->Stride() * y,
   1.601 +           mData + mStride * y,
   1.602 +           mSize.width * 4);
   1.603 +  }
   1.604 +
   1.605 +  return newSurf;
   1.606 +}
   1.607 +
   1.608 +CairoImage::CairoImage()
   1.609 +  : Image(nullptr, ImageFormat::CAIRO_SURFACE)
   1.610 +{}
   1.611 +
   1.612 +CairoImage::~CairoImage()
   1.613 +{
   1.614 +}
   1.615 +
   1.616 +TextureClient*
   1.617 +CairoImage::GetTextureClient(CompositableClient *aClient)
   1.618 +{
   1.619 +  CompositableForwarder* forwarder = aClient->GetForwarder();
   1.620 +  RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial());
   1.621 +  if (textureClient) {
   1.622 +    return textureClient;
   1.623 +  }
   1.624 +
   1.625 +  RefPtr<SourceSurface> surface = GetAsSourceSurface();
   1.626 +  MOZ_ASSERT(surface);
   1.627 +
   1.628 +  // gfx::BackendType::NONE means default to content backend
   1.629 +  textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
   1.630 +                                                         TEXTURE_FLAGS_DEFAULT,
   1.631 +                                                         gfx::BackendType::NONE,
   1.632 +                                                         surface->GetSize());
   1.633 +  MOZ_ASSERT(textureClient->CanExposeDrawTarget());
   1.634 +  if (!textureClient->AllocateForSurface(surface->GetSize()) ||
   1.635 +      !textureClient->Lock(OPEN_WRITE_ONLY)) {
   1.636 +    return nullptr;
   1.637 +  }
   1.638 +
   1.639 +  {
   1.640 +    // We must not keep a reference to the DrawTarget after it has been unlocked.
   1.641 +    RefPtr<DrawTarget> dt = textureClient->GetAsDrawTarget();
   1.642 +    dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
   1.643 +  }
   1.644 +
   1.645 +  textureClient->Unlock();
   1.646 +
   1.647 +  mTextureClients.Put(forwarder->GetSerial(), textureClient);
   1.648 +  return textureClient;
   1.649 +}
   1.650 +
   1.651 +} // namespace
   1.652 +} // namespace

mercurial