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