Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: chrome/browser/android/vr_shell/vr_shell.cc

Issue 2552443002: WebVR: Add sanity checks for decoded pose index values (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/android/vr_shell/vr_shell.h ('k') | device/vr/android/gvr/gvr_device_provider.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698