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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/android/vr_shell/vr_shell.cc
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 90456fd60192c92960f1e2210719bb461e36cc6a..b357a2bd2d3f197942fa0e1e21525710271c4396 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -91,6 +91,10 @@ static constexpr gvr::Rectf kHeadlockedBufferFov = {20.f, 20.f, 20.f, 20.f};
static constexpr int kViewportListPrimaryOffset = 0;
static constexpr int kViewportListHeadlockedOffset = 2;
+// Magic numbers used to mark valid pose index values encoded in frame
+// data. Must match the magic numbers used in blink's VRDisplay.cpp.
+static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}};
+
vr_shell::VrShell* g_instance;
static const char kVrShellUIURL[] = "chrome://vr-shell-ui";
@@ -175,6 +179,7 @@ VrShell::VrShell(JNIEnv* env,
gvr::Mat4f identity;
SetIdentityM(identity);
webvr_head_pose_.resize(kPoseRingBufferSize, identity);
+ webvr_head_pose_valid_.resize(kPoseRingBufferSize, false);
}
void VrShell::UpdateCompositorLayers(JNIEnv* env,
@@ -278,6 +283,10 @@ void VrShell::InitializeGl(JNIEnv* env,
// surface, but store it separately to avoid future confusion.
// TODO(klausw,crbug.com/655722): remove this.
webvr_texture_id_ = content_texture_id_;
+ // Out of paranoia, explicitly reset the "pose valid" flags to false
+ // from the GL thread. The constructor ran in the UI thread.
+ // TODO(klausw,crbug.com/655722): remove this.
+ webvr_head_pose_valid_.assign(kPoseRingBufferSize, false);
gvr_api_->InitializeGl();
std::vector<gvr::BufferSpec> specs;
@@ -543,20 +552,46 @@ void VrShell::SendEventsToTarget(VrInputManager* input_target,
void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) {
webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose;
+ webvr_head_pose_valid_[pose_num % kPoseRingBufferSize] = true;
}
-uint32_t GetPixelEncodedPoseIndex() {
+int GetPixelEncodedPoseIndexByte() {
TRACE_EVENT0("gpu", "VrShell::GetPixelEncodedPoseIndex");
// Read the pose index encoded in a bottom left pixel as color values.
// See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which
// encodes the pose index, and device/vr/android/gvr/gvr_device.cc
- // which tracks poses.
+ // which tracks poses. Returns the low byte (0..255) if valid, or -1
+ // if not valid due to bad magic number.
uint8_t pixels[4];
// Assume we're reading from the framebuffer we just wrote to.
// That's true currently, we may need to use glReadBuffer(GL_BACK)
// or equivalent if the rendering setup changes in the future.
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- return pixels[0] | (pixels[1] << 8) | (pixels[2] << 16);
+
+ // Check for the magic number written by VRDevice.cpp on submit.
+ // This helps avoid glitches from garbage data in the render
+ // buffer that can appear during initialization or resizing. These
+ // often appear as flashes of all-black or all-white pixels.
+ if (pixels[1] == kWebVrPosePixelMagicNumbers[0] &&
+ pixels[2] == kWebVrPosePixelMagicNumbers[1]) {
+ // Pose is good.
+ return pixels[0];
+ }
+ VLOG(1) << "WebVR: reject decoded pose index " << (int)pixels[0] <<
+ ", bad magic number " << (int)pixels[1] << ", " << (int)pixels[2];
+ return -1;
+}
+
+bool VrShell::WebVrPoseByteIsValid(int pose_index_byte) {
+ if (pose_index_byte < 0) {
+ return false;
+ }
+ if (!webvr_head_pose_valid_[pose_index_byte % kPoseRingBufferSize]) {
+ VLOG(1) << "WebVR: reject decoded pose index " << pose_index_byte <<
+ ", not a valid pose";
+ return false;
+ }
+ return true;
}
void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) {
@@ -622,16 +657,24 @@ void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) {
// pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop
// doing this once we have working no-compositor rendering for WebVR.
if (gvr_api_->GetAsyncReprojectionEnabled()) {
- uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex();
- // If we don't get a valid frame ID back we shouldn't attempt to reproject
- // by an invalid matrix, so turn of reprojection instead.
- if (webvr_pose_frame == 0) {
- webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE);
- webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE);
- } else {
+ int pose_index_byte = GetPixelEncodedPoseIndexByte();
+ if (WebVrPoseByteIsValid(pose_index_byte)) {
+ // We have a valid pose, use it for reprojection.
webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_FULL);
webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_FULL);
- head_pose = webvr_head_pose_[webvr_pose_frame % kPoseRingBufferSize];
+ head_pose = webvr_head_pose_[pose_index_byte % kPoseRingBufferSize];
+ // We can't mark the used pose as invalid since unfortunately
+ // we have to reuse them. The compositor will re-submit stale
+ // frames on vsync, and we can't tell that this has happened
+ // until we've read the pose index from it, and at that point
+ // it's too late to skip rendering.
+ } else {
+ // If we don't get a valid frame ID back we shouldn't attempt
+ // to reproject by an invalid matrix, so turn off reprojection
+ // instead. Invalid poses can permanently break reprojection
+ // for this GVR instance: http://crbug.com/667327
+ webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE);
+ webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE);
}
}
}
« 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