michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #include "ImageContainer.h" michael@0: #include // for memcpy, memset michael@0: #include "SharedTextureImage.h" // for SharedTextureImage michael@0: #include "gfx2DGlue.h" michael@0: #include "gfxPlatform.h" // for gfxPlatform michael@0: #include "gfxUtils.h" // for gfxUtils michael@0: #include "mozilla/RefPtr.h" // for TemporaryRef michael@0: #include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc michael@0: #include "mozilla/layers/CompositorTypes.h" michael@0: #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild michael@0: #include "mozilla/layers/ImageClient.h" // for ImageClient michael@0: #include "nsISupportsUtils.h" // for NS_IF_ADDREF michael@0: #include "YCbCrUtils.h" // for YCbCr conversions michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include "GrallocImages.h" michael@0: #endif michael@0: #include "gfx2DGlue.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include "mozilla/gfx/QuartzSupport.h" michael@0: #include "MacIOSurfaceImage.h" michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: #include "gfxD2DSurface.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include michael@0: #include "d3d10/ImageLayerD3D10.h" michael@0: #include "D3D9SurfaceImage.h" michael@0: #endif michael@0: michael@0: using namespace mozilla::ipc; michael@0: using namespace android; michael@0: using namespace mozilla::gfx; michael@0: michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: michael@0: Atomic Image::sSerialCounter(0); michael@0: michael@0: already_AddRefed michael@0: ImageFactory::CreateImage(ImageFormat aFormat, michael@0: const gfx::IntSize &, michael@0: BufferRecycleBin *aRecycleBin) michael@0: { michael@0: nsRefPtr img; michael@0: #ifdef MOZ_WIDGET_GONK michael@0: if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) { michael@0: img = new GrallocImage(); michael@0: return img.forget(); michael@0: } michael@0: #endif michael@0: if (aFormat == ImageFormat::PLANAR_YCBCR) { michael@0: img = new PlanarYCbCrImage(aRecycleBin); michael@0: return img.forget(); michael@0: } michael@0: if (aFormat == ImageFormat::CAIRO_SURFACE) { michael@0: img = new CairoImage(); michael@0: return img.forget(); michael@0: } michael@0: if (aFormat == ImageFormat::SHARED_TEXTURE) { michael@0: img = new SharedTextureImage(); michael@0: return img.forget(); michael@0: } michael@0: #ifdef XP_MACOSX michael@0: if (aFormat == ImageFormat::MAC_IOSURFACE) { michael@0: img = new MacIOSurfaceImage(); michael@0: return img.forget(); michael@0: } michael@0: #endif michael@0: #ifdef XP_WIN michael@0: if (aFormat == ImageFormat::D3D9_RGB32_TEXTURE) { michael@0: img = new D3D9SurfaceImage(); michael@0: return img.forget(); michael@0: } michael@0: #endif michael@0: return nullptr; michael@0: } michael@0: michael@0: BufferRecycleBin::BufferRecycleBin() michael@0: : mLock("mozilla.layers.BufferRecycleBin.mLock") michael@0: { michael@0: } michael@0: michael@0: void michael@0: BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize) michael@0: { michael@0: MutexAutoLock lock(mLock); michael@0: michael@0: if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) { michael@0: mRecycledBuffers.Clear(); michael@0: } michael@0: mRecycledBufferSize = aSize; michael@0: mRecycledBuffers.AppendElement(aBuffer); michael@0: } michael@0: michael@0: uint8_t* michael@0: BufferRecycleBin::GetBuffer(uint32_t aSize) michael@0: { michael@0: MutexAutoLock lock(mLock); michael@0: michael@0: if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize) michael@0: return new uint8_t[aSize]; michael@0: michael@0: uint32_t last = mRecycledBuffers.Length() - 1; michael@0: uint8_t* result = mRecycledBuffers[last].forget(); michael@0: mRecycledBuffers.RemoveElementAt(last); michael@0: return result; michael@0: } michael@0: michael@0: ImageContainer::ImageContainer(int flag) michael@0: : mReentrantMonitor("ImageContainer.mReentrantMonitor"), michael@0: mPaintCount(0), michael@0: mPreviousImagePainted(false), michael@0: mImageFactory(new ImageFactory()), michael@0: mRecycleBin(new BufferRecycleBin()), michael@0: mRemoteData(nullptr), michael@0: mRemoteDataMutex(nullptr), michael@0: mCompositionNotifySink(nullptr), michael@0: mImageClient(nullptr) michael@0: { michael@0: if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) { michael@0: // the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount michael@0: // of this class must be done on the ImageBridge thread. michael@0: mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(BUFFER_IMAGE_SINGLE).drop(); michael@0: MOZ_ASSERT(mImageClient); michael@0: } michael@0: } michael@0: michael@0: ImageContainer::~ImageContainer() michael@0: { michael@0: if (IsAsync()) { michael@0: ImageBridgeChild::DispatchReleaseImageClient(mImageClient); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: ImageContainer::CreateImage(ImageFormat aFormat) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mImageClient) { michael@0: nsRefPtr img = mImageClient->CreateImage(aFormat); michael@0: if (img) { michael@0: return img.forget(); michael@0: } michael@0: } michael@0: return mImageFactory->CreateImage(aFormat, mScaleHint, mRecycleBin); michael@0: } michael@0: michael@0: void michael@0: ImageContainer::SetCurrentImageInternal(Image *aImage) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mRemoteData) { michael@0: NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); michael@0: mRemoteDataMutex->Lock(); michael@0: // This is important since it ensures we won't change the active image michael@0: // when we currently have a locked image that depends on mRemoteData. michael@0: } michael@0: michael@0: mActiveImage = aImage; michael@0: CurrentImageChanged(); michael@0: michael@0: if (mRemoteData) { michael@0: mRemoteDataMutex->Unlock(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ImageContainer::ClearCurrentImage() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: SetCurrentImageInternal(nullptr); michael@0: } michael@0: michael@0: void michael@0: ImageContainer::SetCurrentImage(Image *aImage) michael@0: { michael@0: if (!aImage) { michael@0: ClearAllImages(); michael@0: return; michael@0: } michael@0: michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: if (IsAsync()) { michael@0: ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this); michael@0: } michael@0: SetCurrentImageInternal(aImage); michael@0: } michael@0: michael@0: void michael@0: ImageContainer::ClearAllImages() michael@0: { michael@0: if (IsAsync()) { michael@0: // Let ImageClient release all TextureClients. michael@0: ImageBridgeChild::FlushAllImages(mImageClient, this, false); michael@0: return; michael@0: } michael@0: michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: SetCurrentImageInternal(nullptr); michael@0: } michael@0: michael@0: void michael@0: ImageContainer::ClearAllImagesExceptFront() michael@0: { michael@0: if (IsAsync()) { michael@0: // Let ImageClient release all TextureClients except front one. michael@0: ImageBridgeChild::FlushAllImages(mImageClient, this, true); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ImageContainer::SetCurrentImageInTransaction(Image *aImage) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); michael@0: NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge."); michael@0: michael@0: SetCurrentImageInternal(aImage); michael@0: } michael@0: michael@0: bool ImageContainer::IsAsync() const { michael@0: return mImageClient != nullptr; michael@0: } michael@0: michael@0: uint64_t ImageContainer::GetAsyncContainerID() const michael@0: { michael@0: NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers"); michael@0: if (IsAsync()) { michael@0: return mImageClient->GetAsyncID(); michael@0: } else { michael@0: return 0; // zero is always an invalid AsyncID michael@0: } michael@0: } michael@0: michael@0: bool michael@0: ImageContainer::HasCurrentImage() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mRemoteData) { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); michael@0: michael@0: EnsureActiveImage(); michael@0: michael@0: return !!mActiveImage.get(); michael@0: } michael@0: michael@0: return !!mActiveImage.get(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: ImageContainer::LockCurrentImage() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mRemoteData) { michael@0: NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); michael@0: mRemoteDataMutex->Lock(); michael@0: } michael@0: michael@0: EnsureActiveImage(); michael@0: michael@0: nsRefPtr retval = mActiveImage; michael@0: return retval.forget(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: ImageContainer::LockCurrentAsSourceSurface(gfx::IntSize *aSize, Image** aCurrentImage) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mRemoteData) { michael@0: NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); michael@0: mRemoteDataMutex->Lock(); michael@0: michael@0: EnsureActiveImage(); michael@0: michael@0: if (aCurrentImage) { michael@0: NS_IF_ADDREF(mActiveImage); michael@0: *aCurrentImage = mActiveImage.get(); michael@0: } michael@0: michael@0: if (!mActiveImage) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (mActiveImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) { michael@0: gfxImageFormat fmt = mRemoteData->mFormat == RemoteImageData::BGRX32 michael@0: ? gfxImageFormat::ARGB32 michael@0: : gfxImageFormat::RGB24; michael@0: michael@0: RefPtr newSurf michael@0: = gfx::Factory::CreateWrappingDataSourceSurface(mRemoteData->mBitmap.mData, michael@0: mRemoteData->mBitmap.mStride, michael@0: mRemoteData->mSize, michael@0: gfx::ImageFormatToSurfaceFormat(fmt)); michael@0: *aSize = newSurf->GetSize(); michael@0: michael@0: return newSurf; michael@0: } michael@0: michael@0: *aSize = mActiveImage->GetSize(); michael@0: return mActiveImage->GetAsSourceSurface(); michael@0: } michael@0: michael@0: if (aCurrentImage) { michael@0: NS_IF_ADDREF(mActiveImage); michael@0: *aCurrentImage = mActiveImage.get(); michael@0: } michael@0: michael@0: if (!mActiveImage) { michael@0: return nullptr; michael@0: } michael@0: michael@0: *aSize = mActiveImage->GetSize(); michael@0: return mActiveImage->GetAsSourceSurface(); michael@0: } michael@0: michael@0: void michael@0: ImageContainer::UnlockCurrentImage() michael@0: { michael@0: if (mRemoteData) { michael@0: NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); michael@0: mRemoteDataMutex->Unlock(); michael@0: } michael@0: } michael@0: michael@0: TemporaryRef michael@0: ImageContainer::GetCurrentAsSourceSurface(gfx::IntSize *aSize) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mRemoteData) { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); michael@0: EnsureActiveImage(); michael@0: michael@0: if (!mActiveImage) michael@0: return nullptr; michael@0: *aSize = mRemoteData->mSize; michael@0: } else { michael@0: if (!mActiveImage) michael@0: return nullptr; michael@0: *aSize = mActiveImage->GetSize(); michael@0: } michael@0: return mActiveImage->GetAsSourceSurface(); michael@0: } michael@0: michael@0: gfx::IntSize michael@0: ImageContainer::GetCurrentSize() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: if (mRemoteData) { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); michael@0: michael@0: // We don't need to ensure we have an active image here, as we need to michael@0: // be in the mutex anyway, and this is easiest to return from there. michael@0: return mRemoteData->mSize; michael@0: } michael@0: michael@0: if (!mActiveImage) { michael@0: return gfx::IntSize(0, 0); michael@0: } michael@0: michael@0: return mActiveImage->GetSize(); michael@0: } michael@0: michael@0: void michael@0: ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData."); michael@0: NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData."); michael@0: michael@0: mRemoteData = aData; michael@0: michael@0: if (aData) { michael@0: memset(aData, 0, sizeof(RemoteImageData)); michael@0: } else { michael@0: mActiveImage = nullptr; michael@0: } michael@0: michael@0: mRemoteDataMutex = aMutex; michael@0: } michael@0: michael@0: void michael@0: ImageContainer::EnsureActiveImage() michael@0: { michael@0: if (mRemoteData) { michael@0: if (mRemoteData->mWasUpdated) { michael@0: mActiveImage = nullptr; michael@0: } michael@0: michael@0: if (mRemoteData->mType == RemoteImageData::RAW_BITMAP && michael@0: mRemoteData->mBitmap.mData && !mActiveImage) { michael@0: nsRefPtr newImg = new RemoteBitmapImage(); michael@0: michael@0: newImg->mFormat = mRemoteData->mFormat; michael@0: newImg->mData = mRemoteData->mBitmap.mData; michael@0: newImg->mSize = mRemoteData->mSize; michael@0: newImg->mStride = mRemoteData->mBitmap.mStride; michael@0: mRemoteData->mWasUpdated = false; michael@0: michael@0: mActiveImage = newImg; michael@0: } michael@0: #ifdef XP_WIN michael@0: else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE && michael@0: mRemoteData->mTextureHandle && !mActiveImage) { michael@0: nsRefPtr newImg = new RemoteDXGITextureImage(); michael@0: newImg->mSize = mRemoteData->mSize; michael@0: newImg->mHandle = mRemoteData->mTextureHandle; michael@0: newImg->mFormat = mRemoteData->mFormat; michael@0: mRemoteData->mWasUpdated = false; michael@0: michael@0: mActiveImage = newImg; michael@0: } michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: michael@0: PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin) michael@0: : Image(nullptr, ImageFormat::PLANAR_YCBCR) michael@0: , mBufferSize(0) michael@0: , mOffscreenFormat(gfxImageFormat::Unknown) michael@0: , mRecycleBin(aRecycleBin) michael@0: { michael@0: } michael@0: michael@0: PlanarYCbCrImage::~PlanarYCbCrImage() michael@0: { michael@0: if (mBuffer) { michael@0: mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize); michael@0: } michael@0: } michael@0: michael@0: size_t michael@0: PlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: // Ignoring: michael@0: // - mData - just wraps mBuffer michael@0: // - Surfaces should be reported under gfx-surfaces-*: michael@0: // - mSourceSurface michael@0: // - Base class: michael@0: // - mImplData is not used michael@0: // Not owned: michael@0: // - mRecycleBin michael@0: size_t size = mBuffer.SizeOfExcludingThis(aMallocSizeOf); michael@0: michael@0: // Could add in the future: michael@0: // - mBackendData (from base class) michael@0: michael@0: return size; michael@0: } michael@0: michael@0: uint8_t* michael@0: PlanarYCbCrImage::AllocateBuffer(uint32_t aSize) michael@0: { michael@0: return mRecycleBin->GetBuffer(aSize); michael@0: } michael@0: michael@0: static void michael@0: CopyPlane(uint8_t *aDst, const uint8_t *aSrc, michael@0: const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip) michael@0: { michael@0: if (!aSkip) { michael@0: // Fast path: planar input. michael@0: memcpy(aDst, aSrc, aSize.height * aStride); michael@0: } else { michael@0: int32_t height = aSize.height; michael@0: int32_t width = aSize.width; michael@0: for (int y = 0; y < height; ++y) { michael@0: const uint8_t *src = aSrc; michael@0: uint8_t *dst = aDst; michael@0: // Slow path michael@0: for (int x = 0; x < width; ++x) { michael@0: *dst++ = *src++; michael@0: src += aSkip; michael@0: } michael@0: aSrc += aStride; michael@0: aDst += aStride; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: PlanarYCbCrImage::CopyData(const Data& aData) michael@0: { michael@0: mData = aData; michael@0: michael@0: // update buffer size michael@0: size_t size = mData.mCbCrStride * mData.mCbCrSize.height * 2 + michael@0: mData.mYStride * mData.mYSize.height; michael@0: michael@0: // get new buffer michael@0: mBuffer = AllocateBuffer(size); michael@0: if (!mBuffer) michael@0: return; michael@0: michael@0: // update buffer size michael@0: mBufferSize = size; michael@0: michael@0: mData.mYChannel = mBuffer; michael@0: mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height; michael@0: mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height; michael@0: michael@0: CopyPlane(mData.mYChannel, aData.mYChannel, michael@0: mData.mYSize, mData.mYStride, mData.mYSkip); michael@0: CopyPlane(mData.mCbChannel, aData.mCbChannel, michael@0: mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip); michael@0: CopyPlane(mData.mCrChannel, aData.mCrChannel, michael@0: mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip); michael@0: michael@0: mSize = aData.mPicSize; michael@0: } michael@0: michael@0: void michael@0: PlanarYCbCrImage::SetData(const Data &aData) michael@0: { michael@0: CopyData(aData); michael@0: } michael@0: michael@0: gfxImageFormat michael@0: PlanarYCbCrImage::GetOffscreenFormat() michael@0: { michael@0: return mOffscreenFormat == gfxImageFormat::Unknown ? michael@0: gfxPlatform::GetPlatform()->GetOffscreenFormat() : michael@0: mOffscreenFormat; michael@0: } michael@0: michael@0: void michael@0: PlanarYCbCrImage::SetDataNoCopy(const Data &aData) michael@0: { michael@0: mData = aData; michael@0: mSize = aData.mPicSize; michael@0: } michael@0: michael@0: uint8_t* michael@0: PlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize) michael@0: { michael@0: // get new buffer michael@0: mBuffer = AllocateBuffer(aSize); michael@0: if (mBuffer) { michael@0: // update buffer size michael@0: mBufferSize = aSize; michael@0: } michael@0: return mBuffer; michael@0: } michael@0: michael@0: TemporaryRef michael@0: PlanarYCbCrImage::GetAsSourceSurface() michael@0: { michael@0: if (mSourceSurface) { michael@0: return mSourceSurface.get(); michael@0: } michael@0: michael@0: gfx::IntSize size(mSize); michael@0: gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat()); michael@0: gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size); michael@0: if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION || michael@0: mSize.height > PlanarYCbCrImage::MAX_DIMENSION) { michael@0: NS_ERROR("Illegal image dest width or height"); michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr surface = gfx::Factory::CreateDataSourceSurface(size, format); michael@0: michael@0: gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride()); michael@0: michael@0: mSourceSurface = surface; michael@0: michael@0: return surface.forget(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: RemoteBitmapImage::GetAsSourceSurface() michael@0: { michael@0: gfx::SurfaceFormat fmt = mFormat == RemoteImageData::BGRX32 michael@0: ? gfx::SurfaceFormat::B8G8R8X8 michael@0: : gfx::SurfaceFormat::B8G8R8A8; michael@0: RefPtr newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt); michael@0: michael@0: for (int y = 0; y < mSize.height; y++) { michael@0: memcpy(newSurf->GetData() + newSurf->Stride() * y, michael@0: mData + mStride * y, michael@0: mSize.width * 4); michael@0: } michael@0: michael@0: return newSurf; michael@0: } michael@0: michael@0: CairoImage::CairoImage() michael@0: : Image(nullptr, ImageFormat::CAIRO_SURFACE) michael@0: {} michael@0: michael@0: CairoImage::~CairoImage() michael@0: { michael@0: } michael@0: michael@0: TextureClient* michael@0: CairoImage::GetTextureClient(CompositableClient *aClient) michael@0: { michael@0: CompositableForwarder* forwarder = aClient->GetForwarder(); michael@0: RefPtr textureClient = mTextureClients.Get(forwarder->GetSerial()); michael@0: if (textureClient) { michael@0: return textureClient; michael@0: } michael@0: michael@0: RefPtr surface = GetAsSourceSurface(); michael@0: MOZ_ASSERT(surface); michael@0: michael@0: // gfx::BackendType::NONE means default to content backend michael@0: textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), michael@0: TEXTURE_FLAGS_DEFAULT, michael@0: gfx::BackendType::NONE, michael@0: surface->GetSize()); michael@0: MOZ_ASSERT(textureClient->CanExposeDrawTarget()); michael@0: if (!textureClient->AllocateForSurface(surface->GetSize()) || michael@0: !textureClient->Lock(OPEN_WRITE_ONLY)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: { michael@0: // We must not keep a reference to the DrawTarget after it has been unlocked. michael@0: RefPtr dt = textureClient->GetAsDrawTarget(); michael@0: dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); michael@0: } michael@0: michael@0: textureClient->Unlock(); michael@0: michael@0: mTextureClients.Put(forwarder->GetSerial(), textureClient); michael@0: return textureClient; michael@0: } michael@0: michael@0: } // namespace michael@0: } // namespace