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/. */
7 #include "VRServiceHost.h"
8 #include "VRGPUChild.h"
9 #include "VRPuppetCommandBuffer.h"
10 #include "mozilla/ClearOnShutdown.h"
11 #include "mozilla/gfx/GPUParent.h"
12 #include "service/VRService.h"
13 #include "VRManager.h"
18 static StaticRefPtr
<VRServiceHost
> sVRServiceHostSingleton
;
21 void VRServiceHost::Init(bool aEnableVRProcess
) {
22 MOZ_ASSERT(NS_IsMainThread());
24 if (sVRServiceHostSingleton
== nullptr) {
25 sVRServiceHostSingleton
= new VRServiceHost(aEnableVRProcess
);
26 ClearOnShutdown(&sVRServiceHostSingleton
);
31 VRServiceHost
* VRServiceHost::Get() {
32 MOZ_ASSERT(sVRServiceHostSingleton
!= nullptr);
33 return sVRServiceHostSingleton
;
36 VRServiceHost::VRServiceHost(bool aEnableVRProcess
)
37 : mVRService(nullptr),
38 mVRProcessEnabled(aEnableVRProcess
),
39 mVRProcessStarted(false),
40 mVRServiceReadyInVRProcess(false),
41 mVRServiceRequested(false)
44 MOZ_COUNT_CTOR(VRServiceHost
);
47 VRServiceHost::~VRServiceHost() {
48 MOZ_ASSERT(NS_IsMainThread());
49 MOZ_COUNT_DTOR(VRServiceHost
);
52 void VRServiceHost::StartService() {
53 mVRServiceRequested
= true;
54 if (mVRProcessEnabled
) {
55 // VRService in the VR process
57 } else if (mVRService
) {
58 // VRService in the GPU process if enabled, or
59 // the parent process if the GPU process is not enabled.
64 void VRServiceHost::StopService() {
65 mVRServiceRequested
= false;
66 if (mVRProcessEnabled
) {
67 // VRService in the VR process
69 } else if (mVRService
) {
70 // VRService in the GPU process if enabled, or
71 // the parent process if the GPU process is not enabled.
76 void VRServiceHost::Shutdown() {
82 void VRServiceHost::Refresh() {
84 mVRService
->Refresh();
88 void VRServiceHost::CreateService(volatile VRExternalShmem
* aShmem
) {
89 MOZ_ASSERT(!mVRProcessEnabled
);
90 mVRService
= VRService::Create(aShmem
);
93 bool VRServiceHost::NeedVRProcess() {
94 if (!mVRProcessEnabled
) {
97 return mVRServiceRequested
;
100 void VRServiceHost::RefreshVRProcess() {
101 // Start or stop the VR process if needed
102 if (NeedVRProcess()) {
103 if (!mVRProcessStarted
) {
107 if (mVRProcessStarted
) {
113 void VRServiceHost::CreateVRProcess() {
114 // This is only allowed to run in the main thread of the GPU process
115 if (!XRE_IsGPUProcess()) {
118 // Forward this to the main thread if not already there
119 if (!NS_IsMainThread()) {
120 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
121 "VRServiceHost::CreateVRProcess",
122 []() -> void { VRServiceHost::Get()->CreateVRProcess(); });
123 NS_DispatchToMainThread(task
.forget());
126 if (mVRProcessStarted
) {
130 mVRProcessStarted
= true;
131 // Using PGPU channel to tell the main process
132 // to create the VR process.
133 gfx::GPUParent
* gpu
= GPUParent::GetSingleton();
135 Unused
<< gpu
->SendCreateVRProcess();
138 void VRServiceHost::NotifyVRProcessStarted() {
139 MOZ_ASSERT(NS_IsMainThread());
140 MOZ_ASSERT(mVRProcessEnabled
);
141 if (!mVRProcessStarted
) {
142 // We have received this after the VR process
143 // has been stopped; the VR service is no
144 // longer running in the VR process.
148 if (!VRGPUChild::IsCreated()) {
151 VRGPUChild
* vrGPUChild
= VRGPUChild::Get();
153 // The VR service has started in the VR process
154 // If there were pending puppet commands, we
155 // can send them now.
156 // This must occur before the VRService
157 // is started so the buffer can be seen
158 // by VRPuppetSession::Initialize().
159 if (!mPuppetPendingCommands
.IsEmpty()) {
160 vrGPUChild
->SendPuppetSubmit(mPuppetPendingCommands
);
161 mPuppetPendingCommands
.Clear();
164 vrGPUChild
->SendStartVRService();
165 mVRServiceReadyInVRProcess
= true;
168 void VRServiceHost::ShutdownVRProcess() {
169 // This is only allowed to run in the main thread of the GPU process
170 if (!XRE_IsGPUProcess()) {
173 // Forward this to the main thread if not already there
174 if (!NS_IsMainThread()) {
175 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
176 "VRServiceHost::ShutdownVRProcess",
177 []() -> void { VRServiceHost::Get()->ShutdownVRProcess(); });
178 NS_DispatchToMainThread(task
.forget());
181 if (VRGPUChild::IsCreated()) {
182 VRGPUChild
* vrGPUChild
= VRGPUChild::Get();
183 vrGPUChild
->SendStopVRService();
184 if (!vrGPUChild
->IsClosed()) {
187 VRGPUChild::Shutdown();
189 if (!mVRProcessStarted
) {
192 // Using PGPU channel to tell the main process
193 // to shutdown VR process.
194 gfx::GPUParent
* gpu
= GPUParent::GetSingleton();
196 Unused
<< gpu
->SendShutdownVRProcess();
197 mVRProcessStarted
= false;
198 mVRServiceReadyInVRProcess
= false;
201 void VRServiceHost::PuppetSubmit(const nsTArray
<uint64_t>& aBuffer
) {
202 if (!mVRProcessEnabled
) {
203 // Puppet is running in this process, submit commands directly
204 VRPuppetCommandBuffer::Get().Submit(aBuffer
);
208 // We need to send the buffer to the VR process
209 SendPuppetSubmitToVRProcess(aBuffer
);
212 void VRServiceHost::SendPuppetSubmitToVRProcess(
213 const nsTArray
<uint64_t>& aBuffer
) {
214 // This is only allowed to run in the main thread of the GPU process
215 if (!XRE_IsGPUProcess()) {
218 // Forward this to the main thread if not already there
219 if (!NS_IsMainThread()) {
220 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
221 "VRServiceHost::SendPuppetSubmitToVRProcess",
222 [buffer
{aBuffer
.Clone()}]() -> void {
223 VRServiceHost::Get()->SendPuppetSubmitToVRProcess(buffer
);
225 NS_DispatchToMainThread(task
.forget());
228 if (!mVRServiceReadyInVRProcess
) {
229 // Queue the commands to be sent to the VR process once it is started
230 mPuppetPendingCommands
.AppendElements(aBuffer
);
233 if (VRGPUChild::IsCreated()) {
234 VRGPUChild
* vrGPUChild
= VRGPUChild::Get();
235 vrGPUChild
->SendPuppetSubmit(aBuffer
);
239 void VRServiceHost::PuppetReset() {
240 // If we're already into ShutdownFinal, the VRPuppetCommandBuffer instance
241 // will have been cleared, so don't try to access it after that point.
242 if (!mVRProcessEnabled
&&
243 !(NS_IsMainThread() &&
244 PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal
))) {
245 // Puppet is running in this process, tell it to reset directly.
246 VRPuppetCommandBuffer::Get().Reset();
249 mPuppetPendingCommands
.Clear();
250 if (!mVRProcessStarted
) {
251 // Process is stopped, so puppet state is already clear
255 // We need to tell the VR process to reset the puppet
256 SendPuppetResetToVRProcess();
259 void VRServiceHost::SendPuppetResetToVRProcess() {
260 // This is only allowed to run in the main thread of the GPU process
261 if (!XRE_IsGPUProcess()) {
264 // Forward this to the main thread if not already there
265 if (!NS_IsMainThread()) {
266 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
267 "VRServiceHost::SendPuppetResetToVRProcess",
268 []() -> void { VRServiceHost::Get()->SendPuppetResetToVRProcess(); });
269 NS_DispatchToMainThread(task
.forget());
272 if (VRGPUChild::IsCreated()) {
273 VRGPUChild
* vrGPUChild
= VRGPUChild::Get();
274 vrGPUChild
->SendPuppetReset();
278 void VRServiceHost::CheckForPuppetCompletion() {
279 if (!mVRProcessEnabled
) {
280 // Puppet is running in this process, ask it directly
281 if (VRPuppetCommandBuffer::Get().HasEnded()) {
282 VRManager::Get()->NotifyPuppetComplete();
285 if (!mPuppetPendingCommands
.IsEmpty()) {
286 // There are puppet commands pending to be sent to the
287 // VR process once its started, thus it has not ended.
290 if (!mVRProcessStarted
) {
291 // The VR process will be kept alive as long
292 // as there is a queue in the puppet command
293 // buffer. If the process is stopped, we can
294 // infer that the queue has been cleared and
295 // puppet state is reset.
296 VRManager::Get()->NotifyPuppetComplete();
299 // We need to ask the VR process if the puppet has ended
300 SendPuppetCheckForCompletionToVRProcess();
302 // VRGPUChild::RecvNotifyPuppetComplete will call
303 // VRManager::NotifyPuppetComplete if the puppet has completed
304 // in the VR Process.
307 void VRServiceHost::SendPuppetCheckForCompletionToVRProcess() {
308 // This is only allowed to run in the main thread of the GPU process
309 if (!XRE_IsGPUProcess()) {
312 // Forward this to the main thread if not already there
313 if (!NS_IsMainThread()) {
314 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
315 "VRServiceHost::SendPuppetCheckForCompletionToVRProcess", []() -> void {
316 VRServiceHost::Get()->SendPuppetCheckForCompletionToVRProcess();
318 NS_DispatchToMainThread(task
.forget());
321 if (VRGPUChild::IsCreated()) {
322 VRGPUChild
* vrGPUChild
= VRGPUChild::Get();
323 vrGPUChild
->SendPuppetCheckForCompletion();
328 } // namespace mozilla