OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/vr/VRDisplay.h" | 5 #include "modules/vr/VRDisplay.h" |
6 | 6 |
7 #include "core/css/StylePropertySet.h" | 7 #include "core/css/StylePropertySet.h" |
8 #include "core/dom/DOMException.h" | 8 #include "core/dom/DOMException.h" |
9 #include "core/dom/DocumentUserGestureToken.h" | 9 #include "core/dom/DocumentUserGestureToken.h" |
10 #include "core/dom/FrameRequestCallback.h" | 10 #include "core/dom/FrameRequestCallback.h" |
(...skipping 29 matching lines...) Expand all Loading... | |
40 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; | 40 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; |
41 | 41 |
42 VREye stringToVREye(const String& whichEye) { | 42 VREye stringToVREye(const String& whichEye) { |
43 if (whichEye == "left") | 43 if (whichEye == "left") |
44 return VREyeLeft; | 44 return VREyeLeft; |
45 if (whichEye == "right") | 45 if (whichEye == "right") |
46 return VREyeRight; | 46 return VREyeRight; |
47 return VREyeNone; | 47 return VREyeNone; |
48 } | 48 } |
49 | 49 |
50 class VRDisplayFrameRequestCallback : public FrameRequestCallback { | |
51 public: | |
52 VRDisplayFrameRequestCallback(VRDisplay* vrDisplay) : m_vrDisplay(vrDisplay) { | |
53 m_useLegacyTimeBase = true; | |
54 } | |
55 ~VRDisplayFrameRequestCallback() override {} | |
56 void handleEvent(double highResTimeMs) override { | |
57 Document* doc = m_vrDisplay->document(); | |
58 if (!doc) | |
59 return; | |
60 | |
61 // Need to divide by 1000 here because serviceScriptedAnimations expects | |
62 // time to be given in seconds. | |
63 m_vrDisplay->serviceScriptedAnimations( | |
64 doc->loader()->timing().pseudoWallTimeToMonotonicTime(highResTimeMs / | |
65 1000.0)); | |
66 } | |
67 | |
68 DEFINE_INLINE_VIRTUAL_TRACE() { | |
69 visitor->trace(m_vrDisplay); | |
70 | |
71 FrameRequestCallback::trace(visitor); | |
72 } | |
73 | |
74 Member<VRDisplay> m_vrDisplay; | |
75 }; | |
76 | |
77 } // namespace | 50 } // namespace |
78 | 51 |
79 VRDisplay::VRDisplay(NavigatorVR* navigatorVR, | 52 VRDisplay::VRDisplay(NavigatorVR* navigatorVR, |
80 device::mojom::blink::VRDisplayPtr display, | 53 device::mojom::blink::VRDisplayPtr display, |
81 device::mojom::blink::VRDisplayClientRequest request) | 54 device::mojom::blink::VRDisplayClientRequest request) |
82 : ContextLifecycleObserver(navigatorVR->document()), | 55 : ContextLifecycleObserver(navigatorVR->document()), |
83 m_navigatorVR(navigatorVR), | 56 m_navigatorVR(navigatorVR), |
84 m_isConnected(false), | |
85 m_isPresenting(false), | |
86 m_isValidDeviceForPresenting(true), | |
87 m_canUpdateFramePose(true), | |
88 m_capabilities(new VRDisplayCapabilities()), | 57 m_capabilities(new VRDisplayCapabilities()), |
89 m_eyeParametersLeft(new VREyeParameters()), | 58 m_eyeParametersLeft(new VREyeParameters()), |
90 m_eyeParametersRight(new VREyeParameters()), | 59 m_eyeParametersRight(new VREyeParameters()), |
91 m_depthNear(0.01), | |
92 m_depthFar(10000.0), | |
93 m_fullscreenCheckTimer(this, &VRDisplay::onFullscreenCheck), | 60 m_fullscreenCheckTimer(this, &VRDisplay::onFullscreenCheck), |
94 m_contextGL(nullptr), | |
95 m_animationCallbackRequested(false), | |
96 m_inAnimationFrame(false), | |
97 m_display(std::move(display)), | 61 m_display(std::move(display)), |
98 m_binding(this, std::move(request)) {} | 62 m_displayClientBinding(this, std::move(request)) {} |
99 | 63 |
100 VRDisplay::~VRDisplay() {} | 64 VRDisplay::~VRDisplay() {} |
101 | 65 |
102 VRController* VRDisplay::controller() { | 66 VRController* VRDisplay::controller() { |
103 return m_navigatorVR->controller(); | 67 return m_navigatorVR->controller(); |
104 } | 68 } |
105 | 69 |
106 void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) { | 70 void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) { |
107 m_displayId = display->index; | 71 m_displayId = display->index; |
108 m_displayName = display->displayName; | 72 m_displayName = display->displayName; |
(...skipping 28 matching lines...) Expand all Loading... | |
137 OnPresentChange(); | 101 OnPresentChange(); |
138 } | 102 } |
139 } | 103 } |
140 | 104 |
141 void VRDisplay::disconnected() { | 105 void VRDisplay::disconnected() { |
142 if (m_isConnected) | 106 if (m_isConnected) |
143 m_isConnected = !m_isConnected; | 107 m_isConnected = !m_isConnected; |
144 } | 108 } |
145 | 109 |
146 bool VRDisplay::getFrameData(VRFrameData* frameData) { | 110 bool VRDisplay::getFrameData(VRFrameData* frameData) { |
147 updatePose(); | 111 if (!m_framePose || m_displayBlurred) |
148 | |
149 if (!m_framePose) | |
150 return false; | 112 return false; |
151 | 113 |
152 if (!frameData) | 114 if (!frameData) |
153 return false; | 115 return false; |
154 | 116 |
155 if (m_depthNear == m_depthFar) | 117 if (m_depthNear == m_depthFar) |
156 return false; | 118 return false; |
157 | 119 |
158 return frameData->update(m_framePose, m_eyeParametersLeft, | 120 return frameData->update(m_framePose, m_eyeParametersLeft, |
159 m_eyeParametersRight, m_depthNear, m_depthFar); | 121 m_eyeParametersRight, m_depthNear, m_depthFar); |
160 } | 122 } |
161 | 123 |
162 VRPose* VRDisplay::getPose() { | 124 VRPose* VRDisplay::getPose() { |
163 updatePose(); | 125 if (!m_framePose || m_displayBlurred) |
164 | |
165 if (!m_framePose) | |
166 return nullptr; | 126 return nullptr; |
167 | 127 |
168 VRPose* pose = VRPose::create(); | 128 VRPose* pose = VRPose::create(); |
169 pose->setPose(m_framePose); | 129 pose->setPose(m_framePose); |
170 return pose; | 130 return pose; |
171 } | 131 } |
172 | 132 |
173 void VRDisplay::updatePose() { | |
174 if (m_displayBlurred) { | |
175 // WebVR spec says to return a null pose when the display is blurred. | |
176 m_framePose = nullptr; | |
177 return; | |
178 } | |
179 if (m_canUpdateFramePose) { | |
180 if (!m_display) | |
181 return; | |
182 device::mojom::blink::VRPosePtr pose; | |
183 m_display->GetPose(&pose); | |
184 m_framePose = std::move(pose); | |
185 if (m_isPresenting) | |
186 m_canUpdateFramePose = false; | |
187 } | |
188 } | |
189 | |
190 void VRDisplay::resetPose() { | 133 void VRDisplay::resetPose() { |
191 if (!m_display) | 134 if (!m_display) |
192 return; | 135 return; |
193 | 136 |
194 m_display->ResetPose(); | 137 m_display->ResetPose(); |
195 } | 138 } |
196 | 139 |
197 VREyeParameters* VRDisplay::getEyeParameters(const String& whichEye) { | 140 VREyeParameters* VRDisplay::getEyeParameters(const String& whichEye) { |
198 switch (stringToVREye(whichEye)) { | 141 switch (stringToVREye(whichEye)) { |
199 case VREyeLeft: | 142 case VREyeLeft: |
200 return m_eyeParametersLeft; | 143 return m_eyeParametersLeft; |
201 case VREyeRight: | 144 case VREyeRight: |
202 return m_eyeParametersRight; | 145 return m_eyeParametersRight; |
203 default: | 146 default: |
204 return nullptr; | 147 return nullptr; |
205 } | 148 } |
206 } | 149 } |
207 | 150 |
208 int VRDisplay::requestAnimationFrame(FrameRequestCallback* callback) { | 151 int VRDisplay::requestAnimationFrame(FrameRequestCallback* callback) { |
209 Document* doc = this->document(); | 152 Document* doc = this->document(); |
210 if (!doc) | 153 if (!doc) |
211 return 0; | 154 return 0; |
212 | 155 if (!m_vrVSyncProvider.is_bound() && !m_displayBlurred) { |
213 if (!m_animationCallbackRequested) { | 156 ConnectVSyncProvider(); |
214 doc->requestAnimationFrame(new VRDisplayFrameRequestCallback(this)); | |
215 m_animationCallbackRequested = true; | |
216 } | 157 } |
217 | |
218 callback->m_useLegacyTimeBase = false; | 158 callback->m_useLegacyTimeBase = false; |
219 return ensureScriptedAnimationController(doc).registerCallback(callback); | 159 return ensureScriptedAnimationController(doc).registerCallback(callback); |
220 } | 160 } |
221 | 161 |
222 void VRDisplay::cancelAnimationFrame(int id) { | 162 void VRDisplay::cancelAnimationFrame(int id) { |
223 if (!m_scriptedAnimationController) | 163 if (!m_scriptedAnimationController) |
224 return; | 164 return; |
225 m_scriptedAnimationController->cancelCallback(id); | 165 m_scriptedAnimationController->cancelCallback(id); |
226 } | 166 } |
227 | 167 |
228 void VRDisplay::OnBlur() { | 168 void VRDisplay::OnBlur() { |
229 m_displayBlurred = true; | 169 m_displayBlurred = true; |
230 | 170 m_vrVSyncProvider.reset(); |
231 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 171 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
232 EventTypeNames::vrdisplayblur, true, false, this, "")); | 172 EventTypeNames::vrdisplayblur, true, false, this, "")); |
233 } | 173 } |
234 | 174 |
235 void VRDisplay::OnFocus() { | 175 void VRDisplay::OnFocus() { |
236 m_displayBlurred = false; | 176 m_displayBlurred = false; |
237 // Restart our internal doc requestAnimationFrame callback, if it fired while | 177 ConnectVSyncProvider(); |
bajones
2017/01/13 18:55:53
Calling this unconditionally would begin the vsync
mthiesse
2017/01/13 20:08:54
Done.
| |
238 // the display was blurred. | |
239 // TODO(bajones): Don't use doc->requestAnimationFrame() at all. Animation | |
240 // frames should be tied to the presenting VR display (e.g. should be serviced | |
241 // by GVR library callbacks on Android), and not the doc frame rate. | |
242 if (!m_animationCallbackRequested) { | |
243 Document* doc = this->document(); | |
244 if (!doc) | |
245 return; | |
246 doc->requestAnimationFrame(new VRDisplayFrameRequestCallback(this)); | |
247 } | |
248 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 178 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
249 EventTypeNames::vrdisplayfocus, true, false, this, "")); | 179 EventTypeNames::vrdisplayfocus, true, false, this, "")); |
250 } | 180 } |
251 | 181 |
252 void VRDisplay::serviceScriptedAnimations(double monotonicAnimationStartTime) { | |
253 if (!m_scriptedAnimationController) | |
254 return; | |
255 AutoReset<bool> animating(&m_inAnimationFrame, true); | |
256 m_animationCallbackRequested = false; | |
257 | |
258 // We use an internal rAF callback to run the animation loop at the display | |
259 // speed, and run the user's callback after our internal callback fires. | |
260 // However, when the display is blurred, we want to pause the animation loop, | |
261 // so we don't fire the user's callback until the display is focused. | |
262 if (m_displayBlurred) | |
263 return; | |
264 m_scriptedAnimationController->serviceScriptedAnimations( | |
265 monotonicAnimationStartTime); | |
266 } | |
267 | |
268 void ReportPresentationResult(PresentationResult result) { | 182 void ReportPresentationResult(PresentationResult result) { |
269 // Note that this is called twice for each call to requestPresent - | 183 // Note that this is called twice for each call to requestPresent - |
270 // one to declare that requestPresent was called, and one for the | 184 // one to declare that requestPresent was called, and one for the |
271 // result. | 185 // result. |
272 DEFINE_STATIC_LOCAL( | 186 DEFINE_STATIC_LOCAL( |
273 EnumerationHistogram, vrPresentationResultHistogram, | 187 EnumerationHistogram, vrPresentationResultHistogram, |
274 ("VRDisplayPresentResult", | 188 ("VRDisplayPresentResult", |
275 static_cast<int>(PresentationResult::PresentationResultMax))); | 189 static_cast<int>(PresentationResult::PresentationResultMax))); |
276 vrPresentationResultHistogram.count(static_cast<int>(result)); | 190 vrPresentationResultHistogram.count(static_cast<int>(result)); |
277 } | 191 } |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
642 kWebVrPosePixelMagicNumbers[1] / 255.0f, 1.0f); | 556 kWebVrPosePixelMagicNumbers[1] / 255.0f, 1.0f); |
643 gl->Clear(GL_COLOR_BUFFER_BIT); | 557 gl->Clear(GL_COLOR_BUFFER_BIT); |
644 | 558 |
645 // Set the GL state back to what was set by the WebVR application. | 559 // Set the GL state back to what was set by the WebVR application. |
646 m_renderingContext->restoreScissorEnabled(); | 560 m_renderingContext->restoreScissorEnabled(); |
647 m_renderingContext->restoreScissorBox(); | 561 m_renderingContext->restoreScissorBox(); |
648 m_renderingContext->restoreColorMask(); | 562 m_renderingContext->restoreColorMask(); |
649 m_renderingContext->restoreClearColor(); | 563 m_renderingContext->restoreClearColor(); |
650 | 564 |
651 m_display->SubmitFrame(m_framePose.Clone()); | 565 m_display->SubmitFrame(m_framePose.Clone()); |
652 m_canUpdateFramePose = true; | |
653 } | 566 } |
654 | 567 |
655 Document* VRDisplay::document() { | 568 Document* VRDisplay::document() { |
656 return m_navigatorVR->document(); | 569 return m_navigatorVR->document(); |
657 } | 570 } |
658 | 571 |
659 void VRDisplay::OnPresentChange() { | 572 void VRDisplay::OnPresentChange() { |
660 if (m_isPresenting && !m_isValidDeviceForPresenting) { | 573 if (m_isPresenting && !m_isValidDeviceForPresenting) { |
661 VLOG(1) << __FUNCTION__ << ": device not valid, not sending event"; | 574 VLOG(1) << __FUNCTION__ << ": device not valid, not sending event"; |
662 return; | 575 return; |
(...skipping 24 matching lines...) Expand all Loading... | |
687 m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( | 600 m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( |
688 EventTypeNames::vrdisplayactivate, true, false, this, reason)); | 601 EventTypeNames::vrdisplayactivate, true, false, this, reason)); |
689 } | 602 } |
690 | 603 |
691 void VRDisplay::OnDeactivate( | 604 void VRDisplay::OnDeactivate( |
692 device::mojom::blink::VRDisplayEventReason reason) { | 605 device::mojom::blink::VRDisplayEventReason reason) { |
693 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 606 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
694 EventTypeNames::vrdisplaydeactivate, true, false, this, reason)); | 607 EventTypeNames::vrdisplaydeactivate, true, false, this, reason)); |
695 } | 608 } |
696 | 609 |
610 void VRDisplay::OnVSync(device::mojom::blink::VRPosePtr pose, | |
611 double timeSeconds) { | |
612 if (m_vrVSyncProvider.is_bound()) { | |
bajones
2017/01/13 18:55:53
Are there any ill effects if we stop polling? If n
mthiesse
2017/01/13 20:08:54
Done. No harm stopping polling.
| |
613 m_vrVSyncProvider->GetVSync(convertToBaseCallback( | |
614 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); | |
615 } | |
616 // The VSync provider cannot shut down before replying to pending callbacks, | |
617 // so it will send a null pose with no timestamp to be ignored. | |
618 if (pose.is_null() && timeSeconds == 0) | |
619 return; | |
620 if (m_displayBlurred) | |
621 return; | |
622 if (!m_scriptedAnimationController) | |
623 return; | |
624 Document* doc = this->document(); | |
625 if (!doc) | |
626 return; | |
627 | |
628 // Ensure a consistent timebase with document rAF. | |
629 if (m_timebase < 0) { | |
630 m_timebase = WTF::monotonicallyIncreasingTime() - timeSeconds; | |
631 } | |
632 | |
633 AutoReset<bool> animating(&m_inAnimationFrame, true); | |
634 m_framePose = std::move(pose); | |
635 m_scriptedAnimationController->serviceScriptedAnimations(m_timebase + | |
636 timeSeconds); | |
637 } | |
638 | |
639 void VRDisplay::OnVSyncProviderDisconnected() { | |
640 TaskRunnerHelper::get(TaskType::UnspecedTimer, document()) | |
641 ->postDelayedTask( | |
642 BLINK_FROM_HERE, | |
643 WTF::bind(&VRDisplay::ConnectVSyncProvider, wrapWeakPersistent(this)), | |
644 100); // Short delay to throttle requests. | |
645 } | |
646 | |
647 void VRDisplay::ConnectVSyncProvider() { | |
648 m_display->GetVRVSyncProvider(mojo::MakeRequest(&m_vrVSyncProvider)); | |
649 m_vrVSyncProvider.set_connection_error_handler( | |
650 convertToBaseCallback(WTF::bind(&VRDisplay::OnVSyncProviderDisconnected, | |
651 wrapWeakPersistent(this)))); | |
652 m_vrVSyncProvider->GetVSync(convertToBaseCallback( | |
653 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); | |
654 } | |
655 | |
697 void VRDisplay::onFullscreenCheck(TimerBase*) { | 656 void VRDisplay::onFullscreenCheck(TimerBase*) { |
698 if (!m_isPresenting) { | 657 if (!m_isPresenting) { |
699 m_fullscreenCheckTimer.stop(); | 658 m_fullscreenCheckTimer.stop(); |
700 return; | 659 return; |
701 } | 660 } |
702 // TODO: This is a temporary measure to track if fullscreen mode has been | 661 // TODO: This is a temporary measure to track if fullscreen mode has been |
703 // exited by the UA. If so we need to end VR presentation. Soon we won't | 662 // exited by the UA. If so we need to end VR presentation. Soon we won't |
704 // depend on the Fullscreen API to fake VR presentation, so this will | 663 // depend on the Fullscreen API to fake VR presentation, so this will |
705 // become unnessecary. Until that point, though, this seems preferable to | 664 // become unnessecary. Until that point, though, this seems preferable to |
706 // adding a bunch of notification plumbing to Fullscreen. | 665 // adding a bunch of notification plumbing to Fullscreen. |
(...skipping 25 matching lines...) Expand all Loading... | |
732 | 691 |
733 ScriptedAnimationController& VRDisplay::ensureScriptedAnimationController( | 692 ScriptedAnimationController& VRDisplay::ensureScriptedAnimationController( |
734 Document* doc) { | 693 Document* doc) { |
735 if (!m_scriptedAnimationController) | 694 if (!m_scriptedAnimationController) |
736 m_scriptedAnimationController = ScriptedAnimationController::create(doc); | 695 m_scriptedAnimationController = ScriptedAnimationController::create(doc); |
737 | 696 |
738 return *m_scriptedAnimationController; | 697 return *m_scriptedAnimationController; |
739 } | 698 } |
740 | 699 |
741 void VRDisplay::dispose() { | 700 void VRDisplay::dispose() { |
742 m_binding.Close(); | 701 m_displayClientBinding.Close(); |
702 m_vrVSyncProvider.reset(); | |
743 } | 703 } |
744 | 704 |
745 ExecutionContext* VRDisplay::getExecutionContext() const { | 705 ExecutionContext* VRDisplay::getExecutionContext() const { |
746 return ContextLifecycleObserver::getExecutionContext(); | 706 return ContextLifecycleObserver::getExecutionContext(); |
747 } | 707 } |
748 | 708 |
749 const AtomicString& VRDisplay::interfaceName() const { | 709 const AtomicString& VRDisplay::interfaceName() const { |
750 return EventTargetNames::VRDisplay; | 710 return EventTargetNames::VRDisplay; |
751 } | 711 } |
752 | 712 |
(...skipping 15 matching lines...) Expand all Loading... | |
768 visitor->trace(m_stageParameters); | 728 visitor->trace(m_stageParameters); |
769 visitor->trace(m_eyeParametersLeft); | 729 visitor->trace(m_eyeParametersLeft); |
770 visitor->trace(m_eyeParametersRight); | 730 visitor->trace(m_eyeParametersRight); |
771 visitor->trace(m_layer); | 731 visitor->trace(m_layer); |
772 visitor->trace(m_renderingContext); | 732 visitor->trace(m_renderingContext); |
773 visitor->trace(m_scriptedAnimationController); | 733 visitor->trace(m_scriptedAnimationController); |
774 visitor->trace(m_pendingPresentResolvers); | 734 visitor->trace(m_pendingPresentResolvers); |
775 } | 735 } |
776 | 736 |
777 } // namespace blink | 737 } // namespace blink |
OLD | NEW |