Add DaydreamVR native libraries and services

Upstreaming the main VR system components from master-dreamos-dev
into goog/master.

Bug: None
Test: `m -j32` succeeds. Sailfish boots and basic_vr sample app works
Change-Id: I853015872afc443aecee10411ef2d6b79184d051
diff --git a/libs/vr/libeds/composite_hmd.cpp b/libs/vr/libeds/composite_hmd.cpp
new file mode 100644
index 0000000..d29cd65
--- /dev/null
+++ b/libs/vr/libeds/composite_hmd.cpp
@@ -0,0 +1,256 @@
+#include "include/private/dvr/composite_hmd.h"
+
+#include <base/logging.h>
+#include <private/dvr/numeric.h>
+
+namespace android {
+namespace dvr {
+
+CompositeHmd::CompositeHmd(const HeadMountMetrics& head_mount_metrics,
+                           const DisplayMetrics& display_metrics)
+    : head_mount_metrics_(head_mount_metrics),
+      display_metrics_(display_metrics) {
+  MetricsChanged();
+}
+
+float CompositeHmd::GetTargetFrameDuration() const {
+  return display_metrics_.GetFrameDurationSeconds();
+}
+
+vec2 CompositeHmd::ComputeDistortedPoint(EyeType eye, vec2 position,
+                                         RgbColorChannel channel) const {
+  position = TransformPoint(eye_tan_angle_from_norm_screen_matrix_[eye], position);
+  vec2 distorted =
+      head_mount_metrics_.GetColorChannelDistortion(channel).Distort(position);
+  return TransformPoint(eye_norm_texture_from_tan_angle_matrix_[eye], distorted);
+}
+
+vec2 CompositeHmd::ComputeInverseDistortedPoint(EyeType eye, vec2 position,
+                                                RgbColorChannel channel) const {
+  position = TransformPoint(eye_norm_texture_from_tan_angle_inv_matrix_[eye], position);
+  vec2 distorted =
+      head_mount_metrics_.GetColorChannelDistortion(channel).DistortInverse(
+          position);
+  return TransformPoint(eye_tan_angle_from_norm_screen_inv_matrix_[eye], distorted);
+}
+
+void CompositeHmd::ComputeDistortedVertex(EyeType eye, vec2 uv_in,
+                                          vec2* vertex_out,
+                                          vec2* uv_out) const {
+  // The mesh vertices holds the shape of the distortion.
+  vec2 vertex_position = ComputeInverseDistortedPoint(eye, uv_in, kRed);
+  *vertex_out = vec2(vertex_position.x() - 0.5f, vertex_position.y() - 0.5f);
+
+  if (uv_out) {
+    // Compute the texture coordinate for each vertex coordinate.
+    // Red's is the inverse of the inverse, skip the calculation and use uv_in.
+    uv_out[kRed] = uv_in;
+    uv_out[kGreen] = ComputeDistortedPoint(eye, vertex_position, kGreen);
+    uv_out[kBlue] = ComputeDistortedPoint(eye, vertex_position, kBlue);
+  }
+}
+
+vec2i CompositeHmd::GetRecommendedRenderTargetSize() const {
+  return recommended_render_target_size_;
+}
+
+Range2i CompositeHmd::GetDisplayRange() const { return display_range_; }
+
+mat4 CompositeHmd::GetEyeFromHeadMatrix(EyeType eye) const {
+  return eye_from_head_matrix_[eye];
+}
+
+FieldOfView CompositeHmd::GetEyeFov(EyeType eye) const { return eye_fov_[eye]; }
+
+Range2i CompositeHmd::GetEyeViewportBounds(EyeType eye) const {
+  return eye_viewport_range_[eye];
+}
+
+void CompositeHmd::SetHeadMountMetrics(
+    const HeadMountMetrics& head_mount_metrics) {
+  // Use the assignement operator to do memberwise copy.
+  head_mount_metrics_ = head_mount_metrics;
+  MetricsChanged();
+}
+
+const HeadMountMetrics& CompositeHmd::GetHeadMountMetrics() const {
+  return head_mount_metrics_;
+}
+
+void CompositeHmd::SetDisplayMetrics(const DisplayMetrics& display_metrics) {
+  // Use the assignment operator to do memberwise copy.
+  display_metrics_ = display_metrics;
+  MetricsChanged();
+}
+
+const DisplayMetrics& CompositeHmd::GetDisplayMetrics() const {
+  return display_metrics_;
+}
+
+void CompositeHmd::MetricsChanged() {
+  // Abbreviations in variable names:
+  //   "vp": viewport
+  //   "ta": tan-angle
+  const HeadMountMetrics& mount = head_mount_metrics_;
+  DisplayMetrics display = display_metrics_;
+
+  if (display.IsPortrait()) {
+    // If we're in portrait mode, toggle the orientation so that all
+    // calculations are done in landscape mode.
+    display.ToggleOrientation();
+  }
+
+  float display_width_meters = display.GetSizeMeters()[0];
+  float display_height_meters = display.GetSizeMeters()[1];
+
+  vec2 pixels_per_meter = vec2(1.0f / display.GetMetersPerPixel()[0],
+                               1.0f / display.GetMetersPerPixel()[1]);
+
+  // virtual_eye_to_screen_dist is the distance from the screen to the eye
+  // after it has been projected through the lens.  This would normally be
+  // slightly different from the distance to the actual eye.
+  float virtual_eye_to_screen_dist = mount.GetVirtualEyeToScreenDistance();
+  float meters_per_tan_angle = virtual_eye_to_screen_dist;
+  vec2 pixels_per_tan_angle = pixels_per_meter * meters_per_tan_angle;
+
+  CHECK_NE(0.0f, display_width_meters);
+  CHECK_NE(0.0f, display_height_meters);
+  CHECK_NE(0.0f, virtual_eye_to_screen_dist);
+
+  // Height of lenses from the bottom of the screen.
+  float lens_y_center = 0;
+  float bottom_dist = 0;
+  float top_dist = 0;
+
+  // bottom_display_dist and top_display_dist represent the distance from the
+  // lens center to the edge of the display.
+  float bottom_display_dist = 0;
+  float top_display_dist = 0;
+  switch (mount.GetVerticalAlignment()) {
+    case HeadMountMetrics::kBottom:
+      lens_y_center =
+          mount.GetTrayToLensDistance() - display.GetBorderSizeMeters();
+      bottom_dist = lens_y_center;
+      top_dist = lens_y_center;
+      bottom_display_dist = lens_y_center;
+      top_display_dist = display_height_meters - lens_y_center;
+      break;
+    case HeadMountMetrics::kCenter:
+      // TODO(hendrikw): This should respect the border size, but since we
+      //                 currently hard code the border size, it would break
+      //                 the distortion on some devices.  Revisit when border
+      //                 size is fixed.
+      lens_y_center = display_height_meters * 0.5f;
+      bottom_dist = lens_y_center;
+      top_dist = lens_y_center;
+      bottom_display_dist = lens_y_center;
+      top_display_dist = lens_y_center;
+      break;
+    case HeadMountMetrics::kTop:
+      lens_y_center = display_height_meters - (mount.GetTrayToLensDistance() -
+                                               display.GetBorderSizeMeters());
+      bottom_dist =
+          mount.GetTrayToLensDistance() - display.GetBorderSizeMeters();
+      top_dist = bottom_dist;
+      bottom_display_dist = lens_y_center;
+      top_display_dist = display_height_meters - lens_y_center;
+      break;
+  }
+
+  float inner_dist = mount.GetScreenCenterToLensDistance();
+  float outer_dist = display_width_meters * 0.5f - inner_dist;
+
+  // We don't take chromatic aberration into account yet for computing FOV,
+  // viewport, etc, so we only use the green channel for now. Note the actual
+  // Distort function *does* implement chromatic aberration.
+  const ColorChannelDistortion& distortion =
+      mount.GetColorChannelDistortion(kGreen);
+
+  vec2 outer_point(outer_dist / virtual_eye_to_screen_dist, 0.0f);
+  vec2 inner_point(inner_dist / virtual_eye_to_screen_dist, 0.0f);
+  vec2 bottom_point(0.0f, bottom_dist / virtual_eye_to_screen_dist);
+  vec2 top_point(0.0f, top_dist / virtual_eye_to_screen_dist);
+
+  float outer_angle = atanf(distortion.Distort(outer_point)[0]);
+  float inner_angle = atanf(distortion.Distort(inner_point)[0]);
+  float bottom_angle = atanf(distortion.Distort(bottom_point)[1]);
+  float top_angle = atanf(distortion.Distort(top_point)[1]);
+
+  for (EyeType eye : {kLeftEye, kRightEye}) {
+    const FieldOfView max_fov = mount.GetEyeMaxFov(eye);
+    float left_angle = (eye == kLeftEye) ? outer_angle : inner_angle;
+    float right_angle = (eye == kLeftEye) ? inner_angle : outer_angle;
+
+    eye_fov_[eye] = FieldOfView(std::min(left_angle, max_fov.GetLeft()),
+                                std::min(right_angle, max_fov.GetRight()),
+                                std::min(bottom_angle, max_fov.GetBottom()),
+                                std::min(top_angle, max_fov.GetTop()));
+
+    vec2 texture_vp_ta_p1 =
+        vec2(-tanf(eye_fov_[eye].GetLeft()), -tanf(eye_fov_[eye].GetBottom()));
+    vec2 texture_vp_ta_p2 =
+        vec2(tanf(eye_fov_[eye].GetRight()), tanf(eye_fov_[eye].GetTop()));
+    vec2 texture_vp_size_ta = texture_vp_ta_p2 - texture_vp_ta_p1;
+
+    vec2 texture_vp_sizef_pixels =
+        texture_vp_size_ta.array() * pixels_per_tan_angle.array();
+
+    vec2i texture_vp_size_pixels =
+        vec2i(static_cast<int32_t>(roundf(texture_vp_sizef_pixels[0])),
+              static_cast<int32_t>(roundf(texture_vp_sizef_pixels[1])));
+    int vp_start_x =
+        (eye == kLeftEye) ? 0 : eye_viewport_range_[kLeftEye].p2[0];
+
+    eye_viewport_range_[eye] =
+        Range2i::FromSize(vec2i(vp_start_x, 0), texture_vp_size_pixels);
+    float left_dist = (eye == kLeftEye) ? outer_dist : inner_dist;
+    float right_dist = (eye == kLeftEye) ? inner_dist : outer_dist;
+    vec2 screen_ta_p1(-left_dist / virtual_eye_to_screen_dist,
+                      -bottom_display_dist / virtual_eye_to_screen_dist);
+    vec2 screen_ta_p2(right_dist / virtual_eye_to_screen_dist,
+                      top_display_dist / virtual_eye_to_screen_dist);
+    vec2 screen_ta_size = screen_ta_p2 - screen_ta_p1;
+
+    // Align the tan angle coordinates to the nearest pixel.  This will ensure
+    // that the optical center doesn't straddle multiple pixels.
+    // TODO(hendrikw): verify that this works correctly for Daydream View.
+    vec2 tan_angle_per_pixel(screen_ta_size.array() /
+                             texture_vp_size_pixels.cast<float>().array());
+    vec2 pixel_p1(screen_ta_p1.array() / tan_angle_per_pixel.array());
+    vec2 pixel_shift(roundf(pixel_p1.x()) - pixel_p1.x(),
+                     roundf(pixel_p1.y()) - pixel_p1.y());
+    screen_ta_p1 +=
+        (tan_angle_per_pixel.array() * pixel_shift.array()).matrix();
+    screen_ta_p2 +=
+        (tan_angle_per_pixel.array() * pixel_shift.array()).matrix();
+
+    // Calculate the transformations needed for the distortions.
+    eye_tan_angle_from_norm_screen_matrix_[eye] =
+        TranslationMatrix(vec2(screen_ta_p1)) *
+        ScaleMatrix(screen_ta_size);
+    eye_tan_angle_from_norm_screen_inv_matrix_[eye] =
+        eye_tan_angle_from_norm_screen_matrix_[eye].inverse();
+
+    eye_norm_texture_from_tan_angle_inv_matrix_[eye] =
+        TranslationMatrix(texture_vp_ta_p1) *
+        ScaleMatrix(texture_vp_size_ta);
+    eye_norm_texture_from_tan_angle_matrix_[eye] =
+        eye_norm_texture_from_tan_angle_inv_matrix_[eye].inverse();
+  }
+  vec2i left_vp_size = eye_viewport_range_[kLeftEye].GetSize();
+  vec2i right_vp_size = eye_viewport_range_[kRightEye].GetSize();
+
+  recommended_render_target_size_ =
+      vec2i(left_vp_size[0] + right_vp_size[0],
+            std::max(left_vp_size[1], right_vp_size[1]));
+
+  display_range_ = Range2i::FromSize(vec2i(0, 0), display.GetSizePixels());
+
+  eye_from_head_matrix_[kLeftEye] = Eigen::Translation3f(
+      vec3(mount.GetScreenCenterToLensDistance(), 0.0f, 0.0f));
+  eye_from_head_matrix_[kRightEye] = Eigen::Translation3f(
+      vec3(-mount.GetScreenCenterToLensDistance(), 0.0f, 0.0f));
+}
+
+}  // namespace dvr
+}  // namespace android