// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "garnet/public/lib/escher/hmd/pose_buffer_latching_shader.h"

#include "garnet/public/lib/escher/escher.h"
#include "garnet/public/lib/escher/hmd/pose_buffer.h"
#include "garnet/public/lib/escher/renderer/frame.h"
#include "garnet/public/lib/escher/resources/resource_recycler.h"
#include "garnet/public/lib/escher/scene/camera.h"
#include "garnet/public/lib/escher/vk/buffer.h"
#include "garnet/public/lib/escher/vk/gpu_allocator.h"
#include "garnet/public/lib/escher/vk/texture.h"

namespace escher {
namespace hmd {

namespace {
constexpr char g_kernel_src[] = R"GLSL(
  #version 450
  #extension GL_ARB_separate_shader_objects : enable

  struct Pose {
    vec4 quaternion;
    vec3 position;
    uint reserved;
  };

  layout(push_constant) uniform PushConstants {
    uint latch_index;
  };

  layout (binding = 0) uniform VPMatrices {
    mat4 left_view_transform;
    mat4 left_projection_matrix;
    mat4 right_view_transform;
    mat4 right_projection_matrix;
  };

  layout (binding = 1) buffer PoseBuffer {
    Pose poses[];
  };

  layout (binding = 2) buffer OutputBuffer {
    Pose latched_pose;
    mat4 left_vp_matrix;
    mat4 right_vp_matrix;
  };

  // interpreted from GLM's mat3_cast
  mat3 quaternion_to_mat3(vec4 q)
  {
    mat3 result;
    float qxx = q.x * q.x;
    float qyy = q.y * q.y;
    float qzz = q.z * q.z;
    float qxz = q.x * q.z;
    float qxy = q.x * q.y;
    float qyz = q.y * q.z;
    float qwx = q.w * q.x;
    float qwy = q.w * q.y;
    float qwz = q.w * q.z;

    result[0][0] = float(1) - float(2) * (qyy +  qzz);
    result[0][1] = float(2) * (qxy + qwz);
    result[0][2] = float(2) * (qxz - qwy);

    result[1][0] = float(2) * (qxy - qwz);
    result[1][1] = float(1) - float(2) * (qxx +  qzz);
    result[1][2] = float(2) * (qyz + qwx);

    result[2][0] = float(2) * (qxz + qwy);
    result[2][1] = float(2) * (qyz - qwx);
    result[2][2] = float(1) - float(2) * (qxx +  qyy);

    return result;
  }

  mat4 translate(vec3 t){
    return mat4(
        vec4(1.0, 0.0, 0.0, 0.0),
        vec4(0.0, 1.0, 0.0, 0.0),
        vec4(0.0, 0.0, 1.0, 0.0),
        vec4(t.x, t.y, t.z, 1.0)
    );
  }

  void main() {
    latched_pose = poses[latch_index];
    left_vp_matrix = left_projection_matrix *
                mat4(quaternion_to_mat3(latched_pose.quaternion)) *
                translate(latched_pose.position) * left_view_transform;

    right_vp_matrix = right_projection_matrix *
                mat4(quaternion_to_mat3(latched_pose.quaternion)) *
                translate(latched_pose.position) * right_view_transform;
  }
  )GLSL";
}

static constexpr size_t k4x4MatrixSize = 16 * sizeof(float);

PoseBufferLatchingShader::PoseBufferLatchingShader(EscherWeakPtr escher)
    : escher_(std::move(escher)) {}

BufferPtr PoseBufferLatchingShader::LatchPose(const FramePtr& frame,
                                              const Camera& camera,
                                              PoseBuffer pose_buffer,
                                              int64_t latch_time,
                                              bool host_accessible_output) {
  return LatchStereoPose(frame, camera, camera, pose_buffer, latch_time,
                         host_accessible_output);
}

BufferPtr PoseBufferLatchingShader::LatchStereoPose(
    const FramePtr& frame, const Camera& left_camera,
    const Camera& right_camera, PoseBuffer pose_buffer, int64_t latch_time,
    bool host_accessible_output) {
  vk::DeviceSize buffer_size = 2 * k4x4MatrixSize + sizeof(Pose);

  const vk::MemoryPropertyFlags kOutputMemoryPropertyFlags =
      host_accessible_output ? (vk::MemoryPropertyFlagBits::eHostVisible |
                                vk::MemoryPropertyFlagBits::eHostCoherent)
                             : (vk::MemoryPropertyFlagBits::eDeviceLocal);
  const vk::BufferUsageFlags kOutputBufferUsageFlags =
      vk::BufferUsageFlagBits::eUniformBuffer |
      vk::BufferUsageFlagBits::eStorageBuffer;

  auto output_buffer = frame->gpu_allocator()->AllocateBuffer(
      escher_->resource_recycler(), buffer_size, kOutputBufferUsageFlags,
      kOutputMemoryPropertyFlags);

  const vk::MemoryPropertyFlags kVpMemoryPropertyFlags =
      vk::MemoryPropertyFlagBits::eHostVisible |
      vk::MemoryPropertyFlagBits::eHostCoherent;
  const vk::BufferUsageFlags kVpBufferUsageFlags =
      vk::BufferUsageFlagBits::eUniformBuffer;

  auto vp_matrices_buffer = frame->gpu_allocator()->AllocateBuffer(
      escher_->resource_recycler(), 4 * k4x4MatrixSize, kVpBufferUsageFlags,
      kVpMemoryPropertyFlags);

  auto command_buffer = frame->command_buffer();

  // This should be guaranteed by checks at a higher layer.  For example,
  // Scenic checks this in Session::ApplySetCamerPoseBufferCmd().
  FXL_DCHECK(latch_time >= pose_buffer.base_time);

  uint32_t latch_index =
      ((latch_time - pose_buffer.base_time) / pose_buffer.time_interval) %
      pose_buffer.num_entries;

  FXL_DCHECK(vp_matrices_buffer->host_ptr() != nullptr);
  glm::mat4* vp_matrices =
      reinterpret_cast<glm::mat4*>(vp_matrices_buffer->host_ptr());
  vp_matrices[0] = left_camera.transform();
  vp_matrices[1] = left_camera.projection();
  vp_matrices[2] = right_camera.transform();
  vp_matrices[3] = right_camera.projection();

  if (!kernel_) {
    kernel_ = std::make_unique<impl::ComputeShader>(
        escher_, std::vector<vk::ImageLayout>{},
        std::vector<vk::DescriptorType>{vk::DescriptorType::eUniformBuffer,
                                        vk::DescriptorType::eStorageBuffer,
                                        vk::DescriptorType::eStorageBuffer},
        sizeof(latch_index), g_kernel_src);
  }

  std::vector<TexturePtr> textures;
  std::vector<BufferPtr> buffers;
  buffers.push_back(vp_matrices_buffer);
  buffers.push_back(pose_buffer.buffer);
  buffers.push_back(output_buffer);

  kernel_->Dispatch(textures, buffers, command_buffer, 1, 1, 1, &latch_index);

  return output_buffer;
}
}  // namespace hmd
}  // namespace escher
