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 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1568 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); | 1577 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
| 1569 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); | 1578 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
| 1570 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 1579 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
| 1571 OnVSync(); | 1580 OnVSync(); |
| 1572 } | 1581 } |
| 1573 | 1582 |
| 1574 void VrShellGl::ForceExitVr() { | 1583 void VrShellGl::ForceExitVr() { |
| 1575 browser_->ForceExitVr(); | 1584 browser_->ForceExitVr(); |
| 1576 } | 1585 } |
| 1577 | 1586 |
| 1587 namespace { | |
| 1588 bool ValidateRect(const gfx::RectF& bounds) { | |
| 1589 // Bounds should be between 0 and 1, with positive width/height | |
| 1590 constexpr gfx::SizeF max_size(1, 1); | |
| 1591 constexpr gfx::SizeF min_size(0, 0); | |
| 1592 | |
| 1593 return bounds.x() < bounds.right() && bounds.y() < bounds.bottom() && | |
|
mthiesse
2017/06/22 05:59:47
You can hugely simplify this. I think the set of c
billorr
2017/07/10 18:59:23
Done.
| |
| 1594 bounds.x() <= max_size.width() && bounds.x() >= min_size.width() && | |
| 1595 bounds.right() <= max_size.width() && | |
| 1596 bounds.right() >= min_size.width() && | |
| 1597 bounds.y() <= max_size.height() && bounds.y() >= min_size.height() && | |
| 1598 bounds.bottom() <= max_size.height() && | |
| 1599 bounds.bottom() >= min_size.height(); | |
| 1600 } | |
| 1601 | |
| 1602 bool ValidateSize(const gfx::Size& size) { | |
| 1603 // Size should be between at least 2 in each direction and less than 5000. | |
|
billorr
2017/06/22 00:28:34
arbitrary values - what should we use? Or are we
mthiesse
2017/06/22 05:59:46
Not sure. The only problem I can see is intentiona
| |
| 1604 constexpr gfx::Size max_size(5000, 5000); | |
| 1605 constexpr gfx::Size min_size(2, 2); | |
| 1606 | |
| 1607 return size.width() <= max_size.width() && | |
| 1608 size.height() <= max_size.height() && | |
| 1609 size.width() >= min_size.width() && size.height() >= min_size.height(); | |
| 1610 } | |
| 1611 } // namespace | |
| 1612 | |
| 1578 void VrShellGl::UpdateLayerBounds(int16_t frame_index, | 1613 void VrShellGl::UpdateLayerBounds(int16_t frame_index, |
| 1579 const gfx::RectF& left_bounds, | 1614 const gfx::RectF& left_bounds, |
| 1580 const gfx::RectF& right_bounds, | 1615 const gfx::RectF& right_bounds, |
| 1581 const gfx::Size& source_size) { | 1616 const gfx::Size& source_size) { |
| 1617 if (!ValidateRect(left_bounds) || !ValidateRect(right_bounds) || | |
| 1618 !ValidateSize(source_size)) { | |
| 1619 mojo::ReportBadMessage("UpdateLayerBounds called with invalid bounds"); | |
|
mthiesse
2017/06/22 05:59:46
So I don't think we want to ReportBadMessage in th
| |
| 1620 binding_.Close(); | |
| 1621 return; | |
| 1622 } | |
| 1623 | |
| 1624 if (frame_index >= 0 && | |
| 1625 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) { | |
| 1626 mojo::ReportBadMessage("UpdateLayerBounds called with invalid frame_index"); | |
| 1627 binding_.Close(); | |
| 1628 return; | |
| 1629 } | |
| 1630 | |
| 1582 if (frame_index < 0) { | 1631 if (frame_index < 0) { |
| 1583 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds)); | 1632 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds)); |
| 1584 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds)); | 1633 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds)); |
| 1585 CreateOrResizeWebVRSurface(source_size); | 1634 CreateOrResizeWebVRSurface(source_size); |
| 1586 } else { | 1635 } else { |
| 1587 pending_bounds_.emplace( | 1636 pending_bounds_.emplace( |
| 1588 frame_index, WebVrBounds(left_bounds, right_bounds, source_size)); | 1637 frame_index, WebVrBounds(left_bounds, right_bounds, source_size)); |
| 1589 } | 1638 } |
| 1590 } | 1639 } |
| 1591 | 1640 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1612 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); | 1661 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); |
| 1613 | 1662 |
| 1614 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); | 1663 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); |
| 1615 | 1664 |
| 1616 gfx::Transform head_mat; | 1665 gfx::Transform head_mat; |
| 1617 device::mojom::VRPosePtr pose = | 1666 device::mojom::VRPosePtr pose = |
| 1618 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, | 1667 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, |
| 1619 prediction_nanos); | 1668 prediction_nanos); |
| 1620 | 1669 |
| 1621 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; | 1670 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; |
| 1671 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = true; | |
| 1622 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now(); | 1672 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now(); |
| 1623 | 1673 |
| 1624 std::move(callback).Run( | 1674 std::move(callback).Run( |
| 1625 std::move(pose), time, frame_index, | 1675 std::move(pose), time, frame_index, |
| 1626 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS); | 1676 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS); |
| 1627 } | 1677 } |
| 1628 | 1678 |
| 1629 void VrShellGl::CreateVRDisplayInfo( | 1679 void VrShellGl::CreateVRDisplayInfo( |
| 1630 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, | 1680 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, |
| 1631 uint32_t device_id) { | 1681 uint32_t device_id) { |
| 1632 // This assumes that the initial webvr_surface_size_ was set to the | 1682 // This assumes that the initial webvr_surface_size_ was set to the |
| 1633 // appropriate recommended render resolution as the default size during | 1683 // appropriate recommended render resolution as the default size during |
| 1634 // InitializeGl. Revisit if the initialization order changes. | 1684 // InitializeGl. Revisit if the initialization order changes. |
| 1635 device::mojom::VRDisplayInfoPtr info = | 1685 device::mojom::VRDisplayInfoPtr info = |
| 1636 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), | 1686 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), |
| 1637 webvr_surface_size_, device_id); | 1687 webvr_surface_size_, device_id); |
| 1638 browser_->RunVRDisplayInfoCallback(callback, &info); | 1688 browser_->RunVRDisplayInfoCallback(callback, &info); |
| 1639 } | 1689 } |
| 1640 | 1690 |
| 1641 } // namespace vr_shell | 1691 } // namespace vr_shell |
| OLD | NEW |