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: #include "ImageClient.h" michael@0: #include // for uint32_t michael@0: #include "ImageContainer.h" // for Image, PlanarYCbCrImage, etc michael@0: #include "ImageTypes.h" // for ImageFormat::PLANAR_YCBCR, etc michael@0: #include "SharedTextureImage.h" // for SharedTextureImage::Data, etc michael@0: #include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat michael@0: #include "gfxPlatform.h" // for gfxPlatform michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef michael@0: #include "mozilla/gfx/BaseSize.h" // for BaseSize michael@0: #include "mozilla/gfx/Point.h" // for IntSize michael@0: #include "mozilla/gfx/Types.h" // for SurfaceFormat, etc michael@0: #include "mozilla/layers/CompositableClient.h" // for CompositableClient michael@0: #include "mozilla/layers/CompositableForwarder.h" michael@0: #include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc michael@0: #include "mozilla/layers/ISurfaceAllocator.h" michael@0: #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc michael@0: #include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder michael@0: #include "mozilla/layers/SharedPlanarYCbCrImage.h" michael@0: #include "mozilla/layers/SharedRGBImage.h" michael@0: #include "mozilla/layers/TextureClient.h" // for TextureClient, etc michael@0: #include "mozilla/layers/TextureClientOGL.h" // for SharedTextureClientOGL michael@0: #include "mozilla/mozalloc.h" // for operator delete, etc michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION michael@0: #include "nsISupportsImpl.h" // for Image::Release, etc michael@0: #include "nsRect.h" // for nsIntRect michael@0: #include "mozilla/gfx/2D.h" michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include "GrallocImages.h" michael@0: #endif michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: /* static */ TemporaryRef michael@0: ImageClient::CreateImageClient(CompositableType aCompositableHostType, michael@0: CompositableForwarder* aForwarder, michael@0: TextureFlags aFlags) michael@0: { michael@0: RefPtr result = nullptr; michael@0: switch (aCompositableHostType) { michael@0: case COMPOSITABLE_IMAGE: michael@0: case BUFFER_IMAGE_SINGLE: michael@0: result = new ImageClientSingle(aForwarder, aFlags, COMPOSITABLE_IMAGE); michael@0: break; michael@0: case BUFFER_IMAGE_BUFFERED: michael@0: result = new ImageClientBuffered(aForwarder, aFlags, COMPOSITABLE_IMAGE); michael@0: break; michael@0: case BUFFER_BRIDGE: michael@0: result = new ImageClientBridge(aForwarder, aFlags); michael@0: break; michael@0: case BUFFER_UNKNOWN: michael@0: result = nullptr; michael@0: break; michael@0: default: michael@0: MOZ_CRASH("unhandled program type"); michael@0: } michael@0: michael@0: NS_ASSERTION(result, "Failed to create ImageClient"); michael@0: michael@0: return result.forget(); michael@0: } michael@0: michael@0: ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd, michael@0: TextureFlags aFlags, michael@0: CompositableType aType) michael@0: : ImageClient(aFwd, aFlags, aType) michael@0: { michael@0: } michael@0: michael@0: ImageClientBuffered::ImageClientBuffered(CompositableForwarder* aFwd, michael@0: TextureFlags aFlags, michael@0: CompositableType aType) michael@0: : ImageClientSingle(aFwd, aFlags, aType) michael@0: { michael@0: } michael@0: michael@0: TextureInfo ImageClientSingle::GetTextureInfo() const michael@0: { michael@0: return TextureInfo(COMPOSITABLE_IMAGE); michael@0: } michael@0: michael@0: void michael@0: ImageClientSingle::FlushAllImages(bool aExceptFront) michael@0: { michael@0: if (!aExceptFront && mFrontBuffer) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ImageClientBuffered::FlushAllImages(bool aExceptFront) michael@0: { michael@0: if (!aExceptFront && mFrontBuffer) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: if (mBackBuffer) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mBackBuffer); michael@0: mBackBuffer = nullptr; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: ImageClientSingle::UpdateImage(ImageContainer* aContainer, michael@0: uint32_t aContentFlags) michael@0: { michael@0: bool isSwapped = false; michael@0: return UpdateImageInternal(aContainer, aContentFlags, &isSwapped); michael@0: } michael@0: michael@0: bool michael@0: ImageClientSingle::UpdateImageInternal(ImageContainer* aContainer, michael@0: uint32_t aContentFlags, bool* aIsSwapped) michael@0: { michael@0: AutoLockImage autoLock(aContainer); michael@0: *aIsSwapped = false; michael@0: michael@0: Image *image = autoLock.GetImage(); michael@0: if (!image) { michael@0: return false; michael@0: } michael@0: michael@0: if (mLastPaintedImageSerial == image->GetSerial()) { michael@0: return true; michael@0: } michael@0: michael@0: if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient(this)) { michael@0: // fast path: no need to allocate and/or copy image data michael@0: RefPtr texture = image->AsSharedImage()->GetTextureClient(this); michael@0: michael@0: michael@0: if (mFrontBuffer) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); michael@0: } michael@0: mFrontBuffer = texture; michael@0: if (!AddTextureClient(texture)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: GetForwarder()->UpdatedTexture(this, texture, nullptr); michael@0: GetForwarder()->UseTexture(this, texture); michael@0: } else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { michael@0: PlanarYCbCrImage* ycbcr = static_cast(image); michael@0: const PlanarYCbCrData* data = ycbcr->GetData(); michael@0: if (!data) { michael@0: return false; michael@0: } michael@0: michael@0: if (mFrontBuffer && mFrontBuffer->IsImmutable()) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: michael@0: bool bufferCreated = false; michael@0: if (!mFrontBuffer) { michael@0: mFrontBuffer = CreateBufferTextureClient(gfx::SurfaceFormat::YUV, TEXTURE_FLAGS_DEFAULT); michael@0: gfx::IntSize ySize(data->mYSize.width, data->mYSize.height); michael@0: gfx::IntSize cbCrSize(data->mCbCrSize.width, data->mCbCrSize.height); michael@0: if (!mFrontBuffer->AsTextureClientYCbCr()->AllocateForYCbCr(ySize, cbCrSize, data->mStereoMode)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: bufferCreated = true; michael@0: } michael@0: michael@0: if (!mFrontBuffer->Lock(OPEN_WRITE_ONLY)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: bool status = mFrontBuffer->AsTextureClientYCbCr()->UpdateYCbCr(*data); michael@0: mFrontBuffer->Unlock(); michael@0: michael@0: if (bufferCreated) { michael@0: if (!AddTextureClient(mFrontBuffer)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: if (status) { michael@0: GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); michael@0: GetForwarder()->UseTexture(this, mFrontBuffer); michael@0: } else { michael@0: MOZ_ASSERT(false); michael@0: return false; michael@0: } michael@0: michael@0: } else if (image->GetFormat() == ImageFormat::SHARED_TEXTURE) { michael@0: SharedTextureImage* sharedImage = static_cast(image); michael@0: const SharedTextureImage::Data *data = sharedImage->GetData(); michael@0: gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); michael@0: michael@0: if (mFrontBuffer) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: michael@0: RefPtr buffer = new SharedTextureClientOGL(mTextureFlags); michael@0: buffer->InitWith(data->mHandle, size, data->mShareType, data->mInverted); michael@0: mFrontBuffer = buffer; michael@0: if (!AddTextureClient(mFrontBuffer)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: michael@0: GetForwarder()->UseTexture(this, mFrontBuffer); michael@0: } else { michael@0: RefPtr surface = image->GetAsSourceSurface(); michael@0: MOZ_ASSERT(surface); michael@0: michael@0: gfx::IntSize size = image->GetSize(); michael@0: michael@0: if (mFrontBuffer && michael@0: (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) { michael@0: GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: michael@0: bool bufferCreated = false; michael@0: if (!mFrontBuffer) { michael@0: gfxImageFormat format michael@0: = gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat())); michael@0: mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), michael@0: mTextureFlags, gfx::BackendType::NONE, size); michael@0: MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget()); michael@0: if (!mFrontBuffer->AllocateForSurface(size)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: michael@0: bufferCreated = true; michael@0: } michael@0: michael@0: if (!mFrontBuffer->Lock(OPEN_WRITE_ONLY)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; 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 = mFrontBuffer->GetAsDrawTarget(); michael@0: MOZ_ASSERT(surface.get()); michael@0: dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); michael@0: } michael@0: michael@0: mFrontBuffer->Unlock(); michael@0: michael@0: if (bufferCreated) { michael@0: if (!AddTextureClient(mFrontBuffer)) { michael@0: mFrontBuffer = nullptr; michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); michael@0: GetForwarder()->UseTexture(this, mFrontBuffer); michael@0: } michael@0: michael@0: UpdatePictureRect(image->GetPictureRect()); michael@0: michael@0: mLastPaintedImageSerial = image->GetSerial(); michael@0: aContainer->NotifyPaintedImage(image); michael@0: *aIsSwapped = true; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ImageClientBuffered::UpdateImage(ImageContainer* aContainer, michael@0: uint32_t aContentFlags) michael@0: { michael@0: RefPtr temp = mFrontBuffer; michael@0: mFrontBuffer = mBackBuffer; michael@0: mBackBuffer = temp; michael@0: michael@0: bool isSwapped = false; michael@0: bool ret = ImageClientSingle::UpdateImageInternal(aContainer, aContentFlags, &isSwapped); michael@0: michael@0: if (!isSwapped) { michael@0: // If buffer swap did not happen at Host side, swap back the buffers. michael@0: RefPtr temp = mFrontBuffer; michael@0: mFrontBuffer = mBackBuffer; michael@0: mBackBuffer = temp; michael@0: } michael@0: return ret; michael@0: } michael@0: michael@0: bool michael@0: ImageClientSingle::AddTextureClient(TextureClient* aTexture) michael@0: { michael@0: MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags); michael@0: return CompositableClient::AddTextureClient(aTexture); michael@0: } michael@0: michael@0: void michael@0: ImageClientSingle::OnDetach() michael@0: { michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: michael@0: void michael@0: ImageClientBuffered::OnDetach() michael@0: { michael@0: mFrontBuffer = nullptr; michael@0: mBackBuffer = nullptr; michael@0: } michael@0: michael@0: ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags, michael@0: CompositableType aType) michael@0: : CompositableClient(aFwd, aFlags) michael@0: , mType(aType) michael@0: , mLastPaintedImageSerial(0) michael@0: {} michael@0: michael@0: void michael@0: ImageClient::UpdatePictureRect(nsIntRect aRect) michael@0: { michael@0: if (mPictureRect == aRect) { michael@0: return; michael@0: } michael@0: mPictureRect = aRect; michael@0: MOZ_ASSERT(mForwarder); michael@0: GetForwarder()->UpdatePictureRect(this, aRect); michael@0: } michael@0: michael@0: ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd, michael@0: TextureFlags aFlags) michael@0: : ImageClient(aFwd, aFlags, BUFFER_BRIDGE) michael@0: , mAsyncContainerID(0) michael@0: , mLayer(nullptr) michael@0: { michael@0: } michael@0: michael@0: bool michael@0: ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) michael@0: { michael@0: if (!GetForwarder() || !mLayer) { michael@0: return false; michael@0: } michael@0: if (mAsyncContainerID == aContainer->GetAsyncContainerID()) { michael@0: return true; michael@0: } michael@0: mAsyncContainerID = aContainer->GetAsyncContainerID(); michael@0: static_cast(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer); michael@0: AutoLockImage autoLock(aContainer); michael@0: aContainer->NotifyPaintedImage(autoLock.GetImage()); michael@0: Updated(); michael@0: return true; michael@0: } michael@0: michael@0: already_AddRefed michael@0: ImageClientSingle::CreateImage(ImageFormat aFormat) michael@0: { michael@0: nsRefPtr img; michael@0: switch (aFormat) { michael@0: case ImageFormat::PLANAR_YCBCR: michael@0: img = new SharedPlanarYCbCrImage(this); michael@0: return img.forget(); michael@0: case ImageFormat::SHARED_RGB: michael@0: img = new SharedRGBImage(this); michael@0: return img.forget(); michael@0: #ifdef MOZ_WIDGET_GONK michael@0: case ImageFormat::GRALLOC_PLANAR_YCBCR: michael@0: img = new GrallocImage(); michael@0: return img.forget(); michael@0: #endif michael@0: default: michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: } michael@0: }