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_gl.h" | 5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h" |
6 | 6 |
7 #include <chrono> | 7 #include <chrono> |
8 #include <limits> | 8 #include <limits> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 | 75 |
76 // The GVR viewport list has two entries (left eye and right eye) for each | 76 // The GVR viewport list has two entries (left eye and right eye) for each |
77 // GVR buffer. | 77 // GVR buffer. |
78 static constexpr int kViewportListPrimaryOffset = 0; | 78 static constexpr int kViewportListPrimaryOffset = 0; |
79 static constexpr int kViewportListHeadlockedOffset = 2; | 79 static constexpr int kViewportListHeadlockedOffset = 2; |
80 | 80 |
81 // Buffer size large enough to handle the current backlog of poses which is | 81 // Buffer size large enough to handle the current backlog of poses which is |
82 // 2-3 frames. | 82 // 2-3 frames. |
83 static constexpr unsigned kPoseRingBufferSize = 8; | 83 static constexpr unsigned kPoseRingBufferSize = 8; |
84 | 84 |
| 85 // Number of frames to use for sliding averages for pose timings, |
| 86 // as used for estimating prediction times. |
| 87 static constexpr unsigned kWebVRSlidingAverageSize = 5; |
| 88 |
85 // Criteria for considering holding the app button in combination with | 89 // Criteria for considering holding the app button in combination with |
86 // controller movement as a gesture. | 90 // controller movement as a gesture. |
87 static constexpr float kMinAppButtonGestureAngleRad = 0.25; | 91 static constexpr float kMinAppButtonGestureAngleRad = 0.25; |
88 | 92 |
89 static constexpr gfx::PointF kInvalidTargetPoint = | 93 static constexpr gfx::PointF kInvalidTargetPoint = |
90 gfx::PointF(std::numeric_limits<float>::max(), | 94 gfx::PointF(std::numeric_limits<float>::max(), |
91 std::numeric_limits<float>::max()); | 95 std::numeric_limits<float>::max()); |
92 | 96 |
93 // Generate a quaternion representing the rotation from the negative Z axis | 97 // Generate a quaternion representing the rotation from the negative Z axis |
94 // (0, 0, -1) to a specified vector. This is an optimized version of a more | 98 // (0, 0, -1) to a specified vector. This is an optimized version of a more |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 bool reprojected_rendering, | 220 bool reprojected_rendering, |
217 bool daydream_support, | 221 bool daydream_support, |
218 UiScene* scene) | 222 UiScene* scene) |
219 : web_vr_mode_(initially_web_vr), | 223 : web_vr_mode_(initially_web_vr), |
220 surfaceless_rendering_(reprojected_rendering), | 224 surfaceless_rendering_(reprojected_rendering), |
221 daydream_support_(daydream_support), | 225 daydream_support_(daydream_support), |
222 task_runner_(base::ThreadTaskRunnerHandle::Get()), | 226 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
223 binding_(this), | 227 binding_(this), |
224 browser_(browser), | 228 browser_(browser), |
225 scene_(scene), | 229 scene_(scene), |
226 #if DCHECK_IS_ON() | |
227 fps_meter_(new FPSMeter()), | 230 fps_meter_(new FPSMeter()), |
228 #endif | 231 webvr_js_time_(new SlidingAverage(kWebVRSlidingAverageSize)), |
| 232 webvr_render_time_(new SlidingAverage(kWebVRSlidingAverageSize)), |
229 weak_ptr_factory_(this) { | 233 weak_ptr_factory_(this) { |
230 GvrInit(gvr_api); | 234 GvrInit(gvr_api); |
231 } | 235 } |
232 | 236 |
233 VrShellGl::~VrShellGl() { | 237 VrShellGl::~VrShellGl() { |
234 vsync_task_.Cancel(); | 238 vsync_task_.Cancel(); |
235 // TODO(mthiesse): Can we omit the Close() here? Concern is that if | 239 // TODO(mthiesse): Can we omit the Close() here? Concern is that if |
236 // both ends of the connection ever live in the same process for | 240 // both ends of the connection ever live in the same process for |
237 // some reason, we could receive another VSync request in response | 241 // some reason, we could receive another VSync request in response |
238 // to the closing message in the destructor but fail to respond to | 242 // to the closing message in the destructor but fail to respond to |
(...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1066 } | 1070 } |
1067 | 1071 |
1068 // Report rendering completion to WebVR so that it's permitted to submit | 1072 // Report rendering completion to WebVR so that it's permitted to submit |
1069 // a fresh frame. We could do this earlier, as soon as the frame got pulled | 1073 // a fresh frame. We could do this earlier, as soon as the frame got pulled |
1070 // off the transfer surface, but that appears to result in overstuffed | 1074 // off the transfer surface, but that appears to result in overstuffed |
1071 // buffers. | 1075 // buffers. |
1072 if (submit_client_) { | 1076 if (submit_client_) { |
1073 submit_client_->OnSubmitFrameRendered(); | 1077 submit_client_->OnSubmitFrameRendered(); |
1074 } | 1078 } |
1075 | 1079 |
1076 #if DCHECK_IS_ON() | |
1077 // After saving the timestamp, fps will be available via GetFPS(). | 1080 // After saving the timestamp, fps will be available via GetFPS(). |
1078 // TODO(vollick): enable rendering of this framerate in a HUD. | 1081 // TODO(vollick): enable rendering of this framerate in a HUD. |
1079 fps_meter_->AddFrame(current_time); | 1082 fps_meter_->AddFrame(current_time); |
1080 DVLOG(1) << "fps: " << fps_meter_->GetFPS(); | 1083 DVLOG(1) << "fps: " << fps_meter_->GetFPS(); |
1081 #endif | 1084 TRACE_COUNTER1("gpu", "WebVR FPS", fps_meter_->GetFPS()); |
1082 } | 1085 } |
1083 | 1086 |
1084 void VrShellGl::DrawWorldElements(const vr::Mat4f& head_pose) { | 1087 void VrShellGl::DrawWorldElements(const vr::Mat4f& head_pose) { |
1085 TRACE_EVENT0("gpu", "VrShellGl::DrawWorldElements"); | 1088 TRACE_EVENT0("gpu", "VrShellGl::DrawWorldElements"); |
1086 | 1089 |
1087 if (ShouldDrawWebVr()) { | 1090 if (ShouldDrawWebVr()) { |
1088 // WebVR is incompatible with 3D world compositing since the | 1091 // WebVR is incompatible with 3D world compositing since the |
1089 // depth buffer was already populated with unknown scaling - the | 1092 // depth buffer was already populated with unknown scaling - the |
1090 // WebVR app has full control over zNear/zFar. Just leave the | 1093 // WebVR app has full control over zNear/zFar. Just leave the |
1091 // existing content in place in the primary buffer without | 1094 // existing content in place in the primary buffer without |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1511 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); | 1514 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
1512 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); | 1515 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
1513 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 1516 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
1514 OnVSync(); | 1517 OnVSync(); |
1515 } | 1518 } |
1516 | 1519 |
1517 void VrShellGl::ForceExitVr() { | 1520 void VrShellGl::ForceExitVr() { |
1518 browser_->ForceExitVr(); | 1521 browser_->ForceExitVr(); |
1519 } | 1522 } |
1520 | 1523 |
| 1524 int64_t VrShellGl::GetPredictedFrameTimeNanos() { |
| 1525 int64_t frame_time_micros = vsync_interval_.InMicroseconds(); |
| 1526 // If we aim to submit at vsync, that frame will start scanning out |
| 1527 // one vsync later. Add a half frame to split the difference between |
| 1528 // left and right eye. |
| 1529 int64_t js_micros = webvr_js_time_->GetAverageOrDefault(frame_time_micros); |
| 1530 int64_t render_micros = |
| 1531 webvr_render_time_->GetAverageOrDefault(frame_time_micros); |
| 1532 int64_t overhead_micros = frame_time_micros * 3 / 2; |
| 1533 int64_t expected_frame_micros = js_micros + render_micros + overhead_micros; |
| 1534 TRACE_COUNTER2("gpu", "WebVR frame time (ms)", "javascript", |
| 1535 js_micros / 1000.0, "rendering", render_micros / 1000.0); |
| 1536 TRACE_COUNTER1("gpu", "WebVR pose prediction (ms)", |
| 1537 expected_frame_micros / 1000.0); |
| 1538 return expected_frame_micros * 1000; |
| 1539 } |
| 1540 |
1521 void VrShellGl::SendVSync(base::TimeDelta time, | 1541 void VrShellGl::SendVSync(base::TimeDelta time, |
1522 const GetVSyncCallback& callback) { | 1542 const GetVSyncCallback& callback) { |
1523 uint8_t frame_index = frame_index_++; | 1543 uint8_t frame_index = frame_index_++; |
1524 | 1544 |
1525 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); | 1545 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); |
1526 | 1546 |
| 1547 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); |
| 1548 |
1527 vr::Mat4f head_mat; | 1549 vr::Mat4f head_mat; |
1528 device::mojom::VRPosePtr pose = | 1550 device::mojom::VRPosePtr pose = |
1529 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat); | 1551 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, |
| 1552 prediction_nanos); |
1530 | 1553 |
1531 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; | 1554 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; |
1532 | 1555 |
1533 callback.Run(std::move(pose), time, frame_index, | 1556 callback.Run(std::move(pose), time, frame_index, |
1534 device::mojom::VRVSyncProvider::Status::SUCCESS); | 1557 device::mojom::VRVSyncProvider::Status::SUCCESS); |
1535 } | 1558 } |
1536 | 1559 |
1537 void VrShellGl::CreateVRDisplayInfo( | 1560 void VrShellGl::CreateVRDisplayInfo( |
1538 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, | 1561 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, |
1539 uint32_t device_id) { | 1562 uint32_t device_id) { |
1540 // This assumes that the initial webvr_surface_size_ was set to the | 1563 // This assumes that the initial webvr_surface_size_ was set to the |
1541 // appropriate recommended render resolution as the default size during | 1564 // appropriate recommended render resolution as the default size during |
1542 // InitializeGl. Revisit if the initialization order changes. | 1565 // InitializeGl. Revisit if the initialization order changes. |
1543 device::mojom::VRDisplayInfoPtr info = | 1566 device::mojom::VRDisplayInfoPtr info = |
1544 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), | 1567 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), |
1545 webvr_surface_size_, device_id); | 1568 webvr_surface_size_, device_id); |
1546 browser_->RunVRDisplayInfoCallback(callback, &info); | 1569 browser_->RunVRDisplayInfoCallback(callback, &info); |
1547 } | 1570 } |
1548 | 1571 |
1549 } // namespace vr_shell | 1572 } // namespace vr_shell |
OLD | NEW |