// 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/command_buffer_vk.h"

#include "flutter/fml/logging.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/formats_vk.h"
#include "impeller/renderer/backend/vulkan/render_pass_vk.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/render_target.h"

namespace impeller {

std::shared_ptr<CommandBufferVK> CommandBufferVK::Create(
    std::weak_ptr<const Context> context,
    vk::Device device,
    vk::CommandPool command_pool,
    SurfaceProducerVK* surface_producer) {
  vk::CommandBufferAllocateInfo allocate_info;
  allocate_info.setLevel(vk::CommandBufferLevel::ePrimary);
  allocate_info.setCommandBufferCount(1);
  allocate_info.setCommandPool(command_pool);

  auto res = device.allocateCommandBuffersUnique(allocate_info);
  if (res.result != vk::Result::eSuccess) {
    VALIDATION_LOG << "Failed to allocate command buffer: "
                   << vk::to_string(res.result);
    return nullptr;
  }

  vk::UniqueCommandBuffer cmd = std::move(res.value[0]);
  return std::make_shared<CommandBufferVK>(context, device, surface_producer,
                                           std::move(cmd));
}

CommandBufferVK::CommandBufferVK(std::weak_ptr<const Context> context,
                                 vk::Device device,
                                 SurfaceProducerVK* surface_producer,
                                 vk::UniqueCommandBuffer command_buffer)
    : CommandBuffer(context),
      device_(device),
      command_buffer_(std::move(command_buffer)),
      surface_producer_(surface_producer) {
  is_valid_ = true;
}

CommandBufferVK::~CommandBufferVK() = default;

void CommandBufferVK::SetLabel(const std::string& label) const {
  if (auto context = context_.lock()) {
    reinterpret_cast<const ContextVK*>(context.get())
        ->SetDebugName(*command_buffer_, label);
  }
}

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

bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) {
  bool result = surface_producer_->Submit(*command_buffer_);

  if (callback) {
    callback(result ? CommandBuffer::Status::kCompleted
                    : CommandBuffer::Status::kError);
  }

  return result;
}

std::shared_ptr<RenderPass> CommandBufferVK::OnCreateRenderPass(
    RenderTarget target) const {
  vk::CommandBufferBeginInfo begin_info;
  auto res = command_buffer_->begin(begin_info);
  if (res != vk::Result::eSuccess) {
    VALIDATION_LOG << "Failed to begin command buffer: " << vk::to_string(res);
    return nullptr;
  }

  std::vector<vk::AttachmentDescription> color_attachments;
  for (const auto& [k, attachment] : target.GetColorAttachments()) {
    const TextureDescriptor& tex_desc =
        attachment.texture->GetTextureDescriptor();

    vk::AttachmentDescription color_attachment;
    color_attachment.setFormat(ToVKImageFormat(tex_desc.format));
    color_attachment.setSamples(ToVKSampleCountFlagBits(tex_desc.sample_count));
    color_attachment.setLoadOp(ToVKAttachmentLoadOp(attachment.load_action));
    color_attachment.setStoreOp(ToVKAttachmentStoreOp(attachment.store_action));

    color_attachment.setStencilLoadOp(vk::AttachmentLoadOp::eDontCare);
    color_attachment.setStencilStoreOp(vk::AttachmentStoreOp::eDontCare);
    color_attachment.setInitialLayout(vk::ImageLayout::eUndefined);
    color_attachment.setFinalLayout(vk::ImageLayout::ePresentSrcKHR);

    color_attachments.push_back(color_attachment);
  }

  // TODO (kaushikiska): support depth and stencil attachments.

  vk::AttachmentReference color_attachment_ref;
  color_attachment_ref.setAttachment(0);
  color_attachment_ref.setLayout(vk::ImageLayout::eColorAttachmentOptimal);

  vk::SubpassDescription subpass_desc;
  subpass_desc.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics);
  subpass_desc.setColorAttachmentCount(color_attachments.size());
  subpass_desc.setPColorAttachments(&color_attachment_ref);

  vk::RenderPassCreateInfo render_pass_create;
  render_pass_create.setAttachmentCount(color_attachments.size());
  render_pass_create.setPAttachments(color_attachments.data());
  render_pass_create.setSubpassCount(1);
  render_pass_create.setPSubpasses(&subpass_desc);

  auto render_pass_create_res =
      device_.createRenderPassUnique(render_pass_create);
  if (render_pass_create_res.result != vk::Result::eSuccess) {
    VALIDATION_LOG << "Failed to create render pass: "
                   << vk::to_string(render_pass_create_res.result);
    return nullptr;
  }

  return std::make_shared<RenderPassVK>(
      context_, std::move(target), *command_buffer_,
      std::move(render_pass_create_res.value));
}

std::shared_ptr<BlitPass> CommandBufferVK::OnCreateBlitPass() const {
  FML_UNREACHABLE();
}

std::shared_ptr<ComputePass> CommandBufferVK::OnCreateComputePass() const {
  // TODO(dnfield): https://github.com/flutter/flutter/issues/110622
  VALIDATION_LOG << "ComputePasses unimplemented for Vulkan";
  return nullptr;
}

}  // namespace impeller
