Chromium Code Reviews| 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 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 const gpu::MailboxHolder& mailbox) { | 371 const gpu::MailboxHolder& mailbox) { |
| 372 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame"); | 372 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame"); |
| 373 | 373 |
| 374 // submit_client_ could be null when we exit presentation, if there were | 374 // submit_client_ could be null when we exit presentation, if there were |
| 375 // pending SubmitFrame messages queued. VRDisplayClient::OnExitPresent | 375 // pending SubmitFrame messages queued. VRDisplayClient::OnExitPresent |
| 376 // will clean up state in blink, so it doesn't wait for | 376 // will clean up state in blink, so it doesn't wait for |
| 377 // OnSubmitFrameTransferred or OnSubmitFrameRendered. | 377 // OnSubmitFrameTransferred or OnSubmitFrameRendered. |
| 378 if (!submit_client_.get()) | 378 if (!submit_client_.get()) |
| 379 return; | 379 return; |
| 380 | 380 |
| 381 if (frame_index < 0 || | |
| 382 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) { | |
| 383 mojo::ReportBadMessage("SubmitFrame called with an invalid frame_index"); | |
| 384 binding_.Close(); | |
| 385 return; | |
| 386 } | |
| 387 | |
| 381 webvr_time_js_submit_[frame_index % kPoseRingBufferSize] = | 388 webvr_time_js_submit_[frame_index % kPoseRingBufferSize] = |
| 382 base::TimeTicks::Now(); | 389 base::TimeTicks::Now(); |
| 383 | 390 |
| 384 // Swapping twice on a Surface without calling updateTexImage in | 391 // Swapping twice on a Surface without calling updateTexImage in |
| 385 // between can lose frames, so don't draw+swap if we already have | 392 // between can lose frames, so don't draw+swap if we already have |
| 386 // a pending frame we haven't consumed yet. | 393 // a pending frame we haven't consumed yet. |
| 387 bool swapped = false; | 394 bool swapped = false; |
| 388 if (pending_frames_.empty()) { | 395 if (pending_frames_.empty()) { |
| 389 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox); | 396 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox); |
| 390 if (swapped) { | 397 if (swapped) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 browser_->ToggleCardboardGamepad(true); | 455 browser_->ToggleCardboardGamepad(true); |
| 449 } | 456 } |
| 450 } | 457 } |
| 451 | 458 |
| 452 void VrShellGl::InitializeRenderer() { | 459 void VrShellGl::InitializeRenderer() { |
| 453 gvr_api_->InitializeGl(); | 460 gvr_api_->InitializeGl(); |
| 454 gfx::Transform head_pose; | 461 gfx::Transform head_pose; |
| 455 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); | 462 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); |
| 456 webvr_head_pose_.assign(kPoseRingBufferSize, head_pose); | 463 webvr_head_pose_.assign(kPoseRingBufferSize, head_pose); |
| 457 webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks()); | 464 webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks()); |
| 465 webvr_frame_oustanding_.assign(kPoseRingBufferSize, false); | |
| 458 webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks()); | 466 webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks()); |
| 459 | 467 |
| 460 std::vector<gvr::BufferSpec> specs; | 468 std::vector<gvr::BufferSpec> specs; |
| 461 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 469 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
| 462 specs.push_back(gvr_api_->CreateBufferSpec()); | 470 specs.push_back(gvr_api_->CreateBufferSpec()); |
| 463 gvr::Sizei render_size_primary = specs[kFramePrimaryBuffer].GetSize(); | 471 gvr::Sizei render_size_primary = specs[kFramePrimaryBuffer].GetSize(); |
| 464 render_size_primary_ = {render_size_primary.width, | 472 render_size_primary_ = {render_size_primary.width, |
| 465 render_size_primary.height}; | 473 render_size_primary.height}; |
| 466 render_size_vrshell_ = render_size_primary_; | 474 render_size_vrshell_ = render_size_primary_; |
| 467 | 475 |
| (...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1060 | 1068 |
| 1061 // When using async reprojection, we need to know which pose was | 1069 // When using async reprojection, we need to know which pose was |
| 1062 // used in the WebVR app for drawing this frame and supply it when | 1070 // used in the WebVR app for drawing this frame and supply it when |
| 1063 // submitting. Technically we don't need a pose if not reprojecting, | 1071 // submitting. Technically we don't need a pose if not reprojecting, |
| 1064 // but keeping it uninitialized seems likely to cause problems down | 1072 // but keeping it uninitialized seems likely to cause problems down |
| 1065 // the road. Copying it is cheaper than fetching a new one. | 1073 // the road. Copying it is cheaper than fetching a new one. |
| 1066 if (ShouldDrawWebVr()) { | 1074 if (ShouldDrawWebVr()) { |
| 1067 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), | 1075 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), |
| 1068 "kPoseRingBufferSize must be a power of 2"); | 1076 "kPoseRingBufferSize must be a power of 2"); |
| 1069 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; | 1077 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; |
| 1078 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = false; | |
| 1070 } else { | 1079 } else { |
| 1071 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); | 1080 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); |
| 1072 } | 1081 } |
| 1073 | 1082 |
| 1074 // Update the render position of all UI elements (including desktop). | 1083 // Update the render position of all UI elements (including desktop). |
| 1075 scene_->OnBeginFrame(current_time); | 1084 scene_->OnBeginFrame(current_time); |
| 1076 | 1085 |
| 1077 { | 1086 { |
| 1078 // TODO(crbug.com/704690): Acquire controller state in a way that's timely | 1087 // TODO(crbug.com/704690): Acquire controller state in a way that's timely |
| 1079 // for both the gamepad API and UI input handling. | 1088 // for both the gamepad API and UI input handling. |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1570 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); | 1579 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
| 1571 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); | 1580 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
| 1572 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 1581 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
| 1573 OnVSync(); | 1582 OnVSync(); |
| 1574 } | 1583 } |
| 1575 | 1584 |
| 1576 void VrShellGl::ForceExitVr() { | 1585 void VrShellGl::ForceExitVr() { |
| 1577 browser_->ForceExitVr(); | 1586 browser_->ForceExitVr(); |
| 1578 } | 1587 } |
| 1579 | 1588 |
| 1589 namespace { | |
| 1590 bool ValidateRect(const gfx::RectF& bounds) { | |
| 1591 // Bounds should be between 0 and 1, with positive width/height. | |
| 1592 // We simply clamp to [0,1], but still validate that the bounds are not NAN. | |
| 1593 return !std::isnan(bounds.width()) && !std::isnan(bounds.height()) && | |
| 1594 !std::isnan(bounds.x()) && !std::isnan(bounds.y()); | |
| 1595 } | |
| 1596 | |
| 1597 bool ValidateSize(const gfx::Size& size) { | |
| 1598 // Size should be at least 0 in each direction. | |
| 1599 return size.width() >= 0 && size.height() >= 0; | |
| 1600 } | |
| 1601 | |
| 1602 gfx::RectF ClampRect(const gfx::RectF& bounds) { | |
| 1603 float left = std::max(0.0f, std::min(bounds.x(), 1.0f)); | |
|
mthiesse
2017/07/11 14:52:24
I think you can just use bounds.AdjustToFit(gfx::R
billorr
2017/07/13 00:31:40
That is close enough to the same behavior that I'l
| |
| 1604 float right = std::max(left, std::min(bounds.right(), 1.0f)); | |
| 1605 float top = std::max(0.0f, std::min(bounds.y(), 1.0f)); | |
| 1606 float bottom = std::max(top, std::min(bounds.bottom(), 1.0f)); | |
| 1607 return gfx::RectF(left, top, right - left, bottom - top); | |
|
bajones1
2017/07/11 17:11:06
Sanity check:
Does gfx::RectF enforces that right
billorr
2017/07/13 00:31:41
Yes, setWidth/setHeight will make the width/height
| |
| 1608 } | |
| 1609 | |
| 1610 } // namespace | |
| 1611 | |
| 1580 void VrShellGl::UpdateLayerBounds(int16_t frame_index, | 1612 void VrShellGl::UpdateLayerBounds(int16_t frame_index, |
| 1581 const gfx::RectF& left_bounds, | 1613 const gfx::RectF& left_bounds, |
| 1582 const gfx::RectF& right_bounds, | 1614 const gfx::RectF& right_bounds, |
| 1583 const gfx::Size& source_size) { | 1615 const gfx::Size& source_size) { |
| 1616 if (!ValidateSize(source_size) || !ValidateRect(left_bounds) || | |
| 1617 !ValidateRect(right_bounds)) { | |
| 1618 mojo::ReportBadMessage("UpdateLayerBounds called with invalid bounds"); | |
| 1619 binding_.Close(); | |
| 1620 return; | |
| 1621 } | |
| 1622 | |
| 1623 if (frame_index >= 0 && | |
| 1624 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) { | |
| 1625 mojo::ReportBadMessage("UpdateLayerBounds called with invalid frame_index"); | |
| 1626 binding_.Close(); | |
| 1627 return; | |
| 1628 } | |
| 1629 | |
| 1584 if (frame_index < 0) { | 1630 if (frame_index < 0) { |
| 1585 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds)); | 1631 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(ClampRect(left_bounds))); |
| 1586 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds)); | 1632 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(ClampRect(right_bounds))); |
| 1587 CreateOrResizeWebVRSurface(source_size); | 1633 CreateOrResizeWebVRSurface(source_size); |
| 1634 | |
| 1635 // clear all pending bounds | |
| 1636 pending_bounds_ = std::queue<std::pair<uint8_t, WebVrBounds>>(); | |
| 1588 } else { | 1637 } else { |
| 1589 pending_bounds_.emplace( | 1638 pending_bounds_.emplace( |
| 1590 frame_index, WebVrBounds(left_bounds, right_bounds, source_size)); | 1639 frame_index, WebVrBounds(left_bounds, right_bounds, source_size)); |
| 1591 } | 1640 } |
| 1592 } | 1641 } |
| 1593 | 1642 |
| 1594 int64_t VrShellGl::GetPredictedFrameTimeNanos() { | 1643 int64_t VrShellGl::GetPredictedFrameTimeNanos() { |
| 1595 int64_t frame_time_micros = vsync_interval_.InMicroseconds(); | 1644 int64_t frame_time_micros = vsync_interval_.InMicroseconds(); |
| 1596 // If we aim to submit at vsync, that frame will start scanning out | 1645 // If we aim to submit at vsync, that frame will start scanning out |
| 1597 // one vsync later. Add a half frame to split the difference between | 1646 // one vsync later. Add a half frame to split the difference between |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1614 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); | 1663 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); |
| 1615 | 1664 |
| 1616 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); | 1665 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); |
| 1617 | 1666 |
| 1618 gfx::Transform head_mat; | 1667 gfx::Transform head_mat; |
| 1619 device::mojom::VRPosePtr pose = | 1668 device::mojom::VRPosePtr pose = |
| 1620 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, | 1669 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, |
| 1621 prediction_nanos); | 1670 prediction_nanos); |
| 1622 | 1671 |
| 1623 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; | 1672 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; |
| 1673 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = true; | |
| 1624 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now(); | 1674 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now(); |
| 1625 | 1675 |
| 1626 std::move(callback).Run( | 1676 std::move(callback).Run( |
| 1627 std::move(pose), time, frame_index, | 1677 std::move(pose), time, frame_index, |
| 1628 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS); | 1678 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS); |
| 1629 } | 1679 } |
| 1630 | 1680 |
| 1631 void VrShellGl::CreateVRDisplayInfo( | 1681 void VrShellGl::CreateVRDisplayInfo( |
| 1632 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, | 1682 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, |
| 1633 uint32_t device_id) { | 1683 uint32_t device_id) { |
| 1634 // This assumes that the initial webvr_surface_size_ was set to the | 1684 // This assumes that the initial webvr_surface_size_ was set to the |
| 1635 // appropriate recommended render resolution as the default size during | 1685 // appropriate recommended render resolution as the default size during |
| 1636 // InitializeGl. Revisit if the initialization order changes. | 1686 // InitializeGl. Revisit if the initialization order changes. |
| 1637 device::mojom::VRDisplayInfoPtr info = | 1687 device::mojom::VRDisplayInfoPtr info = |
| 1638 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), | 1688 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), |
| 1639 webvr_surface_size_, device_id); | 1689 webvr_surface_size_, device_id); |
| 1640 browser_->RunVRDisplayInfoCallback(callback, &info); | 1690 browser_->RunVRDisplayInfoCallback(callback, &info); |
| 1641 } | 1691 } |
| 1642 | 1692 |
| 1643 } // namespace vr_shell | 1693 } // namespace vr_shell |
| OLD | NEW |