|
1 /* vim: set ts=2 sw=2 et tw=80: */ |
|
2 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
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 "ImageBridgeParent.h" |
|
8 #include <stdint.h> // for uint64_t, uint32_t |
|
9 #include "CompositableHost.h" // for CompositableParent, Create |
|
10 #include "base/message_loop.h" // for MessageLoop |
|
11 #include "base/process.h" // for ProcessHandle |
|
12 #include "base/process_util.h" // for OpenProcessHandle |
|
13 #include "base/task.h" // for CancelableTask, DeleteTask, etc |
|
14 #include "base/tracked.h" // for FROM_HERE |
|
15 #include "mozilla/gfx/Point.h" // for IntSize |
|
16 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc |
|
17 #include "mozilla/ipc/ProtocolUtils.h" |
|
18 #include "mozilla/ipc/Transport.h" // for Transport |
|
19 #include "mozilla/layers/CompositableTransactionParent.h" |
|
20 #include "mozilla/layers/CompositorParent.h" // for CompositorParent |
|
21 #include "mozilla/layers/LayerManagerComposite.h" |
|
22 #include "mozilla/layers/LayersMessages.h" // for EditReply |
|
23 #include "mozilla/layers/LayersSurfaces.h" // for PGrallocBufferParent |
|
24 #include "mozilla/layers/PCompositableParent.h" |
|
25 #include "mozilla/layers/PImageBridgeParent.h" |
|
26 #include "mozilla/layers/Compositor.h" |
|
27 #include "mozilla/mozalloc.h" // for operator new, etc |
|
28 #include "nsAutoPtr.h" // for nsRefPtr |
|
29 #include "nsDebug.h" // for NS_RUNTIMEABORT, etc |
|
30 #include "nsISupportsImpl.h" // for ImageBridgeParent::Release, etc |
|
31 #include "nsTArray.h" // for nsTArray, nsTArray_Impl |
|
32 #include "nsTArrayForwardDeclare.h" // for InfallibleTArray |
|
33 #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop |
|
34 #include "mozilla/layers/TextureHost.h" |
|
35 #include "nsThreadUtils.h" |
|
36 |
|
37 using namespace mozilla::ipc; |
|
38 using namespace mozilla::gfx; |
|
39 |
|
40 namespace mozilla { |
|
41 namespace layers { |
|
42 |
|
43 class PGrallocBufferParent; |
|
44 |
|
45 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport) |
|
46 : mMessageLoop(aLoop) |
|
47 , mTransport(aTransport) |
|
48 { |
|
49 // creates the map only if it has not been created already, so it is safe |
|
50 // with several bridges |
|
51 CompositableMap::Create(); |
|
52 } |
|
53 |
|
54 ImageBridgeParent::~ImageBridgeParent() |
|
55 { |
|
56 if (mTransport) { |
|
57 XRE_GetIOMessageLoop()->PostTask(FROM_HERE, |
|
58 new DeleteTask<Transport>(mTransport)); |
|
59 } |
|
60 } |
|
61 |
|
62 LayersBackend |
|
63 ImageBridgeParent::GetCompositorBackendType() const |
|
64 { |
|
65 return Compositor::GetBackend(); |
|
66 } |
|
67 |
|
68 void |
|
69 ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) |
|
70 { |
|
71 MessageLoop::current()->PostTask( |
|
72 FROM_HERE, |
|
73 NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy)); |
|
74 } |
|
75 |
|
76 bool |
|
77 ImageBridgeParent::RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply) |
|
78 { |
|
79 // If we don't actually have a compositor, then don't bother |
|
80 // creating any textures. |
|
81 if (Compositor::GetBackend() == LayersBackend::LAYERS_NONE) { |
|
82 return true; |
|
83 } |
|
84 |
|
85 // Clear fence handles used in previsou transaction. |
|
86 ClearPrevFenceHandles(); |
|
87 |
|
88 EditReplyVector replyv; |
|
89 for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) { |
|
90 if (!ReceiveCompositableUpdate(aEdits[i], replyv)) { |
|
91 return false; |
|
92 } |
|
93 } |
|
94 |
|
95 aReply->SetCapacity(replyv.size()); |
|
96 if (replyv.size() > 0) { |
|
97 aReply->AppendElements(&replyv.front(), replyv.size()); |
|
98 } |
|
99 |
|
100 // Ensure that any pending operations involving back and front |
|
101 // buffers have completed, so that neither process stomps on the |
|
102 // other's buffer contents. |
|
103 LayerManagerComposite::PlatformSyncBeforeReplyUpdate(); |
|
104 |
|
105 return true; |
|
106 } |
|
107 |
|
108 bool |
|
109 ImageBridgeParent::RecvUpdateNoSwap(const EditArray& aEdits) |
|
110 { |
|
111 InfallibleTArray<EditReply> noReplies; |
|
112 bool success = RecvUpdate(aEdits, &noReplies); |
|
113 NS_ABORT_IF_FALSE(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits"); |
|
114 return success; |
|
115 } |
|
116 |
|
117 static void |
|
118 ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge, |
|
119 Transport* aTransport, |
|
120 base::ProcessHandle aOtherProcess) |
|
121 { |
|
122 aBridge->Open(aTransport, aOtherProcess, XRE_GetIOMessageLoop(), ipc::ParentSide); |
|
123 } |
|
124 |
|
125 /*static*/ PImageBridgeParent* |
|
126 ImageBridgeParent::Create(Transport* aTransport, ProcessId aOtherProcess) |
|
127 { |
|
128 base::ProcessHandle processHandle; |
|
129 if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) { |
|
130 return nullptr; |
|
131 } |
|
132 |
|
133 MessageLoop* loop = CompositorParent::CompositorLoop(); |
|
134 nsRefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aTransport); |
|
135 bridge->mSelfRef = bridge; |
|
136 loop->PostTask(FROM_HERE, |
|
137 NewRunnableFunction(ConnectImageBridgeInParentProcess, |
|
138 bridge.get(), aTransport, processHandle)); |
|
139 return bridge.get(); |
|
140 } |
|
141 |
|
142 bool ImageBridgeParent::RecvWillStop() |
|
143 { |
|
144 // If there is any texture still alive we have to force it to deallocate the |
|
145 // device data (GL textures, etc.) now because shortly after SenStop() returns |
|
146 // on the child side the widget will be destroyed along with it's associated |
|
147 // GL context. |
|
148 InfallibleTArray<PTextureParent*> textures; |
|
149 ManagedPTextureParent(textures); |
|
150 for (unsigned int i = 0; i < textures.Length(); ++i) { |
|
151 RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]); |
|
152 tex->DeallocateDeviceData(); |
|
153 } |
|
154 return true; |
|
155 } |
|
156 |
|
157 bool ImageBridgeParent::RecvStop() |
|
158 { |
|
159 // Nothing to do. This message just serves as synchronization between the |
|
160 // child and parent threads during shutdown. |
|
161 return true; |
|
162 } |
|
163 |
|
164 static uint64_t GenImageContainerID() { |
|
165 static uint64_t sNextImageID = 1; |
|
166 |
|
167 ++sNextImageID; |
|
168 return sNextImageID; |
|
169 } |
|
170 |
|
171 PGrallocBufferParent* |
|
172 ImageBridgeParent::AllocPGrallocBufferParent(const IntSize& aSize, |
|
173 const uint32_t& aFormat, |
|
174 const uint32_t& aUsage, |
|
175 MaybeMagicGrallocBufferHandle* aOutHandle) |
|
176 { |
|
177 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC |
|
178 return GrallocBufferActor::Create(aSize, aFormat, aUsage, aOutHandle); |
|
179 #else |
|
180 NS_RUNTIMEABORT("No gralloc buffers for you"); |
|
181 return nullptr; |
|
182 #endif |
|
183 } |
|
184 |
|
185 bool |
|
186 ImageBridgeParent::DeallocPGrallocBufferParent(PGrallocBufferParent* actor) |
|
187 { |
|
188 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC |
|
189 delete actor; |
|
190 return true; |
|
191 #else |
|
192 NS_RUNTIMEABORT("Um, how did we get here?"); |
|
193 return false; |
|
194 #endif |
|
195 } |
|
196 |
|
197 PCompositableParent* |
|
198 ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo, |
|
199 uint64_t* aID) |
|
200 { |
|
201 uint64_t id = GenImageContainerID(); |
|
202 *aID = id; |
|
203 return CompositableHost::CreateIPDLActor(this, aInfo, id); |
|
204 } |
|
205 |
|
206 bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor) |
|
207 { |
|
208 return CompositableHost::DestroyIPDLActor(aActor); |
|
209 } |
|
210 |
|
211 PTextureParent* |
|
212 ImageBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, |
|
213 const TextureFlags& aFlags) |
|
214 { |
|
215 return TextureHost::CreateIPDLActor(this, aSharedData, aFlags); |
|
216 } |
|
217 |
|
218 bool |
|
219 ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor) |
|
220 { |
|
221 return TextureHost::DestroyIPDLActor(actor); |
|
222 } |
|
223 |
|
224 MessageLoop * ImageBridgeParent::GetMessageLoop() { |
|
225 return mMessageLoop; |
|
226 } |
|
227 |
|
228 class ReleaseRunnable : public nsRunnable |
|
229 { |
|
230 public: |
|
231 ReleaseRunnable(ImageBridgeParent* aRef) |
|
232 : mRef(aRef) |
|
233 { |
|
234 } |
|
235 |
|
236 NS_IMETHOD Run() |
|
237 { |
|
238 mRef->Release(); |
|
239 return NS_OK; |
|
240 } |
|
241 |
|
242 private: |
|
243 ImageBridgeParent* mRef; |
|
244 }; |
|
245 |
|
246 void |
|
247 ImageBridgeParent::DeferredDestroy() |
|
248 { |
|
249 ImageBridgeParent* self; |
|
250 mSelfRef.forget(&self); |
|
251 |
|
252 nsCOMPtr<nsIRunnable> runnable = new ReleaseRunnable(self); |
|
253 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); |
|
254 } |
|
255 |
|
256 IToplevelProtocol* |
|
257 ImageBridgeParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds, |
|
258 base::ProcessHandle aPeerProcess, |
|
259 mozilla::ipc::ProtocolCloneContext* aCtx) |
|
260 { |
|
261 for (unsigned int i = 0; i < aFds.Length(); i++) { |
|
262 if (aFds[i].protocolId() == unsigned(GetProtocolId())) { |
|
263 Transport* transport = OpenDescriptor(aFds[i].fd(), |
|
264 Transport::MODE_SERVER); |
|
265 PImageBridgeParent* bridge = Create(transport, base::GetProcId(aPeerProcess)); |
|
266 bridge->CloneManagees(this, aCtx); |
|
267 bridge->IToplevelProtocol::SetTransport(transport); |
|
268 return bridge; |
|
269 } |
|
270 } |
|
271 return nullptr; |
|
272 } |
|
273 |
|
274 bool ImageBridgeParent::IsSameProcess() const |
|
275 { |
|
276 return OtherProcess() == ipc::kInvalidProcessHandle; |
|
277 } |
|
278 |
|
279 } // layers |
|
280 } // mozilla |