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

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

Issue 2541023003: WebVR: Add sanity checks for decoded pose index values (Closed)
Patch Set: Add longer wait, 10 frames was not sufficient. Less verbose vlog. 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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698