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

Unified Diff: device/vr/android/gvr/gvr_device.cc

Issue 2584343002: WIP: working copy-no-compositor path
Patch Set: StatTracker destructor, delete old magic numbers, mojo export Created 3 years, 11 months 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
Index: device/vr/android/gvr/gvr_device.cc
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 9dc6b39c8118bd81fb277020ed7047060d877c2d..a6505d082b495e357a0129f437bfd01561ff1abd 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -21,14 +21,64 @@ namespace device {
namespace {
-static const uint64_t kPredictionTimeWithoutVsyncNanos = 50000000;
+// TODO(klausw): adjust this based on historic render times
+static const double kDefaultRenderTimeMillis = 15.0;
+static const double kPredictionTimeWithoutVsyncMillis = 24.0;
} // namespace
-GvrDevice::GvrDevice(GvrDeviceProvider* provider, GvrDelegate* delegate)
- : VRDevice(), delegate_(delegate), gvr_provider_(provider) {}
+// THIS IS A COPY, keep in sync with VRDisplay.cpp ?
+StatTracker::StatTracker(unsigned int capacity) : m_capacity(capacity) {}
-GvrDevice::~GvrDevice() {}
+StatTracker::~StatTracker() = default;
+
+void StatTracker::add(double item) {
+ if (m_items.size() >= m_capacity) {
+ m_items.pop_front();
+ }
+ m_items.push_back(item);
+}
+
+void StatTracker::clear() {
+ m_items.clear();
+}
+
+bool StatTracker::hasPrediction() {
+ return m_items.size() > 0;
+}
+
+double StatTracker::getPrediction() {
+ assert(hasPrediction());
+
+ // If we have 3 or more items, ignore min and max outliers and
+ // average the rest. For 2 or less, minmax.first and minmax.second
+ // will both be m_items.end(), so it's just a plain average.
+ auto minmax = m_items.size() > 2 ?
+ std::minmax_element(m_items.begin(), m_items.end()) :
+ std::minmax_element(m_items.end(), m_items.end());
+
+ double sum = 0.0;
+ int count = 0;
+ //VLOG(2) << __FUNCTION__ << ": stat start";
+ for (auto it = m_items.begin(); it != m_items.end(); ++it) {
+ //VLOG(2) << __FUNCTION__ << ": val=" << *it;
+ if (it == minmax.first || it == minmax.second) continue;
+ sum += *it;
+ ++count;
+ }
+ //VLOG(2) << __FUNCTION__ << ": stat return " << sum / count;
+ return sum / count;
+}
+// COPY end
+
+GvrDevice::GvrDevice(GvrDeviceProvider* provider, GvrDelegate* delegate)
+ : VRDevice(), delegate_(delegate), gvr_provider_(provider) {
+ VLOG(1) << __FUNCTION__ << ": CONSTRUCTOR this=" << (void*)this << " ***********************************************************************************************************";
+}
+
+GvrDevice::~GvrDevice() {
+ VLOG(1) << __FUNCTION__ << ": DESTRUCTOR this=" << (void*)this << " ***********************************************************************************************************";
artem.bolgar 2017/02/14 05:04:24 It is possible that callback_map_ is not empty her
+}
mojom::VRDisplayInfoPtr GvrDevice::GetVRDevice() {
TRACE_EVENT0("input", "GvrDevice::GetVRDevice");
@@ -65,9 +115,12 @@ mojom::VRDisplayInfoPtr GvrDevice::GetVRDevice() {
right_eye->renderHeight = left_eye->renderHeight;
gvr::GvrApi* gvr_api = GetGvrApi();
+ VLOG(1) << __FUNCTION__ << ": gvr_api=" << gvr_api;
if (!gvr_api) {
// We may not be able to get an instance of GvrApi right away, so
// stub in some data till we have one.
+
+ // TODO(klausw): I think we never get here ?!
device->displayName = "Unknown";
left_eye->fieldOfView->upDegrees = 45;
@@ -88,30 +141,34 @@ mojom::VRDisplayInfoPtr GvrDevice::GetVRDevice() {
right_eye->offset[1] = 0.0;
right_eye->offset[2] = 0.03;
+#if 0
// Tell the delegate not to draw yet, to avoid a race condition
// (and visible wobble) on entering VR.
if (delegate_) {
delegate_->SetWebVRRenderSurfaceSize(kInvalidRenderTargetSize.width,
kInvalidRenderTargetSize.height);
}
-
+#endif
return device;
}
- // In compositor mode, we have to use the current compositor window's
- // surface size. Would be nice to change it, but that needs more browser
- // internals to be modified. TODO(klausw,crbug.com/655722): remove this once
- // we can pick our own surface size.
- gvr::Sizei compositor_size = delegate_->GetWebVRCompositorSurfaceSize();
- left_eye->renderWidth = compositor_size.width / 2;
- left_eye->renderHeight = compositor_size.height;
+ render_target_size = gvr_api->GetMaximumEffectiveRenderTargetSize();
+ // Render at less than the maximum effective render target size as a
+ // compromise between image quality and performance, similar to
+ // current polyfill. TODO(klausw): allow clients to override this to
+ // get full resolution.
+ left_eye->renderWidth = render_target_size.width * 55 / 100 / 2;
+ left_eye->renderHeight = render_target_size.height * 55 / 100;
right_eye->renderWidth = left_eye->renderWidth;
right_eye->renderHeight = left_eye->renderHeight;
+ LOG(INFO) << "klausw: render_target_size=" << render_target_size.width << "x"
+ << render_target_size.height;
std::string vendor = gvr_api->GetViewerVendor();
std::string model = gvr_api->GetViewerModel();
device->displayName = vendor + " " + model;
+ VLOG(1) << __FUNCTION__ << ": gvr_api creating buffer viewports";
gvr::BufferViewportList gvr_buffer_viewports =
gvr_api->CreateEmptyBufferViewportList();
gvr_buffer_viewports.SetToRecommendedBufferViewports();
@@ -142,24 +199,24 @@ mojom::VRDisplayInfoPtr GvrDevice::GetVRDevice() {
right_eye->offset[1] = -right_eye_mat.m[1][3];
right_eye->offset[2] = -right_eye_mat.m[2][3];
- if (delegate_) {
- delegate_->SetWebVRRenderSurfaceSize(2 * left_eye->renderWidth,
- left_eye->renderHeight);
- }
-
return device;
}
mojom::VRPosePtr GvrDevice::GetPose() {
TRACE_EVENT0("input", "GvrDevice::GetSensorState");
- mojom::VRPosePtr pose = mojom::VRPose::New();
-
- pose->timestamp = base::Time::Now().ToJsTime();
-
// Increment pose frame counter always, even if it's a faked pose.
- pose->poseIndex = ++pose_index_;
+ ++pose_index_;
+ // Don't allow an actual pose index to be negative or zero, those
+ // are reserved for error or "no pose" states.
+ if (pose_index_ <= 0) pose_index_ = 1;
+ VLOG(2) << __FUNCTION__ << ": frame " << pose_index_;
+ TRACE_EVENT1("media", "klausw:GetPose", "frame", pose_index_);
+
+ mojom::VRPosePtr pose = mojom::VRPose::New();
+ pose->timestamp = base::Time::Now().ToJsTime();
+ pose->poseIndex = pose_index_;
pose->orientation.emplace(4);
gvr::GvrApi* gvr_api = GetGvrApi();
@@ -173,11 +230,26 @@ mojom::VRPosePtr GvrDevice::GetPose() {
return pose;
}
- if (!delegate_)
+ if (!delegate_) {
+ VLOG(2) << __FUNCTION__ << ": no delegate, no pose!";
return nullptr;
+ }
gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow();
- target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos;
+ int64_t pose_time = target_time.monotonic_system_time_nanos;
+
+#if 0
+ int64_t nstime = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
+ LOG(INFO) << "klausw: gvr ns=" << pose_time << " steady ns=" << steady_nanos << " delta=" << pose_time - nstime;
+#endif
+
+ // TODO(klausw): sanity check
+ double render_time_ms = last_processing_ms_.hasPrediction() && last_render_ms_.hasPrediction() ?
+ last_processing_ms_.getPrediction() + last_render_ms_.getPrediction() :
+ kDefaultRenderTimeMillis;
+ double predict_time_ms = render_time_ms + kPredictionTimeWithoutVsyncMillis;
+ VLOG(2) << __FUNCTION__ << ": predict_time_ms=" << predict_time_ms;
+ target_time.monotonic_system_time_nanos += static_cast<uint64_t>(predict_time_ms * 1e6);
gvr::Mat4f head_mat =
gvr_api->GetHeadSpaceFromStartSpaceRotation(target_time);
@@ -207,7 +279,7 @@ mojom::VRPosePtr GvrDevice::GetPose() {
// Save the underlying GVR pose for use by rendering. It can't use a
// VRPosePtr since that's a different data type.
- delegate_->SetGvrPoseForWebVr(head_mat, pose_index_);
+ delegate_->SetWebVRGvrPose(head_mat, pose_index_, pose_time);
return pose;
}
@@ -232,13 +304,50 @@ void GvrDevice::SetSecureOrigin(bool secure_origin) {
}
void GvrDevice::ExitPresent() {
+ // Run pending "frame complete" callbacks
+ for (auto it : callback_map_) {
artem.bolgar 2017/02/14 05:04:24 This cleanup code block should be moved to GvrDevi
+ VLOG(2) << __FUNCTION__ << ": ExitPresent running pending callback for frame: " << it.first;
+ it.second.Run(0, it.first, -1.0);
+ }
+ callback_map_.clear();
gvr_provider_->ExitPresent();
OnExitPresent();
}
-void GvrDevice::SubmitFrame(mojom::VRPosePtr pose) {
- if (delegate_)
- delegate_->SubmitWebVRFrame();
+void GvrDevice::SubmitFrame(int32_t surfaceHandle,
+ mojom::VRPosePtr pose,
+ const mojom::VRDisplay::SubmitFrameCallback& callback) {
+ TRACE_EVENT1("media", "klausw:SubmitFrame", "frame", pose->poseIndex);
+ VLOG(2) << __FUNCTION__ << ": frame " << pose->poseIndex;
+ if (delegate_) {
+ VLOG(2) << __FUNCTION__ << ": save callback for frame index " << pose->poseIndex;
+ callback_map_.insert(std::make_pair(pose->poseIndex, std::move(callback)));
+ last_processing_ms_.add(pose->ts_submit - pose->ts_getPose);
+ delegate_->SubmitWebVRFrame(surfaceHandle, std::move(pose));
+ } else {
+ VLOG(2) << __FUNCTION__ << ": No delegate, calling callback now for frame index " << pose->poseIndex;
+ callback.Run(surfaceHandle, pose->poseIndex, -1.0);
+ VLOG(2) << __FUNCTION__ << ": run callback done";
+ }
+}
+
+void GvrDevice::OnFrameSubmitted(int32_t surfaceHandle, uint32_t frame_index, double elapsed) {
+ auto it = callback_map_.find(frame_index);
+ if (it == callback_map_.end()) {
+ VLOG(2) << __FUNCTION__ << ": no callback found for frame index " << frame_index;
+ } else {
+ VLOG(2) << __FUNCTION__ << ": run callback for frame index " << frame_index;
+ auto callback = std::move(it->second);
+ callback.Run(surfaceHandle, frame_index, elapsed);
+ last_render_ms_.add(elapsed);
+ VLOG(2) << __FUNCTION__ << ": run callback done, erasing";
+ callback_map_.erase(it);
+ VLOG(2) << __FUNCTION__ << ": erasing done";
+ }
+
+ for (auto it : callback_map_) {
+ VLOG(2) << __FUNCTION__ << ": pending frame: " << it.first;
+ }
}
void GvrDevice::UpdateLayerBounds(mojom::VRLayerBoundsPtr left_bounds,
@@ -258,7 +367,16 @@ void GvrDevice::UpdateLayerBounds(mojom::VRLayerBoundsPtr left_bounds,
right_gvr_bounds.right = right_bounds->left + right_bounds->width;
right_gvr_bounds.bottom = 1.0f - (right_bounds->top + right_bounds->height);
- delegate_->UpdateWebVRTextureBounds(left_gvr_bounds, right_gvr_bounds);
+ // TODO(klausw): tie this to pose_index_ for future execution
+ delegate_->UpdateWebVRTextureBounds(left_bounds->forPoseIndex, left_gvr_bounds, right_gvr_bounds);
+}
+
+void GvrDevice::GetSurfaceHandle(int32_t width, int32_t height, const mojom::VRDisplay::GetSurfaceHandleCallback& callback) {
+ // LOG(ERROR) << "klausw:GvrDevice.GetSurfaceHandle, delegate=" << delegate_;
+ if (!delegate_)
+ callback.Run(0);
+
+ delegate_->GetWebVRSurfaceHandle(width, height, callback);
}
void GvrDevice::SetDelegate(GvrDelegate* delegate) {

Powered by Google App Engine
This is Rietveld 408576698