| 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" |
| 11 #include "core/dom/Fullscreen.h" | |
| 12 #include "core/dom/ScriptedAnimationController.h" | 11 #include "core/dom/ScriptedAnimationController.h" |
| 13 #include "core/dom/TaskRunnerHelper.h" | 12 #include "core/dom/TaskRunnerHelper.h" |
| 13 #include "core/frame/FrameView.h" |
| 14 #include "core/frame/ImageBitmap.h" |
| 14 #include "core/frame/UseCounter.h" | 15 #include "core/frame/UseCounter.h" |
| 15 #include "core/inspector/ConsoleMessage.h" | 16 #include "core/inspector/ConsoleMessage.h" |
| 16 #include "core/loader/DocumentLoader.h" | 17 #include "core/loader/DocumentLoader.h" |
| 17 #include "gpu/command_buffer/client/gles2_interface.h" | 18 #include "gpu/command_buffer/client/gles2_interface.h" |
| 18 #include "modules/EventTargetModules.h" | 19 #include "modules/EventTargetModules.h" |
| 19 #include "modules/vr/NavigatorVR.h" | 20 #include "modules/vr/NavigatorVR.h" |
| 20 #include "modules/vr/VRController.h" | 21 #include "modules/vr/VRController.h" |
| 21 #include "modules/vr/VRDisplayCapabilities.h" | 22 #include "modules/vr/VRDisplayCapabilities.h" |
| 22 #include "modules/vr/VREyeParameters.h" | 23 #include "modules/vr/VREyeParameters.h" |
| 23 #include "modules/vr/VRFrameData.h" | 24 #include "modules/vr/VRFrameData.h" |
| 24 #include "modules/vr/VRLayer.h" | 25 #include "modules/vr/VRLayer.h" |
| 25 #include "modules/vr/VRPose.h" | 26 #include "modules/vr/VRPose.h" |
| 26 #include "modules/vr/VRStageParameters.h" | 27 #include "modules/vr/VRStageParameters.h" |
| 27 #include "modules/webgl/WebGLRenderingContextBase.h" | 28 #include "modules/webgl/WebGLRenderingContextBase.h" |
| 28 #include "platform/Histogram.h" | 29 #include "platform/Histogram.h" |
| 29 #include "platform/UserGestureIndicator.h" | 30 #include "platform/UserGestureIndicator.h" |
| 30 #include "public/platform/Platform.h" | 31 #include "public/platform/Platform.h" |
| 31 #include "wtf/AutoReset.h" | 32 #include "wtf/AutoReset.h" |
| 32 #include "wtf/Time.h" | 33 #include "wtf/Time.h" |
| 33 | 34 |
| 34 #include <array> | 35 #include <array> |
| 35 | 36 |
| 36 namespace blink { | 37 namespace blink { |
| 37 | 38 |
| 38 namespace { | 39 namespace { |
| 39 | 40 |
| 40 // Magic numbers used to mark valid pose index values encoded in frame | |
| 41 // data. Must match the magic numbers used in vr_shell.cc. | |
| 42 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; | |
| 43 | |
| 44 VREye stringToVREye(const String& whichEye) { | 41 VREye stringToVREye(const String& whichEye) { |
| 45 if (whichEye == "left") | 42 if (whichEye == "left") |
| 46 return VREyeLeft; | 43 return VREyeLeft; |
| 47 if (whichEye == "right") | 44 if (whichEye == "right") |
| 48 return VREyeRight; | 45 return VREyeRight; |
| 49 return VREyeNone; | 46 return VREyeNone; |
| 50 } | 47 } |
| 51 | 48 |
| 52 } // namespace | 49 } // namespace |
| 53 | 50 |
| 54 VRDisplay::VRDisplay(NavigatorVR* navigatorVR, | 51 VRDisplay::VRDisplay(NavigatorVR* navigatorVR, |
| 55 device::mojom::blink::VRDisplayPtr display, | 52 device::mojom::blink::VRDisplayPtr display, |
| 56 device::mojom::blink::VRDisplayClientRequest request) | 53 device::mojom::blink::VRDisplayClientRequest request) |
| 57 : ContextLifecycleObserver(navigatorVR->document()), | 54 : ContextLifecycleObserver(navigatorVR->document()), |
| 58 m_navigatorVR(navigatorVR), | 55 m_navigatorVR(navigatorVR), |
| 59 m_capabilities(new VRDisplayCapabilities()), | 56 m_capabilities(new VRDisplayCapabilities()), |
| 60 m_eyeParametersLeft(new VREyeParameters()), | 57 m_eyeParametersLeft(new VREyeParameters()), |
| 61 m_eyeParametersRight(new VREyeParameters()), | 58 m_eyeParametersRight(new VREyeParameters()), |
| 62 m_fullscreenCheckTimer( | |
| 63 TaskRunnerHelper::get(TaskType::UnspecedTimer, | |
| 64 navigatorVR->document()->frame()), | |
| 65 this, | |
| 66 &VRDisplay::onFullscreenCheck), | |
| 67 m_display(std::move(display)), | 59 m_display(std::move(display)), |
| 60 m_submit_frame_client_binding(this), |
| 68 m_displayClientBinding(this, std::move(request)) {} | 61 m_displayClientBinding(this, std::move(request)) {} |
| 69 | 62 |
| 70 VRDisplay::~VRDisplay() {} | 63 VRDisplay::~VRDisplay() {} |
| 71 | 64 |
| 72 VRController* VRDisplay::controller() { | 65 VRController* VRDisplay::controller() { |
| 73 return m_navigatorVR->controller(); | 66 return m_navigatorVR->controller(); |
| 74 } | 67 } |
| 75 | 68 |
| 76 void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) { | 69 void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) { |
| 77 m_displayId = display->index; | 70 m_displayId = display->index; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 return m_eyeParametersRight; | 144 return m_eyeParametersRight; |
| 152 default: | 145 default: |
| 153 return nullptr; | 146 return nullptr; |
| 154 } | 147 } |
| 155 } | 148 } |
| 156 | 149 |
| 157 int VRDisplay::requestAnimationFrame(FrameRequestCallback* callback) { | 150 int VRDisplay::requestAnimationFrame(FrameRequestCallback* callback) { |
| 158 Document* doc = this->document(); | 151 Document* doc = this->document(); |
| 159 if (!doc) | 152 if (!doc) |
| 160 return 0; | 153 return 0; |
| 154 VLOG(1) << __FUNCTION__ << ";;;"; |
| 161 m_pendingRaf = true; | 155 m_pendingRaf = true; |
| 162 if (!m_vrVSyncProvider.is_bound()) { | 156 if (!m_vrVSyncProvider.is_bound()) { |
| 163 ConnectVSyncProvider(); | 157 ConnectVSyncProvider(); |
| 164 } else if (!m_displayBlurred && !m_pendingVsync) { | 158 } else if (!m_displayBlurred && !m_pendingVsync) { |
| 165 m_pendingVsync = true; | 159 m_pendingVsync = true; |
| 166 m_vrVSyncProvider->GetVSync(convertToBaseCallback( | 160 m_vrVSyncProvider->GetVSync(convertToBaseCallback( |
| 167 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); | 161 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); |
| 168 } | 162 } |
| 169 callback->m_useLegacyTimeBase = false; | 163 callback->m_useLegacyTimeBase = false; |
| 170 return ensureScriptedAnimationController(doc).registerCallback(callback); | 164 return ensureScriptedAnimationController(doc).registerCallback(callback); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 // allowed outside a user gesture so that the presented content may be | 226 // allowed outside a user gesture so that the presented content may be |
| 233 // updated. | 227 // updated. |
| 234 if (firstPresent && !UserGestureIndicator::utilizeUserGesture()) { | 228 if (firstPresent && !UserGestureIndicator::utilizeUserGesture()) { |
| 235 DOMException* exception = DOMException::create( | 229 DOMException* exception = DOMException::create( |
| 236 InvalidStateError, "API can only be initiated by a user gesture."); | 230 InvalidStateError, "API can only be initiated by a user gesture."); |
| 237 resolver->reject(exception); | 231 resolver->reject(exception); |
| 238 ReportPresentationResult(PresentationResult::NotInitiatedByUserGesture); | 232 ReportPresentationResult(PresentationResult::NotInitiatedByUserGesture); |
| 239 return promise; | 233 return promise; |
| 240 } | 234 } |
| 241 | 235 |
| 242 // TODO(mthiesse): Remove fullscreen requirement for presentation. See | |
| 243 // crbug.com/687369 | |
| 244 Document* doc = this->document(); | |
| 245 if (!doc || !Fullscreen::fullscreenEnabled(*doc)) { | |
| 246 DOMException* exception = | |
| 247 DOMException::create(InvalidStateError, "Fullscreen is not enabled."); | |
| 248 resolver->reject(exception); | |
| 249 ReportPresentationResult(PresentationResult::FullscreenNotEnabled); | |
| 250 return promise; | |
| 251 } | |
| 252 | |
| 253 // A valid number of layers must be provided in order to present. | 236 // A valid number of layers must be provided in order to present. |
| 254 if (layers.size() == 0 || layers.size() > m_capabilities->maxLayers()) { | 237 if (layers.size() == 0 || layers.size() > m_capabilities->maxLayers()) { |
| 255 forceExitPresent(); | 238 forceExitPresent(); |
| 256 DOMException* exception = | 239 DOMException* exception = |
| 257 DOMException::create(InvalidStateError, "Invalid number of layers."); | 240 DOMException::create(InvalidStateError, "Invalid number of layers."); |
| 258 resolver->reject(exception); | 241 resolver->reject(exception); |
| 259 ReportPresentationResult(PresentationResult::InvalidNumberOfLayers); | 242 ReportPresentationResult(PresentationResult::InvalidNumberOfLayers); |
| 260 return promise; | 243 return promise; |
| 261 } | 244 } |
| 262 | 245 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 "VR Presentation not implemented for this VRDisplay."); | 371 "VR Presentation not implemented for this VRDisplay."); |
| 389 while (!m_pendingPresentResolvers.isEmpty()) { | 372 while (!m_pendingPresentResolvers.isEmpty()) { |
| 390 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); | 373 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); |
| 391 resolver->reject(exception); | 374 resolver->reject(exception); |
| 392 } | 375 } |
| 393 ReportPresentationResult( | 376 ReportPresentationResult( |
| 394 PresentationResult::PresentationNotSupportedByDisplay); | 377 PresentationResult::PresentationNotSupportedByDisplay); |
| 395 return; | 378 return; |
| 396 } else { | 379 } else { |
| 397 if (m_layer.source().isHTMLCanvasElement()) { | 380 if (m_layer.source().isHTMLCanvasElement()) { |
| 398 HTMLCanvasElement* canvas = m_layer.source().getAsHTMLCanvasElement(); | 381 // Stop unneeded compositor updates. We do so by hiding the view. We can't |
| 399 // TODO(klausw,crbug.com/655722): Need a proper VR compositor, but | 382 // hide the page, doing so causes an assertion failure (!m_isHidden) in |
| 400 // for the moment on mobile we'll just make the canvas fullscreen | 383 // DrawingBuffer::prepareTextureMailboxInternal(). Do this only when we're |
| 401 // so that VrShell can pick it up through the standard (high | 384 // actually presenting (m_isPresenting is true), see corresponding show() |
| 402 // latency) compositing path. auto canvas = | 385 // in forceExitPresent(). Otherwise the view may remain hidden for failing |
| 403 // m_layer.source().getAsHTMLCanvasElement(); | 386 // DON flow. |
| 404 auto inlineStyle = canvas->inlineStyle(); | 387 m_navigatorVR->document()->view()->hide(); |
| 405 if (inlineStyle) { | |
| 406 // THREE.js's VREffect sets explicit style.width/height on its rendering | |
| 407 // canvas based on the non-fullscreen window dimensions, and it keeps | |
| 408 // those unchanged when presenting. Unfortunately it appears that a | |
| 409 // fullscreened canvas just gets centered if it has explicitly set a | |
| 410 // size smaller than the fullscreen dimensions. Manually set size to | |
| 411 // 100% in this case and restore it when exiting fullscreen. This is a | |
| 412 // stopgap measure since THREE.js's usage appears legal according to the | |
| 413 // WebVR API spec. This will no longer be necessary once we can get rid | |
| 414 // of this fullscreen hack. | |
| 415 m_fullscreenOrigWidth = inlineStyle->getPropertyValue(CSSPropertyWidth); | |
| 416 if (!m_fullscreenOrigWidth.isNull()) { | |
| 417 canvas->setInlineStyleProperty(CSSPropertyWidth, "100%"); | |
| 418 } | |
| 419 m_fullscreenOrigHeight = | |
| 420 inlineStyle->getPropertyValue(CSSPropertyHeight); | |
| 421 if (!m_fullscreenOrigHeight.isNull()) { | |
| 422 canvas->setInlineStyleProperty(CSSPropertyHeight, "100%"); | |
| 423 } | |
| 424 } else { | |
| 425 m_fullscreenOrigWidth = String(); | |
| 426 m_fullscreenOrigHeight = String(); | |
| 427 } | |
| 428 | |
| 429 if (doc) { | |
| 430 // Since the callback for requestPresent is asynchronous, we've lost our | |
| 431 // UserGestureToken, and need to create a new one to enter fullscreen. | |
| 432 gestureIndicator = WTF::wrapUnique( | |
| 433 new UserGestureIndicator(DocumentUserGestureToken::create( | |
| 434 doc, UserGestureToken::Status::PossiblyExistingGesture))); | |
| 435 } | |
| 436 Fullscreen::requestFullscreen(*canvas); | |
| 437 | |
| 438 // Check to see if the canvas is still the current fullscreen | |
| 439 // element once every 2 seconds. | |
| 440 m_fullscreenCheckTimer.startRepeating(2.0, BLINK_FROM_HERE); | |
| 441 m_reenteredFullscreen = false; | |
| 442 } else { | 388 } else { |
| 443 DCHECK(m_layer.source().isOffscreenCanvas()); | 389 DCHECK(m_layer.source().isOffscreenCanvas()); |
| 444 // TODO(junov, crbug.com/695497): Implement OffscreenCanvas presentation | 390 // TODO(junov, crbug.com/695497): Implement OffscreenCanvas presentation |
| 445 forceExitPresent(); | 391 forceExitPresent(); |
| 446 DOMException* exception = DOMException::create( | 392 DOMException* exception = DOMException::create( |
| 447 InvalidStateError, "OffscreenCanvas presentation not implemented."); | 393 InvalidStateError, "OffscreenCanvas presentation not implemented."); |
| 448 while (!m_pendingPresentResolvers.isEmpty()) { | 394 while (!m_pendingPresentResolvers.isEmpty()) { |
| 449 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); | 395 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); |
| 450 resolver->reject(exception); | 396 resolver->reject(exception); |
| 451 } | 397 } |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 return; | 502 return; |
| 557 } | 503 } |
| 558 | 504 |
| 559 if (!m_contextGL) { | 505 if (!m_contextGL) { |
| 560 // Something got confused, we can't submit frames without a GL context. | 506 // Something got confused, we can't submit frames without a GL context. |
| 561 return; | 507 return; |
| 562 } | 508 } |
| 563 | 509 |
| 564 // No frame Id to write before submitting the frame. | 510 // No frame Id to write before submitting the frame. |
| 565 if (m_vrFrameId < 0) { | 511 if (m_vrFrameId < 0) { |
| 566 m_display->SubmitFrame(m_framePose.Clone()); | 512 m_display->SubmitFrame( |
| 513 m_framePose.Clone(), |
| 514 m_submit_frame_client_binding.CreateInterfacePtrAndBind()); |
| 567 return; | 515 return; |
| 568 } | 516 } |
| 569 | 517 |
| 570 // Write the frame number for the pose used into a bottom left pixel block. | 518 m_contextGL->Flush(); |
| 571 // It is read by chrome/browser/android/vr_shell/vr_shell.cc to associate | 519 // m_contextGL->Finish(); |
| 572 // the correct corresponding pose for submission. | 520 auto elem = m_layer.source(); |
| 573 auto gl = m_contextGL; | 521 ImageBitmap* image; |
| 522 if (elem.isHTMLCanvasElement()) { |
| 523 image = ImageBitmap::create(elem.getAsHTMLCanvasElement(), |
| 524 WTF::nullopt, ImageBitmapOptions()); |
| 525 } else { |
| 526 image = ImageBitmap::create(elem.getAsOffscreenCanvas(), |
| 527 WTF::nullopt, ImageBitmapOptions()); |
| 528 } |
| 529 StaticBitmapImage* bitmap = image->bitmapImage(); |
| 530 auto img = bitmap->imageForCurrentFrame(ColorBehavior::tag()); |
| 531 bitmap->ensureMailbox(); |
| 532 bitmap->transfer(); |
| 533 VLOG(1) << __FUNCTION__ << ";;; got bitmap, hasMailbox=" << |
| 534 bitmap->hasMailbox(); |
| 535 auto mailbox = bitmap->mailbox(); |
| 536 m_contextGL->WaitSyncTokenCHROMIUM(bitmap->syncToken().GetData()); |
| 537 VLOG(1) << __FUNCTION__ << ";;; got mailbox, name=" << |
| 538 (int)mailbox.name[0] << "," << (int)mailbox.name[1] << "," << |
| 539 (int)mailbox.name[2] << "," << (int)mailbox.name[3] << "," << |
| 540 (int)mailbox.name[4] << "," << (int)mailbox.name[5] << "," << |
| 541 (int)mailbox.name[6] << "," << (int)mailbox.name[7] << "," << |
| 542 (int)mailbox.name[8] << "," << (int)mailbox.name[9] << "," << |
| 543 (int)mailbox.name[10] << "," << (int)mailbox.name[11] << "," << |
| 544 (int)mailbox.name[12] << "," << (int)mailbox.name[13] << "," << |
| 545 (int)mailbox.name[14] << "," << (int)mailbox.name[15]; |
| 574 | 546 |
| 575 // We must ensure that the WebGL app's GL state is preserved. We do this by | 547 m_framePose->mailbox = gpu::mojom::blink::Mailbox::New(); |
| 576 // calling low-level GL commands directly so that the rendering context's | 548 WTF::Vector<int8_t> tmpname(GL_MAILBOX_SIZE_CHROMIUM); |
| 577 // saved parameters don't get overwritten. | 549 memcpy(&tmpname[0], &mailbox.name[0], GL_MAILBOX_SIZE_CHROMIUM); |
| 550 m_framePose->mailbox->name = std::move(tmpname); |
| 551 //m_prevImage = bitmap; |
| 578 | 552 |
| 579 gl->Enable(GL_SCISSOR_TEST); | 553 m_framePose->frameId = m_vrFrameId; |
| 580 // Use a few pixels to ensure we get a clean color. The resolution for the | 554 VLOG(1) << __FUNCTION__ << ";;; SubmitFrame WAIT for frame=" << m_vrFrameId; |
| 581 // WebGL buffer may not match the final rendered destination size, and | |
| 582 // texture filtering could interfere for single pixels. This isn't visible | |
| 583 // since the final rendering hides the edges via a vignette effect. | |
| 584 gl->Scissor(0, 0, 4, 4); | |
| 585 gl->ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
| 586 // Careful with the arithmetic here. Float color 1.f is equivalent to int 255. | |
| 587 // Use the low byte of the index as the red component, and store an arbitrary | |
| 588 // magic number in green/blue. This number must match the reading code in | |
| 589 // vr_shell.cc. Avoid all-black/all-white. | |
| 590 gl->ClearColor((m_vrFrameId & 255) / 255.0f, | |
| 591 kWebVrPosePixelMagicNumbers[0] / 255.0f, | |
| 592 kWebVrPosePixelMagicNumbers[1] / 255.0f, 1.0f); | |
| 593 gl->Clear(GL_COLOR_BUFFER_BIT); | |
| 594 | 555 |
| 595 // Set the GL state back to what was set by the WebVR application. | 556 // There's two types of synchronization needed for submitting frames: |
| 596 m_renderingContext->restoreScissorEnabled(); | 557 // - Before submitting, need to wait for the previous frame to be |
| 597 m_renderingContext->restoreScissorBox(); | 558 // pulled off the transfer surface to avoid lost frames. |
| 598 m_renderingContext->restoreColorMask(); | 559 // - After submitting, need to wait for the mailbox to be consumed, |
| 599 m_renderingContext->restoreClearColor(); | 560 // and must remain inside the execution context while waiting. |
| 561 while (m_pendingPreviousFrameRender) { |
| 562 if (!m_submit_frame_client_binding.WaitForIncomingMethodCall()) { |
| 563 LOG(ERROR) << __FUNCTION__ << ": failed to receive SubmitFrame response"; |
| 564 break; |
| 565 } |
| 566 } |
| 600 | 567 |
| 601 m_display->SubmitFrame(m_framePose.Clone()); | 568 VLOG(1) << __FUNCTION__ << ";;; SubmitFrame START for frame=" << m_vrFrameId; |
| 569 |
| 570 m_pendingPreviousFrameRender = true; |
| 571 m_pendingSubmitFrame = true; |
| 572 |
| 573 m_display->SubmitFrame( |
| 574 m_framePose.Clone(), |
| 575 m_submit_frame_client_binding.CreateInterfacePtrAndBind()); |
| 576 while (m_pendingSubmitFrame) { |
| 577 if (!m_submit_frame_client_binding.WaitForIncomingMethodCall()) { |
| 578 LOG(ERROR) << __FUNCTION__ << ": failed to receive SubmitFrame response"; |
| 579 break; |
| 580 } |
| 581 } |
| 582 |
| 583 #define WAIT_FOR_CURRENT_RENDER_TO_FINISH 0 |
| 584 #if WAIT_FOR_CURRENT_RENDER_TO_FINISH |
| 585 VLOG(1) << __FUNCTION__ << ";;; SubmitFrame WAIT RENDER for frame=" << m_vrFra
meId; |
| 586 while (m_pendingPreviousFrameRender) { |
| 587 if (!m_submit_frame_client_binding.WaitForIncomingMethodCall()) { |
| 588 LOG(ERROR) << __FUNCTION__ << ": failed to receive SubmitFrame response"; |
| 589 break; |
| 590 } |
| 591 } |
| 592 #endif |
| 593 |
| 594 VLOG(1) << __FUNCTION__ << ";;; SubmitFrame DONE for frame=" << m_vrFrameId; |
| 595 } |
| 596 |
| 597 void VRDisplay::OnSubmitFrameTransferred() { |
| 598 m_pendingSubmitFrame = false; |
| 599 } |
| 600 |
| 601 void VRDisplay::OnSubmitFrameRendered() { |
| 602 m_pendingPreviousFrameRender = false; |
| 602 } | 603 } |
| 603 | 604 |
| 604 Document* VRDisplay::document() { | 605 Document* VRDisplay::document() { |
| 605 return m_navigatorVR->document(); | 606 return m_navigatorVR->document(); |
| 606 } | 607 } |
| 607 | 608 |
| 608 void VRDisplay::OnPresentChange() { | 609 void VRDisplay::OnPresentChange() { |
| 609 if (m_isPresenting && !m_isValidDeviceForPresenting) { | 610 if (m_isPresenting && !m_isValidDeviceForPresenting) { |
| 610 VLOG(1) << __FUNCTION__ << ": device not valid, not sending event"; | 611 VLOG(1) << __FUNCTION__ << ": device not valid, not sending event"; |
| 611 return; | 612 return; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 629 | 630 |
| 630 void VRDisplay::onDisconnected() { | 631 void VRDisplay::onDisconnected() { |
| 631 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 632 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
| 632 EventTypeNames::vrdisplaydisconnect, true, false, this, "disconnect")); | 633 EventTypeNames::vrdisplaydisconnect, true, false, this, "disconnect")); |
| 633 } | 634 } |
| 634 | 635 |
| 635 void VRDisplay::stopPresenting() { | 636 void VRDisplay::stopPresenting() { |
| 636 if (m_isPresenting) { | 637 if (m_isPresenting) { |
| 637 if (!m_capabilities->hasExternalDisplay()) { | 638 if (!m_capabilities->hasExternalDisplay()) { |
| 638 if (m_layer.source().isHTMLCanvasElement()) { | 639 if (m_layer.source().isHTMLCanvasElement()) { |
| 639 auto canvas = m_layer.source().getAsHTMLCanvasElement(); | 640 m_navigatorVR->document()->view()->show(); |
| 640 Fullscreen::fullyExitFullscreen(canvas->document()); | |
| 641 m_fullscreenCheckTimer.stop(); | |
| 642 if (!m_fullscreenOrigWidth.isNull()) { | |
| 643 canvas->setInlineStyleProperty(CSSPropertyWidth, | |
| 644 m_fullscreenOrigWidth); | |
| 645 m_fullscreenOrigWidth = String(); | |
| 646 } | |
| 647 if (!m_fullscreenOrigHeight.isNull()) { | |
| 648 canvas->setInlineStyleProperty(CSSPropertyWidth, | |
| 649 m_fullscreenOrigHeight); | |
| 650 m_fullscreenOrigHeight = String(); | |
| 651 } | |
| 652 } else { | 641 } else { |
| 653 // TODO(junov, crbug.com/695497): Implement for OffscreenCanvas | 642 // TODO(junov, crbug.com/695497): Implement for OffscreenCanvas |
| 654 } | 643 } |
| 655 } else { | 644 } else { |
| 656 // Can't get into this presentation mode, so nothing to do here. | 645 // Can't get into this presentation mode, so nothing to do here. |
| 657 } | 646 } |
| 658 m_isPresenting = false; | 647 m_isPresenting = false; |
| 659 OnPresentChange(); | 648 OnPresentChange(); |
| 660 } | 649 } |
| 661 | 650 |
| 662 m_renderingContext = nullptr; | 651 m_renderingContext = nullptr; |
| 663 m_contextGL = nullptr; | 652 m_contextGL = nullptr; |
| 653 m_pendingSubmitFrame = false; |
| 654 m_pendingPreviousFrameRender = false; |
| 664 } | 655 } |
| 665 | 656 |
| 666 void VRDisplay::OnActivate(device::mojom::blink::VRDisplayEventReason reason) { | 657 void VRDisplay::OnActivate(device::mojom::blink::VRDisplayEventReason reason) { |
| 667 if (!m_navigatorVR->isFocused() || m_displayBlurred) | 658 if (!m_navigatorVR->isFocused() || m_displayBlurred) |
| 668 return; | 659 return; |
| 669 m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( | 660 m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( |
| 670 EventTypeNames::vrdisplayactivate, true, false, this, reason)); | 661 EventTypeNames::vrdisplayactivate, true, false, this, reason)); |
| 671 } | 662 } |
| 672 | 663 |
| 673 void VRDisplay::OnDeactivate( | 664 void VRDisplay::OnDeactivate( |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 if (!m_navigatorVR->isFocused() || m_vrVSyncProvider.is_bound()) | 707 if (!m_navigatorVR->isFocused() || m_vrVSyncProvider.is_bound()) |
| 717 return; | 708 return; |
| 718 m_display->GetVRVSyncProvider(mojo::MakeRequest(&m_vrVSyncProvider)); | 709 m_display->GetVRVSyncProvider(mojo::MakeRequest(&m_vrVSyncProvider)); |
| 719 if (m_pendingRaf && !m_displayBlurred) { | 710 if (m_pendingRaf && !m_displayBlurred) { |
| 720 m_pendingVsync = true; | 711 m_pendingVsync = true; |
| 721 m_vrVSyncProvider->GetVSync(convertToBaseCallback( | 712 m_vrVSyncProvider->GetVSync(convertToBaseCallback( |
| 722 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); | 713 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); |
| 723 } | 714 } |
| 724 } | 715 } |
| 725 | 716 |
| 726 void VRDisplay::onFullscreenCheck(TimerBase*) { | |
| 727 DCHECK(m_layer.source().isHTMLCanvasElement()); | |
| 728 if (!m_isPresenting) { | |
| 729 m_fullscreenCheckTimer.stop(); | |
| 730 return; | |
| 731 } | |
| 732 // TODO: This is a temporary measure to track if fullscreen mode has been | |
| 733 // exited by the UA. If so we need to end VR presentation. Soon we won't | |
| 734 // depend on the Fullscreen API to fake VR presentation, so this will | |
| 735 // become unnessecary. Until that point, though, this seems preferable to | |
| 736 // adding a bunch of notification plumbing to Fullscreen. | |
| 737 if (!Fullscreen::isCurrentFullScreenElement( | |
| 738 *m_layer.source().getAsHTMLCanvasElement())) { | |
| 739 // TODO(mthiesse): Due to asynchronous resizing, we might get kicked out of | |
| 740 // fullscreen when changing display parameters upon entering WebVR. So one | |
| 741 // time only, we reenter fullscreen after having left it; otherwise we exit | |
| 742 // presentation. | |
| 743 if (m_reenteredFullscreen) { | |
| 744 m_isPresenting = false; | |
| 745 OnPresentChange(); | |
| 746 m_fullscreenCheckTimer.stop(); | |
| 747 if (m_display) | |
| 748 m_display->ExitPresent(); | |
| 749 return; | |
| 750 } | |
| 751 m_reenteredFullscreen = true; | |
| 752 auto canvas = m_layer.source().getAsHTMLCanvasElement(); | |
| 753 Document* doc = this->document(); | |
| 754 std::unique_ptr<UserGestureIndicator> gestureIndicator; | |
| 755 if (doc) { | |
| 756 gestureIndicator = WTF::wrapUnique( | |
| 757 new UserGestureIndicator(DocumentUserGestureToken::create( | |
| 758 doc, UserGestureToken::Status::PossiblyExistingGesture))); | |
| 759 } | |
| 760 Fullscreen::requestFullscreen(*canvas); | |
| 761 } | |
| 762 } | |
| 763 | |
| 764 ScriptedAnimationController& VRDisplay::ensureScriptedAnimationController( | 717 ScriptedAnimationController& VRDisplay::ensureScriptedAnimationController( |
| 765 Document* doc) { | 718 Document* doc) { |
| 766 if (!m_scriptedAnimationController) | 719 if (!m_scriptedAnimationController) |
| 767 m_scriptedAnimationController = ScriptedAnimationController::create(doc); | 720 m_scriptedAnimationController = ScriptedAnimationController::create(doc); |
| 768 | 721 |
| 769 return *m_scriptedAnimationController; | 722 return *m_scriptedAnimationController; |
| 770 } | 723 } |
| 771 | 724 |
| 772 void VRDisplay::dispose() { | 725 void VRDisplay::dispose() { |
| 773 m_displayClientBinding.Close(); | 726 m_displayClientBinding.Close(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 visitor->trace(m_stageParameters); | 760 visitor->trace(m_stageParameters); |
| 808 visitor->trace(m_eyeParametersLeft); | 761 visitor->trace(m_eyeParametersLeft); |
| 809 visitor->trace(m_eyeParametersRight); | 762 visitor->trace(m_eyeParametersRight); |
| 810 visitor->trace(m_layer); | 763 visitor->trace(m_layer); |
| 811 visitor->trace(m_renderingContext); | 764 visitor->trace(m_renderingContext); |
| 812 visitor->trace(m_scriptedAnimationController); | 765 visitor->trace(m_scriptedAnimationController); |
| 813 visitor->trace(m_pendingPresentResolvers); | 766 visitor->trace(m_pendingPresentResolvers); |
| 814 } | 767 } |
| 815 | 768 |
| 816 } // namespace blink | 769 } // namespace blink |
| OLD | NEW |