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 11 matching lines...) Expand all Loading... |
22 #include "modules/vr/VREyeParameters.h" | 22 #include "modules/vr/VREyeParameters.h" |
23 #include "modules/vr/VRFrameData.h" | 23 #include "modules/vr/VRFrameData.h" |
24 #include "modules/vr/VRLayer.h" | 24 #include "modules/vr/VRLayer.h" |
25 #include "modules/vr/VRPose.h" | 25 #include "modules/vr/VRPose.h" |
26 #include "modules/vr/VRStageParameters.h" | 26 #include "modules/vr/VRStageParameters.h" |
27 #include "modules/webgl/WebGLRenderingContextBase.h" | 27 #include "modules/webgl/WebGLRenderingContextBase.h" |
28 #include "platform/Histogram.h" | 28 #include "platform/Histogram.h" |
29 #include "platform/UserGestureIndicator.h" | 29 #include "platform/UserGestureIndicator.h" |
30 #include "public/platform/Platform.h" | 30 #include "public/platform/Platform.h" |
31 #include "wtf/AutoReset.h" | 31 #include "wtf/AutoReset.h" |
| 32 #include "wtf/Time.h" |
32 | 33 |
33 #include <array> | 34 #include <array> |
34 | 35 |
35 namespace blink { | 36 namespace blink { |
36 | 37 |
37 namespace { | 38 namespace { |
38 | 39 |
39 // Magic numbers used to mark valid pose index values encoded in frame | 40 // Magic numbers used to mark valid pose index values encoded in frame |
40 // data. Must match the magic numbers used in vr_shell.cc. | 41 // data. Must match the magic numbers used in vr_shell.cc. |
41 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; | 42 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; |
42 | 43 |
43 VREye stringToVREye(const String& whichEye) { | 44 VREye stringToVREye(const String& whichEye) { |
44 if (whichEye == "left") | 45 if (whichEye == "left") |
45 return VREyeLeft; | 46 return VREyeLeft; |
46 if (whichEye == "right") | 47 if (whichEye == "right") |
47 return VREyeRight; | 48 return VREyeRight; |
48 return VREyeNone; | 49 return VREyeNone; |
49 } | 50 } |
50 | 51 |
51 class VRDisplayFrameRequestCallback : public FrameRequestCallback { | |
52 public: | |
53 VRDisplayFrameRequestCallback(VRDisplay* vrDisplay) : m_vrDisplay(vrDisplay) { | |
54 m_useLegacyTimeBase = true; | |
55 } | |
56 ~VRDisplayFrameRequestCallback() override {} | |
57 void handleEvent(double highResTimeMs) override { | |
58 Document* doc = m_vrDisplay->document(); | |
59 if (!doc) | |
60 return; | |
61 | |
62 // Need to divide by 1000 here because serviceScriptedAnimations expects | |
63 // time to be given in seconds. | |
64 m_vrDisplay->serviceScriptedAnimations( | |
65 doc->loader()->timing().pseudoWallTimeToMonotonicTime(highResTimeMs / | |
66 1000.0)); | |
67 } | |
68 | |
69 DEFINE_INLINE_VIRTUAL_TRACE() { | |
70 visitor->trace(m_vrDisplay); | |
71 | |
72 FrameRequestCallback::trace(visitor); | |
73 } | |
74 | |
75 Member<VRDisplay> m_vrDisplay; | |
76 }; | |
77 | |
78 } // namespace | 52 } // namespace |
79 | 53 |
80 VRDisplay::VRDisplay(NavigatorVR* navigatorVR, | 54 VRDisplay::VRDisplay(NavigatorVR* navigatorVR, |
81 device::mojom::blink::VRDisplayPtr display, | 55 device::mojom::blink::VRDisplayPtr display, |
82 device::mojom::blink::VRDisplayClientRequest request) | 56 device::mojom::blink::VRDisplayClientRequest request) |
83 : ContextLifecycleObserver(navigatorVR->document()), | 57 : ContextLifecycleObserver(navigatorVR->document()), |
84 m_navigatorVR(navigatorVR), | 58 m_navigatorVR(navigatorVR), |
85 m_isConnected(false), | |
86 m_isPresenting(false), | |
87 m_isValidDeviceForPresenting(true), | |
88 m_canUpdateFramePose(true), | |
89 m_capabilities(new VRDisplayCapabilities()), | 59 m_capabilities(new VRDisplayCapabilities()), |
90 m_eyeParametersLeft(new VREyeParameters()), | 60 m_eyeParametersLeft(new VREyeParameters()), |
91 m_eyeParametersRight(new VREyeParameters()), | 61 m_eyeParametersRight(new VREyeParameters()), |
92 m_depthNear(0.01), | |
93 m_depthFar(10000.0), | |
94 m_fullscreenCheckTimer( | 62 m_fullscreenCheckTimer( |
95 TaskRunnerHelper::get(TaskType::UnspecedTimer, | 63 TaskRunnerHelper::get(TaskType::UnspecedTimer, |
96 navigatorVR->document()->frame()), | 64 navigatorVR->document()->frame()), |
97 this, | 65 this, |
98 &VRDisplay::onFullscreenCheck), | 66 &VRDisplay::onFullscreenCheck), |
99 m_contextGL(nullptr), | |
100 m_animationCallbackRequested(false), | |
101 m_inAnimationFrame(false), | |
102 m_display(std::move(display)), | 67 m_display(std::move(display)), |
103 m_binding(this, std::move(request)) {} | 68 m_displayClientBinding(this, std::move(request)) {} |
104 | 69 |
105 VRDisplay::~VRDisplay() {} | 70 VRDisplay::~VRDisplay() {} |
106 | 71 |
107 VRController* VRDisplay::controller() { | 72 VRController* VRDisplay::controller() { |
108 return m_navigatorVR->controller(); | 73 return m_navigatorVR->controller(); |
109 } | 74 } |
110 | 75 |
111 void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) { | 76 void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) { |
112 m_displayId = display->index; | 77 m_displayId = display->index; |
113 m_displayName = display->displayName; | 78 m_displayName = display->displayName; |
(...skipping 28 matching lines...) Expand all Loading... |
142 OnPresentChange(); | 107 OnPresentChange(); |
143 } | 108 } |
144 } | 109 } |
145 | 110 |
146 void VRDisplay::disconnected() { | 111 void VRDisplay::disconnected() { |
147 if (m_isConnected) | 112 if (m_isConnected) |
148 m_isConnected = !m_isConnected; | 113 m_isConnected = !m_isConnected; |
149 } | 114 } |
150 | 115 |
151 bool VRDisplay::getFrameData(VRFrameData* frameData) { | 116 bool VRDisplay::getFrameData(VRFrameData* frameData) { |
152 updatePose(); | 117 if (!m_framePose || m_displayBlurred) |
153 | |
154 if (!m_framePose) | |
155 return false; | 118 return false; |
156 | 119 |
157 if (!frameData) | 120 if (!frameData) |
158 return false; | 121 return false; |
159 | 122 |
160 if (m_depthNear == m_depthFar) | 123 if (m_depthNear == m_depthFar) |
161 return false; | 124 return false; |
162 | 125 |
163 return frameData->update(m_framePose, m_eyeParametersLeft, | 126 return frameData->update(m_framePose, m_eyeParametersLeft, |
164 m_eyeParametersRight, m_depthNear, m_depthFar); | 127 m_eyeParametersRight, m_depthNear, m_depthFar); |
165 } | 128 } |
166 | 129 |
167 VRPose* VRDisplay::getPose() { | 130 VRPose* VRDisplay::getPose() { |
168 updatePose(); | 131 if (!m_framePose || m_displayBlurred) |
169 | |
170 if (!m_framePose) | |
171 return nullptr; | 132 return nullptr; |
172 | 133 |
173 VRPose* pose = VRPose::create(); | 134 VRPose* pose = VRPose::create(); |
174 pose->setPose(m_framePose); | 135 pose->setPose(m_framePose); |
175 return pose; | 136 return pose; |
176 } | 137 } |
177 | 138 |
178 void VRDisplay::updatePose() { | |
179 if (m_displayBlurred) { | |
180 // WebVR spec says to return a null pose when the display is blurred. | |
181 m_framePose = nullptr; | |
182 return; | |
183 } | |
184 if (m_canUpdateFramePose) { | |
185 if (!m_display) | |
186 return; | |
187 device::mojom::blink::VRPosePtr pose; | |
188 m_display->GetPose(&pose); | |
189 m_framePose = std::move(pose); | |
190 if (m_isPresenting) | |
191 m_canUpdateFramePose = false; | |
192 } | |
193 } | |
194 | |
195 void VRDisplay::resetPose() { | 139 void VRDisplay::resetPose() { |
196 if (!m_display) | 140 if (!m_display) |
197 return; | 141 return; |
198 | 142 |
199 m_display->ResetPose(); | 143 m_display->ResetPose(); |
200 } | 144 } |
201 | 145 |
202 VREyeParameters* VRDisplay::getEyeParameters(const String& whichEye) { | 146 VREyeParameters* VRDisplay::getEyeParameters(const String& whichEye) { |
203 switch (stringToVREye(whichEye)) { | 147 switch (stringToVREye(whichEye)) { |
204 case VREyeLeft: | 148 case VREyeLeft: |
205 return m_eyeParametersLeft; | 149 return m_eyeParametersLeft; |
206 case VREyeRight: | 150 case VREyeRight: |
207 return m_eyeParametersRight; | 151 return m_eyeParametersRight; |
208 default: | 152 default: |
209 return nullptr; | 153 return nullptr; |
210 } | 154 } |
211 } | 155 } |
212 | 156 |
213 int VRDisplay::requestAnimationFrame(FrameRequestCallback* callback) { | 157 int VRDisplay::requestAnimationFrame(FrameRequestCallback* callback) { |
214 Document* doc = this->document(); | 158 Document* doc = this->document(); |
215 if (!doc) | 159 if (!doc) |
216 return 0; | 160 return 0; |
217 | 161 m_pendingRaf = true; |
218 if (!m_animationCallbackRequested) { | 162 if (!m_vrVSyncProvider.is_bound()) { |
219 doc->requestAnimationFrame(new VRDisplayFrameRequestCallback(this)); | 163 ConnectVSyncProvider(); |
220 m_animationCallbackRequested = true; | 164 } else if (!m_displayBlurred) { |
| 165 m_vrVSyncProvider->GetVSync(convertToBaseCallback( |
| 166 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); |
221 } | 167 } |
222 | |
223 callback->m_useLegacyTimeBase = false; | 168 callback->m_useLegacyTimeBase = false; |
224 return ensureScriptedAnimationController(doc).registerCallback(callback); | 169 return ensureScriptedAnimationController(doc).registerCallback(callback); |
225 } | 170 } |
226 | 171 |
227 void VRDisplay::cancelAnimationFrame(int id) { | 172 void VRDisplay::cancelAnimationFrame(int id) { |
228 if (!m_scriptedAnimationController) | 173 if (!m_scriptedAnimationController) |
229 return; | 174 return; |
230 m_scriptedAnimationController->cancelCallback(id); | 175 m_scriptedAnimationController->cancelCallback(id); |
231 } | 176 } |
232 | 177 |
233 void VRDisplay::OnBlur() { | 178 void VRDisplay::OnBlur() { |
234 m_displayBlurred = true; | 179 m_displayBlurred = true; |
235 | 180 m_vrVSyncProvider.reset(); |
236 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 181 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
237 EventTypeNames::vrdisplayblur, true, false, this, "")); | 182 EventTypeNames::vrdisplayblur, true, false, this, "")); |
238 } | 183 } |
239 | 184 |
240 void VRDisplay::OnFocus() { | 185 void VRDisplay::OnFocus() { |
241 m_displayBlurred = false; | 186 m_displayBlurred = false; |
242 // Restart our internal doc requestAnimationFrame callback, if it fired while | 187 ConnectVSyncProvider(); |
243 // the display was blurred. | |
244 // TODO(bajones): Don't use doc->requestAnimationFrame() at all. Animation | |
245 // frames should be tied to the presenting VR display (e.g. should be serviced | |
246 // by GVR library callbacks on Android), and not the doc frame rate. | |
247 if (!m_animationCallbackRequested) { | |
248 Document* doc = this->document(); | |
249 if (!doc) | |
250 return; | |
251 doc->requestAnimationFrame(new VRDisplayFrameRequestCallback(this)); | |
252 } | |
253 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 188 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
254 EventTypeNames::vrdisplayfocus, true, false, this, "")); | 189 EventTypeNames::vrdisplayfocus, true, false, this, "")); |
255 } | 190 } |
256 | 191 |
257 void VRDisplay::serviceScriptedAnimations(double monotonicAnimationStartTime) { | |
258 if (!m_scriptedAnimationController) | |
259 return; | |
260 AutoReset<bool> animating(&m_inAnimationFrame, true); | |
261 m_animationCallbackRequested = false; | |
262 | |
263 // We use an internal rAF callback to run the animation loop at the display | |
264 // speed, and run the user's callback after our internal callback fires. | |
265 // However, when the display is blurred, we want to pause the animation loop, | |
266 // so we don't fire the user's callback until the display is focused. | |
267 if (m_displayBlurred) | |
268 return; | |
269 m_scriptedAnimationController->serviceScriptedAnimations( | |
270 monotonicAnimationStartTime); | |
271 } | |
272 | |
273 void ReportPresentationResult(PresentationResult result) { | 192 void ReportPresentationResult(PresentationResult result) { |
274 // Note that this is called twice for each call to requestPresent - | 193 // Note that this is called twice for each call to requestPresent - |
275 // one to declare that requestPresent was called, and one for the | 194 // one to declare that requestPresent was called, and one for the |
276 // result. | 195 // result. |
277 DEFINE_STATIC_LOCAL( | 196 DEFINE_STATIC_LOCAL( |
278 EnumerationHistogram, vrPresentationResultHistogram, | 197 EnumerationHistogram, vrPresentationResultHistogram, |
279 ("VRDisplayPresentResult", | 198 ("VRDisplayPresentResult", |
280 static_cast<int>(PresentationResult::PresentationResultMax))); | 199 static_cast<int>(PresentationResult::PresentationResultMax))); |
281 vrPresentationResultHistogram.count(static_cast<int>(result)); | 200 vrPresentationResultHistogram.count(static_cast<int>(result)); |
282 } | 201 } |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 kWebVrPosePixelMagicNumbers[1] / 255.0f, 1.0f); | 567 kWebVrPosePixelMagicNumbers[1] / 255.0f, 1.0f); |
649 gl->Clear(GL_COLOR_BUFFER_BIT); | 568 gl->Clear(GL_COLOR_BUFFER_BIT); |
650 | 569 |
651 // Set the GL state back to what was set by the WebVR application. | 570 // Set the GL state back to what was set by the WebVR application. |
652 m_renderingContext->restoreScissorEnabled(); | 571 m_renderingContext->restoreScissorEnabled(); |
653 m_renderingContext->restoreScissorBox(); | 572 m_renderingContext->restoreScissorBox(); |
654 m_renderingContext->restoreColorMask(); | 573 m_renderingContext->restoreColorMask(); |
655 m_renderingContext->restoreClearColor(); | 574 m_renderingContext->restoreClearColor(); |
656 | 575 |
657 m_display->SubmitFrame(m_framePose.Clone()); | 576 m_display->SubmitFrame(m_framePose.Clone()); |
658 m_canUpdateFramePose = true; | |
659 } | 577 } |
660 | 578 |
661 Document* VRDisplay::document() { | 579 Document* VRDisplay::document() { |
662 return m_navigatorVR->document(); | 580 return m_navigatorVR->document(); |
663 } | 581 } |
664 | 582 |
665 void VRDisplay::OnPresentChange() { | 583 void VRDisplay::OnPresentChange() { |
666 if (m_isPresenting && !m_isValidDeviceForPresenting) { | 584 if (m_isPresenting && !m_isValidDeviceForPresenting) { |
667 VLOG(1) << __FUNCTION__ << ": device not valid, not sending event"; | 585 VLOG(1) << __FUNCTION__ << ": device not valid, not sending event"; |
668 return; | 586 return; |
(...skipping 24 matching lines...) Expand all Loading... |
693 m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( | 611 m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( |
694 EventTypeNames::vrdisplayactivate, true, false, this, reason)); | 612 EventTypeNames::vrdisplayactivate, true, false, this, reason)); |
695 } | 613 } |
696 | 614 |
697 void VRDisplay::OnDeactivate( | 615 void VRDisplay::OnDeactivate( |
698 device::mojom::blink::VRDisplayEventReason reason) { | 616 device::mojom::blink::VRDisplayEventReason reason) { |
699 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 617 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
700 EventTypeNames::vrdisplaydeactivate, true, false, this, reason)); | 618 EventTypeNames::vrdisplaydeactivate, true, false, this, reason)); |
701 } | 619 } |
702 | 620 |
| 621 void VRDisplay::OnVSync(device::mojom::blink::VRPosePtr pose, |
| 622 mojo::common::mojom::blink::TimeDeltaPtr time) { |
| 623 WTF::TimeDelta timeDelta = |
| 624 WTF::TimeDelta::FromMicroseconds(time->microseconds); |
| 625 // The VSync provider cannot shut down before replying to pending callbacks, |
| 626 // so it will send a null pose with no timestamp to be ignored. |
| 627 if (pose.is_null() && timeDelta.is_zero()) { |
| 628 // We need to keep the VSync loop going because we haven't responded to the |
| 629 // previous rAF yet. |
| 630 m_vrVSyncProvider->GetVSync(convertToBaseCallback( |
| 631 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); |
| 632 return; |
| 633 } |
| 634 if (m_displayBlurred) |
| 635 return; |
| 636 if (!m_scriptedAnimationController) |
| 637 return; |
| 638 Document* doc = this->document(); |
| 639 if (!doc) |
| 640 return; |
| 641 |
| 642 // Ensure a consistent timebase with document rAF. |
| 643 if (m_timebase < 0) { |
| 644 m_timebase = WTF::monotonicallyIncreasingTime() - timeDelta.InSecondsF(); |
| 645 } |
| 646 |
| 647 AutoReset<bool> animating(&m_inAnimationFrame, true); |
| 648 m_framePose = std::move(pose); |
| 649 m_pendingRaf = false; |
| 650 m_scriptedAnimationController->serviceScriptedAnimations( |
| 651 m_timebase + timeDelta.InSecondsF()); |
| 652 } |
| 653 |
| 654 void VRDisplay::ConnectVSyncProvider() { |
| 655 m_display->GetVRVSyncProvider(mojo::MakeRequest(&m_vrVSyncProvider)); |
| 656 if (m_pendingRaf && !m_displayBlurred) { |
| 657 m_vrVSyncProvider->GetVSync(convertToBaseCallback( |
| 658 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); |
| 659 } |
| 660 } |
| 661 |
703 void VRDisplay::onFullscreenCheck(TimerBase*) { | 662 void VRDisplay::onFullscreenCheck(TimerBase*) { |
704 if (!m_isPresenting) { | 663 if (!m_isPresenting) { |
705 m_fullscreenCheckTimer.stop(); | 664 m_fullscreenCheckTimer.stop(); |
706 return; | 665 return; |
707 } | 666 } |
708 // TODO: This is a temporary measure to track if fullscreen mode has been | 667 // TODO: This is a temporary measure to track if fullscreen mode has been |
709 // exited by the UA. If so we need to end VR presentation. Soon we won't | 668 // exited by the UA. If so we need to end VR presentation. Soon we won't |
710 // depend on the Fullscreen API to fake VR presentation, so this will | 669 // depend on the Fullscreen API to fake VR presentation, so this will |
711 // become unnessecary. Until that point, though, this seems preferable to | 670 // become unnessecary. Until that point, though, this seems preferable to |
712 // adding a bunch of notification plumbing to Fullscreen. | 671 // adding a bunch of notification plumbing to Fullscreen. |
(...skipping 25 matching lines...) Expand all Loading... |
738 | 697 |
739 ScriptedAnimationController& VRDisplay::ensureScriptedAnimationController( | 698 ScriptedAnimationController& VRDisplay::ensureScriptedAnimationController( |
740 Document* doc) { | 699 Document* doc) { |
741 if (!m_scriptedAnimationController) | 700 if (!m_scriptedAnimationController) |
742 m_scriptedAnimationController = ScriptedAnimationController::create(doc); | 701 m_scriptedAnimationController = ScriptedAnimationController::create(doc); |
743 | 702 |
744 return *m_scriptedAnimationController; | 703 return *m_scriptedAnimationController; |
745 } | 704 } |
746 | 705 |
747 void VRDisplay::dispose() { | 706 void VRDisplay::dispose() { |
748 m_binding.Close(); | 707 m_displayClientBinding.Close(); |
| 708 m_vrVSyncProvider.reset(); |
749 } | 709 } |
750 | 710 |
751 ExecutionContext* VRDisplay::getExecutionContext() const { | 711 ExecutionContext* VRDisplay::getExecutionContext() const { |
752 return ContextLifecycleObserver::getExecutionContext(); | 712 return ContextLifecycleObserver::getExecutionContext(); |
753 } | 713 } |
754 | 714 |
755 const AtomicString& VRDisplay::interfaceName() const { | 715 const AtomicString& VRDisplay::interfaceName() const { |
756 return EventTargetNames::VRDisplay; | 716 return EventTargetNames::VRDisplay; |
757 } | 717 } |
758 | 718 |
(...skipping 16 matching lines...) Expand all Loading... |
775 visitor->trace(m_stageParameters); | 735 visitor->trace(m_stageParameters); |
776 visitor->trace(m_eyeParametersLeft); | 736 visitor->trace(m_eyeParametersLeft); |
777 visitor->trace(m_eyeParametersRight); | 737 visitor->trace(m_eyeParametersRight); |
778 visitor->trace(m_layer); | 738 visitor->trace(m_layer); |
779 visitor->trace(m_renderingContext); | 739 visitor->trace(m_renderingContext); |
780 visitor->trace(m_scriptedAnimationController); | 740 visitor->trace(m_scriptedAnimationController); |
781 visitor->trace(m_pendingPresentResolvers); | 741 visitor->trace(m_pendingPresentResolvers); |
782 } | 742 } |
783 | 743 |
784 } // namespace blink | 744 } // namespace blink |
OLD | NEW |