diff -r 000000000000 -r 6474c204b198 gfx/layers/client/ImageClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/client/ImageClient.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,383 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ImageClient.h" +#include // for uint32_t +#include "ImageContainer.h" // for Image, PlanarYCbCrImage, etc +#include "ImageTypes.h" // for ImageFormat::PLANAR_YCBCR, etc +#include "SharedTextureImage.h" // for SharedTextureImage::Data, etc +#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat +#include "gfxPlatform.h" // for gfxPlatform +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc +#include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef +#include "mozilla/gfx/BaseSize.h" // for BaseSize +#include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/gfx/Types.h" // for SurfaceFormat, etc +#include "mozilla/layers/CompositableClient.h" // for CompositableClient +#include "mozilla/layers/CompositableForwarder.h" +#include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc +#include "mozilla/layers/ISurfaceAllocator.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder +#include "mozilla/layers/SharedPlanarYCbCrImage.h" +#include "mozilla/layers/SharedRGBImage.h" +#include "mozilla/layers/TextureClient.h" // for TextureClient, etc +#include "mozilla/layers/TextureClientOGL.h" // for SharedTextureClientOGL +#include "mozilla/mozalloc.h" // for operator delete, etc +#include "nsAutoPtr.h" // for nsRefPtr +#include "nsCOMPtr.h" // for already_AddRefed +#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION +#include "nsISupportsImpl.h" // for Image::Release, etc +#include "nsRect.h" // for nsIntRect +#include "mozilla/gfx/2D.h" +#ifdef MOZ_WIDGET_GONK +#include "GrallocImages.h" +#endif + +using namespace mozilla::gfx; + +namespace mozilla { +namespace layers { + +/* static */ TemporaryRef +ImageClient::CreateImageClient(CompositableType aCompositableHostType, + CompositableForwarder* aForwarder, + TextureFlags aFlags) +{ + RefPtr result = nullptr; + switch (aCompositableHostType) { + case COMPOSITABLE_IMAGE: + case BUFFER_IMAGE_SINGLE: + result = new ImageClientSingle(aForwarder, aFlags, COMPOSITABLE_IMAGE); + break; + case BUFFER_IMAGE_BUFFERED: + result = new ImageClientBuffered(aForwarder, aFlags, COMPOSITABLE_IMAGE); + break; + case BUFFER_BRIDGE: + result = new ImageClientBridge(aForwarder, aFlags); + break; + case BUFFER_UNKNOWN: + result = nullptr; + break; + default: + MOZ_CRASH("unhandled program type"); + } + + NS_ASSERTION(result, "Failed to create ImageClient"); + + return result.forget(); +} + +ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd, + TextureFlags aFlags, + CompositableType aType) + : ImageClient(aFwd, aFlags, aType) +{ +} + +ImageClientBuffered::ImageClientBuffered(CompositableForwarder* aFwd, + TextureFlags aFlags, + CompositableType aType) + : ImageClientSingle(aFwd, aFlags, aType) +{ +} + +TextureInfo ImageClientSingle::GetTextureInfo() const +{ + return TextureInfo(COMPOSITABLE_IMAGE); +} + +void +ImageClientSingle::FlushAllImages(bool aExceptFront) +{ + if (!aExceptFront && mFrontBuffer) { + GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); + mFrontBuffer = nullptr; + } +} + +void +ImageClientBuffered::FlushAllImages(bool aExceptFront) +{ + if (!aExceptFront && mFrontBuffer) { + GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); + mFrontBuffer = nullptr; + } + if (mBackBuffer) { + GetForwarder()->RemoveTextureFromCompositable(this, mBackBuffer); + mBackBuffer = nullptr; + } +} + +bool +ImageClientSingle::UpdateImage(ImageContainer* aContainer, + uint32_t aContentFlags) +{ + bool isSwapped = false; + return UpdateImageInternal(aContainer, aContentFlags, &isSwapped); +} + +bool +ImageClientSingle::UpdateImageInternal(ImageContainer* aContainer, + uint32_t aContentFlags, bool* aIsSwapped) +{ + AutoLockImage autoLock(aContainer); + *aIsSwapped = false; + + Image *image = autoLock.GetImage(); + if (!image) { + return false; + } + + if (mLastPaintedImageSerial == image->GetSerial()) { + return true; + } + + if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient(this)) { + // fast path: no need to allocate and/or copy image data + RefPtr texture = image->AsSharedImage()->GetTextureClient(this); + + + if (mFrontBuffer) { + GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); + } + mFrontBuffer = texture; + if (!AddTextureClient(texture)) { + mFrontBuffer = nullptr; + return false; + } + GetForwarder()->UpdatedTexture(this, texture, nullptr); + GetForwarder()->UseTexture(this, texture); + } else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { + PlanarYCbCrImage* ycbcr = static_cast(image); + const PlanarYCbCrData* data = ycbcr->GetData(); + if (!data) { + return false; + } + + if (mFrontBuffer && mFrontBuffer->IsImmutable()) { + GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); + mFrontBuffer = nullptr; + } + + bool bufferCreated = false; + if (!mFrontBuffer) { + mFrontBuffer = CreateBufferTextureClient(gfx::SurfaceFormat::YUV, TEXTURE_FLAGS_DEFAULT); + gfx::IntSize ySize(data->mYSize.width, data->mYSize.height); + gfx::IntSize cbCrSize(data->mCbCrSize.width, data->mCbCrSize.height); + if (!mFrontBuffer->AsTextureClientYCbCr()->AllocateForYCbCr(ySize, cbCrSize, data->mStereoMode)) { + mFrontBuffer = nullptr; + return false; + } + bufferCreated = true; + } + + if (!mFrontBuffer->Lock(OPEN_WRITE_ONLY)) { + mFrontBuffer = nullptr; + return false; + } + bool status = mFrontBuffer->AsTextureClientYCbCr()->UpdateYCbCr(*data); + mFrontBuffer->Unlock(); + + if (bufferCreated) { + if (!AddTextureClient(mFrontBuffer)) { + mFrontBuffer = nullptr; + return false; + } + } + + if (status) { + GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); + GetForwarder()->UseTexture(this, mFrontBuffer); + } else { + MOZ_ASSERT(false); + return false; + } + + } else if (image->GetFormat() == ImageFormat::SHARED_TEXTURE) { + SharedTextureImage* sharedImage = static_cast(image); + const SharedTextureImage::Data *data = sharedImage->GetData(); + gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); + + if (mFrontBuffer) { + GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); + mFrontBuffer = nullptr; + } + + RefPtr buffer = new SharedTextureClientOGL(mTextureFlags); + buffer->InitWith(data->mHandle, size, data->mShareType, data->mInverted); + mFrontBuffer = buffer; + if (!AddTextureClient(mFrontBuffer)) { + mFrontBuffer = nullptr; + return false; + } + + GetForwarder()->UseTexture(this, mFrontBuffer); + } else { + RefPtr surface = image->GetAsSourceSurface(); + MOZ_ASSERT(surface); + + gfx::IntSize size = image->GetSize(); + + if (mFrontBuffer && + (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) { + GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); + mFrontBuffer = nullptr; + } + + bool bufferCreated = false; + if (!mFrontBuffer) { + gfxImageFormat format + = gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat())); + mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), + mTextureFlags, gfx::BackendType::NONE, size); + MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget()); + if (!mFrontBuffer->AllocateForSurface(size)) { + mFrontBuffer = nullptr; + return false; + } + + bufferCreated = true; + } + + if (!mFrontBuffer->Lock(OPEN_WRITE_ONLY)) { + mFrontBuffer = nullptr; + return false; + } + + { + // We must not keep a reference to the DrawTarget after it has been unlocked. + RefPtr dt = mFrontBuffer->GetAsDrawTarget(); + MOZ_ASSERT(surface.get()); + dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); + } + + mFrontBuffer->Unlock(); + + if (bufferCreated) { + if (!AddTextureClient(mFrontBuffer)) { + mFrontBuffer = nullptr; + return false; + } + } + + GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); + GetForwarder()->UseTexture(this, mFrontBuffer); + } + + UpdatePictureRect(image->GetPictureRect()); + + mLastPaintedImageSerial = image->GetSerial(); + aContainer->NotifyPaintedImage(image); + *aIsSwapped = true; + return true; +} + +bool +ImageClientBuffered::UpdateImage(ImageContainer* aContainer, + uint32_t aContentFlags) +{ + RefPtr temp = mFrontBuffer; + mFrontBuffer = mBackBuffer; + mBackBuffer = temp; + + bool isSwapped = false; + bool ret = ImageClientSingle::UpdateImageInternal(aContainer, aContentFlags, &isSwapped); + + if (!isSwapped) { + // If buffer swap did not happen at Host side, swap back the buffers. + RefPtr temp = mFrontBuffer; + mFrontBuffer = mBackBuffer; + mBackBuffer = temp; + } + return ret; +} + +bool +ImageClientSingle::AddTextureClient(TextureClient* aTexture) +{ + MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags); + return CompositableClient::AddTextureClient(aTexture); +} + +void +ImageClientSingle::OnDetach() +{ + mFrontBuffer = nullptr; +} + +void +ImageClientBuffered::OnDetach() +{ + mFrontBuffer = nullptr; + mBackBuffer = nullptr; +} + +ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags, + CompositableType aType) +: CompositableClient(aFwd, aFlags) +, mType(aType) +, mLastPaintedImageSerial(0) +{} + +void +ImageClient::UpdatePictureRect(nsIntRect aRect) +{ + if (mPictureRect == aRect) { + return; + } + mPictureRect = aRect; + MOZ_ASSERT(mForwarder); + GetForwarder()->UpdatePictureRect(this, aRect); +} + +ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd, + TextureFlags aFlags) +: ImageClient(aFwd, aFlags, BUFFER_BRIDGE) +, mAsyncContainerID(0) +, mLayer(nullptr) +{ +} + +bool +ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) +{ + if (!GetForwarder() || !mLayer) { + return false; + } + if (mAsyncContainerID == aContainer->GetAsyncContainerID()) { + return true; + } + mAsyncContainerID = aContainer->GetAsyncContainerID(); + static_cast(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer); + AutoLockImage autoLock(aContainer); + aContainer->NotifyPaintedImage(autoLock.GetImage()); + Updated(); + return true; +} + +already_AddRefed +ImageClientSingle::CreateImage(ImageFormat aFormat) +{ + nsRefPtr img; + switch (aFormat) { + case ImageFormat::PLANAR_YCBCR: + img = new SharedPlanarYCbCrImage(this); + return img.forget(); + case ImageFormat::SHARED_RGB: + img = new SharedRGBImage(this); + return img.forget(); +#ifdef MOZ_WIDGET_GONK + case ImageFormat::GRALLOC_PLANAR_YCBCR: + img = new GrallocImage(); + return img.forget(); +#endif + default: + return nullptr; + } +} + +} +}