|
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 "ImageBridgeChild.h" |
|
7 #include <vector> // for vector |
|
8 #include "CompositorParent.h" // for CompositorParent |
|
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 ProcessHandle |
|
16 #include "base/process_util.h" // for OpenProcessHandle |
|
17 #include "base/task.h" // for NewRunnableFunction, etc |
|
18 #include "base/thread.h" // for Thread |
|
19 #include "base/tracked.h" // for FROM_HERE |
|
20 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
|
21 #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock |
|
22 #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc |
|
23 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc |
|
24 #include "mozilla/ipc/Transport.h" // for Transport |
|
25 #include "mozilla/gfx/Point.h" // for IntSize |
|
26 #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc |
|
27 #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator |
|
28 #include "mozilla/layers/ImageClient.h" // for ImageClient |
|
29 #include "mozilla/layers/LayersMessages.h" // for CompositableOperation |
|
30 #include "mozilla/layers/PCompositableChild.h" // for PCompositableChild |
|
31 #include "mozilla/layers/TextureClient.h" // for TextureClient |
|
32 #include "mozilla/mozalloc.h" // for operator new, etc |
|
33 #include "nsAutoPtr.h" // for nsRefPtr |
|
34 #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc |
|
35 #include "nsTArray.h" // for nsAutoTArray, nsTArray, etc |
|
36 #include "nsTArrayForwardDeclare.h" // for AutoInfallibleTArray |
|
37 #include "nsThreadUtils.h" // for NS_IsMainThread |
|
38 #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop |
|
39 #include "mozilla/StaticPtr.h" // for StaticRefPtr |
|
40 #include "mozilla/layers/TextureClient.h" |
|
41 |
|
42 struct nsIntRect; |
|
43 |
|
44 using namespace base; |
|
45 using namespace mozilla::ipc; |
|
46 using namespace mozilla::gfx; |
|
47 |
|
48 namespace mozilla { |
|
49 namespace ipc { |
|
50 class Shmem; |
|
51 } |
|
52 |
|
53 namespace layers { |
|
54 |
|
55 class PGrallocBufferChild; |
|
56 typedef std::vector<CompositableOperation> OpVector; |
|
57 |
|
58 struct CompositableTransaction |
|
59 { |
|
60 CompositableTransaction() |
|
61 : mSwapRequired(false) |
|
62 , mFinished(true) |
|
63 {} |
|
64 ~CompositableTransaction() |
|
65 { |
|
66 End(); |
|
67 } |
|
68 bool Finished() const |
|
69 { |
|
70 return mFinished; |
|
71 } |
|
72 void Begin() |
|
73 { |
|
74 MOZ_ASSERT(mFinished); |
|
75 mFinished = false; |
|
76 } |
|
77 void End() |
|
78 { |
|
79 mFinished = true; |
|
80 mSwapRequired = false; |
|
81 mOperations.clear(); |
|
82 } |
|
83 bool IsEmpty() const |
|
84 { |
|
85 return mOperations.empty(); |
|
86 } |
|
87 void AddNoSwapEdit(const CompositableOperation& op) |
|
88 { |
|
89 NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?"); |
|
90 mOperations.push_back(op); |
|
91 } |
|
92 void AddEdit(const CompositableOperation& op) |
|
93 { |
|
94 AddNoSwapEdit(op); |
|
95 mSwapRequired = true; |
|
96 } |
|
97 |
|
98 OpVector mOperations; |
|
99 bool mSwapRequired; |
|
100 bool mFinished; |
|
101 }; |
|
102 |
|
103 struct AutoEndTransaction { |
|
104 AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {} |
|
105 ~AutoEndTransaction() { mTxn->End(); } |
|
106 CompositableTransaction* mTxn; |
|
107 }; |
|
108 |
|
109 void |
|
110 ImageBridgeChild::UseTexture(CompositableClient* aCompositable, |
|
111 TextureClient* aTexture) |
|
112 { |
|
113 MOZ_ASSERT(aCompositable); |
|
114 MOZ_ASSERT(aTexture); |
|
115 MOZ_ASSERT(aCompositable->GetIPDLActor()); |
|
116 MOZ_ASSERT(aTexture->GetIPDLActor()); |
|
117 mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(), |
|
118 nullptr, aTexture->GetIPDLActor())); |
|
119 } |
|
120 |
|
121 void |
|
122 ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable, |
|
123 TextureClient* aTextureOnBlack, |
|
124 TextureClient* aTextureOnWhite) |
|
125 { |
|
126 MOZ_ASSERT(aCompositable); |
|
127 MOZ_ASSERT(aTextureOnWhite); |
|
128 MOZ_ASSERT(aTextureOnBlack); |
|
129 MOZ_ASSERT(aCompositable->GetIPDLActor()); |
|
130 MOZ_ASSERT(aTextureOnWhite->GetIPDLActor()); |
|
131 MOZ_ASSERT(aTextureOnBlack->GetIPDLActor()); |
|
132 MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize()); |
|
133 mTxn->AddNoSwapEdit(OpUseComponentAlphaTextures(nullptr, aCompositable->GetIPDLActor(), |
|
134 nullptr, aTextureOnBlack->GetIPDLActor(), |
|
135 nullptr, aTextureOnWhite->GetIPDLActor())); |
|
136 } |
|
137 |
|
138 void |
|
139 ImageBridgeChild::UpdatedTexture(CompositableClient* aCompositable, |
|
140 TextureClient* aTexture, |
|
141 nsIntRegion* aRegion) |
|
142 { |
|
143 MOZ_ASSERT(aCompositable); |
|
144 MOZ_ASSERT(aTexture); |
|
145 MOZ_ASSERT(aCompositable->GetIPDLActor()); |
|
146 MOZ_ASSERT(aTexture->GetIPDLActor()); |
|
147 MaybeRegion region = aRegion ? MaybeRegion(*aRegion) |
|
148 : MaybeRegion(null_t()); |
|
149 mTxn->AddNoSwapEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(), |
|
150 nullptr, aTexture->GetIPDLActor(), |
|
151 region)); |
|
152 } |
|
153 |
|
154 void |
|
155 ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable, |
|
156 const nsIntRect& aRect) |
|
157 { |
|
158 MOZ_ASSERT(aCompositable); |
|
159 MOZ_ASSERT(aCompositable->GetIPDLActor()); |
|
160 mTxn->AddNoSwapEdit(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect)); |
|
161 } |
|
162 |
|
163 // Singleton |
|
164 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton; |
|
165 static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton; |
|
166 static Thread *sImageBridgeChildThread = nullptr; |
|
167 |
|
168 void ReleaseImageBridgeParentSingleton() { |
|
169 sImageBridgeParentSingleton = nullptr; |
|
170 } |
|
171 |
|
172 // dispatched function |
|
173 static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) |
|
174 { |
|
175 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
176 |
|
177 NS_ABORT_IF_FALSE(InImageBridgeChildThread(), |
|
178 "Should be in ImageBridgeChild thread."); |
|
179 if (sImageBridgeChildSingleton) { |
|
180 // Force all managed protocols to shut themselves down cleanly |
|
181 InfallibleTArray<PCompositableChild*> compositables; |
|
182 sImageBridgeChildSingleton->ManagedPCompositableChild(compositables); |
|
183 for (int i = compositables.Length() - 1; i >= 0; --i) { |
|
184 CompositableClient::FromIPDLActor(compositables[i])->Destroy(); |
|
185 } |
|
186 InfallibleTArray<PTextureChild*> textures; |
|
187 sImageBridgeChildSingleton->ManagedPTextureChild(textures); |
|
188 for (int i = textures.Length() - 1; i >= 0; --i) { |
|
189 TextureClient::AsTextureClient(textures[i])->ForceRemove(); |
|
190 } |
|
191 sImageBridgeChildSingleton->SendWillStop(); |
|
192 sImageBridgeChildSingleton->MarkShutDown(); |
|
193 // From now on, no message can be sent through the image bridge from the |
|
194 // client side except the final Stop message. |
|
195 } |
|
196 *aDone = true; |
|
197 aBarrier->NotifyAll(); |
|
198 } |
|
199 |
|
200 // dispatched function |
|
201 static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone) |
|
202 { |
|
203 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
204 |
|
205 NS_ABORT_IF_FALSE(InImageBridgeChildThread(), |
|
206 "Should be in ImageBridgeChild thread."); |
|
207 |
|
208 sImageBridgeChildSingleton->SendStop(); |
|
209 |
|
210 sImageBridgeChildSingleton = nullptr; |
|
211 |
|
212 *aDone = true; |
|
213 aBarrier->NotifyAll(); |
|
214 } |
|
215 |
|
216 // dispatched function |
|
217 static void CreateImageClientSync(RefPtr<ImageClient>* result, |
|
218 ReentrantMonitor* barrier, |
|
219 CompositableType aType, |
|
220 bool *aDone) |
|
221 { |
|
222 ReentrantMonitorAutoEnter autoMon(*barrier); |
|
223 *result = sImageBridgeChildSingleton->CreateImageClientNow(aType); |
|
224 *aDone = true; |
|
225 barrier->NotifyAll(); |
|
226 } |
|
227 |
|
228 |
|
229 struct GrallocParam { |
|
230 IntSize size; |
|
231 uint32_t format; |
|
232 uint32_t usage; |
|
233 MaybeMagicGrallocBufferHandle* handle; |
|
234 PGrallocBufferChild** child; |
|
235 |
|
236 GrallocParam(const IntSize& aSize, |
|
237 const uint32_t& aFormat, |
|
238 const uint32_t& aUsage, |
|
239 MaybeMagicGrallocBufferHandle* aHandle, |
|
240 PGrallocBufferChild** aChild) |
|
241 : size(aSize) |
|
242 , format(aFormat) |
|
243 , usage(aUsage) |
|
244 , handle(aHandle) |
|
245 , child(aChild) |
|
246 {} |
|
247 }; |
|
248 |
|
249 // dispatched function |
|
250 static void AllocGrallocBufferSync(const GrallocParam& aParam, |
|
251 Monitor* aBarrier, |
|
252 bool* aDone) |
|
253 { |
|
254 MonitorAutoLock autoMon(*aBarrier); |
|
255 |
|
256 sImageBridgeChildSingleton->AllocGrallocBufferNow(aParam.size, |
|
257 aParam.format, |
|
258 aParam.usage, |
|
259 aParam.handle, |
|
260 aParam.child); |
|
261 *aDone = true; |
|
262 aBarrier->NotifyAll(); |
|
263 } |
|
264 |
|
265 // dispatched function |
|
266 static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent) |
|
267 { |
|
268 MessageLoop *parentMsgLoop = parent->GetMessageLoop(); |
|
269 ipc::MessageChannel *parentChannel = parent->GetIPCChannel(); |
|
270 child->Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide); |
|
271 } |
|
272 |
|
273 ImageBridgeChild::ImageBridgeChild() |
|
274 : mShuttingDown(false) |
|
275 { |
|
276 mTxn = new CompositableTransaction(); |
|
277 } |
|
278 ImageBridgeChild::~ImageBridgeChild() |
|
279 { |
|
280 delete mTxn; |
|
281 } |
|
282 |
|
283 void |
|
284 ImageBridgeChild::MarkShutDown() |
|
285 { |
|
286 MOZ_ASSERT(!mShuttingDown); |
|
287 mShuttingDown = true; |
|
288 } |
|
289 |
|
290 void |
|
291 ImageBridgeChild::Connect(CompositableClient* aCompositable) |
|
292 { |
|
293 MOZ_ASSERT(aCompositable); |
|
294 MOZ_ASSERT(!mShuttingDown); |
|
295 uint64_t id = 0; |
|
296 PCompositableChild* child = |
|
297 SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id); |
|
298 MOZ_ASSERT(child); |
|
299 aCompositable->InitIPDLActor(child, id); |
|
300 } |
|
301 |
|
302 PCompositableChild* |
|
303 ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) |
|
304 { |
|
305 MOZ_ASSERT(!mShuttingDown); |
|
306 return CompositableClient::CreateIPDLActor(); |
|
307 } |
|
308 |
|
309 bool |
|
310 ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor) |
|
311 { |
|
312 return CompositableClient::DestroyIPDLActor(aActor); |
|
313 } |
|
314 |
|
315 |
|
316 Thread* ImageBridgeChild::GetThread() const |
|
317 { |
|
318 return sImageBridgeChildThread; |
|
319 } |
|
320 |
|
321 ImageBridgeChild* ImageBridgeChild::GetSingleton() |
|
322 { |
|
323 return sImageBridgeChildSingleton; |
|
324 } |
|
325 |
|
326 bool ImageBridgeChild::IsCreated() |
|
327 { |
|
328 return GetSingleton() != nullptr; |
|
329 } |
|
330 |
|
331 void ImageBridgeChild::StartUp() |
|
332 { |
|
333 NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); |
|
334 ImageBridgeChild::StartUpOnThread(new Thread("ImageBridgeChild")); |
|
335 } |
|
336 |
|
337 #ifdef MOZ_NUWA_PROCESS |
|
338 #include "ipc/Nuwa.h" |
|
339 #endif |
|
340 |
|
341 static void |
|
342 ConnectImageBridgeInChildProcess(Transport* aTransport, |
|
343 ProcessHandle aOtherProcess) |
|
344 { |
|
345 // Bind the IPC channel to the image bridge thread. |
|
346 sImageBridgeChildSingleton->Open(aTransport, aOtherProcess, |
|
347 XRE_GetIOMessageLoop(), |
|
348 ipc::ChildSide); |
|
349 #ifdef MOZ_NUWA_PROCESS |
|
350 if (IsNuwaProcess()) { |
|
351 sImageBridgeChildThread |
|
352 ->message_loop()->PostTask(FROM_HERE, |
|
353 NewRunnableFunction(NuwaMarkCurrentThread, |
|
354 (void (*)(void *))nullptr, |
|
355 (void *)nullptr)); |
|
356 } |
|
357 #endif |
|
358 } |
|
359 |
|
360 static void ReleaseImageClientNow(ImageClient* aClient) |
|
361 { |
|
362 MOZ_ASSERT(InImageBridgeChildThread()); |
|
363 aClient->Release(); |
|
364 } |
|
365 |
|
366 // static |
|
367 void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient) |
|
368 { |
|
369 if (!IsCreated()) { |
|
370 // CompositableClient::Release should normally happen in the ImageBridgeChild |
|
371 // thread because it usually generate some IPDL messages. |
|
372 // However, if we take this branch it means that the ImageBridgeChild |
|
373 // has already shut down, along with the CompositableChild, which means no |
|
374 // message will be sent and it is safe to run this code from any thread. |
|
375 MOZ_ASSERT(aClient->GetIPDLActor() == nullptr); |
|
376 aClient->Release(); |
|
377 return; |
|
378 } |
|
379 |
|
380 sImageBridgeChildSingleton->GetMessageLoop()->PostTask( |
|
381 FROM_HERE, |
|
382 NewRunnableFunction(&ReleaseImageClientNow, aClient)); |
|
383 } |
|
384 |
|
385 static void ReleaseTextureClientNow(TextureClient* aClient) |
|
386 { |
|
387 MOZ_ASSERT(InImageBridgeChildThread()); |
|
388 aClient->Release(); |
|
389 } |
|
390 |
|
391 // static |
|
392 void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient) |
|
393 { |
|
394 if (!IsCreated()) { |
|
395 // TextureClient::Release should normally happen in the ImageBridgeChild |
|
396 // thread because it usually generate some IPDL messages. |
|
397 // However, if we take this branch it means that the ImageBridgeChild |
|
398 // has already shut down, along with the TextureChild, which means no |
|
399 // message will be sent and it is safe to run this code from any thread. |
|
400 MOZ_ASSERT(aClient->GetIPDLActor() == nullptr); |
|
401 aClient->Release(); |
|
402 return; |
|
403 } |
|
404 |
|
405 sImageBridgeChildSingleton->GetMessageLoop()->PostTask( |
|
406 FROM_HERE, |
|
407 NewRunnableFunction(&ReleaseTextureClientNow, aClient)); |
|
408 } |
|
409 |
|
410 static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContainer) |
|
411 { |
|
412 MOZ_ASSERT(aClient); |
|
413 MOZ_ASSERT(aContainer); |
|
414 sImageBridgeChildSingleton->BeginTransaction(); |
|
415 aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE); |
|
416 aClient->OnTransaction(); |
|
417 sImageBridgeChildSingleton->EndTransaction(); |
|
418 } |
|
419 |
|
420 //static |
|
421 void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, |
|
422 ImageContainer* aContainer) |
|
423 { |
|
424 if (!IsCreated()) { |
|
425 return; |
|
426 } |
|
427 |
|
428 if (InImageBridgeChildThread()) { |
|
429 UpdateImageClientNow(aClient, aContainer); |
|
430 return; |
|
431 } |
|
432 sImageBridgeChildSingleton->GetMessageLoop()->PostTask( |
|
433 FROM_HERE, |
|
434 NewRunnableFunction< |
|
435 void (*)(ImageClient*, ImageContainer*), |
|
436 ImageClient*, |
|
437 nsRefPtr<ImageContainer> >(&UpdateImageClientNow, aClient, aContainer)); |
|
438 } |
|
439 |
|
440 static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront, ReentrantMonitor* aBarrier, bool* aDone) |
|
441 { |
|
442 ImageBridgeChild::FlushAllImagesNow(aClient, aContainer, aExceptFront); |
|
443 |
|
444 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
445 *aDone = true; |
|
446 aBarrier->NotifyAll(); |
|
447 } |
|
448 |
|
449 //static |
|
450 void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront) |
|
451 { |
|
452 if (!IsCreated()) { |
|
453 return; |
|
454 } |
|
455 |
|
456 MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); |
|
457 |
|
458 if (InImageBridgeChildThread()) { |
|
459 FlushAllImagesNow(aClient, aContainer, aExceptFront); |
|
460 return; |
|
461 } |
|
462 |
|
463 ReentrantMonitor barrier("CreateImageClient Lock"); |
|
464 ReentrantMonitorAutoEnter autoMon(barrier); |
|
465 bool done = false; |
|
466 |
|
467 sImageBridgeChildSingleton->GetMessageLoop()->PostTask( |
|
468 FROM_HERE, |
|
469 NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, aExceptFront, &barrier, &done)); |
|
470 |
|
471 // should stop the thread until the ImageClient has been created on |
|
472 // the other thread |
|
473 while (!done) { |
|
474 barrier.Wait(); |
|
475 } |
|
476 } |
|
477 |
|
478 //static |
|
479 void ImageBridgeChild::FlushAllImagesNow(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront) |
|
480 { |
|
481 MOZ_ASSERT(aClient); |
|
482 sImageBridgeChildSingleton->BeginTransaction(); |
|
483 if (aContainer && !aExceptFront) { |
|
484 aContainer->ClearCurrentImage(); |
|
485 } |
|
486 aClient->FlushAllImages(aExceptFront); |
|
487 aClient->OnTransaction(); |
|
488 sImageBridgeChildSingleton->EndTransaction(); |
|
489 } |
|
490 |
|
491 void |
|
492 ImageBridgeChild::BeginTransaction() |
|
493 { |
|
494 MOZ_ASSERT(!mShuttingDown); |
|
495 MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?"); |
|
496 mTxn->Begin(); |
|
497 } |
|
498 |
|
499 class MOZ_STACK_CLASS AutoRemoveTextures |
|
500 { |
|
501 public: |
|
502 AutoRemoveTextures(ImageBridgeChild* aImageBridge) |
|
503 : mImageBridge(aImageBridge) {} |
|
504 |
|
505 ~AutoRemoveTextures() |
|
506 { |
|
507 mImageBridge->RemoveTexturesIfNecessary(); |
|
508 } |
|
509 private: |
|
510 ImageBridgeChild* mImageBridge; |
|
511 }; |
|
512 |
|
513 void |
|
514 ImageBridgeChild::EndTransaction() |
|
515 { |
|
516 MOZ_ASSERT(!mShuttingDown); |
|
517 MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?"); |
|
518 |
|
519 AutoEndTransaction _(mTxn); |
|
520 AutoRemoveTextures autoRemoveTextures(this); |
|
521 |
|
522 if (mTxn->IsEmpty()) { |
|
523 return; |
|
524 } |
|
525 |
|
526 AutoInfallibleTArray<CompositableOperation, 10> cset; |
|
527 cset.SetCapacity(mTxn->mOperations.size()); |
|
528 if (!mTxn->mOperations.empty()) { |
|
529 cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size()); |
|
530 } |
|
531 ShadowLayerForwarder::PlatformSyncBeforeUpdate(); |
|
532 |
|
533 AutoInfallibleTArray<EditReply, 10> replies; |
|
534 |
|
535 if (mTxn->mSwapRequired) { |
|
536 if (!SendUpdate(cset, &replies)) { |
|
537 NS_WARNING("could not send async texture transaction"); |
|
538 return; |
|
539 } |
|
540 } else { |
|
541 // If we don't require a swap we can call SendUpdateNoSwap which |
|
542 // assumes that aReplies is empty (DEBUG assertion) |
|
543 if (!SendUpdateNoSwap(cset)) { |
|
544 NS_WARNING("could not send async texture transaction (no swap)"); |
|
545 return; |
|
546 } |
|
547 } |
|
548 for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) { |
|
549 const EditReply& reply = replies[i]; |
|
550 switch (reply.type()) { |
|
551 case EditReply::TOpTextureSwap: { |
|
552 const OpTextureSwap& ots = reply.get_OpTextureSwap(); |
|
553 |
|
554 CompositableClient* compositable = |
|
555 CompositableClient::FromIPDLActor(ots.compositableChild()); |
|
556 |
|
557 MOZ_ASSERT(compositable); |
|
558 |
|
559 compositable->SetDescriptorFromReply(ots.textureId(), ots.image()); |
|
560 break; |
|
561 } |
|
562 case EditReply::TReturnReleaseFence: { |
|
563 const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence(); |
|
564 FenceHandle fence = rep.fence(); |
|
565 PTextureChild* child = rep.textureChild(); |
|
566 |
|
567 if (!fence.IsValid() || !child) { |
|
568 break; |
|
569 } |
|
570 RefPtr<TextureClient> texture = TextureClient::AsTextureClient(child); |
|
571 if (texture) { |
|
572 texture->SetReleaseFenceHandle(fence); |
|
573 } |
|
574 break; |
|
575 } |
|
576 default: |
|
577 NS_RUNTIMEABORT("not reached"); |
|
578 } |
|
579 } |
|
580 } |
|
581 |
|
582 |
|
583 PImageBridgeChild* |
|
584 ImageBridgeChild::StartUpInChildProcess(Transport* aTransport, |
|
585 ProcessId aOtherProcess) |
|
586 { |
|
587 NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); |
|
588 |
|
589 ProcessHandle processHandle; |
|
590 if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) { |
|
591 return nullptr; |
|
592 } |
|
593 |
|
594 sImageBridgeChildThread = new Thread("ImageBridgeChild"); |
|
595 if (!sImageBridgeChildThread->Start()) { |
|
596 return nullptr; |
|
597 } |
|
598 |
|
599 sImageBridgeChildSingleton = new ImageBridgeChild(); |
|
600 sImageBridgeChildSingleton->GetMessageLoop()->PostTask( |
|
601 FROM_HERE, |
|
602 NewRunnableFunction(ConnectImageBridgeInChildProcess, |
|
603 aTransport, processHandle)); |
|
604 |
|
605 return sImageBridgeChildSingleton; |
|
606 } |
|
607 |
|
608 void ImageBridgeChild::ShutDown() |
|
609 { |
|
610 MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); |
|
611 if (ImageBridgeChild::IsCreated()) { |
|
612 MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); |
|
613 |
|
614 { |
|
615 ReentrantMonitor barrier("ImageBridge ShutdownStep1 lock"); |
|
616 ReentrantMonitorAutoEnter autoMon(barrier); |
|
617 |
|
618 bool done = false; |
|
619 sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, |
|
620 NewRunnableFunction(&ImageBridgeShutdownStep1, &barrier, &done)); |
|
621 while (!done) { |
|
622 barrier.Wait(); |
|
623 } |
|
624 } |
|
625 |
|
626 { |
|
627 ReentrantMonitor barrier("ImageBridge ShutdownStep2 lock"); |
|
628 ReentrantMonitorAutoEnter autoMon(barrier); |
|
629 |
|
630 bool done = false; |
|
631 sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, |
|
632 NewRunnableFunction(&ImageBridgeShutdownStep2, &barrier, &done)); |
|
633 while (!done) { |
|
634 barrier.Wait(); |
|
635 } |
|
636 } |
|
637 |
|
638 delete sImageBridgeChildThread; |
|
639 sImageBridgeChildThread = nullptr; |
|
640 } |
|
641 } |
|
642 |
|
643 bool ImageBridgeChild::StartUpOnThread(Thread* aThread) |
|
644 { |
|
645 NS_ABORT_IF_FALSE(aThread, "ImageBridge needs a thread."); |
|
646 if (sImageBridgeChildSingleton == nullptr) { |
|
647 sImageBridgeChildThread = aThread; |
|
648 if (!aThread->IsRunning()) { |
|
649 aThread->Start(); |
|
650 } |
|
651 sImageBridgeChildSingleton = new ImageBridgeChild(); |
|
652 sImageBridgeParentSingleton = new ImageBridgeParent( |
|
653 CompositorParent::CompositorLoop(), nullptr); |
|
654 sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton); |
|
655 return true; |
|
656 } else { |
|
657 return false; |
|
658 } |
|
659 } |
|
660 |
|
661 bool InImageBridgeChildThread() |
|
662 { |
|
663 return sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId(); |
|
664 } |
|
665 |
|
666 MessageLoop * ImageBridgeChild::GetMessageLoop() const |
|
667 { |
|
668 return sImageBridgeChildThread->message_loop(); |
|
669 } |
|
670 |
|
671 void ImageBridgeChild::ConnectAsync(ImageBridgeParent* aParent) |
|
672 { |
|
673 GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectImageBridge, |
|
674 this, aParent)); |
|
675 } |
|
676 |
|
677 void |
|
678 ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier) |
|
679 { |
|
680 if (sImageBridgeChildSingleton) { |
|
681 sImageBridgeChildSingleton->IdentifyTextureHost(aIdentifier); |
|
682 } |
|
683 } |
|
684 |
|
685 TemporaryRef<ImageClient> |
|
686 ImageBridgeChild::CreateImageClient(CompositableType aType) |
|
687 { |
|
688 if (InImageBridgeChildThread()) { |
|
689 return CreateImageClientNow(aType); |
|
690 } |
|
691 ReentrantMonitor barrier("CreateImageClient Lock"); |
|
692 ReentrantMonitorAutoEnter autoMon(barrier); |
|
693 bool done = false; |
|
694 |
|
695 RefPtr<ImageClient> result = nullptr; |
|
696 GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateImageClientSync, |
|
697 &result, &barrier, aType, &done)); |
|
698 // should stop the thread until the ImageClient has been created on |
|
699 // the other thread |
|
700 while (!done) { |
|
701 barrier.Wait(); |
|
702 } |
|
703 return result.forget(); |
|
704 } |
|
705 |
|
706 TemporaryRef<ImageClient> |
|
707 ImageBridgeChild::CreateImageClientNow(CompositableType aType) |
|
708 { |
|
709 MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); |
|
710 RefPtr<ImageClient> client |
|
711 = ImageClient::CreateImageClient(aType, this, 0); |
|
712 MOZ_ASSERT(client, "failed to create ImageClient"); |
|
713 if (client) { |
|
714 client->Connect(); |
|
715 } |
|
716 return client.forget(); |
|
717 } |
|
718 |
|
719 PGrallocBufferChild* |
|
720 ImageBridgeChild::AllocPGrallocBufferChild(const IntSize&, const uint32_t&, const uint32_t&, |
|
721 MaybeMagicGrallocBufferHandle*) |
|
722 { |
|
723 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC |
|
724 return GrallocBufferActor::Create(); |
|
725 #else |
|
726 NS_RUNTIMEABORT("No gralloc buffers for you"); |
|
727 return nullptr; |
|
728 #endif |
|
729 } |
|
730 |
|
731 bool |
|
732 ImageBridgeChild::DeallocPGrallocBufferChild(PGrallocBufferChild* actor) |
|
733 { |
|
734 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC |
|
735 delete actor; |
|
736 return true; |
|
737 #else |
|
738 NS_RUNTIMEABORT("Um, how did we get here?"); |
|
739 return false; |
|
740 #endif |
|
741 } |
|
742 |
|
743 bool |
|
744 ImageBridgeChild::AllocUnsafeShmem(size_t aSize, |
|
745 ipc::SharedMemory::SharedMemoryType aType, |
|
746 ipc::Shmem* aShmem) |
|
747 { |
|
748 MOZ_ASSERT(!mShuttingDown); |
|
749 if (InImageBridgeChildThread()) { |
|
750 return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem); |
|
751 } else { |
|
752 return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe |
|
753 } |
|
754 } |
|
755 |
|
756 bool |
|
757 ImageBridgeChild::AllocShmem(size_t aSize, |
|
758 ipc::SharedMemory::SharedMemoryType aType, |
|
759 ipc::Shmem* aShmem) |
|
760 { |
|
761 if (InImageBridgeChildThread()) { |
|
762 return PImageBridgeChild::AllocShmem(aSize, aType, aShmem); |
|
763 } else { |
|
764 return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe |
|
765 } |
|
766 } |
|
767 |
|
768 // NewRunnableFunction accepts a limited number of parameters so we need a |
|
769 // struct here |
|
770 struct AllocShmemParams { |
|
771 RefPtr<ISurfaceAllocator> mAllocator; |
|
772 size_t mSize; |
|
773 ipc::SharedMemory::SharedMemoryType mType; |
|
774 ipc::Shmem* mShmem; |
|
775 bool mUnsafe; |
|
776 bool mSuccess; |
|
777 }; |
|
778 |
|
779 static void ProxyAllocShmemNow(AllocShmemParams* aParams, |
|
780 ReentrantMonitor* aBarrier, |
|
781 bool* aDone) |
|
782 { |
|
783 MOZ_ASSERT(aParams); |
|
784 MOZ_ASSERT(aDone); |
|
785 MOZ_ASSERT(aBarrier); |
|
786 |
|
787 if (aParams->mUnsafe) { |
|
788 aParams->mSuccess = aParams->mAllocator->AllocUnsafeShmem(aParams->mSize, |
|
789 aParams->mType, |
|
790 aParams->mShmem); |
|
791 } else { |
|
792 aParams->mSuccess = aParams->mAllocator->AllocShmem(aParams->mSize, |
|
793 aParams->mType, |
|
794 aParams->mShmem); |
|
795 } |
|
796 |
|
797 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
798 *aDone = true; |
|
799 aBarrier->NotifyAll(); |
|
800 } |
|
801 |
|
802 bool |
|
803 ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize, |
|
804 SharedMemory::SharedMemoryType aType, |
|
805 ipc::Shmem* aShmem, |
|
806 bool aUnsafe) |
|
807 { |
|
808 ReentrantMonitor barrier("AllocatorProxy alloc"); |
|
809 ReentrantMonitorAutoEnter autoMon(barrier); |
|
810 |
|
811 AllocShmemParams params = { |
|
812 this, aSize, aType, aShmem, aUnsafe, true |
|
813 }; |
|
814 bool done = false; |
|
815 |
|
816 GetMessageLoop()->PostTask(FROM_HERE, |
|
817 NewRunnableFunction(&ProxyAllocShmemNow, |
|
818 ¶ms, |
|
819 &barrier, |
|
820 &done)); |
|
821 while (!done) { |
|
822 barrier.Wait(); |
|
823 } |
|
824 return params.mSuccess; |
|
825 } |
|
826 |
|
827 static void ProxyDeallocShmemNow(ISurfaceAllocator* aAllocator, |
|
828 ipc::Shmem* aShmem, |
|
829 ReentrantMonitor* aBarrier, |
|
830 bool* aDone) |
|
831 { |
|
832 MOZ_ASSERT(aShmem); |
|
833 MOZ_ASSERT(aDone); |
|
834 MOZ_ASSERT(aBarrier); |
|
835 |
|
836 aAllocator->DeallocShmem(*aShmem); |
|
837 |
|
838 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
839 *aDone = true; |
|
840 aBarrier->NotifyAll(); |
|
841 } |
|
842 |
|
843 void |
|
844 ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) |
|
845 { |
|
846 if (InImageBridgeChildThread()) { |
|
847 PImageBridgeChild::DeallocShmem(aShmem); |
|
848 } else { |
|
849 ReentrantMonitor barrier("AllocatorProxy Dealloc"); |
|
850 ReentrantMonitorAutoEnter autoMon(barrier); |
|
851 |
|
852 bool done = false; |
|
853 GetMessageLoop()->PostTask(FROM_HERE, |
|
854 NewRunnableFunction(&ProxyDeallocShmemNow, |
|
855 this, |
|
856 &aShmem, |
|
857 &barrier, |
|
858 &done)); |
|
859 while (!done) { |
|
860 barrier.Wait(); |
|
861 } |
|
862 } |
|
863 } |
|
864 |
|
865 PGrallocBufferChild* |
|
866 ImageBridgeChild::AllocGrallocBuffer(const IntSize& aSize, |
|
867 uint32_t aFormat, |
|
868 uint32_t aUsage, |
|
869 MaybeMagicGrallocBufferHandle* aHandle) |
|
870 { |
|
871 if (InImageBridgeChildThread()) { |
|
872 PGrallocBufferChild* child = nullptr; |
|
873 ImageBridgeChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aHandle, &child); |
|
874 return child; |
|
875 } |
|
876 |
|
877 Monitor barrier("AllocGrallocBuffer Lock"); |
|
878 MonitorAutoLock autoMon(barrier); |
|
879 bool done = false; |
|
880 PGrallocBufferChild* child = nullptr; |
|
881 |
|
882 GetMessageLoop()->PostTask( |
|
883 FROM_HERE, |
|
884 NewRunnableFunction(&AllocGrallocBufferSync, |
|
885 GrallocParam(aSize, aFormat, aUsage, aHandle, &child), &barrier, &done)); |
|
886 |
|
887 while (!done) { |
|
888 barrier.Wait(); |
|
889 } |
|
890 |
|
891 return child; |
|
892 } |
|
893 |
|
894 void |
|
895 ImageBridgeChild::AllocGrallocBufferNow(const gfx::IntSize& aSize, |
|
896 uint32_t aFormat, uint32_t aUsage, |
|
897 MaybeMagicGrallocBufferHandle* aHandle, |
|
898 PGrallocBufferChild** aChild) |
|
899 { |
|
900 #ifdef MOZ_WIDGET_GONK |
|
901 *aChild = SendPGrallocBufferConstructor(aSize, |
|
902 aFormat, |
|
903 aUsage, |
|
904 aHandle); |
|
905 #else |
|
906 NS_RUNTIMEABORT("not implemented"); |
|
907 aChild = nullptr; |
|
908 #endif |
|
909 } |
|
910 |
|
911 static void ProxyDeallocGrallocBufferNow(ISurfaceAllocator* aAllocator, |
|
912 PGrallocBufferChild* aChild, |
|
913 ReentrantMonitor* aBarrier, |
|
914 bool* aDone) |
|
915 { |
|
916 MOZ_ASSERT(aChild); |
|
917 MOZ_ASSERT(aDone); |
|
918 MOZ_ASSERT(aBarrier); |
|
919 |
|
920 #ifdef MOZ_WIDGET_GONK |
|
921 PGrallocBufferChild::Send__delete__(aChild); |
|
922 #else |
|
923 NS_RUNTIMEABORT("not implemented"); |
|
924 #endif |
|
925 |
|
926 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
927 *aDone = true; |
|
928 aBarrier->NotifyAll(); |
|
929 } |
|
930 |
|
931 void |
|
932 ImageBridgeChild::DeallocGrallocBuffer(PGrallocBufferChild* aChild) |
|
933 { |
|
934 MOZ_ASSERT(aChild); |
|
935 if (InImageBridgeChildThread()) { |
|
936 #ifdef MOZ_WIDGET_GONK |
|
937 PGrallocBufferChild::Send__delete__(aChild); |
|
938 #else |
|
939 NS_RUNTIMEABORT("not implemented"); |
|
940 #endif |
|
941 } else { |
|
942 ReentrantMonitor barrier("AllocatorProxy Dealloc"); |
|
943 ReentrantMonitorAutoEnter autoMon(barrier); |
|
944 |
|
945 bool done = false; |
|
946 GetMessageLoop()->PostTask(FROM_HERE, |
|
947 NewRunnableFunction(&ProxyDeallocGrallocBufferNow, |
|
948 this, |
|
949 aChild, |
|
950 &barrier, |
|
951 &done)); |
|
952 while (!done) { |
|
953 barrier.Wait(); |
|
954 } |
|
955 } |
|
956 } |
|
957 |
|
958 PTextureChild* |
|
959 ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&, |
|
960 const TextureFlags&) |
|
961 { |
|
962 MOZ_ASSERT(!mShuttingDown); |
|
963 return TextureClient::CreateIPDLActor(); |
|
964 } |
|
965 |
|
966 bool |
|
967 ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor) |
|
968 { |
|
969 return TextureClient::DestroyIPDLActor(actor); |
|
970 } |
|
971 |
|
972 PTextureChild* |
|
973 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, |
|
974 TextureFlags aFlags) |
|
975 { |
|
976 MOZ_ASSERT(!mShuttingDown); |
|
977 return SendPTextureConstructor(aSharedData, aFlags); |
|
978 } |
|
979 |
|
980 void |
|
981 ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable, |
|
982 TextureClient* aTexture) |
|
983 { |
|
984 MOZ_ASSERT(!mShuttingDown); |
|
985 if (aTexture->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { |
|
986 mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), |
|
987 nullptr, aTexture->GetIPDLActor())); |
|
988 } else { |
|
989 mTxn->AddNoSwapEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), |
|
990 nullptr, aTexture->GetIPDLActor())); |
|
991 } |
|
992 // Hold texture until transaction complete. |
|
993 HoldUntilTransaction(aTexture); |
|
994 } |
|
995 |
|
996 static void RemoveTextureSync(TextureClient* aTexture, ReentrantMonitor* aBarrier, bool* aDone) |
|
997 { |
|
998 aTexture->ForceRemove(); |
|
999 |
|
1000 ReentrantMonitorAutoEnter autoMon(*aBarrier); |
|
1001 *aDone = true; |
|
1002 aBarrier->NotifyAll(); |
|
1003 } |
|
1004 |
|
1005 void ImageBridgeChild::RemoveTexture(TextureClient* aTexture) |
|
1006 { |
|
1007 if (InImageBridgeChildThread()) { |
|
1008 MOZ_ASSERT(!mShuttingDown); |
|
1009 aTexture->ForceRemove(); |
|
1010 return; |
|
1011 } |
|
1012 |
|
1013 ReentrantMonitor barrier("RemoveTexture Lock"); |
|
1014 ReentrantMonitorAutoEnter autoMon(barrier); |
|
1015 bool done = false; |
|
1016 |
|
1017 sImageBridgeChildSingleton->GetMessageLoop()->PostTask( |
|
1018 FROM_HERE, |
|
1019 NewRunnableFunction(&RemoveTextureSync, aTexture, &barrier, &done)); |
|
1020 |
|
1021 // should stop the thread until the ImageClient has been created on |
|
1022 // the other thread |
|
1023 while (!done) { |
|
1024 barrier.Wait(); |
|
1025 } |
|
1026 } |
|
1027 |
|
1028 bool ImageBridgeChild::IsSameProcess() const |
|
1029 { |
|
1030 return OtherProcess() == ipc::kInvalidProcessHandle; |
|
1031 } |
|
1032 |
|
1033 } // layers |
|
1034 } // mozilla |