diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/ipc/SharedRGBImage.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/gfx/layers/ipc/SharedRGBImage.cpp b/gfx/layers/ipc/SharedRGBImage.cpp new file mode 100644 index 0000000000..392cb09610 --- /dev/null +++ b/gfx/layers/ipc/SharedRGBImage.cpp @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "SharedRGBImage.h" +#include "ImageTypes.h" // for ImageFormat::SHARED_RGB, etc +#include "mozilla/ipc/Shmem.h" // for Shmem +#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat, etc +#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat +#include "mozilla/gfx/Point.h" // for IntSIze +#include "mozilla/layers/BufferTexture.h" +#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator, etc +#include "mozilla/layers/ImageClient.h" // for ImageClient +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc +#include "mozilla/layers/TextureClientRecycleAllocator.h" // for ITextureClientAllocationHelper +#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild +#include "mozilla/mozalloc.h" // for operator delete, etc +#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION +#include "nsISupportsImpl.h" // for Image::AddRef, etc +#include "nsProxyRelease.h" +#include "nsRect.h" // for mozilla::gfx::IntRect + +// Just big enough for a 1080p RGBA32 frame +#define MAX_FRAME_SIZE (16 * 1024 * 1024) + +namespace mozilla { +namespace layers { + +class TextureClientForRawBufferAccessAllocationHelper + : public ITextureClientAllocationHelper { + public: + TextureClientForRawBufferAccessAllocationHelper(gfx::SurfaceFormat aFormat, + gfx::IntSize aSize, + TextureFlags aTextureFlags) + : ITextureClientAllocationHelper(aFormat, aSize, BackendSelector::Content, + aTextureFlags, ALLOC_DEFAULT) {} + + bool IsCompatible(TextureClient* aTextureClient) override { + bool ret = aTextureClient->GetFormat() == mFormat && + aTextureClient->GetSize() == mSize; + return ret; + } + + already_AddRefed<TextureClient> Allocate( + KnowsCompositor* aAllocator) override { + return TextureClient::CreateForRawBufferAccess( + aAllocator, mFormat, mSize, gfx::BackendType::NONE, mTextureFlags); + } +}; + +SharedRGBImage::SharedRGBImage(ImageClient* aCompositable) + : Image(nullptr, ImageFormat::SHARED_RGB), mCompositable(aCompositable) { + MOZ_COUNT_CTOR(SharedRGBImage); +} + +SharedRGBImage::SharedRGBImage(TextureClientRecycleAllocator* aRecycleAllocator) + : Image(nullptr, ImageFormat::SHARED_RGB), + mRecycleAllocator(aRecycleAllocator) { + MOZ_COUNT_CTOR(SharedRGBImage); +} + +SharedRGBImage::~SharedRGBImage() { + MOZ_COUNT_DTOR(SharedRGBImage); + NS_ReleaseOnMainThread("SharedRGBImage::mSourceSurface", + mSourceSurface.forget()); +} + +TextureClientRecycleAllocator* SharedRGBImage::RecycleAllocator() { + static const uint32_t MAX_POOLED_VIDEO_COUNT = 5; + + if (!mRecycleAllocator && mCompositable) { + if (!mCompositable->HasTextureClientRecycler()) { + // Initialize TextureClientRecycler + mCompositable->GetTextureClientRecycler()->SetMaxPoolSize( + MAX_POOLED_VIDEO_COUNT); + } + mRecycleAllocator = mCompositable->GetTextureClientRecycler(); + } + return mRecycleAllocator; +} + +bool SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { + mSize = aSize; + + TextureFlags flags = + mCompositable ? mCompositable->GetTextureFlags() : TextureFlags::DEFAULT; + { + TextureClientForRawBufferAccessAllocationHelper helper(aFormat, aSize, + flags); + mTextureClient = RecycleAllocator()->CreateOrRecycle(helper); + } + + return !!mTextureClient; +} + +gfx::IntSize SharedRGBImage::GetSize() const { return mSize; } + +TextureClient* SharedRGBImage::GetTextureClient( + KnowsCompositor* aKnowsCompositor) { + return mTextureClient.get(); +} + +static void ReleaseTextureClient(void* aData) { + RELEASE_MANUALLY(static_cast<TextureClient*>(aData)); +} + +static gfx::UserDataKey sTextureClientKey; + +already_AddRefed<gfx::SourceSurface> SharedRGBImage::GetAsSourceSurface() { + NS_ASSERTION(NS_IsMainThread(), "Must be main thread"); + + if (mSourceSurface) { + RefPtr<gfx::SourceSurface> surface(mSourceSurface); + return surface.forget(); + } + + RefPtr<gfx::SourceSurface> surface; + { + // We are 'borrowing' the DrawTarget and retaining a permanent reference to + // the underlying data (via the surface). It is in this instance since we + // know that the TextureClient is always wrapping a BufferTextureData and + // therefore it won't go away underneath us. + BufferTextureData* decoded_buffer = + mTextureClient->GetInternalData()->AsBufferTextureData(); + RefPtr<gfx::DrawTarget> drawTarget = decoded_buffer->BorrowDrawTarget(); + + if (!drawTarget) { + return nullptr; + } + + surface = drawTarget->Snapshot(); + if (!surface) { + return nullptr; + } + + // The surface may outlive the owning TextureClient. So, we need to ensure + // that the surface keeps the TextureClient alive via a reference held in + // user data. The TextureClient's DrawTarget only has a weak reference to + // the surface, so we won't create any cycles by just referencing the + // TextureClient. + if (!surface->GetUserData(&sTextureClientKey)) { + surface->AddUserData(&sTextureClientKey, mTextureClient, + ReleaseTextureClient); + ADDREF_MANUALLY(mTextureClient); + } + } + + mSourceSurface = surface; + return surface.forget(); +} + +} // namespace layers +} // namespace mozilla |