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