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/libdvrgraphics/blur.cpp b/libs/vr/libdvrgraphics/blur.cpp
new file mode 100644
index 0000000..7365b0e
--- /dev/null
+++ b/libs/vr/libdvrgraphics/blur.cpp
@@ -0,0 +1,247 @@
+#include "include/private/dvr/graphics/blur.h"
+
+// clang-format off
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+// clang-format on
+#include <hardware/gralloc.h>
+
+#include <string>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <private/dvr/debug.h>
+#include <private/dvr/graphics/egl_image.h>
+#include <private/dvr/graphics/shader_program.h>
+#include <private/dvr/types.h>
+
+#define POSITION_ATTR 0
+#define OFFSET_BINDING 0
+#define SAMPLER_BINDING 1
+
+namespace {
+
+std::string screen_space_vert_shader = SHADER0([]() {  // NOLINT
+  layout(location = 0) in vec4 position_uv;
+  out vec2 texCoords;
+
+  void main() {
+    gl_Position = vec4(position_uv.xy, 0.0, 1.0);
+    texCoords = position_uv.zw;
+  }
+});
+
+std::string kawase_blur_frag_shader = SHADER0([]() {  // NOLINT
+  precision mediump float;
+  layout(location = 0) uniform vec2 uSampleOffsets[4];
+  layout(binding = 1) uniform APP_SAMPLER_2D uTexture;
+  in vec2 texCoords;
+  out vec4 color;
+
+  void main() {
+    vec2 tc = texCoords;
+    color = texture(uTexture, tc + uSampleOffsets[0]);
+    color += texture(uTexture, tc + uSampleOffsets[1]);
+    color += texture(uTexture, tc + uSampleOffsets[2]);
+    color += texture(uTexture, tc + uSampleOffsets[3]);
+    color *= (1.0 / 4.0);
+  }
+});
+
+constexpr int g_num_samples = 4;
+
+// Modified kernel patterns originally based on:
+// https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms
+// The modification is left and right rotations of the 3rd and 4th patterns.
+const android::dvr::vec2 g_blur_samples[][g_num_samples] = {
+    {{0.5f, 0.5f}, {-0.5f, 0.5f}, {0.5f, -0.5f}, {-0.5f, -0.5f}},
+    {{1.5f, 1.5f}, {-1.5f, 1.5f}, {1.5f, -1.5f}, {-1.5f, -1.5f}},
+    {{2.5f, 1.5f}, {-1.5f, 2.5f}, {1.5f, -2.5f}, {-2.5f, -1.5f}},
+    {{2.5f, 3.5f}, {-3.5f, 2.5f}, {3.5f, -2.5f}, {-2.5f, -3.5f}},
+    // Last pass disabled, because it is more blur than we need.
+    // {{3.5f, 3.5f}, {-3.5f, 3.5f}, {3.5f, -3.5f}, {-3.5f, -3.5f}},
+};
+
+}  // namespace
+
+namespace android {
+namespace dvr {
+
+Blur::Blur(int w, int h, GLuint source_texture, GLint source_texture_target,
+           GLint target_texture_target, bool is_external, EGLDisplay display,
+           int num_blur_outputs)
+    : display_(display),
+      target_texture_target_(target_texture_target),
+      width_(w),
+      height_(h),
+      fbo_q_free_(1 + num_blur_outputs) {
+  CHECK(num_blur_outputs > 0);
+  source_fbo_ =
+      CreateFbo(w, h, source_texture, source_texture_target, is_external);
+  fbo_half_ = CreateFbo(w / 2, h / 2, 0, target_texture_target, is_external);
+  // Create the quarter res fbos.
+  for (size_t i = 0; i < fbo_q_free_.GetCapacity(); ++i)
+    fbo_q_.push_back(
+        CreateFbo(w / 4, h / 4, 0, target_texture_target, is_external));
+  scale_ = 1.0f;
+}
+
+Blur::~Blur() {
+  glFinish();
+  glDeleteFramebuffers(1, &source_fbo_.fbo);
+  glDeleteFramebuffers(1, &fbo_half_.fbo);
+  // Note: source_fbo_.texture is not deleted because it was created externally.
+  glDeleteTextures(1, &fbo_half_.texture);
+  if (fbo_half_.egl_image)
+    eglDestroyImageKHR(display_, fbo_half_.egl_image);
+  for (const auto& fbo : fbo_q_) {
+    glDeleteFramebuffers(1, &fbo.fbo);
+    glDeleteTextures(1, &fbo.texture);
+    if (fbo.egl_image)
+      eglDestroyImageKHR(display_, fbo.egl_image);
+  }
+  CHECK_GL();
+}
+
+void Blur::StartFrame() {
+  fbo_q_free_.Clear();
+  for (const auto& fbo : fbo_q_)
+    fbo_q_free_.Append(fbo);
+}
+
+GLuint Blur::DrawBlur(GLuint source_texture) {
+  CHECK(fbo_q_free_.GetSize() >= 2);
+
+  // Downsample to half w x half h.
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, source_fbo_.fbo);
+  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_half_.fbo);
+  glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                         target_texture_target_, source_texture, 0);
+  glBlitFramebuffer(0, 0, width_, height_, 0, 0, width_ / 2, height_ / 2,
+                    GL_COLOR_BUFFER_BIT, GL_LINEAR);
+  CHECK_GL();
+
+  // Downsample to quarter w x quarter h.
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_half_.fbo);
+  Fbo fbo_out = fbo_q_free_.Front();
+  fbo_q_free_.PopFront();
+  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_out.fbo);
+  glBlitFramebuffer(0, 0, width_ / 2, height_ / 2, 0, 0, width_ / 4,
+                    height_ / 4, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+  CHECK_GL();
+
+  // Blur shader is initialized statically to share between multiple blur
+  // instances.
+  static ShaderProgram kawase_prog[2];
+  int prog_index = (target_texture_target_ == GL_TEXTURE_EXTERNAL_OES) ? 1 : 0;
+  if (!kawase_prog[prog_index].IsUsable()) {
+    std::string prefix = "#version 310 es\n";
+    if (target_texture_target_ == GL_TEXTURE_EXTERNAL_OES) {
+      prefix += "#extension GL_OES_EGL_image_external_essl3 : require\n";
+      prefix += "#define APP_SAMPLER_2D samplerExternalOES\n";
+    } else {
+      prefix += "#define APP_SAMPLER_2D sampler2D\n";
+    }
+    std::string vert = prefix + screen_space_vert_shader;
+    std::string frag = prefix + kawase_blur_frag_shader;
+    kawase_prog[prog_index].Link(vert, frag);
+    CHECK_GL();
+  }
+
+  int blur_w = width_ / 4;
+  int blur_h = height_ / 4;
+  float pix_w = 1.0f / static_cast<float>(blur_w);
+  float pix_h = 1.0f / static_cast<float>(blur_h);
+  vec2 pixel_size(pix_w, pix_h);
+  constexpr int num_passes = sizeof(g_blur_samples) / sizeof(g_blur_samples[0]);
+  vec2 blur_offsets[num_passes][g_num_samples];
+  for (int i = 0; i < num_passes; ++i) {
+    for (int dir = 0; dir < g_num_samples; ++dir) {
+      blur_offsets[i][dir] = pixel_size.array() *
+          g_blur_samples[i][dir].array() * scale_;
+    }
+  }
+
+  kawase_prog[prog_index].Use();
+
+  vec4 screen_tri_strip[4] = {vec4(-1, 1, 0, 1), vec4(-1, -1, 0, 0),
+                              vec4(1, 1, 1, 1), vec4(1, -1, 1, 0)};
+
+  glViewport(0, 0, blur_w, blur_h);
+  glVertexAttribPointer(POSITION_ATTR, 4, GL_FLOAT, GL_FALSE, sizeof(vec4),
+                        screen_tri_strip);
+  glEnableVertexAttribArray(POSITION_ATTR);
+  CHECK_GL();
+
+  // Ping-pong between fbos from fbo_q_free_ to compute the passes.
+  Fbo fbo_in = fbo_out;
+  for (int i = 0; i < num_passes; ++i) {
+    fbo_out = fbo_q_free_.Front();
+    fbo_q_free_.PopFront();
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo_out.fbo);
+    glActiveTexture(GL_TEXTURE0 + SAMPLER_BINDING);
+    glBindTexture(target_texture_target_, fbo_in.texture);
+    glUniform2fv(OFFSET_BINDING, 4, &blur_offsets[i][0][0]);
+    glClear(GL_COLOR_BUFFER_BIT);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    CHECK_GL();
+    // Put fbo_in back into the free fbo pool.
+    fbo_q_free_.Append(fbo_in);
+    // Next iteration's in buffer is this iteration's out buffer.
+    fbo_in = fbo_out;
+  }
+  glDisableVertexAttribArray(POSITION_ATTR);
+  glBindTexture(target_texture_target_, 0);
+  glUseProgram(0);
+  glActiveTexture(GL_TEXTURE0);
+  CHECK_GL();
+  // fbo_out remains out of the fbo_q_free_ list, since the application will be
+  // using it as a texture.
+  return fbo_out.texture;
+}
+
+Blur::Fbo Blur::CreateFbo(int w, int h, GLuint source_texture, GLint tex_target,
+                          bool is_external) {
+  Fbo fbo;
+  glGenFramebuffers(1, &fbo.fbo);
+  if (source_texture) {
+    fbo.texture = source_texture;
+  } else {
+    glGenTextures(1, &fbo.texture);
+  }
+
+  glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
+  CHECK_GL();
+
+  if (!source_texture) {
+    glBindTexture(tex_target, fbo.texture);
+    glTexParameteri(tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    if (is_external) {
+      fbo.egl_image =
+          CreateEglImage(display_, w, h, HAL_PIXEL_FORMAT_RGBA_8888,
+                         GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER);
+      glEGLImageTargetTexture2DOES(tex_target, fbo.egl_image);
+    } else {
+      glTexImage2D(tex_target, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                   nullptr);
+    }
+  }
+  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_target,
+                         fbo.texture, 0);
+  CHECK_GL();
+  CHECK_GL_FBO();
+
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+  return fbo;
+}
+
+}  // namespace dvr
+}  // namespace android