/src/mozilla-central/gfx/layers/ipc/ImageBridgeChild.cpp
Line | Count | Source (jump to first uncovered line) |
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 "ImageBridgeChild.h" |
8 | | #include <vector> // for vector |
9 | | #include "ImageBridgeParent.h" // for ImageBridgeParent |
10 | | #include "ImageContainer.h" // for ImageContainer |
11 | | #include "Layers.h" // for Layer, etc |
12 | | #include "ShadowLayers.h" // for ShadowLayerForwarder |
13 | | #include "base/message_loop.h" // for MessageLoop |
14 | | #include "base/platform_thread.h" // for PlatformThread |
15 | | #include "base/process.h" // for ProcessId |
16 | | #include "base/task.h" // for NewRunnableFunction, etc |
17 | | #include "base/thread.h" // for Thread |
18 | | #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
19 | | #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock |
20 | | #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc |
21 | | #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc |
22 | | #include "mozilla/ipc/Transport.h" // for Transport |
23 | | #include "mozilla/gfx/Point.h" // for IntSize |
24 | | #include "mozilla/layers/AsyncCanvasRenderer.h" |
25 | | #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager |
26 | | #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild |
27 | | #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc |
28 | | #include "mozilla/layers/CompositorThread.h" |
29 | | #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator |
30 | | #include "mozilla/layers/ImageClient.h" // for ImageClient |
31 | | #include "mozilla/layers/LayersMessages.h" // for CompositableOperation |
32 | | #include "mozilla/layers/TextureClient.h" // for TextureClient |
33 | | #include "mozilla/dom/ContentChild.h" |
34 | | #include "mozilla/mozalloc.h" // for operator new, etc |
35 | | #include "mtransport/runnable_utils.h" |
36 | | #include "nsContentUtils.h" |
37 | | #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc |
38 | | #include "nsTArray.h" // for AutoTArray, nsTArray, etc |
39 | | #include "nsTArrayForwardDeclare.h" // for AutoTArray |
40 | | #include "nsThreadUtils.h" // for NS_IsMainThread |
41 | | #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop |
42 | | #include "mozilla/StaticMutex.h" |
43 | | #include "mozilla/StaticPtr.h" // for StaticRefPtr |
44 | | #include "mozilla/layers/TextureClient.h" |
45 | | #include "SynchronousTask.h" |
46 | | |
47 | | #if defined(XP_WIN) |
48 | | #include "mozilla/gfx/DeviceManagerDx.h" |
49 | | #endif |
50 | | |
51 | | namespace mozilla { |
52 | | namespace ipc { |
53 | | class Shmem; |
54 | | } // namespace ipc |
55 | | |
56 | | namespace layers { |
57 | | |
58 | | using base::Thread; |
59 | | using base::ProcessId; |
60 | | using namespace mozilla::ipc; |
61 | | using namespace mozilla::gfx; |
62 | | using namespace mozilla::media; |
63 | | |
64 | | typedef std::vector<CompositableOperation> OpVector; |
65 | | typedef nsTArray<OpDestroy> OpDestroyVector; |
66 | | |
67 | | struct CompositableTransaction |
68 | | { |
69 | | CompositableTransaction() |
70 | | : mFinished(true) |
71 | 0 | {} |
72 | | ~CompositableTransaction() |
73 | 0 | { |
74 | 0 | End(); |
75 | 0 | } |
76 | | bool Finished() const |
77 | 0 | { |
78 | 0 | return mFinished; |
79 | 0 | } |
80 | | void Begin() |
81 | 0 | { |
82 | 0 | MOZ_ASSERT(mFinished); |
83 | 0 | mFinished = false; |
84 | 0 | } |
85 | | void End() |
86 | 0 | { |
87 | 0 | mFinished = true; |
88 | 0 | mOperations.clear(); |
89 | 0 | mDestroyedActors.Clear(); |
90 | 0 | } |
91 | | bool IsEmpty() const |
92 | 0 | { |
93 | 0 | return mOperations.empty() && mDestroyedActors.IsEmpty(); |
94 | 0 | } |
95 | | void AddNoSwapEdit(const CompositableOperation& op) |
96 | 0 | { |
97 | 0 | MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); |
98 | 0 | mOperations.push_back(op); |
99 | 0 | } |
100 | | |
101 | | OpVector mOperations; |
102 | | OpDestroyVector mDestroyedActors; |
103 | | |
104 | | bool mFinished; |
105 | | }; |
106 | | |
107 | | struct AutoEndTransaction { |
108 | 0 | explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {} |
109 | 0 | ~AutoEndTransaction() { mTxn->End(); } |
110 | | CompositableTransaction* mTxn; |
111 | | }; |
112 | | |
113 | | void |
114 | | ImageBridgeChild::UseTextures(CompositableClient* aCompositable, |
115 | | const nsTArray<TimedTextureClient>& aTextures) |
116 | 0 | { |
117 | 0 | MOZ_ASSERT(aCompositable); |
118 | 0 | MOZ_ASSERT(aCompositable->GetIPCHandle()); |
119 | 0 | MOZ_ASSERT(aCompositable->IsConnected()); |
120 | 0 |
|
121 | 0 | AutoTArray<TimedTexture,4> textures; |
122 | 0 |
|
123 | 0 | for (auto& t : aTextures) { |
124 | 0 | MOZ_ASSERT(t.mTextureClient); |
125 | 0 | MOZ_ASSERT(t.mTextureClient->GetIPDLActor()); |
126 | 0 |
|
127 | 0 | if (!t.mTextureClient->IsSharedWithCompositor()) { |
128 | 0 | return; |
129 | 0 | } |
130 | 0 | |
131 | 0 | bool readLocked = t.mTextureClient->OnForwardedToHost(); |
132 | 0 | textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), |
133 | 0 | t.mTimeStamp, t.mPictureRect, |
134 | 0 | t.mFrameID, t.mProducerID, |
135 | 0 | readLocked)); |
136 | 0 |
|
137 | 0 | // Wait end of usage on host side if TextureFlags::RECYCLE is set |
138 | 0 | HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient); |
139 | 0 | } |
140 | 0 | mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(), |
141 | 0 | OpUseTexture(textures))); |
142 | 0 | } |
143 | | |
144 | | void |
145 | | ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable, |
146 | | TextureClient* aTextureOnBlack, |
147 | | TextureClient* aTextureOnWhite) |
148 | 0 | { |
149 | 0 | MOZ_CRASH("should not be called"); |
150 | 0 | } |
151 | | |
152 | | void |
153 | | ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient) |
154 | 0 | { |
155 | 0 | // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on ImageBridge. |
156 | 0 | if (!aClient || |
157 | 0 | !(aClient->GetFlags() & TextureFlags::RECYCLE)) { |
158 | 0 | return; |
159 | 0 | } |
160 | 0 | aClient->SetLastFwdTransactionId(GetFwdTransactionId()); |
161 | 0 | mTexturesWaitingRecycled.emplace(aClient->GetSerial(), aClient); |
162 | 0 | } |
163 | | |
164 | | void |
165 | | ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId) |
166 | 0 | { |
167 | 0 | auto it = mTexturesWaitingRecycled.find(aTextureId); |
168 | 0 | if (it != mTexturesWaitingRecycled.end()) { |
169 | 0 | if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) { |
170 | 0 | // Released on host side, but client already requested newer use texture. |
171 | 0 | return; |
172 | 0 | } |
173 | 0 | mTexturesWaitingRecycled.erase(it); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | void |
178 | | ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId) |
179 | 0 | { |
180 | 0 | MOZ_ASSERT(InImageBridgeChildThread()); |
181 | 0 | mTexturesWaitingRecycled.erase(aTextureId); |
182 | 0 | } |
183 | | |
184 | | // Singleton |
185 | | static StaticMutex sImageBridgeSingletonLock; |
186 | | static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton; |
187 | | static Thread *sImageBridgeChildThread = nullptr; |
188 | | |
189 | | // dispatched function |
190 | | void |
191 | | ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask) |
192 | 0 | { |
193 | 0 | AutoCompleteTask complete(aTask); |
194 | 0 |
|
195 | 0 | MOZ_ASSERT(InImageBridgeChildThread(), |
196 | 0 | "Should be in ImageBridgeChild thread."); |
197 | 0 |
|
198 | 0 | MediaSystemResourceManager::Shutdown(); |
199 | 0 |
|
200 | 0 | // Force all managed protocols to shut themselves down cleanly |
201 | 0 | InfallibleTArray<PTextureChild*> textures; |
202 | 0 | ManagedPTextureChild(textures); |
203 | 0 | for (int i = textures.Length() - 1; i >= 0; --i) { |
204 | 0 | RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]); |
205 | 0 | if (client) { |
206 | 0 | client->Destroy(); |
207 | 0 | } |
208 | 0 | } |
209 | 0 |
|
210 | 0 | if (mCanSend) { |
211 | 0 | SendWillClose(); |
212 | 0 | } |
213 | 0 | MarkShutDown(); |
214 | 0 |
|
215 | 0 | // From now on, no message can be sent through the image bridge from the |
216 | 0 | // client side except the final Stop message. |
217 | 0 | } |
218 | | |
219 | | // dispatched function |
220 | | void |
221 | | ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask) |
222 | 0 | { |
223 | 0 | AutoCompleteTask complete(aTask); |
224 | 0 |
|
225 | 0 | MOZ_ASSERT(InImageBridgeChildThread(), |
226 | 0 | "Should be in ImageBridgeChild thread."); |
227 | 0 | if (!mDestroyed) { |
228 | 0 | Close(); |
229 | 0 | } |
230 | 0 | } |
231 | | |
232 | | void |
233 | | ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy) |
234 | 0 | { |
235 | 0 | mCanSend = false; |
236 | 0 | mDestroyed = true; |
237 | 0 | { |
238 | 0 | MutexAutoLock lock(mContainerMapLock); |
239 | 0 | mImageContainerListeners.clear(); |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | | void |
244 | | ImageBridgeChild::DeallocPImageBridgeChild() |
245 | 0 | { |
246 | 0 | this->Release(); |
247 | 0 | } |
248 | | |
249 | | void |
250 | | ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask, |
251 | | RefPtr<ImageClient>* result, |
252 | | CompositableType aType, |
253 | | ImageContainer* aImageContainer) |
254 | 0 | { |
255 | 0 | AutoCompleteTask complete(aTask); |
256 | 0 | *result = CreateImageClientNow(aType, aImageContainer); |
257 | 0 | } |
258 | | |
259 | | // dispatched function |
260 | | void |
261 | | ImageBridgeChild::CreateCanvasClientSync(SynchronousTask* aTask, |
262 | | CanvasClient::CanvasClientType aType, |
263 | | TextureFlags aFlags, |
264 | | RefPtr<CanvasClient>* const outResult) |
265 | 0 | { |
266 | 0 | AutoCompleteTask complete(aTask); |
267 | 0 | *outResult = CreateCanvasClientNow(aType, aFlags); |
268 | 0 | } |
269 | | |
270 | | ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace) |
271 | | : mNamespace(aNamespace) |
272 | | , mCanSend(false) |
273 | | , mDestroyed(false) |
274 | | , mFwdTransactionId(0) |
275 | | , mContainerMapLock("ImageBridgeChild.mContainerMapLock") |
276 | 0 | { |
277 | 0 | MOZ_ASSERT(mNamespace); |
278 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
279 | 0 |
|
280 | 0 | mTxn = new CompositableTransaction(); |
281 | 0 | } |
282 | | |
283 | | ImageBridgeChild::~ImageBridgeChild() |
284 | 0 | { |
285 | 0 | delete mTxn; |
286 | 0 | } |
287 | | |
288 | | void |
289 | | ImageBridgeChild::MarkShutDown() |
290 | 0 | { |
291 | 0 | mTexturesWaitingRecycled.clear(); |
292 | 0 |
|
293 | 0 | mCanSend = false; |
294 | 0 | } |
295 | | |
296 | | void |
297 | | ImageBridgeChild::Connect(CompositableClient* aCompositable, |
298 | | ImageContainer* aImageContainer) |
299 | 0 | { |
300 | 0 | MOZ_ASSERT(aCompositable); |
301 | 0 | MOZ_ASSERT(InImageBridgeChildThread()); |
302 | 0 | MOZ_ASSERT(CanSend()); |
303 | 0 |
|
304 | 0 | // Note: this is static, rather than per-IBC, so IDs are not re-used across |
305 | 0 | // ImageBridgeChild instances. This is relevant for the GPU process, where |
306 | 0 | // we don't want old IDs to potentially leak into a recreated ImageBridge. |
307 | 0 | static uint64_t sNextID = 1; |
308 | 0 | uint64_t id = sNextID++; |
309 | 0 |
|
310 | 0 | // ImageClient of ImageContainer provides aImageContainer. |
311 | 0 | // But offscreen canvas does not provide it. |
312 | 0 | if (aImageContainer) { |
313 | 0 | MutexAutoLock lock(mContainerMapLock); |
314 | 0 | MOZ_ASSERT(mImageContainerListeners.find(id) == mImageContainerListeners.end()); |
315 | 0 | mImageContainerListeners.emplace(id, aImageContainer->GetImageContainerListener()); |
316 | 0 | } |
317 | 0 |
|
318 | 0 | CompositableHandle handle(id); |
319 | 0 | aCompositable->InitIPDL(handle); |
320 | 0 | SendNewCompositable(handle, aCompositable->GetTextureInfo(), GetCompositorBackendType()); |
321 | 0 | } |
322 | | |
323 | | void |
324 | | ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle) |
325 | 0 | { |
326 | 0 | MutexAutoLock lock(mContainerMapLock); |
327 | 0 | mImageContainerListeners.erase(aHandle.Value()); |
328 | 0 | } |
329 | | |
330 | | Thread* ImageBridgeChild::GetThread() const |
331 | 0 | { |
332 | 0 | return sImageBridgeChildThread; |
333 | 0 | } |
334 | | |
335 | | /* static */ RefPtr<ImageBridgeChild> |
336 | | ImageBridgeChild::GetSingleton() |
337 | 0 | { |
338 | 0 | StaticMutexAutoLock lock(sImageBridgeSingletonLock); |
339 | 0 | return sImageBridgeChildSingleton; |
340 | 0 | } |
341 | | |
342 | | void |
343 | | ImageBridgeChild::UpdateImageClient(RefPtr<ImageContainer> aContainer) |
344 | 0 | { |
345 | 0 | if (!aContainer) { |
346 | 0 | return; |
347 | 0 | } |
348 | 0 | |
349 | 0 | if (!InImageBridgeChildThread()) { |
350 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
351 | 0 | RefPtr<ImageBridgeChild>(this), |
352 | 0 | &ImageBridgeChild::UpdateImageClient, |
353 | 0 | aContainer); |
354 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
355 | 0 | return; |
356 | 0 | } |
357 | 0 | |
358 | 0 | if (!CanSend()) { |
359 | 0 | return; |
360 | 0 | } |
361 | 0 | |
362 | 0 | RefPtr<ImageClient> client = aContainer->GetImageClient(); |
363 | 0 | if (NS_WARN_IF(!client)) { |
364 | 0 | return; |
365 | 0 | } |
366 | 0 | |
367 | 0 | // If the client has become disconnected before this event was dispatched, |
368 | 0 | // early return now. |
369 | 0 | if (!client->IsConnected()) { |
370 | 0 | return; |
371 | 0 | } |
372 | 0 | |
373 | 0 | BeginTransaction(); |
374 | 0 | client->UpdateImage(aContainer, Layer::CONTENT_OPAQUE); |
375 | 0 | EndTransaction(); |
376 | 0 | } |
377 | | |
378 | | void |
379 | | ImageBridgeChild::UpdateAsyncCanvasRendererSync(SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper) |
380 | 0 | { |
381 | 0 | AutoCompleteTask complete(aTask); |
382 | 0 |
|
383 | 0 | UpdateAsyncCanvasRendererNow(aWrapper); |
384 | 0 | } |
385 | | |
386 | | void |
387 | | ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper) |
388 | 0 | { |
389 | 0 | aWrapper->GetCanvasClient()->UpdateAsync(aWrapper); |
390 | 0 |
|
391 | 0 | if (InImageBridgeChildThread()) { |
392 | 0 | UpdateAsyncCanvasRendererNow(aWrapper); |
393 | 0 | return; |
394 | 0 | } |
395 | 0 | |
396 | 0 | SynchronousTask task("UpdateAsyncCanvasRenderer Lock"); |
397 | 0 |
|
398 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
399 | 0 | RefPtr<ImageBridgeChild>(this), |
400 | 0 | &ImageBridgeChild::UpdateAsyncCanvasRendererSync, |
401 | 0 | &task, |
402 | 0 | aWrapper); |
403 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
404 | 0 |
|
405 | 0 | task.Wait(); |
406 | 0 | } |
407 | | |
408 | | void |
409 | | ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper) |
410 | 0 | { |
411 | 0 | MOZ_ASSERT(aWrapper); |
412 | 0 |
|
413 | 0 | if (!CanSend()) { |
414 | 0 | return; |
415 | 0 | } |
416 | 0 | |
417 | 0 | BeginTransaction(); |
418 | 0 | aWrapper->GetCanvasClient()->Updated(); |
419 | 0 | EndTransaction(); |
420 | 0 | } |
421 | | |
422 | | void |
423 | | ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask, |
424 | | ImageClient* aClient, |
425 | | ImageContainer* aContainer) |
426 | 0 | { |
427 | 0 | AutoCompleteTask complete(aTask); |
428 | 0 |
|
429 | 0 | if (!CanSend()) { |
430 | 0 | return; |
431 | 0 | } |
432 | 0 | |
433 | 0 | MOZ_ASSERT(aClient); |
434 | 0 | BeginTransaction(); |
435 | 0 | if (aContainer) { |
436 | 0 | aContainer->ClearImagesFromImageBridge(); |
437 | 0 | } |
438 | 0 | aClient->FlushAllImages(); |
439 | 0 | EndTransaction(); |
440 | 0 | } |
441 | | |
442 | | void |
443 | | ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer) |
444 | 0 | { |
445 | 0 | MOZ_ASSERT(aClient); |
446 | 0 | MOZ_ASSERT(!InImageBridgeChildThread()); |
447 | 0 |
|
448 | 0 | if (InImageBridgeChildThread()) { |
449 | 0 | NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread."); |
450 | 0 | return; |
451 | 0 | } |
452 | 0 |
|
453 | 0 | SynchronousTask task("FlushAllImages Lock"); |
454 | 0 |
|
455 | 0 | // RefPtrs on arguments are not needed since this dispatches synchronously. |
456 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
457 | 0 | RefPtr<ImageBridgeChild>(this), |
458 | 0 | &ImageBridgeChild::FlushAllImagesSync, |
459 | 0 | &task, |
460 | 0 | aClient, |
461 | 0 | aContainer); |
462 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
463 | 0 |
|
464 | 0 | task.Wait(); |
465 | 0 | } |
466 | | |
467 | | void |
468 | | ImageBridgeChild::BeginTransaction() |
469 | 0 | { |
470 | 0 | MOZ_ASSERT(CanSend()); |
471 | 0 | MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?"); |
472 | 0 | UpdateFwdTransactionId(); |
473 | 0 | mTxn->Begin(); |
474 | 0 | } |
475 | | |
476 | | void |
477 | | ImageBridgeChild::EndTransaction() |
478 | 0 | { |
479 | 0 | MOZ_ASSERT(CanSend()); |
480 | 0 | MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?"); |
481 | 0 |
|
482 | 0 | AutoEndTransaction _(mTxn); |
483 | 0 |
|
484 | 0 | if (mTxn->IsEmpty()) { |
485 | 0 | return; |
486 | 0 | } |
487 | 0 | |
488 | 0 | AutoTArray<CompositableOperation, 10> cset; |
489 | 0 | cset.SetCapacity(mTxn->mOperations.size()); |
490 | 0 | if (!mTxn->mOperations.empty()) { |
491 | 0 | cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size()); |
492 | 0 | } |
493 | 0 |
|
494 | 0 | if (!IsSameProcess()) { |
495 | 0 | ShadowLayerForwarder::PlatformSyncBeforeUpdate(); |
496 | 0 | } |
497 | 0 |
|
498 | 0 | if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) { |
499 | 0 | NS_WARNING("could not send async texture transaction"); |
500 | 0 | return; |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | | bool |
505 | | ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace) |
506 | 0 | { |
507 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
508 | 0 |
|
509 | 0 | gfxPlatform::GetPlatform(); |
510 | 0 |
|
511 | 0 | if (!sImageBridgeChildThread) { |
512 | 0 | sImageBridgeChildThread = new Thread("ImageBridgeChild"); |
513 | 0 | bool success = sImageBridgeChildThread->Start(); |
514 | 0 | MOZ_RELEASE_ASSERT(success, "Failed to start ImageBridgeChild thread!"); |
515 | 0 | } |
516 | 0 |
|
517 | 0 | RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace); |
518 | 0 |
|
519 | 0 | RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>( |
520 | 0 | "layers::ImageBridgeChild::Bind", |
521 | 0 | child, |
522 | 0 | &ImageBridgeChild::Bind, |
523 | 0 | std::move(aEndpoint)); |
524 | 0 | child->GetMessageLoop()->PostTask(runnable.forget()); |
525 | 0 |
|
526 | 0 | // Assign this after so other threads can't post messages before we connect to IPDL. |
527 | 0 | { |
528 | 0 | StaticMutexAutoLock lock(sImageBridgeSingletonLock); |
529 | 0 | sImageBridgeChildSingleton = child; |
530 | 0 | } |
531 | 0 |
|
532 | 0 | return true; |
533 | 0 | } |
534 | | |
535 | | bool |
536 | | ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace) |
537 | 0 | { |
538 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
539 | 0 |
|
540 | 0 | // Note that at this point, ActorDestroy may not have been called yet, |
541 | 0 | // meaning mCanSend is still true. In this case we will try to send a |
542 | 0 | // synchronous WillClose message to the parent, and will certainly get a |
543 | 0 | // false result and a MsgDropped processing error. This is okay. |
544 | 0 | ShutdownSingleton(); |
545 | 0 |
|
546 | 0 | return InitForContent(std::move(aEndpoint), aNamespace); |
547 | 0 | } |
548 | | |
549 | | void |
550 | | ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint) |
551 | 0 | { |
552 | 0 | if (!aEndpoint.Bind(this)) { |
553 | 0 | return; |
554 | 0 | } |
555 | 0 | |
556 | 0 | // This reference is dropped in DeallocPImageBridgeChild. |
557 | 0 | this->AddRef(); |
558 | 0 |
|
559 | 0 | mCanSend = true; |
560 | 0 | } |
561 | | |
562 | | void |
563 | | ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent) |
564 | 0 | { |
565 | 0 | MessageLoop *parentMsgLoop = aParent->GetMessageLoop(); |
566 | 0 | ipc::MessageChannel *parentChannel = aParent->GetIPCChannel(); |
567 | 0 | Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide); |
568 | 0 |
|
569 | 0 | // This reference is dropped in DeallocPImageBridgeChild. |
570 | 0 | this->AddRef(); |
571 | 0 |
|
572 | 0 | mCanSend = true; |
573 | 0 | } |
574 | | |
575 | | /* static */ void |
576 | | ImageBridgeChild::ShutDown() |
577 | 0 | { |
578 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
579 | 0 |
|
580 | 0 | ShutdownSingleton(); |
581 | 0 |
|
582 | 0 | delete sImageBridgeChildThread; |
583 | 0 | sImageBridgeChildThread = nullptr; |
584 | 0 | } |
585 | | |
586 | | /* static */ void |
587 | | ImageBridgeChild::ShutdownSingleton() |
588 | 0 | { |
589 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
590 | 0 |
|
591 | 0 | if (RefPtr<ImageBridgeChild> child = GetSingleton()) { |
592 | 0 | child->WillShutdown(); |
593 | 0 |
|
594 | 0 | StaticMutexAutoLock lock(sImageBridgeSingletonLock); |
595 | 0 | sImageBridgeChildSingleton = nullptr; |
596 | 0 | } |
597 | 0 | } |
598 | | |
599 | | void |
600 | | ImageBridgeChild::WillShutdown() |
601 | 0 | { |
602 | 0 | { |
603 | 0 | SynchronousTask task("ImageBridge ShutdownStep1 lock"); |
604 | 0 |
|
605 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
606 | 0 | RefPtr<ImageBridgeChild>(this), |
607 | 0 | &ImageBridgeChild::ShutdownStep1, |
608 | 0 | &task); |
609 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
610 | 0 |
|
611 | 0 | task.Wait(); |
612 | 0 | } |
613 | 0 |
|
614 | 0 | { |
615 | 0 | SynchronousTask task("ImageBridge ShutdownStep2 lock"); |
616 | 0 |
|
617 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
618 | 0 | RefPtr<ImageBridgeChild>(this), |
619 | 0 | &ImageBridgeChild::ShutdownStep2, |
620 | 0 | &task); |
621 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
622 | 0 |
|
623 | 0 | task.Wait(); |
624 | 0 | } |
625 | 0 | } |
626 | | |
627 | | void |
628 | | ImageBridgeChild::InitSameProcess(uint32_t aNamespace) |
629 | 0 | { |
630 | 0 | NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); |
631 | 0 |
|
632 | 0 | MOZ_ASSERT(!sImageBridgeChildSingleton); |
633 | 0 | MOZ_ASSERT(!sImageBridgeChildThread); |
634 | 0 |
|
635 | 0 | sImageBridgeChildThread = new Thread("ImageBridgeChild"); |
636 | 0 | if (!sImageBridgeChildThread->IsRunning()) { |
637 | 0 | sImageBridgeChildThread->Start(); |
638 | 0 | } |
639 | 0 |
|
640 | 0 | RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace); |
641 | 0 | RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess(); |
642 | 0 |
|
643 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
644 | 0 | child, |
645 | 0 | &ImageBridgeChild::BindSameProcess, |
646 | 0 | parent); |
647 | 0 | child->GetMessageLoop()->PostTask(runnable.forget()); |
648 | 0 |
|
649 | 0 | // Assign this after so other threads can't post messages before we connect to IPDL. |
650 | 0 | { |
651 | 0 | StaticMutexAutoLock lock(sImageBridgeSingletonLock); |
652 | 0 | sImageBridgeChildSingleton = child; |
653 | 0 | } |
654 | 0 | } |
655 | | |
656 | | /* static */ void |
657 | | ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace) |
658 | 0 | { |
659 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
660 | 0 | MOZ_ASSERT(!sImageBridgeChildSingleton); |
661 | 0 | MOZ_ASSERT(!sImageBridgeChildThread); |
662 | 0 |
|
663 | 0 | sImageBridgeChildThread = new Thread("ImageBridgeChild"); |
664 | 0 | if (!sImageBridgeChildThread->IsRunning()) { |
665 | 0 | sImageBridgeChildThread->Start(); |
666 | 0 | } |
667 | 0 |
|
668 | 0 | RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace); |
669 | 0 |
|
670 | 0 | MessageLoop* loop = child->GetMessageLoop(); |
671 | 0 | loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>( |
672 | 0 | "layers::ImageBridgeChild::Bind", |
673 | 0 | child, |
674 | 0 | &ImageBridgeChild::Bind, |
675 | 0 | std::move(aEndpoint))); |
676 | 0 |
|
677 | 0 | // Assign this after so other threads can't post messages before we connect to IPDL. |
678 | 0 | { |
679 | 0 | StaticMutexAutoLock lock(sImageBridgeSingletonLock); |
680 | 0 | sImageBridgeChildSingleton = child; |
681 | 0 | } |
682 | 0 | } |
683 | | |
684 | | bool InImageBridgeChildThread() |
685 | 0 | { |
686 | 0 | return sImageBridgeChildThread && |
687 | 0 | sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId(); |
688 | 0 | } |
689 | | |
690 | | MessageLoop * ImageBridgeChild::GetMessageLoop() const |
691 | 0 | { |
692 | 0 | return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr; |
693 | 0 | } |
694 | | |
695 | | /* static */ void |
696 | | ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier) |
697 | 0 | { |
698 | 0 | if (RefPtr<ImageBridgeChild> child = GetSingleton()) { |
699 | 0 | child->UpdateTextureFactoryIdentifier(aIdentifier); |
700 | 0 | } |
701 | 0 | } |
702 | | |
703 | | void |
704 | | ImageBridgeChild::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aIdentifier) |
705 | 0 | { |
706 | 0 | // ImageHost is incompatible between WebRender enabled and WebRender disabled. |
707 | 0 | // Then drop all ImageContainers' ImageClients during disabling WebRender. |
708 | 0 | bool disablingWebRender = GetCompositorBackendType() == LayersBackend::LAYERS_WR && |
709 | 0 | aIdentifier.mParentBackend != LayersBackend::LAYERS_WR; |
710 | 0 | // D3DTexture might become obsolte. To prevent to use obsoleted D3DTexture, |
711 | 0 | // drop all ImageContainers' ImageClients. |
712 | 0 |
|
713 | 0 | bool needsDrop = disablingWebRender; |
714 | 0 |
|
715 | | #if defined(XP_WIN) |
716 | | RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice(); |
717 | | needsDrop |= !!mImageDevice && |
718 | | mImageDevice != device && |
719 | | GetCompositorBackendType() == LayersBackend::LAYERS_D3D11; |
720 | | mImageDevice = device; |
721 | | #endif |
722 | |
|
723 | 0 | IdentifyTextureHost(aIdentifier); |
724 | 0 | if (needsDrop) { |
725 | 0 | nsTArray<RefPtr<ImageContainerListener> > listeners; |
726 | 0 | { |
727 | 0 | MutexAutoLock lock(mContainerMapLock); |
728 | 0 | for (const auto& entry : mImageContainerListeners) { |
729 | 0 | listeners.AppendElement(entry.second); |
730 | 0 | } |
731 | 0 | } |
732 | 0 | // Drop ImageContainer's ImageClient whithout holding mContainerMapLock to avoid deadlock. |
733 | 0 | for (auto container : listeners) { |
734 | 0 | container->DropImageClient(); |
735 | 0 | } |
736 | 0 | } |
737 | 0 | } |
738 | | |
739 | | RefPtr<ImageClient> |
740 | | ImageBridgeChild::CreateImageClient(CompositableType aType, |
741 | | ImageContainer* aImageContainer) |
742 | 0 | { |
743 | 0 | if (InImageBridgeChildThread()) { |
744 | 0 | return CreateImageClientNow(aType, aImageContainer); |
745 | 0 | } |
746 | 0 | |
747 | 0 | SynchronousTask task("CreateImageClient Lock"); |
748 | 0 |
|
749 | 0 | RefPtr<ImageClient> result = nullptr; |
750 | 0 |
|
751 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
752 | 0 | RefPtr<ImageBridgeChild>(this), |
753 | 0 | &ImageBridgeChild::CreateImageClientSync, |
754 | 0 | &task, |
755 | 0 | &result, |
756 | 0 | aType, |
757 | 0 | aImageContainer); |
758 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
759 | 0 |
|
760 | 0 | task.Wait(); |
761 | 0 |
|
762 | 0 | return result; |
763 | 0 | } |
764 | | |
765 | | RefPtr<ImageClient> |
766 | | ImageBridgeChild::CreateImageClientNow(CompositableType aType, |
767 | | ImageContainer* aImageContainer) |
768 | 0 | { |
769 | 0 | MOZ_ASSERT(InImageBridgeChildThread()); |
770 | 0 | if (!CanSend()) { |
771 | 0 | return nullptr; |
772 | 0 | } |
773 | 0 | |
774 | 0 | RefPtr<ImageClient> client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS); |
775 | 0 | MOZ_ASSERT(client, "failed to create ImageClient"); |
776 | 0 | if (client) { |
777 | 0 | client->Connect(aImageContainer); |
778 | 0 | } |
779 | 0 | return client; |
780 | 0 | } |
781 | | |
782 | | already_AddRefed<CanvasClient> |
783 | | ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType, |
784 | | TextureFlags aFlag) |
785 | 0 | { |
786 | 0 | if (InImageBridgeChildThread()) { |
787 | 0 | return CreateCanvasClientNow(aType, aFlag); |
788 | 0 | } |
789 | 0 | |
790 | 0 | SynchronousTask task("CreateCanvasClient Lock"); |
791 | 0 |
|
792 | 0 | // RefPtrs on arguments are not needed since this dispatches synchronously. |
793 | 0 | RefPtr<CanvasClient> result = nullptr; |
794 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
795 | 0 | RefPtr<ImageBridgeChild>(this), |
796 | 0 | &ImageBridgeChild::CreateCanvasClientSync, |
797 | 0 | &task, |
798 | 0 | aType, |
799 | 0 | aFlag, |
800 | 0 | &result); |
801 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
802 | 0 |
|
803 | 0 | task.Wait(); |
804 | 0 |
|
805 | 0 | return result.forget(); |
806 | 0 | } |
807 | | |
808 | | already_AddRefed<CanvasClient> |
809 | | ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType, |
810 | | TextureFlags aFlag) |
811 | 0 | { |
812 | 0 | RefPtr<CanvasClient> client |
813 | 0 | = CanvasClient::CreateCanvasClient(aType, this, aFlag); |
814 | 0 | MOZ_ASSERT(client, "failed to create CanvasClient"); |
815 | 0 | if (client) { |
816 | 0 | client->Connect(); |
817 | 0 | } |
818 | 0 | return client.forget(); |
819 | 0 | } |
820 | | |
821 | | bool |
822 | | ImageBridgeChild::AllocUnsafeShmem(size_t aSize, |
823 | | ipc::SharedMemory::SharedMemoryType aType, |
824 | | ipc::Shmem* aShmem) |
825 | 0 | { |
826 | 0 | if (!InImageBridgeChildThread()) { |
827 | 0 | return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe |
828 | 0 | } |
829 | 0 | |
830 | 0 | if (!CanSend()) { |
831 | 0 | return false; |
832 | 0 | } |
833 | 0 | return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem); |
834 | 0 | } |
835 | | |
836 | | bool |
837 | | ImageBridgeChild::AllocShmem(size_t aSize, |
838 | | ipc::SharedMemory::SharedMemoryType aType, |
839 | | ipc::Shmem* aShmem) |
840 | 0 | { |
841 | 0 | if (!InImageBridgeChildThread()) { |
842 | 0 | return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe |
843 | 0 | } |
844 | 0 | |
845 | 0 | if (!CanSend()) { |
846 | 0 | return false; |
847 | 0 | } |
848 | 0 | return PImageBridgeChild::AllocShmem(aSize, aType, aShmem); |
849 | 0 | } |
850 | | |
851 | | // NewRunnableFunction accepts a limited number of parameters so we need a |
852 | | // struct here |
853 | | struct AllocShmemParams { |
854 | | size_t mSize; |
855 | | ipc::SharedMemory::SharedMemoryType mType; |
856 | | ipc::Shmem* mShmem; |
857 | | bool mUnsafe; |
858 | | bool mSuccess; |
859 | | }; |
860 | | |
861 | | void |
862 | | ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams) |
863 | 0 | { |
864 | 0 | AutoCompleteTask complete(aTask); |
865 | 0 |
|
866 | 0 | if (!CanSend()) { |
867 | 0 | return; |
868 | 0 | } |
869 | 0 | |
870 | 0 | bool ok = false; |
871 | 0 | if (aParams->mUnsafe) { |
872 | 0 | ok = AllocUnsafeShmem(aParams->mSize, aParams->mType, aParams->mShmem); |
873 | 0 | } else { |
874 | 0 | ok = AllocShmem(aParams->mSize, aParams->mType, aParams->mShmem); |
875 | 0 | } |
876 | 0 | aParams->mSuccess = ok; |
877 | 0 | } |
878 | | |
879 | | bool |
880 | | ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize, |
881 | | SharedMemory::SharedMemoryType aType, |
882 | | ipc::Shmem* aShmem, |
883 | | bool aUnsafe) |
884 | 0 | { |
885 | 0 | SynchronousTask task("AllocatorProxy alloc"); |
886 | 0 |
|
887 | 0 | AllocShmemParams params = { |
888 | 0 | aSize, aType, aShmem, aUnsafe, false |
889 | 0 | }; |
890 | 0 |
|
891 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
892 | 0 | RefPtr<ImageBridgeChild>(this), |
893 | 0 | &ImageBridgeChild::ProxyAllocShmemNow, |
894 | 0 | &task, |
895 | 0 | ¶ms); |
896 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
897 | 0 |
|
898 | 0 | task.Wait(); |
899 | 0 |
|
900 | 0 | return params.mSuccess; |
901 | 0 | } |
902 | | |
903 | | void |
904 | | ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask, |
905 | | ipc::Shmem* aShmem, |
906 | | bool* aResult) |
907 | 0 | { |
908 | 0 | AutoCompleteTask complete(aTask); |
909 | 0 |
|
910 | 0 | if (!CanSend()) { |
911 | 0 | return; |
912 | 0 | } |
913 | 0 | *aResult = DeallocShmem(*aShmem); |
914 | 0 | } |
915 | | |
916 | | bool |
917 | | ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) |
918 | 0 | { |
919 | 0 | if (InImageBridgeChildThread()) { |
920 | 0 | if (!CanSend()) { |
921 | 0 | return false; |
922 | 0 | } |
923 | 0 | return PImageBridgeChild::DeallocShmem(aShmem); |
924 | 0 | } |
925 | 0 | |
926 | 0 | // If we can't post a task, then we definitely cannot send, so there's |
927 | 0 | // no reason to queue up this send. |
928 | 0 | if (!CanPostTask()) { |
929 | 0 | return false; |
930 | 0 | } |
931 | 0 | |
932 | 0 | SynchronousTask task("AllocatorProxy Dealloc"); |
933 | 0 | bool result = false; |
934 | 0 |
|
935 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
936 | 0 | RefPtr<ImageBridgeChild>(this), |
937 | 0 | &ImageBridgeChild::ProxyDeallocShmemNow, |
938 | 0 | &task, |
939 | 0 | &aShmem, |
940 | 0 | &result); |
941 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
942 | 0 |
|
943 | 0 | task.Wait(); |
944 | 0 | return result; |
945 | 0 | } |
946 | | |
947 | | PTextureChild* |
948 | | ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&, |
949 | | const ReadLockDescriptor&, |
950 | | const LayersBackend&, |
951 | | const TextureFlags&, |
952 | | const uint64_t& aSerial, |
953 | | const wr::MaybeExternalImageId& aExternalImageId) |
954 | 0 | { |
955 | 0 | MOZ_ASSERT(CanSend()); |
956 | 0 | return TextureClient::CreateIPDLActor(); |
957 | 0 | } |
958 | | |
959 | | bool |
960 | | ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor) |
961 | 0 | { |
962 | 0 | return TextureClient::DestroyIPDLActor(actor); |
963 | 0 | } |
964 | | |
965 | | PMediaSystemResourceManagerChild* |
966 | | ImageBridgeChild::AllocPMediaSystemResourceManagerChild() |
967 | 0 | { |
968 | 0 | MOZ_ASSERT(CanSend()); |
969 | 0 | return new mozilla::media::MediaSystemResourceManagerChild(); |
970 | 0 | } |
971 | | |
972 | | bool |
973 | | ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor) |
974 | 0 | { |
975 | 0 | MOZ_ASSERT(aActor); |
976 | 0 | delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor); |
977 | 0 | return true; |
978 | 0 | } |
979 | | |
980 | | mozilla::ipc::IPCResult |
981 | | ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) |
982 | 0 | { |
983 | 0 | for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) { |
984 | 0 | const AsyncParentMessageData& message = aMessages[i]; |
985 | 0 |
|
986 | 0 | switch (message.type()) { |
987 | 0 | case AsyncParentMessageData::TOpNotifyNotUsed: { |
988 | 0 | const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed(); |
989 | 0 | NotifyNotUsed(op.TextureId(), op.fwdTransactionId()); |
990 | 0 | break; |
991 | 0 | } |
992 | 0 | default: |
993 | 0 | NS_ERROR("unknown AsyncParentMessageData type"); |
994 | 0 | return IPC_FAIL_NO_REASON(this); |
995 | 0 | } |
996 | 0 | } |
997 | 0 | return IPC_OK(); |
998 | 0 | } |
999 | | |
1000 | | RefPtr<ImageContainerListener> |
1001 | | ImageBridgeChild::FindListener(const CompositableHandle& aHandle) |
1002 | 0 | { |
1003 | 0 | RefPtr<ImageContainerListener> listener; |
1004 | 0 | MutexAutoLock lock(mContainerMapLock); |
1005 | 0 | auto it = mImageContainerListeners.find(aHandle.Value()); |
1006 | 0 | if (it != mImageContainerListeners.end()) { |
1007 | 0 | listener = it->second; |
1008 | 0 | } |
1009 | 0 | return listener; |
1010 | 0 | } |
1011 | | |
1012 | | mozilla::ipc::IPCResult |
1013 | | ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications) |
1014 | 0 | { |
1015 | 0 | for (auto& n : aNotifications) { |
1016 | 0 | RefPtr<ImageContainerListener> listener = FindListener(n.compositable()); |
1017 | 0 | if (listener) { |
1018 | 0 | listener->NotifyComposite(n); |
1019 | 0 | } |
1020 | 0 | } |
1021 | 0 | return IPC_OK(); |
1022 | 0 | } |
1023 | | |
1024 | | mozilla::ipc::IPCResult |
1025 | | ImageBridgeChild::RecvReportFramesDropped(const CompositableHandle& aHandle, const uint32_t& aFrames) |
1026 | 0 | { |
1027 | 0 | RefPtr<ImageContainerListener> listener = FindListener(aHandle); |
1028 | 0 | if (listener) { |
1029 | 0 | listener->NotifyDropped(aFrames); |
1030 | 0 | } |
1031 | 0 |
|
1032 | 0 | return IPC_OK(); |
1033 | 0 | } |
1034 | | |
1035 | | PTextureChild* |
1036 | | ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, |
1037 | | const ReadLockDescriptor& aReadLock, |
1038 | | LayersBackend aLayersBackend, |
1039 | | TextureFlags aFlags, |
1040 | | uint64_t aSerial, |
1041 | | wr::MaybeExternalImageId& aExternalImageId, |
1042 | | nsIEventTarget* aTarget) |
1043 | 0 | { |
1044 | 0 | MOZ_ASSERT(CanSend()); |
1045 | 0 | return SendPTextureConstructor(aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId); |
1046 | 0 | } |
1047 | | |
1048 | | static bool |
1049 | | IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op) |
1050 | 0 | { |
1051 | 0 | if (aTxn->Finished()) { |
1052 | 0 | return false; |
1053 | 0 | } |
1054 | 0 | |
1055 | 0 | aTxn->mDestroyedActors.AppendElement(op); |
1056 | 0 | return true; |
1057 | 0 | } |
1058 | | |
1059 | | bool |
1060 | | ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture) |
1061 | 0 | { |
1062 | 0 | return IBCAddOpDestroy(mTxn, OpDestroy(aTexture)); |
1063 | 0 | } |
1064 | | |
1065 | | bool |
1066 | | ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle) |
1067 | 0 | { |
1068 | 0 | return IBCAddOpDestroy(mTxn, OpDestroy(aHandle)); |
1069 | 0 | } |
1070 | | |
1071 | | void |
1072 | | ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable, |
1073 | | TextureClient* aTexture) |
1074 | 0 | { |
1075 | 0 | MOZ_ASSERT(CanSend()); |
1076 | 0 | MOZ_ASSERT(aTexture); |
1077 | 0 | MOZ_ASSERT(aTexture->IsSharedWithCompositor()); |
1078 | 0 | MOZ_ASSERT(aCompositable->IsConnected()); |
1079 | 0 | if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) { |
1080 | 0 | return; |
1081 | 0 | } |
1082 | 0 | |
1083 | 0 | mTxn->AddNoSwapEdit(CompositableOperation( |
1084 | 0 | aCompositable->GetIPCHandle(), |
1085 | 0 | OpRemoveTexture(nullptr, aTexture->GetIPDLActor()))); |
1086 | 0 | } |
1087 | | |
1088 | | bool ImageBridgeChild::IsSameProcess() const |
1089 | 0 | { |
1090 | 0 | return OtherPid() == base::GetCurrentProcId(); |
1091 | 0 | } |
1092 | | |
1093 | | bool |
1094 | | ImageBridgeChild::CanPostTask() const |
1095 | 0 | { |
1096 | 0 | // During shutdown, the cycle collector may free objects that are holding a |
1097 | 0 | // reference to ImageBridgeChild. Since this happens on the main thread, |
1098 | 0 | // ImageBridgeChild will attempt to post a task to the ImageBridge thread. |
1099 | 0 | // However the thread manager has already been shut down, so the task cannot |
1100 | 0 | // post. |
1101 | 0 | // |
1102 | 0 | // It's okay if this races. We only care about the shutdown case where |
1103 | 0 | // everything's happening on the main thread. Even if it races outside of |
1104 | 0 | // shutdown, it's still harmless to post the task, since the task must |
1105 | 0 | // check CanSend(). |
1106 | 0 | return !mDestroyed; |
1107 | 0 | } |
1108 | | |
1109 | | void |
1110 | | ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle) |
1111 | 0 | { |
1112 | 0 | if (!InImageBridgeChildThread()) { |
1113 | 0 | // If we can't post a task, then we definitely cannot send, so there's |
1114 | 0 | // no reason to queue up this send. |
1115 | 0 | if (!CanPostTask()) { |
1116 | 0 | return; |
1117 | 0 | } |
1118 | 0 | |
1119 | 0 | RefPtr<Runnable> runnable = WrapRunnable( |
1120 | 0 | RefPtr<ImageBridgeChild>(this), |
1121 | 0 | &ImageBridgeChild::ReleaseCompositable, |
1122 | 0 | aHandle); |
1123 | 0 | GetMessageLoop()->PostTask(runnable.forget()); |
1124 | 0 | return; |
1125 | 0 | } |
1126 | 0 | |
1127 | 0 | if (!CanSend()) { |
1128 | 0 | return; |
1129 | 0 | } |
1130 | 0 | |
1131 | 0 | if (!DestroyInTransaction(aHandle)) { |
1132 | 0 | SendReleaseCompositable(aHandle); |
1133 | 0 | } |
1134 | 0 |
|
1135 | 0 | { |
1136 | 0 | MutexAutoLock lock(mContainerMapLock); |
1137 | 0 | mImageContainerListeners.erase(aHandle.Value()); |
1138 | 0 | } |
1139 | 0 | } |
1140 | | |
1141 | | bool |
1142 | | ImageBridgeChild::CanSend() const |
1143 | 0 | { |
1144 | 0 | MOZ_ASSERT(InImageBridgeChildThread()); |
1145 | 0 | return mCanSend; |
1146 | 0 | } |
1147 | | |
1148 | | void |
1149 | | ImageBridgeChild::HandleFatalError(const char* aMsg) const |
1150 | 0 | { |
1151 | 0 | dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid()); |
1152 | 0 | } |
1153 | | |
1154 | | wr::MaybeExternalImageId |
1155 | | ImageBridgeChild::GetNextExternalImageId() |
1156 | 0 | { |
1157 | 0 | static uint32_t sNextID = 1; |
1158 | 0 | ++sNextID; |
1159 | 0 | MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX); |
1160 | 0 |
|
1161 | 0 | uint64_t imageId = mNamespace; |
1162 | 0 | imageId = imageId << 32 | sNextID; |
1163 | 0 | return Some(wr::ToExternalImageId(imageId)); |
1164 | 0 | } |
1165 | | |
1166 | | } // namespace layers |
1167 | | } // namespace mozilla |