Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/vr/./../../../gfx/vr/ipc/VRManagerChild.cpp
Warning:line 170, column 9
Value stored to 'found' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_gfx_vr0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/vr -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/vr -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/vr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/vr -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/canvas -I /root/firefox-clang/gfx/cairo/cairo/src -I /root/firefox-clang/gfx/layers/d3d11 -I /root/firefox-clang/gfx/thebes -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0/unix-print -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cloudproviders -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/harfbuzz -I /usr/include/atk-1.0 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_gfx_vr0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "VRManagerChild.h"
6
7#include "VRDisplayClient.h"
8#include "VRLayerChild.h"
9#include "VRManagerParent.h"
10#include "VRThread.h"
11#include "mozilla/ProfilerMarkers.h"
12#include "mozilla/StaticPtr.h"
13#include "mozilla/dom/ContentChild.h"
14#include "mozilla/dom/GamepadManager.h"
15#include "mozilla/dom/Navigator.h"
16#include "mozilla/dom/VREventObserver.h"
17#include "mozilla/dom/WebXRBinding.h"
18#include "mozilla/dom/WindowBinding.h" // for FrameRequestCallback
19#include "mozilla/dom/XRFrame.h"
20#include "mozilla/dom/XRSystem.h"
21#include "mozilla/ipc/Endpoint.h"
22#include "mozilla/layers/CompositorThread.h" // for CompositorThread
23#include "mozilla/layers/SyncObject.h"
24#include "mozilla/layers/TextureForwarder.h"
25#include "nsContentUtils.h"
26#include "nsGlobalWindowInner.h"
27
28using namespace mozilla::dom;
29
30namespace {
31const nsTArray<RefPtr<mozilla::gfx::VRManagerEventObserver>>::index_type
32 kNoIndex = nsTArray<RefPtr<mozilla::gfx::VRManagerEventObserver>>::NoIndex;
33} // namespace
34
35namespace mozilla {
36namespace gfx {
37
38static StaticRefPtr<VRManagerChild> sVRManagerChildSingleton;
39static StaticRefPtr<VRManagerParent> sVRManagerParentSingleton;
40
41static TimeStamp sMostRecentFrameEnd;
42static TimeDuration sAverageFrameInterval;
43
44void ReleaseVRManagerParentSingleton() { sVRManagerParentSingleton = nullptr; }
45
46VRManagerChild::VRManagerChild(uint32_t aNamespace)
47 : mNamespace(aNamespace),
48 mRuntimeCapabilities(VRDisplayCapabilityFlags::Cap_None),
49 mFrameRequestCallbackCounter(0),
50 mWaitingForEnumeration(false),
51 mBackend(layers::LayersBackend::LAYERS_NONE) {
52 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 52); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 52); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
53
54 mStartTimeStamp = TimeStamp::Now();
55}
56
57VRManagerChild::~VRManagerChild() { MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 57); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 57); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
; }
58
59/*static*/
60void VRManagerChild::IdentifyTextureHost(
61 const TextureFactoryIdentifier& aIdentifier) {
62 if (sVRManagerChildSingleton) {
63 sVRManagerChildSingleton->mBackend = aIdentifier.mParentBackend;
64 }
65}
66
67layers::LayersBackend VRManagerChild::GetBackendType() const {
68 return mBackend;
69}
70
71/*static*/
72VRManagerChild* VRManagerChild::Get() {
73 MOZ_ASSERT(sVRManagerChildSingleton)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sVRManagerChildSingleton)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sVRManagerChildSingleton))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("sVRManagerChildSingleton"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 73); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "sVRManagerChildSingleton" ")"); do { MOZ_CrashSequence
(__null, 73); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
74 return sVRManagerChildSingleton;
75}
76
77/* static */
78bool VRManagerChild::IsCreated() { return !!sVRManagerChildSingleton; }
79
80/* static */
81bool VRManagerChild::IsPresenting() {
82 if (!VRManagerChild::IsCreated()) {
83 return false;
84 }
85
86 nsTArray<RefPtr<VRDisplayClient>> displays;
87 sVRManagerChildSingleton->GetVRDisplays(displays);
88
89 bool result = false;
90 for (auto& display : displays) {
91 result |= display->IsPresenting();
92 }
93 return result;
94}
95
96TimeStamp VRManagerChild::GetIdleDeadlineHint(TimeStamp aDefault) {
97 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 97); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 97); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
98 if (!VRManagerChild::IsCreated() || sMostRecentFrameEnd.IsNull()) {
99 return aDefault;
100 }
101
102 TimeStamp idleEnd = sMostRecentFrameEnd + sAverageFrameInterval;
103 return idleEnd < aDefault ? idleEnd : aDefault;
104}
105
106/* static */
107bool VRManagerChild::InitForContent(Endpoint<PVRManagerChild>&& aEndpoint,
108 uint32_t aNamespace) {
109 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 109); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 109); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
110
111 RefPtr<VRManagerChild> child(new VRManagerChild(aNamespace));
112 if (!aEndpoint.Bind(child)) {
113 return false;
114 }
115 sVRManagerChildSingleton = child;
116 return true;
117}
118
119/*static*/
120void VRManagerChild::InitSameProcess(uint32_t aNamespace) {
121 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 121); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 121); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
122 MOZ_ASSERT(!sVRManagerChildSingleton)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sVRManagerChildSingleton)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sVRManagerChildSingleton)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sVRManagerChildSingleton"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 122); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!sVRManagerChildSingleton" ")"); do { MOZ_CrashSequence
(__null, 122); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
123
124 sVRManagerChildSingleton = new VRManagerChild(aNamespace);
125 sVRManagerParentSingleton = VRManagerParent::CreateSameProcess(aNamespace);
126 sVRManagerChildSingleton->Open(sVRManagerParentSingleton, CompositorThread(),
127 mozilla::ipc::ChildSide);
128}
129
130/* static */
131void VRManagerChild::InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint,
132 uint32_t aNamespace) {
133 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 133); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 133); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
134 MOZ_ASSERT(!sVRManagerChildSingleton)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sVRManagerChildSingleton)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sVRManagerChildSingleton)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sVRManagerChildSingleton"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 134); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!sVRManagerChildSingleton" ")"); do { MOZ_CrashSequence
(__null, 134); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
135
136 sVRManagerChildSingleton = new VRManagerChild(aNamespace);
137 if (!aEndpoint.Bind(sVRManagerChildSingleton)) {
138 MOZ_CRASH("Couldn't Open() Compositor channel.")do { do { } while (false); MOZ_ReportCrash("" "Couldn't Open() Compositor channel."
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 138); AnnotateMozCrashReason
("MOZ_CRASH(" "Couldn't Open() Compositor channel." ")"); do {
MOZ_CrashSequence(__null, 138); __attribute__((nomerge)) ::abort
(); } while (false); } while (false)
;
139 }
140}
141
142/*static*/
143void VRManagerChild::ShutDown() {
144 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 144); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 144); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
145 if (!sVRManagerChildSingleton) {
146 return;
147 }
148 sVRManagerChildSingleton->Close();
149 sVRManagerChildSingleton = nullptr;
150}
151
152void VRManagerChild::ActorDestroy(ActorDestroyReason aReason) {
153 if (sVRManagerChildSingleton == this) {
154 sVRManagerChildSingleton = nullptr;
155 }
156}
157
158void VRManagerChild::UpdateDisplayInfo(const VRDisplayInfo& aDisplayInfo) {
159 nsTArray<uint32_t> disconnectedDisplays;
160 nsTArray<uint32_t> connectedDisplays;
161
162 const nsTArray<RefPtr<VRDisplayClient>> prevDisplays(mDisplays.Clone());
163
164 // Check if any displays have been disconnected
165 for (auto& display : prevDisplays) {
166 bool found = false;
167 if (aDisplayInfo.GetDisplayID() != 0) {
168 if (display->GetDisplayInfo().GetDisplayID() ==
169 aDisplayInfo.GetDisplayID()) {
170 found = true;
Value stored to 'found' is never read
171 break;
172 }
173 }
174 if (!found) {
175 // In order to make the current VRDisplay can continue to apply for the
176 // newest VRDisplayInfo, we need to exit presentionation before
177 // disconnecting.
178 if (display->IsPresentationGenerationCurrent()) {
179 NotifyPresentationGenerationChangedInternal(
180 display->GetDisplayInfo().GetDisplayID());
181
182 RefPtr<VRManagerChild> vm = VRManagerChild::Get();
183 vm->FireDOMVRDisplayPresentChangeEvent(
184 display->GetDisplayInfo().GetDisplayID());
185 }
186 display->NotifyDisconnected();
187 disconnectedDisplays.AppendElement(
188 display->GetDisplayInfo().GetDisplayID());
189 }
190 }
191
192 // mDisplays could be a hashed container for more scalability, but not worth
193 // it now as we expect < 10 entries.
194 nsTArray<RefPtr<VRDisplayClient>> displays;
195 if (aDisplayInfo.GetDisplayID() != 0) {
196 bool isNewDisplay = true;
197 for (auto& display : prevDisplays) {
198 const VRDisplayInfo& prevInfo = display->GetDisplayInfo();
199 if (prevInfo.GetDisplayID() == aDisplayInfo.GetDisplayID()) {
200 if (aDisplayInfo.GetIsConnected() && !prevInfo.GetIsConnected()) {
201 connectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
202 }
203 if (!aDisplayInfo.GetIsConnected() && prevInfo.GetIsConnected()) {
204 disconnectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
205 }
206 // MOZ_KnownLive because 'prevDisplays' is guaranteed to keep it alive.
207 //
208 // This can go away once
209 // https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
210 MOZ_KnownLive(display)(display)->UpdateDisplayInfo(aDisplayInfo);
211 displays.AppendElement(display);
212 isNewDisplay = false;
213 break;
214 }
215 }
216 if (isNewDisplay) {
217 displays.AppendElement(new VRDisplayClient(aDisplayInfo));
218 connectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
219 }
220 }
221
222 mDisplays = std::move(displays);
223
224 // We wish to fire the events only after mDisplays is updated
225 for (uint32_t displayID : disconnectedDisplays) {
226 FireDOMVRDisplayDisconnectEvent(displayID);
227 }
228
229 for (uint32_t displayID : connectedDisplays) {
230 FireDOMVRDisplayConnectEvent(displayID);
231 }
232}
233
234bool VRManagerChild::RuntimeSupportsVR() const {
235 return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_ImmersiveVR);
236}
237bool VRManagerChild::RuntimeSupportsAR() const {
238 return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_ImmersiveAR);
239}
240bool VRManagerChild::RuntimeSupportsInline() const {
241 return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_Inline);
242}
243
244mozilla::ipc::IPCResult VRManagerChild::RecvUpdateRuntimeCapabilities(
245 const VRDisplayCapabilityFlags& aCapabilities) {
246 mRuntimeCapabilities = aCapabilities;
247 nsContentUtils::AddScriptRunner(NewRunnableMethod<>(
248 "gfx::VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal", this,
249 &VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal));
250 return IPC_OK()mozilla::ipc::IPCResult::Ok();
251}
252
253void VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal() {
254 const nsTArray<RefPtr<VRManagerEventObserver>> listeners = mListeners.Clone();
255 for (auto& listener : listeners) {
256 listener->NotifyDetectRuntimesCompleted();
257 }
258}
259
260mozilla::ipc::IPCResult VRManagerChild::RecvUpdateDisplayInfo(
261 const VRDisplayInfo& aDisplayInfo) {
262 UpdateDisplayInfo(aDisplayInfo);
263 for (auto& windowId : mNavigatorCallbacks) {
264 /** We must call NotifyVRDisplaysUpdated for every
265 * window's Navigator in mNavigatorCallbacks to ensure that
266 * the promise returned by Navigator.GetVRDevices
267 * can resolve. This must happen even if no changes
268 * to VRDisplays have been detected here.
269 */
270 nsGlobalWindowInner* window =
271 nsGlobalWindowInner::GetInnerWindowWithId(windowId);
272 if (!window) {
273 continue;
274 }
275 dom::Navigator* nav = window->Navigator();
276 if (!nav) {
277 continue;
278 }
279 nav->NotifyVRDisplaysUpdated();
280 }
281 mNavigatorCallbacks.Clear();
282 if (mWaitingForEnumeration) {
283 nsContentUtils::AddScriptRunner(NewRunnableMethod<>(
284 "gfx::VRManagerChild::NotifyEnumerationCompletedInternal", this,
285 &VRManagerChild::NotifyEnumerationCompletedInternal));
286 mWaitingForEnumeration = false;
287 }
288 return IPC_OK()mozilla::ipc::IPCResult::Ok();
289}
290
291mozilla::ipc::IPCResult VRManagerChild::RecvNotifyPuppetCommandBufferCompleted(
292 bool aSuccess) {
293 RefPtr<dom::Promise> promise = mRunPuppetPromise;
294 mRunPuppetPromise = nullptr;
295 if (aSuccess) {
296 promise->MaybeResolve(JS::UndefinedHandleValue);
297 } else {
298 promise->MaybeRejectWithUndefined();
299 }
300 return IPC_OK()mozilla::ipc::IPCResult::Ok();
301}
302
303mozilla::ipc::IPCResult VRManagerChild::RecvNotifyPuppetResetComplete() {
304 nsTArray<RefPtr<dom::Promise>> promises;
305 promises.AppendElements(mResetPuppetPromises);
306 mResetPuppetPromises.Clear();
307 for (const auto& promise : promises) {
308 promise->MaybeResolve(JS::UndefinedHandleValue);
309 }
310 return IPC_OK()mozilla::ipc::IPCResult::Ok();
311}
312
313void VRManagerChild::RunPuppet(const nsTArray<uint64_t>& aBuffer,
314 dom::Promise* aPromise, ErrorResult& aRv) {
315 if (mRunPuppetPromise) {
316 // We only allow one puppet script to run simultaneously.
317 // The prior promise must be resolved before running a new
318 // script.
319 aRv.Throw(NS_ERROR_INVALID_ARG);
320 return;
321 }
322 if (!SendRunPuppet(aBuffer)) {
323 aRv.Throw(NS_ERROR_FAILURE);
324 return;
325 }
326 mRunPuppetPromise = aPromise;
327}
328
329void VRManagerChild::ResetPuppet(dom::Promise* aPromise, ErrorResult& aRv) {
330 if (!SendResetPuppet()) {
331 aRv.Throw(NS_ERROR_FAILURE);
332 return;
333 }
334 mResetPuppetPromises.AppendElement(aPromise);
335}
336
337void VRManagerChild::GetVRDisplays(
338 nsTArray<RefPtr<VRDisplayClient>>& aDisplays) {
339 aDisplays = mDisplays.Clone();
340}
341
342bool VRManagerChild::RefreshVRDisplaysWithCallback(uint64_t aWindowId) {
343 bool success = SendRefreshDisplays();
344 if (success) {
345 mNavigatorCallbacks.AppendElement(aWindowId);
346 }
347 return success;
348}
349
350bool VRManagerChild::EnumerateVRDisplays() {
351 bool success = SendRefreshDisplays();
352 if (success) {
353 mWaitingForEnumeration = true;
354 }
355 return success;
356}
357
358void VRManagerChild::DetectRuntimes() { (void)SendDetectRuntimes(); }
359
360already_AddRefed<VRLayerChild> VRManagerChild::CreateVRLayer(
361 uint32_t aDisplayID, uint32_t aGroup) {
362 RefPtr<VRLayerChild> vrLayerChild = VRLayerChild::CreateIPDLActor();
363 if (!SendPVRLayerConstructor(vrLayerChild, aDisplayID, aGroup)) {
364 return nullptr;
365 }
366 return vrLayerChild.forget();
367}
368
369void VRManagerChild::XRFrameRequest::Call(
370 const DOMHighResTimeStamp& aTimeStamp) {
371 if (mCallback) {
372 RefPtr<mozilla::dom::FrameRequestCallback> callback = mCallback;
373 callback->Call(aTimeStamp);
374 } else {
375 RefPtr<mozilla::dom::XRFrameRequestCallback> callback = mXRCallback;
376 RefPtr<mozilla::dom::XRFrame> frame = mXRFrame;
377 callback->Call(aTimeStamp, *frame);
378 }
379}
380
381nsresult VRManagerChild::ScheduleFrameRequestCallback(
382 mozilla::dom::FrameRequestCallback& aCallback, int32_t* aHandle) {
383 if (mFrameRequestCallbackCounter == INT32_MAX(2147483647)) {
384 // Can't increment without overflowing; bail out
385 return NS_ERROR_NOT_AVAILABLE;
386 }
387 int32_t newHandle = ++mFrameRequestCallbackCounter;
388
389 mFrameRequestCallbacks.AppendElement(XRFrameRequest(aCallback, newHandle));
390
391 *aHandle = newHandle;
392 return NS_OK;
393}
394
395void VRManagerChild::CancelFrameRequestCallback(int32_t aHandle) {
396 // mFrameRequestCallbacks is stored sorted by handle
397 mFrameRequestCallbacks.RemoveElementSorted(aHandle);
398}
399
400void VRManagerChild::RunFrameRequestCallbacks() {
401 AUTO_PROFILER_MARKER("RunFrameRequestCallbacks", GRAPHICS)AutoProfilerTracing raiiObject401( "RunFrameRequestCallbacks"
, geckoprofiler::category::GRAPHICS, mozilla::Nothing())
;
402
403 TimeStamp nowTime = TimeStamp::Now();
404 mozilla::TimeDuration duration = nowTime - mStartTimeStamp;
405 DOMHighResTimeStamp timeStamp = duration.ToMilliseconds();
406
407 if (!sMostRecentFrameEnd.IsNull()) {
408 TimeDuration frameInterval = nowTime - sMostRecentFrameEnd;
409 if (sAverageFrameInterval.IsZero()) {
410 sAverageFrameInterval = frameInterval;
411 } else {
412 // Calculate the average interval between frame end and next frame start.
413 // Apply some smoothing to make it more stable.
414 const double smooth = 0.9;
415 sAverageFrameInterval = sAverageFrameInterval.MultDouble(smooth) +
416 frameInterval.MultDouble(1.0 - smooth);
417 }
418 }
419
420 nsTArray<XRFrameRequest> callbacks;
421 callbacks.AppendElements(mFrameRequestCallbacks);
422 mFrameRequestCallbacks.Clear();
423 for (auto& callback : callbacks) {
424 // The FrameRequest copied into the on-stack array holds a strong ref to its
425 // mCallback and there's nothing that can drop that ref until we return.
426 MOZ_KnownLive(callback.mCallback)(callback.mCallback)->Call(timeStamp);
427 }
428
429 if (IsPresenting()) {
430 sMostRecentFrameEnd = TimeStamp::Now();
431 }
432}
433
434void VRManagerChild::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
435 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
436 "gfx::VRManagerChild::NotifyPresentationGenerationChangedInternal", this,
437 &VRManagerChild::NotifyPresentationGenerationChangedInternal,
438 aDisplayID));
439}
440
441void VRManagerChild::FireDOMVRDisplayMountedEvent(uint32_t aDisplayID) {
442 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
443 "gfx::VRManagerChild::FireDOMVRDisplayMountedEventInternal", this,
444 &VRManagerChild::FireDOMVRDisplayMountedEventInternal, aDisplayID));
445}
446
447void VRManagerChild::FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID) {
448 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
449 "gfx::VRManagerChild::FireDOMVRDisplayUnmountedEventInternal", this,
450 &VRManagerChild::FireDOMVRDisplayUnmountedEventInternal, aDisplayID));
451}
452
453void VRManagerChild::FireDOMVRDisplayConnectEvent(uint32_t aDisplayID) {
454 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
455 "gfx::VRManagerChild::FireDOMVRDisplayConnectEventInternal", this,
456 &VRManagerChild::FireDOMVRDisplayConnectEventInternal, aDisplayID));
457}
458
459void VRManagerChild::FireDOMVRDisplayDisconnectEvent(uint32_t aDisplayID) {
460 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
461 "gfx::VRManagerChild::FireDOMVRDisplayDisconnectEventInternal", this,
462 &VRManagerChild::FireDOMVRDisplayDisconnectEventInternal, aDisplayID));
463}
464
465void VRManagerChild::FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID) {
466 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
467 "gfx::VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal", this,
468 &VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal, aDisplayID));
469
470 if (!IsPresenting()) {
471 sMostRecentFrameEnd = TimeStamp();
472 sAverageFrameInterval = nullptr;
473 }
474}
475
476void VRManagerChild::FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID) {
477 // Iterate over a copy of mListeners, as dispatched events may modify it.
478 for (auto& listener : mListeners.Clone()) {
479 listener->NotifyVRDisplayMounted(aDisplayID);
480 }
481}
482
483void VRManagerChild::FireDOMVRDisplayUnmountedEventInternal(
484 uint32_t aDisplayID) {
485 // Iterate over a copy of mListeners, as dispatched events may modify it.
486 for (auto& listener : mListeners.Clone()) {
487 listener->NotifyVRDisplayUnmounted(aDisplayID);
488 }
489}
490
491void VRManagerChild::FireDOMVRDisplayConnectEventInternal(uint32_t aDisplayID) {
492 // Iterate over a copy of mListeners, as dispatched events may modify it.
493 for (auto& listener : mListeners.Clone()) {
494 listener->NotifyVRDisplayConnect(aDisplayID);
495 }
496}
497
498void VRManagerChild::FireDOMVRDisplayDisconnectEventInternal(
499 uint32_t aDisplayID) {
500 // Iterate over a copy of mListeners, as dispatched events may modify it.
501 for (auto& listener : mListeners.Clone()) {
502 listener->NotifyVRDisplayDisconnect(aDisplayID);
503 }
504}
505
506void VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal(
507 uint32_t aDisplayID) {
508 // Iterate over a copy of mListeners, as dispatched events may modify it.
509 for (auto& listener : mListeners.Clone()) {
510 // MOZ_KnownLive because 'listeners' is guaranteed to keep it alive.
511 //
512 // This can go away once
513 // https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
514 MOZ_KnownLive(listener)(listener)->NotifyVRDisplayPresentChange(aDisplayID);
515 }
516}
517
518void VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal(
519 uint32_t aDisplayID, VRManagerEventObserver* aObserver) {
520 aObserver->NotifyVRDisplayConnect(aDisplayID);
521}
522
523void VRManagerChild::NotifyPresentationGenerationChangedInternal(
524 uint32_t aDisplayID) {
525 for (auto& listener : mListeners.Clone()) {
526 listener->NotifyPresentationGenerationChanged(aDisplayID);
527 }
528}
529
530void VRManagerChild::NotifyEnumerationCompletedInternal() {
531 for (auto& listener : mListeners.Clone()) {
532 listener->NotifyEnumerationCompleted();
533 }
534}
535
536void VRManagerChild::FireDOMVRDisplayConnectEventsForLoad(
537 VRManagerEventObserver* aObserver) {
538 // We need to fire the VRDisplayConnect event when a page is loaded
539 // for each VR Display that has already been enumerated
540 for (const auto& display : mDisplays.Clone()) {
541 const VRDisplayInfo& info = display->GetDisplayInfo();
542 if (info.GetIsConnected()) {
543 nsContentUtils::AddScriptRunner(NewRunnableMethod<
544 uint32_t, RefPtr<VRManagerEventObserver>>(
545 "gfx::VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal",
546 this, &VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal,
547 info.GetDisplayID(), aObserver));
548 }
549 }
550}
551
552void VRManagerChild::AddListener(VRManagerEventObserver* aObserver) {
553 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "./../../../gfx/vr/ipc/VRManagerChild.cpp"
, 553); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { MOZ_CrashSequence(__null, 553); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
554
555 if (mListeners.IndexOf(aObserver) != kNoIndex) {
556 return; // already exists
557 }
558
559 mListeners.AppendElement(aObserver);
560 if (mListeners.Length() == 1) {
561 (void)SendSetHaveEventListener(true);
562 }
563}
564
565void VRManagerChild::RemoveListener(VRManagerEventObserver* aObserver) {
566 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "./../../../gfx/vr/ipc/VRManagerChild.cpp"
, 566); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { MOZ_CrashSequence(__null, 566); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
567
568 mListeners.RemoveElement(aObserver);
569 if (mListeners.IsEmpty()) {
570 (void)SendSetHaveEventListener(false);
571 }
572}
573
574void VRManagerChild::StartActivity() { (void)SendStartActivity(); }
575
576void VRManagerChild::StopActivity() {
577 for (auto& listener : mListeners) {
578 if (!listener->GetStopActivityStatus()) {
579 // We are still showing VR in the active window.
580 return;
581 }
582 }
583
584 (void)SendStopActivity();
585}
586
587void VRManagerChild::HandleFatalError(const char* aMsg) {
588 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID());
589}
590
591void VRManagerChild::AddPromise(const uint32_t& aID, dom::Promise* aPromise) {
592 MOZ_ASSERT(!mGamepadPromiseList.Contains(aID))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGamepadPromiseList.Contains(aID))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mGamepadPromiseList.Contains
(aID)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mGamepadPromiseList.Contains(aID)", "./../../../gfx/vr/ipc/VRManagerChild.cpp"
, 592); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGamepadPromiseList.Contains(aID)"
")"); do { MOZ_CrashSequence(__null, 592); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
593 mGamepadPromiseList.InsertOrUpdate(aID, RefPtr{aPromise});
594}
595
596gfx::VRAPIMode VRManagerChild::GetVRAPIMode(uint32_t aDisplayID) const {
597 for (auto& display : mDisplays) {
598 if (display->GetDisplayInfo().GetDisplayID() == aDisplayID) {
599 return display->GetXRAPIMode();
600 }
601 }
602 return VRAPIMode::WebXR;
603}
604
605mozilla::ipc::IPCResult VRManagerChild::RecvReplyGamepadVibrateHaptic(
606 const uint32_t& aPromiseID) {
607 // VRManagerChild could be at other processes, but GamepadManager
608 // only exists at the content process or the same process
609 // in non-e10s mode.
610 MOZ_ASSERT(XRE_IsContentProcess() || IsSameProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess() || IsSameProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(XRE_IsContentProcess() || IsSameProcess()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess() || IsSameProcess()"
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 610); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "XRE_IsContentProcess() || IsSameProcess()"
")"); do { MOZ_CrashSequence(__null, 610); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
611
612 RefPtr<dom::Promise> p;
613 if (!mGamepadPromiseList.Get(aPromiseID, getter_AddRefs(p))) {
614 MOZ_CRASH("We should always have a promise.")do { do { } while (false); MOZ_ReportCrash("" "We should always have a promise."
, "./../../../gfx/vr/ipc/VRManagerChild.cpp", 614); AnnotateMozCrashReason
("MOZ_CRASH(" "We should always have a promise." ")"); do { MOZ_CrashSequence
(__null, 614); __attribute__((nomerge)) ::abort(); } while (false
); } while (false)
;
615 }
616
617 p->MaybeResolve(true);
618 mGamepadPromiseList.Remove(aPromiseID);
619 return IPC_OK()mozilla::ipc::IPCResult::Ok();
620}
621
622} // namespace gfx
623} // namespace mozilla