//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// VulkanSecondaryCommandBuffer:
//    Implementation of VulkanSecondaryCommandBuffer.
//

#include "libANGLE/renderer/vulkan/VulkanSecondaryCommandBuffer.h"

#include "common/debug.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"

namespace rx
{
namespace vk
{
angle::Result VulkanSecondaryCommandBuffer::InitializeCommandPool(Context *context,
                                                                  CommandPool *pool,
                                                                  uint32_t queueFamilyIndex,
                                                                  bool hasProtectedContent)
{
    VkCommandPoolCreateInfo poolInfo = {};
    poolInfo.sType                   = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
    poolInfo.flags                   = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
    poolInfo.queueFamilyIndex        = queueFamilyIndex;
    if (hasProtectedContent)
    {
        poolInfo.flags |= VK_COMMAND_POOL_CREATE_PROTECTED_BIT;
    }
    ANGLE_VK_TRY(context, pool->init(context->getDevice(), poolInfo));
    return angle::Result::Continue;
}

angle::Result VulkanSecondaryCommandBuffer::InitializeRenderPassInheritanceInfo(
    ContextVk *contextVk,
    const Framebuffer &framebuffer,
    const RenderPassDesc &renderPassDesc,
    VkCommandBufferInheritanceInfo *inheritanceInfoOut)
{
    vk::RenderPass *compatibleRenderPass = nullptr;
    ANGLE_TRY(contextVk->getCompatibleRenderPass(renderPassDesc, &compatibleRenderPass));

    inheritanceInfoOut->sType       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
    inheritanceInfoOut->renderPass  = compatibleRenderPass->getHandle();
    inheritanceInfoOut->subpass     = 0;
    inheritanceInfoOut->framebuffer = framebuffer.getHandle();

    return angle::Result::Continue;
}

angle::Result VulkanSecondaryCommandBuffer::initialize(Context *context,
                                                       vk::CommandPool *pool,
                                                       bool isRenderPassCommandBuffer,
                                                       angle::PoolAllocator *allocator)
{
    VkDevice device = context->getDevice();

    mCommandTracker.reset();
    mAnyCommand = false;

    VkCommandBufferAllocateInfo allocInfo = {};
    allocInfo.sType                       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    allocInfo.level                       = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
    allocInfo.commandBufferCount          = 1;
    allocInfo.commandPool                 = pool->getHandle();

    ANGLE_VK_TRY(context, init(device, allocInfo));

    // Outside-RP command buffers are begun automatically here.  RP command buffers are begun when
    // the render pass itself starts, as they require inheritence info.
    if (!isRenderPassCommandBuffer)
    {
        VkCommandBufferInheritanceInfo inheritanceInfo = {};
        inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
        ANGLE_TRY(begin(context, inheritanceInfo));
    }

    return angle::Result::Continue;
}

angle::Result VulkanSecondaryCommandBuffer::begin(
    Context *context,
    const VkCommandBufferInheritanceInfo &inheritanceInfo)
{
    ASSERT(!mAnyCommand);

    VkCommandBufferBeginInfo beginInfo = {};
    beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    beginInfo.flags                    = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    beginInfo.pInheritanceInfo         = &inheritanceInfo;
    if (inheritanceInfo.renderPass != VK_NULL_HANDLE)
    {
        beginInfo.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
    }

    ANGLE_VK_TRY(context, CommandBuffer::begin(beginInfo));
    return angle::Result::Continue;
}

angle::Result VulkanSecondaryCommandBuffer::end(Context *context)
{
    ANGLE_VK_TRY(context, CommandBuffer::end());
    return angle::Result::Continue;
}

VkResult VulkanSecondaryCommandBuffer::reset()
{
    mCommandTracker.reset();
    mAnyCommand = false;
    return CommandBuffer::reset();
}
}  // namespace vk
}  // namespace rx
