Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "SharedRGBImage.h"
6 : #include "ImageTypes.h" // for ImageFormat::SHARED_RGB, etc
7 : #include "Shmem.h" // for Shmem
8 : #include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat, etc
9 : #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
10 : #include "mozilla/gfx/Point.h" // for IntSIze
11 : #include "mozilla/layers/BufferTexture.h"
12 : #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator, etc
13 : #include "mozilla/layers/ImageClient.h" // for ImageClient
14 : #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
15 : #include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc
16 : #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
17 : #include "mozilla/mozalloc.h" // for operator delete, etc
18 : #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
19 : #include "nsISupportsImpl.h" // for Image::AddRef, etc
20 : #include "nsRect.h" // for mozilla::gfx::IntRect
21 :
22 : // Just big enough for a 1080p RGBA32 frame
23 : #define MAX_FRAME_SIZE (16 * 1024 * 1024)
24 :
25 : namespace mozilla {
26 : namespace layers {
27 :
28 : already_AddRefed<Image>
29 0 : CreateSharedRGBImage(ImageContainer *aImageContainer,
30 : gfx::IntSize aSize,
31 : gfxImageFormat aImageFormat)
32 : {
33 0 : NS_ASSERTION(aImageFormat == gfx::SurfaceFormat::A8R8G8B8_UINT32 ||
34 : aImageFormat == gfx::SurfaceFormat::X8R8G8B8_UINT32 ||
35 : aImageFormat == gfx::SurfaceFormat::R5G6B5_UINT16,
36 : "RGB formats supported only");
37 :
38 0 : if (!aImageContainer) {
39 0 : NS_WARNING("No ImageContainer to allocate SharedRGBImage");
40 0 : return nullptr;
41 : }
42 :
43 0 : RefPtr<SharedRGBImage> rgbImage = aImageContainer->CreateSharedRGBImage();
44 0 : if (!rgbImage) {
45 0 : NS_WARNING("Failed to create SharedRGBImage");
46 0 : return nullptr;
47 : }
48 0 : if (!rgbImage->Allocate(aSize, gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
49 0 : NS_WARNING("Failed to allocate a shared image");
50 0 : return nullptr;
51 : }
52 0 : return rgbImage.forget();
53 : }
54 :
55 0 : SharedRGBImage::SharedRGBImage(ImageClient* aCompositable)
56 : : Image(nullptr, ImageFormat::SHARED_RGB)
57 0 : , mCompositable(aCompositable)
58 : {
59 0 : MOZ_COUNT_CTOR(SharedRGBImage);
60 0 : }
61 :
62 0 : SharedRGBImage::~SharedRGBImage()
63 : {
64 0 : MOZ_COUNT_DTOR(SharedRGBImage);
65 :
66 0 : if (mCompositable->GetAsyncHandle() && !InImageBridgeChildThread()) {
67 0 : ADDREF_MANUALLY(mTextureClient);
68 0 : ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
69 0 : mTextureClient = nullptr;
70 : }
71 0 : }
72 :
73 : bool
74 0 : SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
75 : {
76 0 : mSize = aSize;
77 0 : mTextureClient = mCompositable->CreateBufferTextureClient(aFormat, aSize,
78 : gfx::BackendType::NONE,
79 0 : TextureFlags::DEFAULT);
80 0 : return !!mTextureClient;
81 : }
82 :
83 : uint8_t*
84 0 : SharedRGBImage::GetBuffer()
85 : {
86 0 : MappedTextureData mapped;
87 0 : if (mTextureClient && mTextureClient->BorrowMappedData(mapped)) {
88 0 : return mapped.data;
89 : }
90 0 : return 0;
91 : }
92 :
93 : gfx::IntSize
94 0 : SharedRGBImage::GetSize()
95 : {
96 0 : return mSize;
97 : }
98 :
99 : TextureClient*
100 0 : SharedRGBImage::GetTextureClient(KnowsCompositor* aForwarder)
101 : {
102 0 : return mTextureClient.get();
103 : }
104 :
105 : static void
106 0 : ReleaseTextureClient(void* aData)
107 : {
108 0 : RELEASE_MANUALLY(static_cast<TextureClient*>(aData));
109 0 : }
110 :
111 : static gfx::UserDataKey sTextureClientKey;
112 :
113 : already_AddRefed<gfx::SourceSurface>
114 0 : SharedRGBImage::GetAsSourceSurface()
115 : {
116 0 : NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
117 :
118 0 : if (mSourceSurface) {
119 0 : RefPtr<gfx::SourceSurface> surface(mSourceSurface);
120 0 : return surface.forget();
121 : }
122 :
123 0 : RefPtr<gfx::SourceSurface> surface;
124 : {
125 : // We are 'borrowing' the DrawTarget and retaining a permanent reference to
126 : // the underlying data (via the surface). It is in this instance since we
127 : // know that the TextureClient is always wrapping a BufferTextureData and
128 : // therefore it won't go away underneath us.
129 : BufferTextureData* decoded_buffer =
130 0 : mTextureClient->GetInternalData()->AsBufferTextureData();
131 0 : RefPtr<gfx::DrawTarget> drawTarget = decoded_buffer->BorrowDrawTarget();
132 :
133 0 : if (!drawTarget) {
134 0 : return nullptr;
135 : }
136 :
137 0 : surface = drawTarget->Snapshot();
138 0 : if (!surface) {
139 0 : return nullptr;
140 : }
141 :
142 : // The surface may outlive the owning TextureClient. So, we need to ensure
143 : // that the surface keeps the TextureClient alive via a reference held in
144 : // user data. The TextureClient's DrawTarget only has a weak reference to the
145 : // surface, so we won't create any cycles by just referencing the TextureClient.
146 0 : if (!surface->GetUserData(&sTextureClientKey)) {
147 0 : surface->AddUserData(&sTextureClientKey, mTextureClient, ReleaseTextureClient);
148 0 : ADDREF_MANUALLY(mTextureClient);
149 : }
150 : }
151 :
152 0 : mSourceSurface = surface;
153 0 : return surface.forget();
154 : }
155 :
156 : } // namespace layers
157 : } // namespace mozilla
|