/* -*- 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 "mozilla/layers/TextureClient.h" #include "mozilla/layers/TextureClientOGL.h" #include "mozilla/layers/ImageClient.h" #include "mozilla/layers/CanvasClient.h" #include "mozilla/layers/ContentClient.h" #include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/SharedPlanarYCbCrImage.h" #include "GLContext.h" #include "BasicLayers.h" // for PaintContext #include "mozilla/layers/YCbCrImageDataSerializer.h" #include "gfxReusableSurfaceWrapper.h" #include "gfxPlatform.h" #include "mozilla/layers/ImageDataSerializer.h" #include "gfx2DGlue.h" #include using namespace mozilla::gl; namespace mozilla { namespace layers { TextureClient::TextureClient(TextureFlags aFlags) : mID(0) , mFlags(aFlags) {} TextureClient::~TextureClient() {} bool TextureClient::ShouldDeallocateInDestructor() const { return IsAllocated() && !IsSharedWithCompositor() && !(GetFlags() & (TEXTURE_DEALLOCATE_HOST|TEXTURE_DEALLOCATE_CLIENT)); } bool ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) { if (!IsAllocated() || GetFormat() == gfx::FORMAT_UNKNOWN) { return false; } aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat()); return true; } ISurfaceAllocator* ShmemTextureClient::GetAllocator() const { return mCompositable->GetForwarder(); } bool ShmemTextureClient::Allocate(uint32_t aSize) { ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType(); mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem); return mAllocated; } uint8_t* ShmemTextureClient::GetBuffer() const { if (mAllocated) { return mShmem.get(); } return nullptr; } size_t ShmemTextureClient::GetBufferSize() const { return mShmem.Size(); } ShmemTextureClient::ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat) : BufferTextureClient(aCompositable, aFormat) , mAllocated(false) { MOZ_COUNT_CTOR(ShmemTextureClient); } ShmemTextureClient::~ShmemTextureClient() { MOZ_COUNT_DTOR(ShmemTextureClient); if (ShouldDeallocateInDestructor()) { // if the buffer has never been shared we must deallocate it or ir would // leak. mCompositable->GetForwarder()->DeallocShmem(mShmem); } } bool MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) { if (!IsAllocated() || GetFormat() == gfx::FORMAT_UNKNOWN) { return false; } aDescriptor = SurfaceDescriptorMemory(reinterpret_cast(mBuffer), GetFormat()); return true; } bool MemoryTextureClient::Allocate(uint32_t aSize) { MOZ_ASSERT(!mBuffer); mBuffer = new uint8_t[aSize]; mBufSize = aSize; return true; } MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat) : BufferTextureClient(aCompositable, aFormat) , mBuffer(nullptr) , mBufSize(0) { MOZ_COUNT_CTOR(MemoryTextureClient); } MemoryTextureClient::~MemoryTextureClient() { MOZ_COUNT_DTOR(MemoryTextureClient); if (ShouldDeallocateInDestructor()) { // if the buffer has never been shared we must deallocate it or ir would // leak. delete mBuffer; } } BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat) : TextureClient() , mCompositable(aCompositable) , mFormat(aFormat) {} BufferTextureClient::~BufferTextureClient() {} bool BufferTextureClient::UpdateSurface(gfxASurface* aSurface) { MOZ_ASSERT(aSurface); ImageDataSerializer serializer(GetBuffer()); if (!serializer.IsValid()) { return false; } RefPtr surf = serializer.GetAsThebesSurface(); if (!surf) { return false; } nsRefPtr tmpCtx = new gfxContext(surf.get()); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width, serializer.GetSize().height)); return true; } bool BufferTextureClient::AllocateForSurface(gfx::IntSize aSize) { MOZ_ASSERT(mFormat != gfx::FORMAT_YUV, "This textureClient cannot use YCbCr data"); int bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat); if (!Allocate(bufSize)) { return false; } ImageDataSerializer serializer(GetBuffer()); serializer.InitializeBufferInfo(aSize, mFormat); return true; } bool BufferTextureClient::UpdateYCbCr(const PlanarYCbCrImage::Data& aData) { MOZ_ASSERT(mFormat == gfx::FORMAT_YUV, "This textureClient can only use YCbCr data"); MOZ_ASSERT(!IsImmutable()); MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip); YCbCrImageDataSerializer serializer(GetBuffer()); MOZ_ASSERT(serializer.IsValid()); if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel, aData.mYSize, aData.mYStride, aData.mCbCrSize, aData.mCbCrStride, aData.mYSkip, aData.mCbSkip)) { NS_WARNING("Failed to copy image data!"); return false; } return true; } bool BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize) { size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize, aCbCrSize); if (!Allocate(bufSize)) { return false; } YCbCrImageDataSerializer serializer(GetBuffer()); serializer.InitializeBufferInfo(aYSize, aCbCrSize); return true; } DeprecatedTextureClient::DeprecatedTextureClient(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo) : mForwarder(aForwarder) , mTextureInfo(aTextureInfo) , mAccessMode(ACCESS_READ_WRITE) { MOZ_COUNT_CTOR(DeprecatedTextureClient); } DeprecatedTextureClient::~DeprecatedTextureClient() { MOZ_COUNT_DTOR(DeprecatedTextureClient); MOZ_ASSERT(mDescriptor.type() == SurfaceDescriptor::T__None, "Need to release surface!"); } DeprecatedTextureClientShmem::DeprecatedTextureClientShmem(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo) : DeprecatedTextureClient(aForwarder, aTextureInfo) , mSurface(nullptr) , mSurfaceAsImage(nullptr) { } void DeprecatedTextureClientShmem::ReleaseResources() { if (mSurface) { mSurface = nullptr; ShadowLayerForwarder::CloseDescriptor(mDescriptor); } if (mTextureInfo.mTextureFlags & TEXTURE_DEALLOCATE_HOST) { mDescriptor = SurfaceDescriptor(); return; } if (IsSurfaceDescriptorValid(mDescriptor)) { mForwarder->DestroySharedSurface(&mDescriptor); mDescriptor = SurfaceDescriptor(); } } void DeprecatedTextureClientShmem::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aContentType) { if (aSize != mSize || aContentType != mContentType || !IsSurfaceDescriptorValid(mDescriptor)) { ReleaseResources(); mContentType = aContentType; mSize = aSize; if (!mForwarder->AllocSurfaceDescriptor(gfxIntSize(mSize.width, mSize.height), mContentType, &mDescriptor)) { NS_WARNING("creating SurfaceDescriptor failed!"); } } } void DeprecatedTextureClientShmem::SetDescriptor(const SurfaceDescriptor& aDescriptor) { if (IsSurfaceDescriptorValid(aDescriptor)) { ReleaseResources(); mDescriptor = aDescriptor; } else { EnsureAllocated(mSize, mContentType); } mSurface = nullptr; NS_ASSERTION(mDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc || mDescriptor.type() == SurfaceDescriptor::TShmem || mDescriptor.type() == SurfaceDescriptor::TMemoryImage || mDescriptor.type() == SurfaceDescriptor::TRGBImage, "Invalid surface descriptor"); } gfxASurface* DeprecatedTextureClientShmem::GetSurface() { if (!mSurface) { if (!IsSurfaceDescriptorValid(mDescriptor)) { return nullptr; } MOZ_ASSERT(mAccessMode == ACCESS_READ_WRITE || mAccessMode == ACCESS_READ_ONLY); OpenMode mode = mAccessMode == ACCESS_READ_WRITE ? OPEN_READ_WRITE : OPEN_READ_ONLY; mSurface = ShadowLayerForwarder::OpenDescriptor(mode, mDescriptor); } return mSurface.get(); } gfx::DrawTarget* DeprecatedTextureClientShmem::LockDrawTarget() { if (mDrawTarget) { return mDrawTarget; } gfxASurface* surface = GetSurface(); mDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, mSize); return mDrawTarget; } void DeprecatedTextureClientShmem::Unlock() { mSurface = nullptr; mSurfaceAsImage = nullptr; mDrawTarget = nullptr; ShadowLayerForwarder::CloseDescriptor(mDescriptor); } gfxImageSurface* DeprecatedTextureClientShmem::LockImageSurface() { if (!mSurfaceAsImage) { mSurfaceAsImage = GetSurface()->GetAsImageSurface(); } return mSurfaceAsImage.get(); } DeprecatedTextureClientTile::DeprecatedTextureClientTile(const DeprecatedTextureClientTile& aOther) : DeprecatedTextureClient(aOther.mForwarder, aOther.mTextureInfo) , mSurface(aOther.mSurface) {} DeprecatedTextureClientTile::~DeprecatedTextureClientTile() {} void DeprecatedTextureClientShmemYCbCr::ReleaseResources() { GetForwarder()->DestroySharedSurface(&mDescriptor); } void DeprecatedTextureClientShmemYCbCr::SetDescriptor(const SurfaceDescriptor& aDescriptor) { MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TYCbCrImage); if (IsSurfaceDescriptorValid(mDescriptor)) { GetForwarder()->DestroySharedSurface(&mDescriptor); } mDescriptor = aDescriptor; MOZ_ASSERT(IsSurfaceDescriptorValid(mDescriptor)); } void DeprecatedTextureClientShmemYCbCr::SetDescriptorFromReply(const SurfaceDescriptor& aDescriptor) { MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TYCbCrImage); DeprecatedSharedPlanarYCbCrImage* shYCbCr = DeprecatedSharedPlanarYCbCrImage::FromSurfaceDescriptor(aDescriptor); if (shYCbCr) { shYCbCr->Release(); mDescriptor = SurfaceDescriptor(); } else { SetDescriptor(aDescriptor); } } void DeprecatedTextureClientShmemYCbCr::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) { NS_RUNTIMEABORT("not enough arguments to do this (need both Y and CbCr sizes)"); } DeprecatedTextureClientTile::DeprecatedTextureClientTile(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo) : DeprecatedTextureClient(aForwarder, aTextureInfo) , mSurface(nullptr) { mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED; } void DeprecatedTextureClientTile::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) { if (!mSurface || mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) { gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(aSize.width, aSize.height), gfxPlatform::GetPlatform()->OptimalFormatForContent(aType), aType != gfxASurface::CONTENT_COLOR); mSurface = new gfxReusableSurfaceWrapper(tmpTile); mContentType = aType; } } gfxImageSurface* DeprecatedTextureClientTile::LockImageSurface() { // Use the gfxReusableSurfaceWrapper, which will reuse the surface // if the compositor no longer has a read lock, otherwise the surface // will be copied into a new writable surface. gfxImageSurface* writableSurface = nullptr; mSurface = mSurface->GetWritable(&writableSurface); return writableSurface; } // XXX - All the code below can be removed as soon as we remove // DeprecatedImageClientSingle (which has already been ported to the new // textures). bool AutoLockShmemClient::Update(Image* aImage, uint32_t aContentFlags, gfxASurface *aSurface) { if (!aImage) { return false; } gfxIntSize size = aImage->GetSize(); gfxASurface::gfxContentType contentType = aSurface->GetContentType(); bool isOpaque = (aContentFlags & Layer::CONTENT_OPAQUE); if (contentType != gfxASurface::CONTENT_ALPHA && isOpaque) { contentType = gfxASurface::CONTENT_COLOR; } mDeprecatedTextureClient->EnsureAllocated(gfx::IntSize(size.width, size.height), contentType); OpenMode mode = mDeprecatedTextureClient->GetAccessMode() == DeprecatedTextureClient::ACCESS_READ_WRITE ? OPEN_READ_WRITE : OPEN_READ_ONLY; nsRefPtr tmpASurface = ShadowLayerForwarder::OpenDescriptor(mode, *mDeprecatedTextureClient->LockSurfaceDescriptor()); if (!tmpASurface) { return false; } nsRefPtr tmpCtx = new gfxContext(tmpASurface.get()); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); tmpCtx->DrawSurface(aSurface, gfxSize(size.width, size.height)); return true; } bool AutoLockYCbCrClient::Update(PlanarYCbCrImage* aImage) { MOZ_ASSERT(aImage); MOZ_ASSERT(mDescriptor); const PlanarYCbCrImage::Data *data = aImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); if (!data) { return false; } if (!EnsureDeprecatedTextureClient(aImage)) { return false; } ipc::Shmem& shmem = mDescriptor->get_YCbCrImage().data(); YCbCrImageDataSerializer serializer(shmem.get()); if (!serializer.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel, data->mYSize, data->mYStride, data->mCbCrSize, data->mCbCrStride, data->mYSkip, data->mCbSkip)) { NS_WARNING("Failed to copy image data!"); return false; } return true; } bool AutoLockYCbCrClient::EnsureDeprecatedTextureClient(PlanarYCbCrImage* aImage) { MOZ_ASSERT(aImage); if (!aImage) { return false; } const PlanarYCbCrImage::Data *data = aImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); if (!data) { return false; } bool needsAllocation = false; if (mDescriptor->type() != SurfaceDescriptor::TYCbCrImage) { needsAllocation = true; } else { ipc::Shmem& shmem = mDescriptor->get_YCbCrImage().data(); YCbCrImageDataSerializer serializer(shmem.get()); if (serializer.GetYSize() != data->mYSize || serializer.GetCbCrSize() != data->mCbCrSize) { needsAllocation = true; } } if (!needsAllocation) { return true; } mDeprecatedTextureClient->ReleaseResources(); ipc::SharedMemory::SharedMemoryType shmType = OptimalShmemType(); size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(data->mYSize, data->mCbCrSize); ipc::Shmem shmem; if (!mDeprecatedTextureClient->GetForwarder()->AllocUnsafeShmem(size, shmType, &shmem)) { return false; } YCbCrImageDataSerializer serializer(shmem.get()); serializer.InitializeBufferInfo(data->mYSize, data->mCbCrSize); *mDescriptor = YCbCrImage(shmem, 0); return true; } } }