Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / gfx / vr / VRServiceHost.cpp
blob933a5467e5d8d281059e06d169c8ff298ab9175f
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"
15 namespace mozilla {
16 namespace gfx {
18 static StaticRefPtr<VRServiceHost> sVRServiceHostSingleton;
20 /* static */
21 void VRServiceHost::Init(bool aEnableVRProcess) {
22 MOZ_ASSERT(NS_IsMainThread());
24 if (sVRServiceHostSingleton == nullptr) {
25 sVRServiceHostSingleton = new VRServiceHost(aEnableVRProcess);
26 ClearOnShutdown(&sVRServiceHostSingleton);
30 /* static */
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
56 RefreshVRProcess();
57 } else if (mVRService) {
58 // VRService in the GPU process if enabled, or
59 // the parent process if the GPU process is not enabled.
60 mVRService->Start();
64 void VRServiceHost::StopService() {
65 mVRServiceRequested = false;
66 if (mVRProcessEnabled) {
67 // VRService in the VR process
68 RefreshVRProcess();
69 } else if (mVRService) {
70 // VRService in the GPU process if enabled, or
71 // the parent process if the GPU process is not enabled.
72 mVRService->Stop();
76 void VRServiceHost::Shutdown() {
77 PuppetReset();
78 StopService();
79 mVRService = nullptr;
82 void VRServiceHost::Refresh() {
83 if (mVRService) {
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) {
95 return false;
97 return mVRServiceRequested;
100 void VRServiceHost::RefreshVRProcess() {
101 // Start or stop the VR process if needed
102 if (NeedVRProcess()) {
103 if (!mVRProcessStarted) {
104 CreateVRProcess();
106 } else {
107 if (mVRProcessStarted) {
108 ShutdownVRProcess();
113 void VRServiceHost::CreateVRProcess() {
114 // This is only allowed to run in the main thread of the GPU process
115 if (!XRE_IsGPUProcess()) {
116 return;
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());
124 return;
126 if (mVRProcessStarted) {
127 return;
130 mVRProcessStarted = true;
131 // Using PGPU channel to tell the main process
132 // to create the VR process.
133 gfx::GPUParent* gpu = GPUParent::GetSingleton();
134 MOZ_ASSERT(gpu);
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.
145 return;
148 if (!VRGPUChild::IsCreated()) {
149 return;
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()) {
171 return;
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());
179 return;
181 if (VRGPUChild::IsCreated()) {
182 VRGPUChild* vrGPUChild = VRGPUChild::Get();
183 vrGPUChild->SendStopVRService();
184 if (!vrGPUChild->IsClosed()) {
185 vrGPUChild->Close();
187 VRGPUChild::Shutdown();
189 if (!mVRProcessStarted) {
190 return;
192 // Using PGPU channel to tell the main process
193 // to shutdown VR process.
194 gfx::GPUParent* gpu = GPUParent::GetSingleton();
195 MOZ_ASSERT(gpu);
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);
205 return;
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()) {
216 return;
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());
226 return;
228 if (!mVRServiceReadyInVRProcess) {
229 // Queue the commands to be sent to the VR process once it is started
230 mPuppetPendingCommands.AppendElements(aBuffer);
231 return;
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
252 return;
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()) {
262 return;
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());
270 return;
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.
288 return;
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()) {
310 return;
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());
319 return;
321 if (VRGPUChild::IsCreated()) {
322 VRGPUChild* vrGPUChild = VRGPUChild::Get();
323 vrGPUChild->SendPuppetCheckForCompletion();
327 } // namespace gfx
328 } // namespace mozilla