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.

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

mercurial