| 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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 content_compositor_.reset(new VrCompositor(content_window, false)); | 168 content_compositor_.reset(new VrCompositor(content_window, false)); |
| 169 ui_compositor_.reset(new VrCompositor(ui_window, true)); | 169 ui_compositor_.reset(new VrCompositor(ui_window, true)); |
| 170 vr_web_contents_observer_.reset( | 170 vr_web_contents_observer_.reset( |
| 171 new VrWebContentsObserver(main_contents, html_interface_.get())); | 171 new VrWebContentsObserver(main_contents, html_interface_.get())); |
| 172 | 172 |
| 173 LoadUIContent(); | 173 LoadUIContent(); |
| 174 | 174 |
| 175 gvr::Mat4f identity; | 175 gvr::Mat4f identity; |
| 176 SetIdentityM(identity); | 176 SetIdentityM(identity); |
| 177 webvr_head_pose_.resize(kPoseRingBufferSize, identity); | 177 webvr_head_pose_.resize(kPoseRingBufferSize, identity); |
| 178 webvr_head_pose_valid_.resize(kPoseRingBufferSize, false); |
| 178 } | 179 } |
| 179 | 180 |
| 180 void VrShell::UpdateCompositorLayers(JNIEnv* env, | 181 void VrShell::UpdateCompositorLayers(JNIEnv* env, |
| 181 const JavaParamRef<jobject>& obj) { | 182 const JavaParamRef<jobject>& obj) { |
| 182 content_compositor_->SetLayer(main_contents_); | 183 content_compositor_->SetLayer(main_contents_); |
| 183 ui_compositor_->SetLayer(ui_contents_); | 184 ui_compositor_->SetLayer(ui_contents_); |
| 184 } | 185 } |
| 185 | 186 |
| 186 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 187 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 187 delete this; | 188 delete this; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 break; | 261 break; |
| 261 } | 262 } |
| 262 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), | 263 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), |
| 263 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); | 264 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); |
| 264 } | 265 } |
| 265 | 266 |
| 266 void VrShell::InitializeGl(JNIEnv* env, | 267 void VrShell::InitializeGl(JNIEnv* env, |
| 267 const JavaParamRef<jobject>& obj, | 268 const JavaParamRef<jobject>& obj, |
| 268 jint content_texture_handle, | 269 jint content_texture_handle, |
| 269 jint ui_texture_handle) { | 270 jint ui_texture_handle) { |
| 271 VLOG(1) << "VrShell initializing GL start"; |
| 270 CHECK(gl::GetGLImplementation() != gl::kGLImplementationNone || | 272 CHECK(gl::GetGLImplementation() != gl::kGLImplementationNone || |
| 271 gl::init::InitializeGLOneOff()); | 273 gl::init::InitializeGLOneOff()); |
| 272 | 274 |
| 273 content_texture_id_ = content_texture_handle; | 275 content_texture_id_ = content_texture_handle; |
| 274 ui_texture_id_ = ui_texture_handle; | 276 ui_texture_id_ = ui_texture_handle; |
| 275 | 277 |
| 276 // While WebVR is going through the compositor path, it shares | 278 // While WebVR is going through the compositor path, it shares |
| 277 // the same texture ID. This will change once it gets its own | 279 // the same texture ID. This will change once it gets its own |
| 278 // surface, but store it separately to avoid future confusion. | 280 // surface, but store it separately to avoid future confusion. |
| 279 // TODO(klausw,crbug.com/655722): remove this. | 281 // TODO(klausw,crbug.com/655722): remove this. |
| 280 webvr_texture_id_ = content_texture_id_; | 282 webvr_texture_id_ = content_texture_id_; |
| 283 // Out of paranoia, explicitly reset the "pose valid" flags to false |
| 284 // from the GL thread. The constructor ran in the UI thread. |
| 285 // TODO(klausw,crbug.com/655722): remove this. |
| 286 webvr_head_pose_valid_.assign(kPoseRingBufferSize, false); |
| 287 webvr_valid_poses_seen_ = 0; |
| 281 | 288 |
| 282 gvr_api_->InitializeGl(); | 289 gvr_api_->InitializeGl(); |
| 283 std::vector<gvr::BufferSpec> specs; | 290 std::vector<gvr::BufferSpec> specs; |
| 284 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 291 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
| 285 specs.push_back(gvr_api_->CreateBufferSpec()); | 292 specs.push_back(gvr_api_->CreateBufferSpec()); |
| 286 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 293 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
| 287 render_size_primary_vrshell_ = render_size_primary_; | 294 render_size_primary_vrshell_ = render_size_primary_; |
| 288 | 295 |
| 289 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). | 296 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). |
| 290 // Set this up at fixed resolution, the (smaller) FOV gets set below. | 297 // Set this up at fixed resolution, the (smaller) FOV gets set below. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 new gvr::BufferViewport(gvr_api_->CreateBufferViewport())); | 342 new gvr::BufferViewport(gvr_api_->CreateBufferViewport())); |
| 336 buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE, | 343 buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE, |
| 337 webvr_left_viewport_.get()); | 344 webvr_left_viewport_.get()); |
| 338 webvr_left_viewport_->SetSourceBufferIndex(kFramePrimaryBuffer); | 345 webvr_left_viewport_->SetSourceBufferIndex(kFramePrimaryBuffer); |
| 339 | 346 |
| 340 webvr_right_viewport_.reset( | 347 webvr_right_viewport_.reset( |
| 341 new gvr::BufferViewport(gvr_api_->CreateBufferViewport())); | 348 new gvr::BufferViewport(gvr_api_->CreateBufferViewport())); |
| 342 buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE, | 349 buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE, |
| 343 webvr_right_viewport_.get()); | 350 webvr_right_viewport_.get()); |
| 344 webvr_right_viewport_->SetSourceBufferIndex(kFramePrimaryBuffer); | 351 webvr_right_viewport_->SetSourceBufferIndex(kFramePrimaryBuffer); |
| 352 VLOG(1) << "VrShell initializing GL done"; |
| 345 } | 353 } |
| 346 | 354 |
| 347 void VrShell::UpdateController(const gvr::Vec3f& forward_vector) { | 355 void VrShell::UpdateController(const gvr::Vec3f& forward_vector) { |
| 348 controller_->UpdateState(); | 356 controller_->UpdateState(); |
| 349 | 357 |
| 350 #if defined(ENABLE_VR_SHELL) | 358 #if defined(ENABLE_VR_SHELL) |
| 351 // Note that button up/down state is transient, so IsButtonUp only returns | 359 // Note that button up/down state is transient, so IsButtonUp only returns |
| 352 // true for a single frame (and we're guaranteed not to miss it). | 360 // true for a single frame (and we're guaranteed not to miss it). |
| 353 if (controller_->IsButtonUp( | 361 if (controller_->IsButtonUp( |
| 354 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_APP)) { | 362 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_APP)) { |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 } | 544 } |
| 537 gesture->type = WebInputEvent::GestureTapDown; | 545 gesture->type = WebInputEvent::GestureTapDown; |
| 538 gesture->data.tapDown.width = pixel_x; | 546 gesture->data.tapDown.width = pixel_x; |
| 539 gesture->data.tapDown.height = pixel_y; | 547 gesture->data.tapDown.height = pixel_y; |
| 540 current_input_target_->ProcessUpdatedGesture(*gesture.get()); | 548 current_input_target_->ProcessUpdatedGesture(*gesture.get()); |
| 541 } | 549 } |
| 542 } | 550 } |
| 543 | 551 |
| 544 void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { | 552 void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { |
| 545 webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose; | 553 webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose; |
| 554 webvr_head_pose_valid_[pose_num % kPoseRingBufferSize] = true; |
| 546 } | 555 } |
| 547 | 556 |
| 548 uint32_t GetPixelEncodedPoseIndex() { | 557 int GetPixelEncodedPoseIndexByte() { |
| 549 TRACE_EVENT0("gpu", "VrShell::GetPixelEncodedPoseIndex"); | 558 TRACE_EVENT0("gpu", "VrShell::GetPixelEncodedPoseIndex"); |
| 550 // Read the pose index encoded in a bottom left pixel as color values. | 559 // 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 | 560 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which |
| 552 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc | 561 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc |
| 553 // which tracks poses. | 562 // which tracks poses. Returns the low byte (0..255) if valid, or -1 |
| 563 // if not valid due to bad magic number. |
| 554 uint8_t pixels[4]; | 564 uint8_t pixels[4]; |
| 555 // Assume we're reading from the framebuffer we just wrote to. | 565 // Assume we're reading from the framebuffer we just wrote to. |
| 556 // That's true currently, we may need to use glReadBuffer(GL_BACK) | 566 // That's true currently, we may need to use glReadBuffer(GL_BACK) |
| 557 // or equivalent if the rendering setup changes in the future. | 567 // or equivalent if the rendering setup changes in the future. |
| 558 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | 568 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| 559 return pixels[0] | (pixels[1] << 8) | (pixels[2] << 16); | 569 |
| 570 // Check for the magic number written in VRDevice.cpp on submit. |
| 571 // This helps avoid glitches from garbage data in the render |
| 572 // buffer that can appear during initialization or resizing. These |
| 573 // often appear as flashes of all-black or all-white pixels. |
| 574 if (pixels[1] == 42 && pixels[2] == 142) { |
| 575 return pixels[0]; |
| 576 } |
| 577 VLOG(2) << "WebVR: reject decoded pose index " << (int)pixels[0] << |
| 578 ", bad magic number " << (int)pixels[1] << ", " << (int)pixels[2]; |
| 579 return -1; |
| 580 } |
| 581 |
| 582 bool VrShell::WebVrPoseByteIsValid(int pose_index_byte) { |
| 583 if (pose_index_byte < 0) { |
| 584 return false; |
| 585 } |
| 586 if (!webvr_head_pose_valid_[pose_index_byte % kPoseRingBufferSize]) { |
| 587 VLOG(1) << "WebVR: reject decoded pose index " << pose_index_byte << |
| 588 ", not a valid pose"; |
| 589 return false; |
| 590 } |
| 591 |
| 592 if (webvr_valid_poses_seen_ < webvr_min_valid_poses_) { |
| 593 VLOG_IF(2, webvr_valid_poses_seen_ == 0) << |
| 594 "WebVR: reject decoded pose index " << pose_index_byte << |
| 595 ", waiting for " << webvr_min_valid_poses_ << " more good poses"; |
| 596 ++webvr_valid_poses_seen_; |
| 597 if (webvr_valid_poses_seen_ == webvr_min_valid_poses_) { |
| 598 VLOG(2) << "WebVR: got sufficient good poses, enabling reprojection"; |
| 599 return true; |
| 600 } |
| 601 return false; |
| 602 } |
| 603 return true; |
| 560 } | 604 } |
| 561 | 605 |
| 562 void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 606 void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 563 TRACE_EVENT0("gpu", "VrShell::DrawFrame"); | 607 TRACE_EVENT0("gpu", "VrShell::DrawFrame"); |
| 564 // Reset the viewport list to just the pair of viewports for the | 608 // Reset the viewport list to just the pair of viewports for the |
| 565 // primary buffer each frame. Head-locked viewports get added by | 609 // primary buffer each frame. Head-locked viewports get added by |
| 566 // DrawVrShell if needed. | 610 // DrawVrShell if needed. |
| 567 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 611 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
| 568 | 612 |
| 569 if (html_interface_->GetMode() == UiInterface::Mode::WEB_VR) { | 613 if (html_interface_->GetMode() == UiInterface::Mode::WEB_VR) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 DrawWebVr(); | 659 DrawWebVr(); |
| 616 | 660 |
| 617 // When using async reprojection, we need to know which pose was used in | 661 // 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 | 662 // the WebVR app for drawing this frame. Due to unknown amounts of |
| 619 // buffering in the compositor and SurfaceTexture, we read the pose number | 663 // 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 | 664 // 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 | 665 // distortion rendering since that doesn't need a pose, and reading back |
| 622 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | 666 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop |
| 623 // doing this once we have working no-compositor rendering for WebVR. | 667 // doing this once we have working no-compositor rendering for WebVR. |
| 624 if (gvr_api_->GetAsyncReprojectionEnabled()) { | 668 if (gvr_api_->GetAsyncReprojectionEnabled()) { |
| 625 uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex(); | 669 int pose_index_byte = GetPixelEncodedPoseIndexByte(); |
| 626 // If we don't get a valid frame ID back we shouldn't attempt to reproject | 670 if (WebVrPoseByteIsValid(pose_index_byte)) { |
| 627 // by an invalid matrix, so turn of reprojection instead. | 671 // We have a valid pose, use it for reprojection. |
| 628 if (webvr_pose_frame == 0) { | 672 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_FULL); |
| 673 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_FULL); |
| 674 head_pose = webvr_head_pose_[pose_index_byte % kPoseRingBufferSize]; |
| 675 // We can't mark the used pose as invalid since unfortunately |
| 676 // we have to reuse them. The compositor will re-submit stale |
| 677 // frames on vsync, and we can't tell that this has happened |
| 678 // until we've read the pose index from it, and at that point |
| 679 // it's too late to skip rendering. |
| 680 } else { |
| 681 // If we don't get a valid frame ID back we shouldn't attempt |
| 682 // to reproject by an invalid matrix, so turn off reprojection |
| 683 // instead. Invalid poses can permanently break reprojection |
| 684 // for this GVR instance: http://crbug.com/667327 |
| 629 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | 685 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE); |
| 630 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | 686 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 } | 687 } |
| 636 } | 688 } |
| 637 } | 689 } |
| 638 | 690 |
| 639 DrawVrShell(head_pose, frame); | 691 DrawVrShell(head_pose, frame); |
| 640 | 692 |
| 641 frame.Unbind(); | 693 frame.Unbind(); |
| 642 frame.Submit(*buffer_viewport_list_, head_pose); | 694 frame.Submit(*buffer_viewport_list_, head_pose); |
| 643 } | 695 } |
| 644 | 696 |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 const JavaParamRef<jobject>& ui_web_contents, | 1105 const JavaParamRef<jobject>& ui_web_contents, |
| 1054 jlong ui_window_android) { | 1106 jlong ui_window_android) { |
| 1055 return reinterpret_cast<intptr_t>(new VrShell( | 1107 return reinterpret_cast<intptr_t>(new VrShell( |
| 1056 env, obj, content::WebContents::FromJavaWebContents(content_web_contents), | 1108 env, obj, content::WebContents::FromJavaWebContents(content_web_contents), |
| 1057 reinterpret_cast<ui::WindowAndroid*>(content_window_android), | 1109 reinterpret_cast<ui::WindowAndroid*>(content_window_android), |
| 1058 content::WebContents::FromJavaWebContents(ui_web_contents), | 1110 content::WebContents::FromJavaWebContents(ui_web_contents), |
| 1059 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); | 1111 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); |
| 1060 } | 1112 } |
| 1061 | 1113 |
| 1062 } // namespace vr_shell | 1114 } // namespace vr_shell |
| OLD | NEW |