SharedRGBImage.cpp (5898B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "SharedRGBImage.h" 8 #include "ImageTypes.h" // for ImageFormat::SHARED_RGB, etc 9 #include "mozilla/ipc/Shmem.h" // for Shmem 10 #include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat, etc 11 #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat 12 #include "mozilla/gfx/Point.h" // for IntSIze 13 #include "mozilla/layers/BufferTexture.h" 14 #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator, etc 15 #include "mozilla/layers/ImageClient.h" // for ImageClient 16 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc 17 #include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc 18 #include "mozilla/layers/TextureClientRecycleAllocator.h" // for ITextureClientAllocationHelper 19 #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild 20 #include "mozilla/mozalloc.h" // for operator delete, etc 21 #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION 22 #include "nsISupportsImpl.h" // for Image::AddRef, etc 23 #include "nsProxyRelease.h" 24 #include "nsRect.h" // for mozilla::gfx::IntRect 25 26 // Just big enough for a 1080p RGBA32 frame 27 #define MAX_FRAME_SIZE (16 * 1024 * 1024) 28 29 namespace mozilla { 30 namespace layers { 31 32 class TextureClientForRawBufferAccessAllocationHelper 33 : public ITextureClientAllocationHelper { 34 public: 35 TextureClientForRawBufferAccessAllocationHelper(gfx::SurfaceFormat aFormat, 36 gfx::IntSize aSize, 37 TextureFlags aTextureFlags) 38 : ITextureClientAllocationHelper(aFormat, aSize, BackendSelector::Content, 39 aTextureFlags, ALLOC_DEFAULT) {} 40 41 bool IsCompatible(TextureClient* aTextureClient) override { 42 bool ret = aTextureClient->GetFormat() == mFormat && 43 aTextureClient->GetSize() == mSize; 44 return ret; 45 } 46 47 already_AddRefed<TextureClient> Allocate( 48 KnowsCompositor* aAllocator) override { 49 return TextureClient::CreateForRawBufferAccess( 50 aAllocator, mFormat, mSize, gfx::BackendType::NONE, mTextureFlags); 51 } 52 }; 53 54 SharedRGBImage::SharedRGBImage(ImageClient* aCompositable) 55 : Image(nullptr, ImageFormat::SHARED_RGB), mCompositable(aCompositable) { 56 MOZ_COUNT_CTOR(SharedRGBImage); 57 } 58 59 SharedRGBImage::SharedRGBImage(TextureClientRecycleAllocator* aRecycleAllocator) 60 : Image(nullptr, ImageFormat::SHARED_RGB), 61 mRecycleAllocator(aRecycleAllocator) { 62 MOZ_COUNT_CTOR(SharedRGBImage); 63 } 64 65 SharedRGBImage::~SharedRGBImage() { 66 MOZ_COUNT_DTOR(SharedRGBImage); 67 NS_ReleaseOnMainThread("SharedRGBImage::mSourceSurface", 68 mSourceSurface.forget()); 69 } 70 71 TextureClientRecycleAllocator* SharedRGBImage::RecycleAllocator() { 72 static const uint32_t MAX_POOLED_VIDEO_COUNT = 5; 73 74 if (!mRecycleAllocator && mCompositable) { 75 if (!mCompositable->HasTextureClientRecycler()) { 76 // Initialize TextureClientRecycler 77 mCompositable->GetTextureClientRecycler()->SetMaxPoolSize( 78 MAX_POOLED_VIDEO_COUNT); 79 } 80 mRecycleAllocator = mCompositable->GetTextureClientRecycler(); 81 } 82 return mRecycleAllocator; 83 } 84 85 bool SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { 86 mSize = aSize; 87 88 TextureFlags flags = 89 mCompositable ? mCompositable->GetTextureFlags() : TextureFlags::DEFAULT; 90 { 91 TextureClientForRawBufferAccessAllocationHelper helper(aFormat, aSize, 92 flags); 93 mTextureClient = 94 RecycleAllocator()->CreateOrRecycle(helper).unwrapOr(nullptr); 95 } 96 97 return !!mTextureClient; 98 } 99 100 gfx::IntSize SharedRGBImage::GetSize() const { return mSize; } 101 102 TextureClient* SharedRGBImage::GetTextureClient( 103 KnowsCompositor* aKnowsCompositor) { 104 return mTextureClient.get(); 105 } 106 107 static void ReleaseTextureClient(void* aData) { 108 RELEASE_MANUALLY(static_cast<TextureClient*>(aData)); 109 } 110 111 static gfx::UserDataKey sTextureClientKey; 112 113 already_AddRefed<gfx::SourceSurface> SharedRGBImage::GetAsSourceSurface() { 114 NS_ASSERTION(NS_IsMainThread(), "Must be main thread"); 115 116 if (mSourceSurface) { 117 RefPtr<gfx::SourceSurface> surface(mSourceSurface); 118 return surface.forget(); 119 } 120 121 RefPtr<gfx::SourceSurface> surface; 122 { 123 // We are 'borrowing' the DrawTarget and retaining a permanent reference to 124 // the underlying data (via the surface). It is in this instance since we 125 // know that the TextureClient is always wrapping a BufferTextureData and 126 // therefore it won't go away underneath us. 127 BufferTextureData* decoded_buffer = 128 mTextureClient->GetInternalData()->AsBufferTextureData(); 129 RefPtr<gfx::DrawTarget> drawTarget = decoded_buffer->BorrowDrawTarget(); 130 131 if (!drawTarget) { 132 return nullptr; 133 } 134 135 surface = drawTarget->Snapshot(); 136 if (!surface) { 137 return nullptr; 138 } 139 140 // The surface may outlive the owning TextureClient. So, we need to ensure 141 // that the surface keeps the TextureClient alive via a reference held in 142 // user data. The TextureClient's DrawTarget only has a weak reference to 143 // the surface, so we won't create any cycles by just referencing the 144 // TextureClient. 145 if (!surface->GetUserData(&sTextureClientKey)) { 146 surface->AddUserData(&sTextureClientKey, mTextureClient, 147 ReleaseTextureClient); 148 ADDREF_MANUALLY(mTextureClient); 149 } 150 } 151 152 mSourceSurface = surface; 153 return surface.forget(); 154 } 155 156 } // namespace layers 157 } // namespace mozilla