Chromium Code Reviews| 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/dom/DOMException.h" | 7 #include "core/dom/DOMException.h" |
| 8 #include "core/dom/Fullscreen.h" | 8 #include "core/dom/Fullscreen.h" |
| 9 #include "core/inspector/ConsoleMessage.h" | 9 #include "core/inspector/ConsoleMessage.h" |
| 10 #include "modules/vr/NavigatorVR.h" | 10 #include "modules/vr/NavigatorVR.h" |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 if (!m_isPresenting && !UserGestureIndicator::utilizeUserGesture()) { | 167 if (!m_isPresenting && !UserGestureIndicator::utilizeUserGesture()) { |
| 168 DOMException* exception = DOMException::create(InvalidStateError, "API c an only be initiated by a user gesture."); | 168 DOMException* exception = DOMException::create(InvalidStateError, "API c an only be initiated by a user gesture."); |
| 169 resolver->reject(exception); | 169 resolver->reject(exception); |
| 170 return promise; | 170 return promise; |
| 171 } | 171 } |
| 172 | 172 |
| 173 m_isPresenting = false; | 173 m_isPresenting = false; |
| 174 | 174 |
| 175 // A valid number of layers must be provided in order to present. | 175 // A valid number of layers must be provided in order to present. |
| 176 if (layers.size() == 0 || layers.size() > m_capabilities->maxLayers()) { | 176 if (layers.size() == 0 || layers.size() > m_capabilities->maxLayers()) { |
| 177 forceExitPresent(); | |
| 177 DOMException* exception = DOMException::create(InvalidStateError, "Inval id number of layers."); | 178 DOMException* exception = DOMException::create(InvalidStateError, "Inval id number of layers."); |
| 178 if (m_isPresenting) { | |
| 179 exitPresent(scriptState); | |
| 180 } | |
| 181 resolver->reject(exception); | 179 resolver->reject(exception); |
| 182 return promise; | 180 return promise; |
| 183 } | 181 } |
| 184 | 182 |
| 185 m_layer = layers[0]; | 183 m_layer = layers[0]; |
| 186 | 184 |
| 187 if (m_layer.source()) { | 185 if (!m_layer.source()) { |
| 188 if (!m_capabilities->hasExternalDisplay()) { | 186 forceExitPresent(); |
| 189 // TODO: Need a proper VR compositor, but for the moment on mobile | |
| 190 // we'll just make the canvas fullscreen so that VrShell can pick it | |
| 191 // up through the standard (high latency) compositing path. | |
| 192 Fullscreen::requestFullscreen(*m_layer.source(), Fullscreen::Unprefi xedRequest); | |
| 193 | |
| 194 m_isPresenting = true; | |
| 195 | |
| 196 resolver->resolve(); | |
| 197 | |
| 198 m_navigatorVR->fireVRDisplayPresentChange(this); | |
| 199 | |
| 200 // Check to see if the canvas is still the current fullscreen | |
| 201 // element once per second. | |
| 202 m_fullscreenCheckTimer.startRepeating(1.0, BLINK_FROM_HERE); | |
| 203 | |
| 204 controller()->requestPresent(m_displayId); | |
| 205 } else { | |
| 206 DOMException* exception = DOMException::create(InvalidStateError, "V R Presentation not implemented for this VRDisplay."); | |
| 207 resolver->reject(exception); | |
| 208 } | |
| 209 | |
| 210 // Set up the texture bounds for the provided layer | |
| 211 device::blink::VRLayerBoundsPtr leftBounds = device::blink::VRLayerBound s::New(); | |
| 212 device::blink::VRLayerBoundsPtr rightBounds = device::blink::VRLayerBoun ds::New(); | |
| 213 | |
| 214 if (m_layer.hasLeftBounds()) { | |
| 215 leftBounds->left = m_layer.leftBounds()[0]; | |
| 216 leftBounds->top = m_layer.leftBounds()[1]; | |
| 217 leftBounds->width = m_layer.leftBounds()[2]; | |
| 218 leftBounds->height = m_layer.leftBounds()[3]; | |
| 219 } else { | |
| 220 // Left eye defaults | |
| 221 leftBounds->left = 0.0f; | |
| 222 leftBounds->top = 0.0f; | |
| 223 leftBounds->width = 0.5f; | |
| 224 leftBounds->height = 1.0f; | |
| 225 } | |
| 226 | |
| 227 if (m_layer.hasRightBounds()) { | |
| 228 rightBounds->left = m_layer.rightBounds()[0]; | |
| 229 rightBounds->top = m_layer.rightBounds()[1]; | |
| 230 rightBounds->width = m_layer.rightBounds()[2]; | |
| 231 rightBounds->height = m_layer.rightBounds()[3]; | |
| 232 } else { | |
| 233 // Right eye defaults | |
| 234 rightBounds->left = 0.5f; | |
| 235 rightBounds->top = 0.0f; | |
| 236 rightBounds->width = 0.5f; | |
| 237 rightBounds->height = 1.0f; | |
| 238 } | |
| 239 | |
| 240 controller()->updateLayerBounds(m_displayId, std::move(leftBounds), std: :move(rightBounds)); | |
| 241 } else { | |
| 242 DOMException* exception = DOMException::create(InvalidStateError, "Inval id layer source."); | 187 DOMException* exception = DOMException::create(InvalidStateError, "Inval id layer source."); |
| 243 resolver->reject(exception); | 188 resolver->reject(exception); |
| 189 return promise; | |
| 190 } | |
| 191 | |
| 192 CanvasRenderingContext* renderingContext = m_layer.source()->renderingContex t(); | |
| 193 | |
| 194 if (!renderingContext || !renderingContext->is3d()) { | |
| 195 forceExitPresent(); | |
| 196 DOMException* exception = DOMException::create(InvalidStateError, "Layer source must have a WebGLRenderingContext"); | |
| 197 resolver->reject(exception); | |
| 198 return promise; | |
| 199 } | |
| 200 | |
| 201 if (!m_capabilities->hasExternalDisplay()) { | |
| 202 // TODO: Need a proper VR compositor, but for the moment on mobile | |
| 203 // we'll just make the canvas fullscreen so that VrShell can pick it | |
| 204 // up through the standard (high latency) compositing path. | |
| 205 Fullscreen::requestFullscreen(*m_layer.source(), Fullscreen::UnprefixedR equest); | |
| 206 | |
| 207 // Check to see if the canvas is still the current fullscreen | |
| 208 // element once per second. | |
| 209 m_fullscreenCheckTimer.startRepeating(1.0, BLINK_FROM_HERE); | |
|
mthiesse
2016/09/13 18:46:15
ew. I know this is already landed, so don't let my
bajones
2016/09/13 19:42:57
NO! It's not anywhere close to the best way to do
| |
| 210 } | |
| 211 | |
| 212 if (firstPresent) { | |
| 213 controller()->requestPresent(resolver, m_displayId); | |
| 214 } else { | |
| 215 updateLayerBounds(); | |
| 216 resolver->resolve(); | |
| 244 } | 217 } |
| 245 | 218 |
| 246 return promise; | 219 return promise; |
| 247 } | 220 } |
| 248 | 221 |
| 249 ScriptPromise VRDisplay::exitPresent(ScriptState* scriptState) | 222 ScriptPromise VRDisplay::exitPresent(ScriptState* scriptState) |
| 250 { | 223 { |
| 251 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; | 224 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; |
| 252 ScriptPromise promise = resolver->promise(); | 225 ScriptPromise promise = resolver->promise(); |
| 253 | 226 |
| 254 if (!m_isPresenting) { | 227 if (!m_isPresenting) { |
| 255 // Can't stop presenting if we're not presenting. | 228 // Can't stop presenting if we're not presenting. |
| 256 DOMException* exception = DOMException::create(InvalidStateError, "VRDis play is not presenting."); | 229 DOMException* exception = DOMException::create(InvalidStateError, "VRDis play is not presenting."); |
| 257 resolver->reject(exception); | 230 resolver->reject(exception); |
| 258 return promise; | 231 return promise; |
| 259 } | 232 } |
| 260 | 233 |
| 261 if (!m_capabilities->hasExternalDisplay()) { | 234 controller()->exitPresent(m_displayId); |
| 262 Fullscreen::fullyExitFullscreen(m_layer.source()->document()); | |
| 263 m_fullscreenCheckTimer.stop(); | |
| 264 controller()->exitPresent(m_displayId); | |
| 265 } else { | |
| 266 // Can't get into this presentation mode, so nothing to do here. | |
| 267 } | |
| 268 | 235 |
| 269 m_isPresenting = false; | |
| 270 | |
| 271 // TODO: Resolve when exit is confirmed | |
| 272 resolver->resolve(); | 236 resolver->resolve(); |
| 273 | 237 |
| 274 m_navigatorVR->fireVRDisplayPresentChange(this); | 238 forceExitPresent(); |
| 275 | 239 |
| 276 return promise; | 240 return promise; |
| 277 } | 241 } |
| 278 | 242 |
| 243 void VRDisplay::beginPresent(ScriptPromiseResolver* resolver) | |
| 244 { | |
| 245 if (m_capabilities->hasExternalDisplay()) { | |
| 246 forceExitPresent(); | |
| 247 DOMException* exception = DOMException::create(InvalidStateError, "VR Pr esentation not implemented for this VRDisplay."); | |
| 248 resolver->reject(exception); | |
| 249 return; | |
| 250 } | |
| 251 | |
| 252 m_isPresenting = true; | |
| 253 | |
| 254 resolver->resolve(); | |
| 255 m_navigatorVR->fireVRDisplayPresentChange(this); | |
| 256 | |
| 257 updateLayerBounds(); | |
|
mthiesse
2016/09/13 18:46:15
This feels like it should go before the PresentCha
bajones
2016/09/13 19:42:57
Done.
| |
| 258 } | |
| 259 | |
| 260 void VRDisplay::forceExitPresent() | |
| 261 { | |
| 262 if (m_isPresenting) { | |
| 263 if (!m_capabilities->hasExternalDisplay()) { | |
| 264 Fullscreen::fullyExitFullscreen(m_layer.source()->document()); | |
| 265 m_fullscreenCheckTimer.stop(); | |
| 266 } else { | |
| 267 // Can't get into this presentation mode, so nothing to do here. | |
| 268 } | |
| 269 m_navigatorVR->fireVRDisplayPresentChange(this); | |
| 270 } | |
| 271 | |
| 272 m_isPresenting = false; | |
| 273 } | |
| 274 | |
| 275 void VRDisplay::updateLayerBounds() | |
| 276 { | |
| 277 // Set up the texture bounds for the provided layer | |
| 278 device::blink::VRLayerBoundsPtr leftBounds = device::blink::VRLayerBounds::N ew(); | |
| 279 device::blink::VRLayerBoundsPtr rightBounds = device::blink::VRLayerBounds:: New(); | |
| 280 | |
| 281 if (m_layer.hasLeftBounds()) { | |
| 282 leftBounds->left = m_layer.leftBounds()[0]; | |
| 283 leftBounds->top = m_layer.leftBounds()[1]; | |
| 284 leftBounds->width = m_layer.leftBounds()[2]; | |
| 285 leftBounds->height = m_layer.leftBounds()[3]; | |
| 286 } else { | |
| 287 // Left eye defaults | |
| 288 leftBounds->left = 0.0f; | |
| 289 leftBounds->top = 0.0f; | |
| 290 leftBounds->width = 0.5f; | |
| 291 leftBounds->height = 1.0f; | |
| 292 } | |
| 293 | |
| 294 if (m_layer.hasRightBounds()) { | |
| 295 rightBounds->left = m_layer.rightBounds()[0]; | |
| 296 rightBounds->top = m_layer.rightBounds()[1]; | |
| 297 rightBounds->width = m_layer.rightBounds()[2]; | |
| 298 rightBounds->height = m_layer.rightBounds()[3]; | |
| 299 } else { | |
| 300 // Right eye defaults | |
| 301 rightBounds->left = 0.5f; | |
| 302 rightBounds->top = 0.0f; | |
| 303 rightBounds->width = 0.5f; | |
| 304 rightBounds->height = 1.0f; | |
| 305 } | |
| 306 | |
| 307 controller()->updateLayerBounds(m_displayId, std::move(leftBounds), std::mov e(rightBounds)); | |
| 308 } | |
| 309 | |
| 279 HeapVector<VRLayer> VRDisplay::getLayers() | 310 HeapVector<VRLayer> VRDisplay::getLayers() |
| 280 { | 311 { |
| 281 HeapVector<VRLayer> layers; | 312 HeapVector<VRLayer> layers; |
| 282 | 313 |
| 283 if (m_isPresenting) { | 314 if (m_isPresenting) { |
| 284 layers.append(m_layer); | 315 layers.append(m_layer); |
| 285 } | 316 } |
| 286 | 317 |
| 287 return layers; | 318 return layers; |
| 288 } | 319 } |
| 289 | 320 |
| 290 void VRDisplay::submitFrame() | 321 void VRDisplay::submitFrame() |
| 291 { | 322 { |
| 292 controller()->submitFrame(m_displayId); | 323 controller()->submitFrame(m_displayId, m_framePose.Clone()); |
| 293 m_canUpdateFramePose = true; | 324 m_canUpdateFramePose = true; |
| 294 } | 325 } |
| 295 | 326 |
| 296 void VRDisplay::onFullscreenCheck(TimerBase*) | 327 void VRDisplay::onFullscreenCheck(TimerBase*) |
| 297 { | 328 { |
| 298 // TODO: This is a temporary measure to track if fullscreen mode has been | 329 // TODO: This is a temporary measure to track if fullscreen mode has been |
| 299 // exited by the UA. If so we need to end VR presentation. Soon we won't | 330 // exited by the UA. If so we need to end VR presentation. Soon we won't |
| 300 // depend on the Fullscreen API to fake VR presentation, so this will | 331 // depend on the Fullscreen API to fake VR presentation, so this will |
| 301 // become unnessecary. Until that point, though, this seems preferable to | 332 // become unnessecary. Until that point, though, this seems preferable to |
| 302 // adding a bunch of notification plumbing to Fullscreen. | 333 // adding a bunch of notification plumbing to Fullscreen. |
| 303 if (!Fullscreen::isCurrentFullScreenElement(*m_layer.source())) { | 334 if (!Fullscreen::isCurrentFullScreenElement(*m_layer.source())) { |
| 304 m_isPresenting = false; | 335 m_isPresenting = false; |
| 305 m_navigatorVR->fireVRDisplayPresentChange(this); | 336 m_navigatorVR->fireVRDisplayPresentChange(this); |
| 306 m_fullscreenCheckTimer.stop(); | 337 m_fullscreenCheckTimer.stop(); |
| 307 controller()->exitPresent(m_displayId); | 338 controller()->exitPresent(m_displayId); |
| 308 } | 339 } |
| 309 } | 340 } |
| 310 | 341 |
| 311 DEFINE_TRACE(VRDisplay) | 342 DEFINE_TRACE(VRDisplay) |
| 312 { | 343 { |
| 313 visitor->trace(m_navigatorVR); | 344 visitor->trace(m_navigatorVR); |
| 314 visitor->trace(m_capabilities); | 345 visitor->trace(m_capabilities); |
| 315 visitor->trace(m_stageParameters); | 346 visitor->trace(m_stageParameters); |
| 316 visitor->trace(m_eyeParametersLeft); | 347 visitor->trace(m_eyeParametersLeft); |
| 317 visitor->trace(m_eyeParametersRight); | 348 visitor->trace(m_eyeParametersRight); |
| 318 visitor->trace(m_layer); | 349 visitor->trace(m_layer); |
| 319 } | 350 } |
| 320 | 351 |
| 321 } // namespace blink | 352 } // namespace blink |
| OLD | NEW |