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