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 "ImageClient.h"
8
9 #include <stdint.h> // for uint32_t
10
11 #include "ClientLayerManager.h" // for ClientLayer
12 #include "ImageContainer.h" // for Image, PlanarYCbCrImage, etc
13 #include "ImageTypes.h" // for ImageFormat::PLANAR_YCBCR, etc
14 #include "GLImages.h" // for SurfaceTextureImage::Data, etc
15 #include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
16 #include "gfxPlatform.h" // for gfxPlatform
17 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
18 #include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
19 #include "mozilla/gfx/2D.h"
20 #include "mozilla/gfx/BaseSize.h" // for BaseSize
21 #include "mozilla/gfx/Point.h" // for IntSize
22 #include "mozilla/gfx/Types.h" // for SurfaceFormat, etc
23 #include "mozilla/layers/CompositableClient.h" // for CompositableClient
24 #include "mozilla/layers/CompositableForwarder.h"
25 #include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc
26 #include "mozilla/layers/ISurfaceAllocator.h"
27 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
28 #include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
29 #include "mozilla/layers/TextureClient.h" // for TextureClient, etc
30 #include "mozilla/layers/TextureClientOGL.h" // for SurfaceTextureClient
31 #include "mozilla/mozalloc.h" // for operator delete, etc
32 #include "nsCOMPtr.h" // for already_AddRefed
33 #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
34 #include "nsISupportsImpl.h" // for Image::Release, etc
35 #include "nsRect.h" // for mozilla::gfx::IntRect
36
37 namespace mozilla {
38 namespace layers {
39
40 using namespace mozilla::gfx;
41
42 /* static */
CreateImageClient(CompositableType aCompositableHostType,CompositableForwarder * aForwarder,TextureFlags aFlags)43 already_AddRefed<ImageClient> ImageClient::CreateImageClient(
44 CompositableType aCompositableHostType, CompositableForwarder* aForwarder,
45 TextureFlags aFlags) {
46 RefPtr<ImageClient> result = nullptr;
47 switch (aCompositableHostType) {
48 case CompositableType::IMAGE:
49 result =
50 new ImageClientSingle(aForwarder, aFlags, CompositableType::IMAGE);
51 break;
52 case CompositableType::IMAGE_BRIDGE:
53 result = new ImageClientBridge(aForwarder, aFlags);
54 break;
55 case CompositableType::UNKNOWN:
56 result = nullptr;
57 break;
58 default:
59 MOZ_CRASH("GFX: unhandled program type image");
60 }
61
62 NS_ASSERTION(result, "Failed to create ImageClient");
63
64 return result.forget();
65 }
66
RemoveTexture(TextureClient * aTexture)67 void ImageClient::RemoveTexture(TextureClient* aTexture) {
68 GetForwarder()->RemoveTextureFromCompositable(this, aTexture);
69 }
70
ImageClientSingle(CompositableForwarder * aFwd,TextureFlags aFlags,CompositableType aType)71 ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
72 TextureFlags aFlags,
73 CompositableType aType)
74 : ImageClient(aFwd, aFlags, aType) {}
75
GetTextureInfo() const76 TextureInfo ImageClientSingle::GetTextureInfo() const {
77 return TextureInfo(CompositableType::IMAGE);
78 }
79
FlushAllImages()80 void ImageClientSingle::FlushAllImages() {
81 for (auto& b : mBuffers) {
82 // It should be safe to just assume a default render root here, even if
83 // the texture actually presents in a content render root, as the only
84 // risk would be if the content render root has not / is not going to
85 // generate a frame before the texture gets cleared.
86 RemoveTexture(b.mTextureClient);
87 }
88 mBuffers.Clear();
89 }
90
91 /* static */
CreateTextureClientForImage(Image * aImage,KnowsCompositor * aKnowsCompositor)92 already_AddRefed<TextureClient> ImageClient::CreateTextureClientForImage(
93 Image* aImage, KnowsCompositor* aKnowsCompositor) {
94 RefPtr<TextureClient> texture;
95 if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
96 PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage);
97 const PlanarYCbCrData* data = ycbcr->GetData();
98 if (!data) {
99 return nullptr;
100 }
101 texture = TextureClient::CreateForYCbCr(
102 aKnowsCompositor, data->GetPictureRect(), data->mYSize, data->mYStride,
103 data->mCbCrSize, data->mCbCrStride, data->mStereoMode,
104 data->mColorDepth, data->mYUVColorSpace, data->mColorRange,
105 TextureFlags::DEFAULT);
106 if (!texture) {
107 return nullptr;
108 }
109
110 TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
111 if (!autoLock.Succeeded()) {
112 return nullptr;
113 }
114
115 bool status = UpdateYCbCrTextureClient(texture, *data);
116 MOZ_ASSERT(status);
117 if (!status) {
118 return nullptr;
119 }
120 #ifdef MOZ_WIDGET_ANDROID
121 } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
122 gfx::IntSize size = aImage->GetSize();
123 SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage();
124 texture = AndroidSurfaceTextureData::CreateTextureClient(
125 typedImage->GetHandle(), size, typedImage->GetContinuous(),
126 typedImage->GetOriginPos(), typedImage->GetHasAlpha(),
127 aKnowsCompositor->GetTextureForwarder(), TextureFlags::DEFAULT);
128 #endif
129 } else {
130 RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface();
131 MOZ_ASSERT(surface);
132 texture = TextureClient::CreateForDrawing(
133 aKnowsCompositor, surface->GetFormat(), aImage->GetSize(),
134 BackendSelector::Content, TextureFlags::DEFAULT);
135 if (!texture) {
136 return nullptr;
137 }
138
139 MOZ_ASSERT(texture->CanExposeDrawTarget());
140
141 if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
142 return nullptr;
143 }
144
145 {
146 // We must not keep a reference to the DrawTarget after it has been
147 // unlocked.
148 DrawTarget* dt = texture->BorrowDrawTarget();
149 if (!dt) {
150 gfxWarning()
151 << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
152 return nullptr;
153 }
154 MOZ_ASSERT(surface.get());
155 dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()),
156 IntPoint());
157 }
158
159 texture->Unlock();
160 }
161 return texture.forget();
162 }
163
UpdateImage(ImageContainer * aContainer,uint32_t aContentFlags)164 bool ImageClientSingle::UpdateImage(ImageContainer* aContainer,
165 uint32_t aContentFlags) {
166 AutoTArray<ImageContainer::OwningImage, 4> images;
167 uint32_t generationCounter;
168 aContainer->GetCurrentImages(&images, &generationCounter);
169
170 if (mLastUpdateGenerationCounter == generationCounter) {
171 return true;
172 }
173 mLastUpdateGenerationCounter = generationCounter;
174
175 // Don't try to update to invalid images.
176 images.RemoveElementsBy(
177 [](const auto& image) { return !image.mImage->IsValid(); });
178 if (images.IsEmpty()) {
179 // This can happen if a ClearAllImages raced with SetCurrentImages from
180 // another thread and ClearImagesFromImageBridge ran after the
181 // SetCurrentImages call but before UpdateImageClientNow.
182 // This can also happen if all images in the list are invalid.
183 // We return true because the caller would attempt to recreate the
184 // ImageClient otherwise, and that isn't going to help.
185 for (auto& b : mBuffers) {
186 RemoveTexture(b.mTextureClient);
187 }
188 mBuffers.Clear();
189 return true;
190 }
191
192 nsTArray<Buffer> newBuffers;
193 AutoTArray<CompositableForwarder::TimedTextureClient, 4> textures;
194
195 for (auto& img : images) {
196 Image* image = img.mImage;
197
198 RefPtr<TextureClient> texture = image->GetTextureClient(GetForwarder());
199 const bool hasTextureClient = !!texture;
200
201 for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
202 if (mBuffers[i].mImageSerial == image->GetSerial()) {
203 if (hasTextureClient) {
204 MOZ_ASSERT(image->GetTextureClient(GetForwarder()) ==
205 mBuffers[i].mTextureClient);
206 } else {
207 texture = mBuffers[i].mTextureClient;
208 }
209 // Remove this element from mBuffers so mBuffers only contains
210 // images that aren't present in 'images'
211 mBuffers.RemoveElementAt(i);
212 }
213 }
214
215 if (!texture) {
216 // Slow path, we should not be hitting it very often and if we do it means
217 // we are using an Image class that is not backed by textureClient and we
218 // should fix it.
219 texture = CreateTextureClientForImage(image, GetForwarder());
220 }
221
222 if (!texture) {
223 return false;
224 }
225
226 // We check if the texture's allocator is still open, since in between media
227 // decoding a frame and adding it to the compositable, we could have
228 // restarted the GPU process.
229 if (!texture->GetAllocator()->IPCOpen()) {
230 continue;
231 }
232 if (!AddTextureClient(texture)) {
233 return false;
234 }
235
236 CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
237 t->mTextureClient = texture;
238 t->mTimeStamp = img.mTimeStamp;
239 t->mPictureRect = image->GetPictureRect();
240 t->mFrameID = img.mFrameID;
241 t->mProducerID = img.mProducerID;
242
243 Buffer* newBuf = newBuffers.AppendElement();
244 newBuf->mImageSerial = image->GetSerial();
245 newBuf->mTextureClient = texture;
246
247 texture->SyncWithObject(GetForwarder()->GetSyncObject());
248 }
249
250 GetForwarder()->UseTextures(this, textures);
251
252 for (auto& b : mBuffers) {
253 RemoveTexture(b.mTextureClient);
254 }
255 mBuffers = std::move(newBuffers);
256
257 return true;
258 }
259
GetForwardedTexture()260 RefPtr<TextureClient> ImageClientSingle::GetForwardedTexture() {
261 if (mBuffers.Length() == 0) {
262 return nullptr;
263 }
264 return mBuffers[0].mTextureClient;
265 }
266
AddTextureClient(TextureClient * aTexture)267 bool ImageClientSingle::AddTextureClient(TextureClient* aTexture) {
268 MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
269 return CompositableClient::AddTextureClient(aTexture);
270 }
271
OnDetach()272 void ImageClientSingle::OnDetach() { mBuffers.Clear(); }
273
ImageClient(CompositableForwarder * aFwd,TextureFlags aFlags,CompositableType aType)274 ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
275 CompositableType aType)
276 : CompositableClient(aFwd, aFlags),
277 mLayer(nullptr),
278 mType(aType),
279 mLastUpdateGenerationCounter(0) {}
280
ImageClientBridge(CompositableForwarder * aFwd,TextureFlags aFlags)281 ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
282 TextureFlags aFlags)
283 : ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE) {}
284
UpdateImage(ImageContainer * aContainer,uint32_t aContentFlags)285 bool ImageClientBridge::UpdateImage(ImageContainer* aContainer,
286 uint32_t aContentFlags) {
287 if (!GetForwarder() || !mLayer) {
288 return false;
289 }
290 if (mAsyncContainerHandle == aContainer->GetAsyncContainerHandle()) {
291 return true;
292 }
293
294 mAsyncContainerHandle = aContainer->GetAsyncContainerHandle();
295 if (!mAsyncContainerHandle) {
296 // If we couldn't contact a working ImageBridgeParent, just return.
297 return true;
298 }
299
300 static_cast<ShadowLayerForwarder*>(GetForwarder())
301 ->AttachAsyncCompositable(mAsyncContainerHandle, mLayer);
302 return true;
303 }
304
305 } // namespace layers
306 } // namespace mozilla
307