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 "chrome/browser/android/vr_shell/vr_shell.h" | 5 #include "chrome/browser/android/vr_shell/vr_shell.h" |
6 | 6 |
7 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
8 #include "chrome/browser/android/vr_shell/ui_elements.h" | 8 #include "chrome/browser/android/vr_shell/ui_elements.h" |
9 #include "chrome/browser/android/vr_shell/ui_interface.h" | 9 #include "chrome/browser/android/vr_shell/ui_interface.h" |
10 #include "chrome/browser/android/vr_shell/ui_scene.h" | 10 #include "chrome/browser/android/vr_shell/ui_scene.h" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
66 static constexpr float kReticleOffset = 0.99f; | 66 static constexpr float kReticleOffset = 0.99f; |
67 | 67 |
68 // Limit the rendering distance of the reticle to the distance to a corner of | 68 // Limit the rendering distance of the reticle to the distance to a corner of |
69 // the content quad, times this value. This lets the rendering distance | 69 // the content quad, times this value. This lets the rendering distance |
70 // adjust according to content quad placement. | 70 // adjust according to content quad placement. |
71 static constexpr float kReticleDistanceMultiplier = 1.5f; | 71 static constexpr float kReticleDistanceMultiplier = 1.5f; |
72 | 72 |
73 // UI element 0 is the browser content rectangle. | 73 // UI element 0 is the browser content rectangle. |
74 static constexpr int kBrowserUiElementId = 0; | 74 static constexpr int kBrowserUiElementId = 0; |
75 | 75 |
76 // Positions and sizes of statically placed UI elements in the UI texture. | |
77 // TODO(klausw): replace the hardcoded positions with JS position/offset | |
78 // retrieval once the infrastructure for that is hooked up. | |
79 // | |
80 // UI is designed with 1 pixel = 1mm at 1m distance. It's rescaled to | |
81 // maintain the same angular resolution if placed closer or further. | |
82 // The warning overlays should be fairly close since they cut holes | |
83 // into geometry (they ignore the Z buffer), leading to odd effects | |
84 // if they are far away. | |
85 static constexpr vr_shell::Recti kWebVrWarningTransientRect = { | |
86 0, 128, 512, 256}; | |
87 static constexpr vr_shell::Recti kWebVrWarningPermanentRect = {0, 0, 512, 128}; | |
88 static constexpr float kWebVrWarningDistance = 0.7f; // meters | |
89 static constexpr float kWebVrWarningPermanentAngle = 16.3f; // degrees up | |
90 // How long the transient warning needs to be displayed. | |
91 static constexpr int64_t kWebVrWarningSeconds = 30; | |
92 | |
93 vr_shell::VrShell* g_instance; | 76 vr_shell::VrShell* g_instance; |
94 | 77 |
95 static const char kVrShellUIURL[] = "chrome://vr-shell-ui"; | 78 static const char kVrShellUIURL[] = "chrome://vr-shell-ui"; |
96 | 79 |
97 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { | 80 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { |
98 float xdiff = (vec1.x - vec2.x); | 81 float xdiff = (vec1.x - vec2.x); |
99 float ydiff = (vec1.y - vec2.y); | 82 float ydiff = (vec1.y - vec2.y); |
100 float zdiff = (vec1.z - vec2.z); | 83 float zdiff = (vec1.z - vec2.z); |
101 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; | 84 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; |
102 return std::sqrt(scale); | 85 return std::sqrt(scale); |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
414 // The head pose has redundant data. Assume we're only using the | 397 // The head pose has redundant data. Assume we're only using the |
415 // object_from_reference_matrix, we're not updating position_external. | 398 // object_from_reference_matrix, we're not updating position_external. |
416 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 399 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
417 // it. For now, removing it seems working fine. | 400 // it. For now, removing it seems working fine. |
418 gvr_api_->ApplyNeckModel(head_pose, 1.0f); | 401 gvr_api_->ApplyNeckModel(head_pose, 1.0f); |
419 } | 402 } |
420 | 403 |
421 // Bind back to the default framebuffer. | 404 // Bind back to the default framebuffer. |
422 frame.BindBuffer(0); | 405 frame.BindBuffer(0); |
423 | 406 |
407 HandleQueuedTasks(); | |
408 | |
409 // Update the render position of all UI elements (including desktop). | |
410 float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f; | |
411 scene_->UpdateTransforms(screen_tilt, UiScene::TimeInMicroseconds()); | |
412 | |
424 if (webvr_mode_) { | 413 if (webvr_mode_) { |
425 DrawWebVr(); | 414 DrawWebVr(); |
426 if (!webvr_secure_origin_) { | |
427 DrawWebVrOverlay(target_time.monotonic_system_time_nanos); | |
428 } | |
429 | |
430 // When using async reprojection, we need to know which pose was used in | 415 // When using async reprojection, we need to know which pose was used in |
431 // the WebVR app for drawing this frame. Due to unknown amounts of | 416 // the WebVR app for drawing this frame. Due to unknown amounts of |
432 // buffering in the compositor and SurfaceTexture, we read the pose number | 417 // buffering in the compositor and SurfaceTexture, we read the pose number |
433 // from a corner pixel. There's no point in doing this for legacy | 418 // from a corner pixel. There's no point in doing this for legacy |
434 // distortion rendering since that doesn't need a pose, and reading back | 419 // distortion rendering since that doesn't need a pose, and reading back |
435 // pixels is an expensive operation. TODO(klausw): stop doing this once we | 420 // pixels is an expensive operation. TODO(klausw): stop doing this once we |
436 // have working no-compositor rendering for WebVR. | 421 // have working no-compositor rendering for WebVR. |
437 if (gvr_api_->GetAsyncReprojectionEnabled()) { | 422 if (gvr_api_->GetAsyncReprojectionEnabled()) { |
438 uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex(); | 423 uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex(); |
439 head_pose = webvr_head_pose_[webvr_pose_frame % kPoseRingBufferSize]; | 424 head_pose = webvr_head_pose_[webvr_pose_frame % kPoseRingBufferSize]; |
440 } | 425 } |
441 } else { | 426 } else { |
442 DrawVrShell(head_pose); | 427 UpdateController(GetForwardVector(head_pose)); |
443 } | 428 } |
444 | 429 |
430 DrawVrShell(head_pose); | |
431 | |
445 frame.Unbind(); | 432 frame.Unbind(); |
446 frame.Submit(*buffer_viewport_list_, head_pose); | 433 frame.Submit(*buffer_viewport_list_, head_pose); |
447 } | 434 } |
448 | 435 |
449 void VrShell::DrawVrShell(const gvr::Mat4f& head_pose) { | 436 void VrShell::DrawVrShell(const gvr::Mat4f& head_pose) { |
450 float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f; | 437 if (!webvr_mode_) { |
451 | 438 glEnable(GL_CULL_FACE); |
452 HandleQueuedTasks(); | 439 glEnable(GL_DEPTH_TEST); |
453 | 440 glEnable(GL_SCISSOR_TEST); |
454 // Update the render position of all UI elements (including desktop). | 441 glClearColor(0.1f, 0.1f, 0.1f, 1.0f); |
455 scene_->UpdateTransforms(screen_tilt, UiScene::TimeInMicroseconds()); | 442 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
456 | 443 } |
457 UpdateController(GetForwardVector(head_pose)); | |
458 | |
459 // Use culling to remove back faces. | |
460 glEnable(GL_CULL_FACE); | |
461 | |
462 // Enable depth testing. | |
463 glEnable(GL_DEPTH_TEST); | |
464 glEnable(GL_SCISSOR_TEST); | |
465 | |
466 glClearColor(0.1f, 0.1f, 0.1f, 1.0f); | |
467 | 444 |
468 buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE, | 445 buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE, |
469 buffer_viewport_.get()); | 446 buffer_viewport_.get()); |
470 DrawEye(GVR_LEFT_EYE, head_pose, *buffer_viewport_); | 447 DrawEye(GVR_LEFT_EYE, head_pose, *buffer_viewport_); |
471 buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE, | 448 buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE, |
472 buffer_viewport_.get()); | 449 buffer_viewport_.get()); |
473 DrawEye(GVR_RIGHT_EYE, head_pose, *buffer_viewport_); | 450 DrawEye(GVR_RIGHT_EYE, head_pose, *buffer_viewport_); |
474 } | 451 } |
475 | 452 |
476 void VrShell::DrawEye(gvr::Eye eye, | 453 void VrShell::DrawEye(gvr::Eye eye, |
(...skipping 15 matching lines...) Expand all Loading... | |
492 PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar), | 469 PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar), |
493 eye_matrix); | 470 eye_matrix); |
494 const gvr::Mat4f world_render_matrix = MatrixMul( | 471 const gvr::Mat4f world_render_matrix = MatrixMul( |
495 PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar), | 472 PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar), |
496 head_matrix); | 473 head_matrix); |
497 | 474 |
498 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 475 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
499 | 476 |
500 // TODO(mthiesse): Draw order for transparency. | 477 // TODO(mthiesse): Draw order for transparency. |
501 DrawUI(world_render_matrix, fov_render_matrix); | 478 DrawUI(world_render_matrix, fov_render_matrix); |
502 DrawCursor(world_render_matrix); | 479 if (!webvr_mode_) { |
503 } | 480 DrawCursor(world_render_matrix); |
504 | 481 } |
505 bool VrShell::IsUiTextureReady() { | |
506 return ui_tex_width_ > 0 && ui_tex_height_ > 0; | |
507 } | |
508 | |
509 Rectf VrShell::MakeUiGlCopyRect(Recti pixel_rect) { | |
510 CHECK(IsUiTextureReady()); | |
511 return Rectf({ | |
512 static_cast<float>(pixel_rect.x) / ui_tex_width_, | |
513 static_cast<float>(pixel_rect.y) / ui_tex_height_, | |
514 static_cast<float>(pixel_rect.width) / ui_tex_width_, | |
515 static_cast<float>(pixel_rect.height) / ui_tex_height_}); | |
516 } | 482 } |
517 | 483 |
518 void VrShell::DrawUI(const gvr::Mat4f& world_matrix, | 484 void VrShell::DrawUI(const gvr::Mat4f& world_matrix, |
519 const gvr::Mat4f& fov_matrix) { | 485 const gvr::Mat4f& fov_matrix) { |
520 for (const auto& rect : scene_->GetUiElements()) { | 486 for (const auto& rect : scene_->GetUiElements()) { |
521 if (!rect->visible) { | 487 if (!rect->visible) { |
522 continue; | 488 continue; |
523 } | 489 } |
490 if (webvr_mode_ && rect->id == kBrowserUiElementId) { | |
mthiesse
2016/10/21 14:14:50
Technically we could still control this through ja
cjgrant
2016/10/24 20:00:18
This decoupling is a bit involved, and hence is up
| |
491 continue; | |
492 } | |
524 | 493 |
525 Rectf copy_rect; | 494 Rectf copy_rect; |
526 jint texture_handle; | 495 jint texture_handle; |
527 if (rect->id == kBrowserUiElementId) { | 496 if (rect->id == kBrowserUiElementId) { |
528 copy_rect = {0, 0, 1, 1}; | 497 copy_rect = {0, 0, 1, 1}; |
529 texture_handle = content_texture_id_; | 498 texture_handle = content_texture_id_; |
530 } else { | 499 } else { |
531 copy_rect.x = static_cast<float>(rect->copy_rect.x) / ui_tex_width_; | 500 copy_rect.x = static_cast<float>(rect->copy_rect.x) / ui_tex_width_; |
532 copy_rect.y = static_cast<float>(rect->copy_rect.y) / ui_tex_height_; | 501 copy_rect.y = static_cast<float>(rect->copy_rect.y) / ui_tex_height_; |
533 copy_rect.width = static_cast<float>(rect->copy_rect.width) / | 502 copy_rect.width = static_cast<float>(rect->copy_rect.width) / |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 glDisable(GL_BLEND); | 597 glDisable(GL_BLEND); |
629 glDisable(GL_POLYGON_OFFSET_FILL); | 598 glDisable(GL_POLYGON_OFFSET_FILL); |
630 | 599 |
631 // Don't need to clear, since we're drawing over the entire render target. | 600 // Don't need to clear, since we're drawing over the entire render target. |
632 glClear(GL_COLOR_BUFFER_BIT); | 601 glClear(GL_COLOR_BUFFER_BIT); |
633 | 602 |
634 glViewport(0, 0, render_size_.width, render_size_.height); | 603 glViewport(0, 0, render_size_.width, render_size_.height); |
635 vr_shell_renderer_->GetWebVrRenderer()->Draw(content_texture_id_); | 604 vr_shell_renderer_->GetWebVrRenderer()->Draw(content_texture_id_); |
636 } | 605 } |
637 | 606 |
638 void VrShell::DrawWebVrOverlay(int64_t present_time_nanos) { | |
639 // Draw WebVR security warning overlays for each eye. This uses the | |
640 // eye-from-head matrices but not the pose, goal is to place the icons in an | |
641 // eye-relative position so that they follow along with head rotations. | |
642 | |
643 gvr::Mat4f left_eye_view_matrix = | |
644 gvr_api_->GetEyeFromHeadMatrix(GVR_LEFT_EYE); | |
645 gvr::Mat4f right_eye_view_matrix = | |
646 gvr_api_->GetEyeFromHeadMatrix(GVR_RIGHT_EYE); | |
647 | |
648 buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE, | |
649 buffer_viewport_.get()); | |
650 DrawWebVrEye(left_eye_view_matrix, *buffer_viewport_, present_time_nanos); | |
651 buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE, | |
652 buffer_viewport_.get()); | |
653 DrawWebVrEye(right_eye_view_matrix, *buffer_viewport_, present_time_nanos); | |
654 } | |
655 | |
656 void VrShell::DrawWebVrEye(const gvr::Mat4f& view_matrix, | |
657 const gvr::BufferViewport& params, | |
658 int64_t present_time_nanos) { | |
659 gvr::Recti pixel_rect = | |
660 CalculatePixelSpaceRect(render_size_, params.GetSourceUv()); | |
661 glViewport(pixel_rect.left, pixel_rect.bottom, | |
662 pixel_rect.right - pixel_rect.left, | |
663 pixel_rect.top - pixel_rect.bottom); | |
664 glScissor(pixel_rect.left, pixel_rect.bottom, | |
665 pixel_rect.right - pixel_rect.left, | |
666 pixel_rect.top - pixel_rect.bottom); | |
667 | |
668 gvr::Mat4f projection_matrix = | |
669 PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar); | |
670 | |
671 if (!IsUiTextureReady()) { | |
672 // If the UI texture hasn't been initialized yet, we can't draw the overlay. | |
673 return; | |
674 } | |
675 | |
676 // Show IDS_WEBSITE_SETTINGS_INSECURE_WEBVR_CONTENT_PERMANENT text. | |
677 gvr::Mat4f icon_pos; | |
678 SetIdentityM(icon_pos); | |
679 // The UI is designed in pixels with the assumption that 1px = 1mm at 1m | |
680 // distance. Scale mm-to-m and adjust to keep the same angular size if the | |
681 // distance changes. | |
682 const float small_icon_width = | |
683 kWebVrWarningPermanentRect.width / 1000.f * kWebVrWarningDistance; | |
684 const float small_icon_height = | |
685 kWebVrWarningPermanentRect.height / 1000.f * kWebVrWarningDistance; | |
686 const float small_icon_angle = | |
687 kWebVrWarningPermanentAngle * M_PI / 180.f; // Degrees to radians. | |
688 ScaleM(icon_pos, icon_pos, small_icon_width, small_icon_height, 1.0f); | |
689 TranslateM(icon_pos, icon_pos, 0.0f, 0.0f, -kWebVrWarningDistance); | |
690 icon_pos = MatrixMul( | |
691 QuatToMatrix(QuatFromAxisAngle({1.f, 0.f, 0.f}, small_icon_angle)), | |
692 icon_pos); | |
693 gvr::Mat4f combined = MatrixMul(projection_matrix, | |
694 MatrixMul(view_matrix, icon_pos)); | |
695 vr_shell_renderer_->GetTexturedQuadRenderer()->Draw( | |
696 ui_texture_id_, combined, MakeUiGlCopyRect(kWebVrWarningPermanentRect)); | |
697 | |
698 // Check if we also need to show the transient warning. | |
699 if (present_time_nanos > webvr_warning_end_nanos_) { | |
700 return; | |
701 } | |
702 | |
703 // Show IDS_WEBSITE_SETTINGS_INSECURE_WEBVR_CONTENT_TRANSIENT text. | |
704 SetIdentityM(icon_pos); | |
705 const float large_icon_width = | |
706 kWebVrWarningTransientRect.width / 1000.f * kWebVrWarningDistance; | |
707 const float large_icon_height = | |
708 kWebVrWarningTransientRect.height / 1000.f * kWebVrWarningDistance; | |
709 ScaleM(icon_pos, icon_pos, large_icon_width, large_icon_height, 1.0f); | |
710 TranslateM(icon_pos, icon_pos, 0.0f, 0.0f, -kWebVrWarningDistance); | |
711 combined = MatrixMul(projection_matrix, | |
712 MatrixMul(view_matrix, icon_pos)); | |
713 vr_shell_renderer_->GetTexturedQuadRenderer()->Draw( | |
714 ui_texture_id_, combined, MakeUiGlCopyRect(kWebVrWarningTransientRect)); | |
715 | |
716 } | |
717 | |
718 void VrShell::OnTriggerEvent(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 607 void VrShell::OnTriggerEvent(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
719 // Set a flag to handle this on the render thread at the next frame. | 608 // Set a flag to handle this on the render thread at the next frame. |
720 touch_pending_ = true; | 609 touch_pending_ = true; |
721 } | 610 } |
722 | 611 |
723 void VrShell::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 612 void VrShell::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
724 if (gvr_api_ == nullptr) | 613 if (gvr_api_ == nullptr) |
725 return; | 614 return; |
726 controller_->OnPause(); | 615 controller_->OnPause(); |
727 gvr_api_->PauseTracking(); | 616 gvr_api_->PauseTracking(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
767 constexpr int64_t seconds_to_nanos = 1000 * 1000 * 1000; | 656 constexpr int64_t seconds_to_nanos = 1000 * 1000 * 1000; |
768 webvr_warning_end_nanos_ = now + kWebVrWarningSeconds * seconds_to_nanos; | 657 webvr_warning_end_nanos_ = now + kWebVrWarningSeconds * seconds_to_nanos; |
769 html_interface_->SetMode(UiInterface::Mode::WEB_VR); | 658 html_interface_->SetMode(UiInterface::Mode::WEB_VR); |
770 } else { | 659 } else { |
771 webvr_warning_end_nanos_ = 0; | 660 webvr_warning_end_nanos_ = 0; |
772 html_interface_->SetMode(UiInterface::Mode::STANDARD); | 661 html_interface_->SetMode(UiInterface::Mode::STANDARD); |
773 } | 662 } |
774 } | 663 } |
775 | 664 |
776 void VrShell::SetWebVRSecureOrigin(bool secure_origin) { | 665 void VrShell::SetWebVRSecureOrigin(bool secure_origin) { |
777 webvr_secure_origin_ = secure_origin; | 666 html_interface_->SetSecureOrigin(secure_origin); |
778 } | 667 } |
779 | 668 |
780 void VrShell::SubmitWebVRFrame() { | 669 void VrShell::SubmitWebVRFrame() { |
781 } | 670 } |
782 | 671 |
783 void VrShell::UpdateWebVRTextureBounds( | 672 void VrShell::UpdateWebVRTextureBounds( |
784 int eye, float left, float top, float width, float height) { | 673 int eye, float left, float top, float width, float height) { |
785 gvr::Rectf bounds = { left, top, width, height }; | 674 gvr::Rectf bounds = { left, top, width, height }; |
786 vr_shell_renderer_->GetWebVrRenderer()->UpdateTextureBounds(eye, bounds); | 675 vr_shell_renderer_->GetWebVrRenderer()->UpdateTextureBounds(eye, bounds); |
787 } | 676 } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
880 const JavaParamRef<jobject>& ui_web_contents, | 769 const JavaParamRef<jobject>& ui_web_contents, |
881 jlong ui_window_android) { | 770 jlong ui_window_android) { |
882 return reinterpret_cast<intptr_t>(new VrShell( | 771 return reinterpret_cast<intptr_t>(new VrShell( |
883 env, obj, content::WebContents::FromJavaWebContents(content_web_contents), | 772 env, obj, content::WebContents::FromJavaWebContents(content_web_contents), |
884 reinterpret_cast<ui::WindowAndroid*>(content_window_android), | 773 reinterpret_cast<ui::WindowAndroid*>(content_window_android), |
885 content::WebContents::FromJavaWebContents(ui_web_contents), | 774 content::WebContents::FromJavaWebContents(ui_web_contents), |
886 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); | 775 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); |
887 } | 776 } |
888 | 777 |
889 } // namespace vr_shell | 778 } // namespace vr_shell |
OLD | NEW |