// Copyright 2013 The Flutter 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 "impeller/renderer/backend/vulkan/render_pass_vk.h"

#include <array>
#include <cstdint>
#include <vector>

#include "fml/logging.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/device_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/formats_vk.h"
#include "impeller/renderer/backend/vulkan/pipeline_vk.h"
#include "impeller/renderer/backend/vulkan/sampler_vk.h"
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "impeller/renderer/sampler.h"
#include "impeller/renderer/shader_types.h"
#include "vulkan/vulkan_enums.hpp"
#include "vulkan/vulkan_structs.hpp"

namespace impeller {

static vk::AttachmentDescription CreateAttachmentDescription(
    const Attachment& attachment,
    AttachmentKind kind,
    bool resolve_texture = false) {
  const auto& texture = resolve_texture
                            ? attachment.resolve_texture->GetTextureDescriptor()
                            : attachment.texture->GetTextureDescriptor();
  return CreateAttachmentDescription(texture.format,          //
                                     texture.sample_count,    //
                                     kind,                    //
                                     attachment.load_action,  //
                                     attachment.store_action  //
  );
}

static vk::UniqueRenderPass CreateVKRenderPass(const vk::Device& device,
                                               const RenderTarget& target) {
  std::vector<vk::AttachmentDescription> attachments;

  std::vector<vk::AttachmentReference> color_refs;
  std::vector<vk::AttachmentReference> resolve_refs;
  vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference;

  // Spec says: "Each element of the pColorAttachments array corresponds to an
  // output location in the shader, i.e. if the shader declares an output
  // variable decorated with a Location value of X, then it uses the attachment
  // provided in pColorAttachments[X]. If the attachment member of any element
  // of pColorAttachments is VK_ATTACHMENT_UNUSED."
  //
  // Just initialize all the elements as unused and fill in the valid bind
  // points in the loop below.
  color_refs.resize(target.GetMaxColorAttacmentBindIndex() + 1u,
                    kUnusedAttachmentReference);
  resolve_refs.resize(target.GetMaxColorAttacmentBindIndex() + 1u,
                      kUnusedAttachmentReference);

  for (const auto& [bind_point, color] : target.GetColorAttachments()) {
    color_refs[bind_point] =
        vk::AttachmentReference{static_cast<uint32_t>(attachments.size()),
                                vk::ImageLayout::eColorAttachmentOptimal};
    attachments.emplace_back(
        CreateAttachmentDescription(color, AttachmentKind::kColor));
    if (color.resolve_texture) {
      resolve_refs[bind_point] =
          vk::AttachmentReference{static_cast<uint32_t>(attachments.size()),
                                  vk::ImageLayout::eColorAttachmentOptimal};
      attachments.emplace_back(
          CreateAttachmentDescription(color, AttachmentKind::kColor, true));
    }
  }

  if (auto depth = target.GetDepthAttachment(); depth.has_value()) {
    depth_stencil_ref = vk::AttachmentReference{
        static_cast<uint32_t>(attachments.size()),
        vk::ImageLayout::eDepthStencilAttachmentOptimal};
    attachments.emplace_back(
        CreateAttachmentDescription(depth.value(), AttachmentKind::kDepth));
  } else if (auto stencil = target.GetStencilAttachment();
             stencil.has_value()) {
    depth_stencil_ref = vk::AttachmentReference{
        static_cast<uint32_t>(attachments.size()),
        vk::ImageLayout::eDepthStencilAttachmentOptimal};
    attachments.emplace_back(
        CreateAttachmentDescription(stencil.value(), AttachmentKind::kStencil));
  }

  vk::SubpassDescription subpass_desc;
  subpass_desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
  subpass_desc.setColorAttachments(color_refs);
  subpass_desc.setResolveAttachments(resolve_refs);
  subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref);

  vk::RenderPassCreateInfo render_pass_desc;
  render_pass_desc.setAttachments(attachments);
  render_pass_desc.setPSubpasses(&subpass_desc);
  render_pass_desc.setSubpassCount(1u);

  auto [result, pass] = device.createRenderPassUnique(render_pass_desc);
  if (result != vk::Result::eSuccess) {
    VALIDATION_LOG << "Failed to create render pass: " << vk::to_string(result);
    return {};
  }

  return std::move(pass);
}

RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
                           const RenderTarget& target,
                           std::weak_ptr<CommandEncoderVK> encoder)
    : RenderPass(context, target),
      render_pass_(
          CreateVKRenderPass(ContextVK::Cast(*context).GetDevice(), target)),
      encoder_(std::move(encoder)) {
  if (!render_pass_) {
    return;
  }
  is_valid_ = true;
}

RenderPassVK::~RenderPassVK() = default;

bool RenderPassVK::IsValid() const {
  return is_valid_;
}

void RenderPassVK::OnSetLabel(std::string label) {
  auto context = GetContext().lock();
  if (!context) {
    return;
  }
  ContextVK::Cast(*context).SetDebugName(*render_pass_, label.c_str());
  debug_label_ = std::move(label);
}

static vk::ClearColorValue VKClearValueFromColor(Color color) {
  vk::ClearColorValue value;
  value.setFloat32(
      std::array<float, 4>{color.red, color.green, color.blue, color.alpha});
  return value;
}

static vk::ClearDepthStencilValue VKClearValueFromDepth(Scalar depth) {
  vk::ClearDepthStencilValue value;
  value.depth = depth;
  return value;
}

static vk::ClearDepthStencilValue VKClearValueFromStencil(uint32_t stencil) {
  vk::ClearDepthStencilValue value;
  value.stencil = stencil;
  return value;
}

static std::vector<vk::ClearValue> GetVKClearValues(
    const RenderTarget& target) {
  std::vector<vk::ClearValue> clears;

  for (const auto& [_, color] : target.GetColorAttachments()) {
    clears.emplace_back(VKClearValueFromColor(color.clear_color));
    if (color.resolve_texture) {
      clears.emplace_back(VKClearValueFromColor(color.clear_color));
    }
  }

  if (auto depth = target.GetDepthAttachment(); depth.has_value()) {
    clears.emplace_back(VKClearValueFromDepth(depth->clear_depth));
  }

  if (auto stencil = target.GetStencilAttachment(); stencil.has_value()) {
    clears.emplace_back(VKClearValueFromStencil(stencil->clear_stencil));
  }

  return clears;
}

static vk::UniqueFramebuffer CreateFramebuffer(const vk::Device& device,
                                               const RenderTarget& target,
                                               const vk::RenderPass& pass) {
  vk::FramebufferCreateInfo fb_info;

  fb_info.renderPass = pass;

  const auto target_size = target.GetRenderTargetSize();
  fb_info.width = target_size.width;
  fb_info.height = target_size.height;

  fb_info.layers = 1u;

  std::vector<vk::ImageView> attachments;

  // This bit must be consistent to ensure compatibility with the pass created
  // earlier. Follow this order: Color attachments, then depth, then stencil.
  for (const auto& [_, color] : target.GetColorAttachments()) {
    // The bind point doesn't matter here since that information is present in
    // the render pass.
    attachments.emplace_back(TextureVK::Cast(*color.texture).GetImageView());
    if (color.resolve_texture) {
      attachments.emplace_back(
          TextureVK::Cast(*color.resolve_texture).GetImageView());
    }
  }
  if (auto depth = target.GetDepthAttachment(); depth.has_value()) {
    attachments.emplace_back(TextureVK::Cast(*depth->texture).GetImageView());
  }
  if (auto stencil = target.GetStencilAttachment(); stencil.has_value()) {
    attachments.emplace_back(TextureVK::Cast(*stencil->texture).GetImageView());
  }

  fb_info.setAttachments(attachments);

  auto [result, framebuffer] = device.createFramebufferUnique(fb_info);

  if (result != vk::Result::eSuccess) {
    VALIDATION_LOG << "Could not create framebuffer: " << vk::to_string(result);
    return {};
  }

  return std::move(framebuffer);
}

static bool ConfigureRenderTargetAttachmentLayouts(
    const RenderTarget& target,
    const vk::CommandBuffer& command_buffer) {
  for (const auto& [_, color] : target.GetColorAttachments()) {
    if (!TextureVK::Cast(*color.texture)
             .SetLayout(vk::ImageLayout::eColorAttachmentOptimal,
                        command_buffer)) {
      return false;
    }
    if (color.resolve_texture) {
      if (!TextureVK::Cast(*color.resolve_texture)
               .SetLayout(vk::ImageLayout::eColorAttachmentOptimal,
                          command_buffer)) {
        return false;
      }
    }
  }
  if (auto depth = target.GetDepthAttachment(); depth.has_value()) {
    if (!TextureVK::Cast(*depth->texture)
             .SetLayout(vk::ImageLayout::eDepthAttachmentOptimal,
                        command_buffer)) {
      return false;
    }
  }
  if (auto stencil = target.GetStencilAttachment(); stencil.has_value()) {
    if (!TextureVK::Cast(*stencil->texture)
             .SetLayout(vk::ImageLayout::eStencilAttachmentOptimal,
                        command_buffer)) {
      return false;
    }
  }
  return true;
}

static bool UpdateBindingLayouts(const Bindings& bindings,
                                 const vk::CommandBuffer& buffer) {
  for (const auto& [_, texture] : bindings.textures) {
    if (!TextureVK::Cast(*texture.resource)
             .SetLayout(vk::ImageLayout::eShaderReadOnlyOptimal, buffer)) {
      return false;
    }
  }
  return true;
}

static bool UpdateBindingLayouts(const Command& command,
                                 const vk::CommandBuffer& buffer) {
  return UpdateBindingLayouts(command.vertex_bindings, buffer) &&
         UpdateBindingLayouts(command.fragment_bindings, buffer);
}

static bool UpdateBindingLayouts(const std::vector<Command>& commands,
                                 const vk::CommandBuffer& buffer) {
  for (const auto& command : commands) {
    if (!UpdateBindingLayouts(command, buffer)) {
      return false;
    }
  }
  return true;
}

static bool UpdateDescriptorSets(vk::Device device,
                                 const Bindings& bindings,
                                 Allocator& allocator,
                                 vk::DescriptorSet desc_set,
                                 CommandEncoderVK& encoder) {
  std::vector<vk::WriteDescriptorSet> writes;

  //----------------------------------------------------------------------------
  /// Setup buffer descriptors.
  ///
  std::vector<vk::DescriptorBufferInfo> buffer_desc;
  for (const auto& [buffer_index, view] : bindings.buffers) {
    const auto& buffer_view = view.resource.buffer;

    auto device_buffer = buffer_view->GetDeviceBuffer(allocator);
    if (!device_buffer) {
      VALIDATION_LOG << "Failed to get device buffer for vertex binding";
      return false;
    }

    auto buffer = DeviceBufferVK::Cast(*device_buffer).GetVKBufferHandle();
    if (!buffer) {
      return false;
    }

    // Reserved index used for per-vertex data.
    if (buffer_index == VertexDescriptor::kReservedVertexBufferIndex) {
      continue;
    }

    if (!encoder.Track(device_buffer)) {
      return false;
    }

    uint32_t offset = view.resource.range.offset;

    vk::DescriptorBufferInfo desc_buffer_info;
    desc_buffer_info.setBuffer(buffer);
    desc_buffer_info.setOffset(offset);
    desc_buffer_info.setRange(view.resource.range.length);
    buffer_desc.push_back(desc_buffer_info);

    const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index);

    vk::WriteDescriptorSet write_set;
    write_set.setDstSet(desc_set);
    write_set.setDstBinding(uniform.binding);
    write_set.setDescriptorCount(1);
    write_set.setDescriptorType(vk::DescriptorType::eUniformBuffer);
    write_set.setPBufferInfo(&buffer_desc.back());

    writes.push_back(write_set);
  }

  //----------------------------------------------------------------------------
  /// Setup image descriptors.
  ///
  std::vector<vk::DescriptorImageInfo> image_descs;
  for (const auto& [index, sampler_handle] : bindings.samplers) {
    if (bindings.textures.find(index) == bindings.textures.end()) {
      VALIDATION_LOG << "Missing texture for sampler: " << index;
      return false;
    }

    auto texture = bindings.textures.at(index).resource;
    const auto& texture_vk = TextureVK::Cast(*texture);
    const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource);

    if (!encoder.Track(texture) || !encoder.Track(sampler.GetSharedSampler())) {
      return false;
    }

    const SampledImageSlot& slot = bindings.sampled_images.at(index);

    vk::DescriptorImageInfo desc_image_info;
    desc_image_info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
    desc_image_info.setSampler(sampler.GetSamplerVK());
    desc_image_info.setImageView(texture_vk.GetImageView());
    image_descs.push_back(desc_image_info);

    vk::WriteDescriptorSet write_set;
    write_set.setDstSet(desc_set);
    write_set.setDstBinding(slot.binding);
    write_set.setDescriptorCount(1);
    write_set.setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
    write_set.setPImageInfo(&image_descs.back());

    writes.push_back(write_set);
  }

  if (writes.empty()) {
    return true;
  }
  device.updateDescriptorSets(writes, {});
  return true;
}

static bool AllocateAndBindDescriptorSets(
    const ContextVK& context,
    const Command& command,
    CommandEncoderVK& encoder,
    PipelineCreateInfoVK* pipeline_create_info) {
  auto& allocator = *context.GetResourceAllocator();
  vk::PipelineLayout pipeline_layout =
      pipeline_create_info->GetPipelineLayout();

  vk::DescriptorSetAllocateInfo alloc_info;
  std::array<vk::DescriptorSetLayout, 1> dsls = {
      pipeline_create_info->GetDescriptorSetLayout(),
  };

  alloc_info.setDescriptorPool(context.GetDescriptorPool());
  alloc_info.setSetLayouts(dsls);

  auto [sets_result, sets] =
      context.GetDevice().allocateDescriptorSetsUnique(alloc_info);
  if (sets_result != vk::Result::eSuccess) {
    VALIDATION_LOG << "Failed to allocate descriptor sets: "
                   << vk::to_string(sets_result);
    return false;
  }

  const auto set = MakeSharedVK<vk::DescriptorSet>(std::move(sets[0]));

  if (!encoder.Track(set)) {
    return false;
  }

  bool update_vertex_descriptors =
      UpdateDescriptorSets(context.GetDevice(),      //
                           command.vertex_bindings,  //
                           allocator,                //
                           *set,                     //
                           encoder                   //
      );
  if (!update_vertex_descriptors) {
    return false;
  }
  bool update_frag_descriptors =
      UpdateDescriptorSets(context.GetDevice(),        //
                           command.fragment_bindings,  //
                           allocator,                  //
                           *set,                       //
                           encoder                     //
      );
  if (!update_frag_descriptors) {
    return false;
  }

  encoder.GetCommandBuffer().bindDescriptorSets(
      vk::PipelineBindPoint::eGraphics,  // bind point
      pipeline_layout,                   // layout
      0,                                 // first set
      {vk::DescriptorSet{*set}},         // sets
      nullptr                            // offsets
  );
  return true;
}

static void SetViewportAndScissor(const Command& command,
                                  const vk::CommandBuffer& cmd_buffer,
                                  const ISize& target_size) {
  // Set the viewport.
  const auto& vp = command.viewport.value_or<Viewport>(
      {.rect = Rect::MakeSize(target_size)});
  vk::Viewport viewport = vk::Viewport()
                              .setWidth(vp.rect.size.width)
                              .setHeight(-vp.rect.size.height)
                              .setY(vp.rect.size.height)
                              .setMinDepth(0.0f)
                              .setMaxDepth(1.0f);
  cmd_buffer.setViewport(0, 1, &viewport);

  // Set the scissor rect.
  const auto& sc = command.scissor.value_or(IRect::MakeSize(target_size));
  vk::Rect2D scissor =
      vk::Rect2D()
          .setOffset(vk::Offset2D(sc.origin.x, sc.origin.y))
          .setExtent(vk::Extent2D(sc.size.width, sc.size.height));
  cmd_buffer.setScissor(0, 1, &scissor);
}

static bool EncodeCommand(const Context& context,
                          const Command& command,
                          CommandEncoderVK& encoder,
                          const ISize& target_size) {
  if (command.index_count == 0u || command.instance_count == 0u) {
    return true;
  }

  fml::ScopedCleanupClosure pop_marker(
      [&encoder]() { encoder.PopDebugGroup(); });
  if (!command.label.empty()) {
    encoder.PushDebugGroup(command.label.c_str());
  } else {
    pop_marker.Release();
  }

  const auto& cmd_buffer = encoder.GetCommandBuffer();

  auto& pipeline_vk = PipelineVK::Cast(*command.pipeline);
  PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo();

  if (!AllocateAndBindDescriptorSets(ContextVK::Cast(context),  //
                                     command,                   //
                                     encoder,                   //
                                     pipeline_create_info       //
                                     )) {
    return false;
  }

  cmd_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics,
                          pipeline_create_info->GetVKPipeline());

  // Set the viewport and scissors.
  SetViewportAndScissor(command, cmd_buffer, target_size);

  // Set the stencil reference.
  cmd_buffer.setStencilReference(
      vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
      command.stencil_reference);

  // Configure vertex and index and buffers for binding.
  auto vertex_buffer_view = command.GetVertexBuffer();
  auto index_buffer_view = command.index_buffer;

  if (!vertex_buffer_view || !index_buffer_view) {
    return false;
  }

  auto& allocator = *context.GetResourceAllocator();

  auto vertex_buffer = vertex_buffer_view.buffer->GetDeviceBuffer(allocator);
  auto index_buffer = index_buffer_view.buffer->GetDeviceBuffer(allocator);

  if (!vertex_buffer || !index_buffer) {
    VALIDATION_LOG << "Failed to acquire device buffers"
                   << " for vertex and index buffer views";
    return false;
  }

  if (!encoder.Track(vertex_buffer) || !encoder.Track(index_buffer)) {
    return false;
  }

  // Bind the vertex buffer.
  auto vertex_buffer_handle =
      DeviceBufferVK::Cast(*vertex_buffer).GetVKBufferHandle();
  vk::Buffer vertex_buffers[] = {vertex_buffer_handle};
  vk::DeviceSize vertex_buffer_offsets[] = {vertex_buffer_view.range.offset};
  cmd_buffer.bindVertexBuffers(0u, 1u, vertex_buffers, vertex_buffer_offsets);

  // Bind the index buffer.
  auto index_buffer_handle =
      DeviceBufferVK::Cast(*index_buffer).GetVKBufferHandle();
  cmd_buffer.bindIndexBuffer(index_buffer_handle,
                             index_buffer_view.range.offset,
                             ToVKIndexType(command.index_type));

  // Engage!
  cmd_buffer.drawIndexed(command.index_count,     // index count
                         command.instance_count,  // instance count
                         0u,                      // first index
                         command.base_vertex,     // vertex offset
                         0u                       // first instance
  );
  return true;
}

bool RenderPassVK::OnEncodeCommands(const Context& context) const {
  if (!IsValid()) {
    return false;
  }

  if (commands_.empty()) {
    return true;
  }

  const auto& vk_context = ContextVK::Cast(context);

  const auto& render_target = GetRenderTarget();
  if (!render_target.HasColorAttachment(0u)) {
    VALIDATION_LOG
        << "Render target doesn't have a color attachment at index 0.";
    return false;
  }

  auto encoder = encoder_.lock();
  if (!encoder) {
    VALIDATION_LOG << "Command encoder died before commands could be encoded.";
    return false;
  }

  fml::ScopedCleanupClosure pop_marker(
      [&encoder]() { encoder->PopDebugGroup(); });
  if (!debug_label_.empty()) {
    encoder->PushDebugGroup(debug_label_.c_str());
  } else {
    pop_marker.Release();
  }

  auto cmd_buffer = encoder->GetCommandBuffer();

  if (!UpdateBindingLayouts(commands_, cmd_buffer)) {
    return false;
  }

  if (!ConfigureRenderTargetAttachmentLayouts(render_target, cmd_buffer)) {
    VALIDATION_LOG << "Could not complete attachment layout transitions.";
    return false;
  }

  const auto& target_size = render_target.GetRenderTargetSize();

  auto framebuffer = MakeSharedVK(
      CreateFramebuffer(vk_context.GetDevice(), render_target_, *render_pass_));
  if (!encoder->Track(framebuffer)) {
    return false;
  }

  auto clear_values = GetVKClearValues(render_target);

  vk::RenderPassBeginInfo pass_info;
  pass_info.renderPass = *render_pass_;
  pass_info.framebuffer = *framebuffer;
  pass_info.renderArea.extent.width = static_cast<uint32_t>(target_size.width);
  pass_info.renderArea.extent.height =
      static_cast<uint32_t>(target_size.height);
  pass_info.setClearValues(clear_values);

  {
    cmd_buffer.beginRenderPass(pass_info, vk::SubpassContents::eInline);

    fml::ScopedCleanupClosure end_render_pass(
        [cmd_buffer]() { cmd_buffer.endRenderPass(); });

    for (const auto& command : commands_) {
      if (!command.pipeline) {
        continue;
      }

      if (!EncodeCommand(context, command, *encoder, target_size)) {
        return false;
      }
    }
  }

  return true;
}

}  // namespace impeller
