| 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 // is currently sized to fit the WebVR "insecure transport" warnings, | 84 // is currently sized to fit the WebVR "insecure transport" warnings, |
| 85 // adjust it as needed if there is additional content. | 85 // adjust it as needed if there is additional content. |
| 86 static constexpr gvr::Sizei kHeadlockedBufferDimensions = {1024, 1024}; | 86 static constexpr gvr::Sizei kHeadlockedBufferDimensions = {1024, 1024}; |
| 87 static constexpr gvr::Rectf kHeadlockedBufferFov = {20.f, 20.f, 20.f, 20.f}; | 87 static constexpr gvr::Rectf kHeadlockedBufferFov = {20.f, 20.f, 20.f, 20.f}; |
| 88 | 88 |
| 89 // The GVR viewport list has two entries (left eye and right eye) for each | 89 // The GVR viewport list has two entries (left eye and right eye) for each |
| 90 // GVR buffer. | 90 // GVR buffer. |
| 91 static constexpr int kViewportListPrimaryOffset = 0; | 91 static constexpr int kViewportListPrimaryOffset = 0; |
| 92 static constexpr int kViewportListHeadlockedOffset = 2; | 92 static constexpr int kViewportListHeadlockedOffset = 2; |
| 93 | 93 |
| 94 // Magic numbers used to mark valid pose index values encoded in frame |
| 95 // data. Must match the magic numbers used in blink's VRDisplay.cpp. |
| 96 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; |
| 97 |
| 94 vr_shell::VrShell* g_instance; | 98 vr_shell::VrShell* g_instance; |
| 95 | 99 |
| 96 static const char kVrShellUIURL[] = "chrome://vr-shell-ui"; | 100 static const char kVrShellUIURL[] = "chrome://vr-shell-ui"; |
| 97 | 101 |
| 98 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { | 102 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { |
| 99 float xdiff = (vec1.x - vec2.x); | 103 float xdiff = (vec1.x - vec2.x); |
| 100 float ydiff = (vec1.y - vec2.y); | 104 float ydiff = (vec1.y - vec2.y); |
| 101 float zdiff = (vec1.z - vec2.z); | 105 float zdiff = (vec1.z - vec2.z); |
| 102 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; | 106 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; |
| 103 return std::sqrt(scale); | 107 return std::sqrt(scale); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 content_compositor_.reset(new VrCompositor(content_window, false)); | 172 content_compositor_.reset(new VrCompositor(content_window, false)); |
| 169 ui_compositor_.reset(new VrCompositor(ui_window, true)); | 173 ui_compositor_.reset(new VrCompositor(ui_window, true)); |
| 170 vr_web_contents_observer_.reset( | 174 vr_web_contents_observer_.reset( |
| 171 new VrWebContentsObserver(main_contents, html_interface_.get())); | 175 new VrWebContentsObserver(main_contents, html_interface_.get())); |
| 172 | 176 |
| 173 LoadUIContent(); | 177 LoadUIContent(); |
| 174 | 178 |
| 175 gvr::Mat4f identity; | 179 gvr::Mat4f identity; |
| 176 SetIdentityM(identity); | 180 SetIdentityM(identity); |
| 177 webvr_head_pose_.resize(kPoseRingBufferSize, identity); | 181 webvr_head_pose_.resize(kPoseRingBufferSize, identity); |
| 182 webvr_head_pose_valid_.resize(kPoseRingBufferSize, false); |
| 178 } | 183 } |
| 179 | 184 |
| 180 void VrShell::UpdateCompositorLayers(JNIEnv* env, | 185 void VrShell::UpdateCompositorLayers(JNIEnv* env, |
| 181 const JavaParamRef<jobject>& obj) { | 186 const JavaParamRef<jobject>& obj) { |
| 182 content_compositor_->SetLayer(main_contents_); | 187 content_compositor_->SetLayer(main_contents_); |
| 183 ui_compositor_->SetLayer(ui_contents_); | 188 ui_compositor_->SetLayer(ui_contents_); |
| 184 } | 189 } |
| 185 | 190 |
| 186 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 191 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 187 delete this; | 192 delete this; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 gl::init::InitializeGLOneOff()); | 276 gl::init::InitializeGLOneOff()); |
| 272 | 277 |
| 273 content_texture_id_ = content_texture_handle; | 278 content_texture_id_ = content_texture_handle; |
| 274 ui_texture_id_ = ui_texture_handle; | 279 ui_texture_id_ = ui_texture_handle; |
| 275 | 280 |
| 276 // While WebVR is going through the compositor path, it shares | 281 // While WebVR is going through the compositor path, it shares |
| 277 // the same texture ID. This will change once it gets its own | 282 // the same texture ID. This will change once it gets its own |
| 278 // surface, but store it separately to avoid future confusion. | 283 // surface, but store it separately to avoid future confusion. |
| 279 // TODO(klausw,crbug.com/655722): remove this. | 284 // TODO(klausw,crbug.com/655722): remove this. |
| 280 webvr_texture_id_ = content_texture_id_; | 285 webvr_texture_id_ = content_texture_id_; |
| 286 // Out of paranoia, explicitly reset the "pose valid" flags to false |
| 287 // from the GL thread. The constructor ran in the UI thread. |
| 288 // TODO(klausw,crbug.com/655722): remove this. |
| 289 webvr_head_pose_valid_.assign(kPoseRingBufferSize, false); |
| 281 | 290 |
| 282 gvr_api_->InitializeGl(); | 291 gvr_api_->InitializeGl(); |
| 283 std::vector<gvr::BufferSpec> specs; | 292 std::vector<gvr::BufferSpec> specs; |
| 284 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 293 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
| 285 specs.push_back(gvr_api_->CreateBufferSpec()); | 294 specs.push_back(gvr_api_->CreateBufferSpec()); |
| 286 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 295 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
| 287 render_size_primary_vrshell_ = render_size_primary_; | 296 render_size_primary_vrshell_ = render_size_primary_; |
| 288 | 297 |
| 289 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). | 298 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). |
| 290 // Set this up at fixed resolution, the (smaller) FOV gets set below. | 299 // Set this up at fixed resolution, the (smaller) FOV gets set below. |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 } | 545 } |
| 537 gesture->type = WebInputEvent::GestureTapDown; | 546 gesture->type = WebInputEvent::GestureTapDown; |
| 538 gesture->data.tapDown.width = pixel_x; | 547 gesture->data.tapDown.width = pixel_x; |
| 539 gesture->data.tapDown.height = pixel_y; | 548 gesture->data.tapDown.height = pixel_y; |
| 540 current_input_target_->ProcessUpdatedGesture(*gesture.get()); | 549 current_input_target_->ProcessUpdatedGesture(*gesture.get()); |
| 541 } | 550 } |
| 542 } | 551 } |
| 543 | 552 |
| 544 void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { | 553 void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { |
| 545 webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose; | 554 webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose; |
| 555 webvr_head_pose_valid_[pose_num % kPoseRingBufferSize] = true; |
| 546 } | 556 } |
| 547 | 557 |
| 548 uint32_t GetPixelEncodedPoseIndex() { | 558 int GetPixelEncodedPoseIndexByte() { |
| 549 TRACE_EVENT0("gpu", "VrShell::GetPixelEncodedPoseIndex"); | 559 TRACE_EVENT0("gpu", "VrShell::GetPixelEncodedPoseIndex"); |
| 550 // Read the pose index encoded in a bottom left pixel as color values. | 560 // Read the pose index encoded in a bottom left pixel as color values. |
| 551 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which | 561 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which |
| 552 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc | 562 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc |
| 553 // which tracks poses. | 563 // which tracks poses. Returns the low byte (0..255) if valid, or -1 |
| 564 // if not valid due to bad magic number. |
| 554 uint8_t pixels[4]; | 565 uint8_t pixels[4]; |
| 555 // Assume we're reading from the framebuffer we just wrote to. | 566 // Assume we're reading from the framebuffer we just wrote to. |
| 556 // That's true currently, we may need to use glReadBuffer(GL_BACK) | 567 // That's true currently, we may need to use glReadBuffer(GL_BACK) |
| 557 // or equivalent if the rendering setup changes in the future. | 568 // or equivalent if the rendering setup changes in the future. |
| 558 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | 569 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| 559 return pixels[0] | (pixels[1] << 8) | (pixels[2] << 16); | 570 |
| 571 // Check for the magic number written by VRDevice.cpp on submit. |
| 572 // This helps avoid glitches from garbage data in the render |
| 573 // buffer that can appear during initialization or resizing. These |
| 574 // often appear as flashes of all-black or all-white pixels. |
| 575 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && |
| 576 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { |
| 577 // Pose is good. |
| 578 return pixels[0]; |
| 579 } |
| 580 VLOG(1) << "WebVR: reject decoded pose index " << (int)pixels[0] << |
| 581 ", bad magic number " << (int)pixels[1] << ", " << (int)pixels[2]; |
| 582 return -1; |
| 583 } |
| 584 |
| 585 bool VrShell::WebVrPoseByteIsValid(int pose_index_byte) { |
| 586 if (pose_index_byte < 0) { |
| 587 return false; |
| 588 } |
| 589 if (!webvr_head_pose_valid_[pose_index_byte % kPoseRingBufferSize]) { |
| 590 VLOG(1) << "WebVR: reject decoded pose index " << pose_index_byte << |
| 591 ", not a valid pose"; |
| 592 return false; |
| 593 } |
| 594 return true; |
| 560 } | 595 } |
| 561 | 596 |
| 562 void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 597 void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 563 TRACE_EVENT0("gpu", "VrShell::DrawFrame"); | 598 TRACE_EVENT0("gpu", "VrShell::DrawFrame"); |
| 564 // Reset the viewport list to just the pair of viewports for the | 599 // Reset the viewport list to just the pair of viewports for the |
| 565 // primary buffer each frame. Head-locked viewports get added by | 600 // primary buffer each frame. Head-locked viewports get added by |
| 566 // DrawVrShell if needed. | 601 // DrawVrShell if needed. |
| 567 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 602 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
| 568 | 603 |
| 569 if (html_interface_->GetMode() == UiInterface::Mode::WEB_VR) { | 604 if (html_interface_->GetMode() == UiInterface::Mode::WEB_VR) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 DrawWebVr(); | 650 DrawWebVr(); |
| 616 | 651 |
| 617 // When using async reprojection, we need to know which pose was used in | 652 // When using async reprojection, we need to know which pose was used in |
| 618 // the WebVR app for drawing this frame. Due to unknown amounts of | 653 // the WebVR app for drawing this frame. Due to unknown amounts of |
| 619 // buffering in the compositor and SurfaceTexture, we read the pose number | 654 // buffering in the compositor and SurfaceTexture, we read the pose number |
| 620 // from a corner pixel. There's no point in doing this for legacy | 655 // from a corner pixel. There's no point in doing this for legacy |
| 621 // distortion rendering since that doesn't need a pose, and reading back | 656 // distortion rendering since that doesn't need a pose, and reading back |
| 622 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | 657 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop |
| 623 // doing this once we have working no-compositor rendering for WebVR. | 658 // doing this once we have working no-compositor rendering for WebVR. |
| 624 if (gvr_api_->GetAsyncReprojectionEnabled()) { | 659 if (gvr_api_->GetAsyncReprojectionEnabled()) { |
| 625 uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex(); | 660 int pose_index_byte = GetPixelEncodedPoseIndexByte(); |
| 626 // If we don't get a valid frame ID back we shouldn't attempt to reproject | 661 if (WebVrPoseByteIsValid(pose_index_byte)) { |
| 627 // by an invalid matrix, so turn of reprojection instead. | 662 // We have a valid pose, use it for reprojection. |
| 628 if (webvr_pose_frame == 0) { | 663 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_FULL); |
| 664 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_FULL); |
| 665 head_pose = webvr_head_pose_[pose_index_byte % kPoseRingBufferSize]; |
| 666 // We can't mark the used pose as invalid since unfortunately |
| 667 // we have to reuse them. The compositor will re-submit stale |
| 668 // frames on vsync, and we can't tell that this has happened |
| 669 // until we've read the pose index from it, and at that point |
| 670 // it's too late to skip rendering. |
| 671 } else { |
| 672 // If we don't get a valid frame ID back we shouldn't attempt |
| 673 // to reproject by an invalid matrix, so turn off reprojection |
| 674 // instead. Invalid poses can permanently break reprojection |
| 675 // for this GVR instance: http://crbug.com/667327 |
| 629 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | 676 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE); |
| 630 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | 677 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE); |
| 631 } else { | |
| 632 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_FULL); | |
| 633 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_FULL); | |
| 634 head_pose = webvr_head_pose_[webvr_pose_frame % kPoseRingBufferSize]; | |
| 635 } | 678 } |
| 636 } | 679 } |
| 637 } | 680 } |
| 638 | 681 |
| 639 DrawVrShell(head_pose, frame); | 682 DrawVrShell(head_pose, frame); |
| 640 | 683 |
| 641 frame.Unbind(); | 684 frame.Unbind(); |
| 642 frame.Submit(*buffer_viewport_list_, head_pose); | 685 frame.Submit(*buffer_viewport_list_, head_pose); |
| 643 } | 686 } |
| 644 | 687 |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 const JavaParamRef<jobject>& ui_web_contents, | 1096 const JavaParamRef<jobject>& ui_web_contents, |
| 1054 jlong ui_window_android) { | 1097 jlong ui_window_android) { |
| 1055 return reinterpret_cast<intptr_t>(new VrShell( | 1098 return reinterpret_cast<intptr_t>(new VrShell( |
| 1056 env, obj, content::WebContents::FromJavaWebContents(content_web_contents), | 1099 env, obj, content::WebContents::FromJavaWebContents(content_web_contents), |
| 1057 reinterpret_cast<ui::WindowAndroid*>(content_window_android), | 1100 reinterpret_cast<ui::WindowAndroid*>(content_window_android), |
| 1058 content::WebContents::FromJavaWebContents(ui_web_contents), | 1101 content::WebContents::FromJavaWebContents(ui_web_contents), |
| 1059 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); | 1102 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); |
| 1060 } | 1103 } |
| 1061 | 1104 |
| 1062 } // namespace vr_shell | 1105 } // namespace vr_shell |
| OLD | NEW |