// 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 <gtest/gtest.h>

#include "src/ui/lib/escher/escher.h"
#include "src/ui/lib/escher/test/common/gtest_escher.h"
#include "src/ui/lib/escher/test/common/gtest_vulkan.h"
#include "src/ui/lib/escher/test/common/test_with_vk_validation_layer.h"

#include <vulkan/vulkan.hpp>

namespace escher {
namespace test {

namespace {

vk::BindSparseInfo bind_sparse_info;

// This function will generate a |vk::ImageCreateInfo| which will cause no errors / warnings in
// Vulkan validation layers.
auto CorrectImageCreateInfo() {
  vk::ImageCreateInfo create_info;
  create_info.pNext = nullptr;
  create_info.imageType = vk::ImageType::e2D;
  create_info.format = vk::Format::eR8G8B8A8Unorm;
  create_info.extent = vk::Extent3D{128, 128, 1};
  create_info.mipLevels = 1;
  create_info.arrayLayers = 1;
  create_info.samples = vk::SampleCountFlagBits::e1;
  create_info.tiling = vk::ImageTiling::eOptimal;
  create_info.usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled |
                      vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
  create_info.sharingMode = vk::SharingMode::eExclusive;
  create_info.initialLayout = vk::ImageLayout::eUndefined;
  create_info.flags = vk::ImageCreateFlags();
  return create_info;
}

// This function will generate a |vk::ImageCreateInfo| which will cause the following validation
// error when creating |vk::Image| using this create info:
// Validation Error: [ VUID-VkImageCreateInfo-pNext-pNext ] Object 0: handle = 0xa605cd0a8, type =
// VK_OBJECT_TYPE_DEVICE; | MessageID = 0x69dad144 | vkCreateImage: pCreateInfo->pNext chain
// includes a structure with unexpected VkStructureType VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; [...]
// This error is based on the Valid Usage documentation for version 198 of the Vulkan header.  It is
// possible that you are using a struct from a private extension or an extension that was added to a
// later version of the Vulkan header, in which case the use of pCreateInfo->pNext is undefined and
// may not work correctly with validation enabled The Vulkan spec states: Each pNext member of any
// structure (including this one) in the pNext chain must be either NULL or a pointer to a valid
// instance of [...]
// (https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-pNext)
auto ErrorImageCreateInfo() {
  vk::ImageCreateInfo create_info = CorrectImageCreateInfo();
  // VK_STRUCTURE_TYPE_BIND_SPARSE_INFO is not legal to chain onto
  // vk::ImageCreateInfo and almost certainly will never be. It's unlikely to
  // cause asserts in drivers, since they're likely to ignore invalid structs.
  create_info.pNext = &bind_sparse_info;
  return create_info;
}

}  // anonymous namespace

VK_TEST(ValidationLayer, ValidationLayerIsSupported) {
  std::optional<std::string> validation_layer_name = VulkanInstance::GetValidationLayerName();

  ASSERT_TRUE(validation_layer_name);
  ASSERT_TRUE(*validation_layer_name == "VK_LAYER_KHRONOS_validation");

  VulkanInstance::Params instance_params{
      {*validation_layer_name},             // layer_names
      {VK_EXT_DEBUG_UTILS_EXTENSION_NAME},  // extension_names
      false                                 // requires_surface
  };
  VulkanInstancePtr vulkan_instance = VulkanInstance::New(instance_params);
  ASSERT_TRUE(vulkan_instance);
}

using ValidationLayerDefaultHandler = TestWithVkValidationLayer;

// This test tests the |TestWithVkValidationLayer| class.
VK_TEST_F(ValidationLayerDefaultHandler, HandlerTest) {
  Escher* escher = GetEscher();

  auto device = escher->vk_device();
  {
    auto create_info = ErrorImageCreateInfo();
    auto create_result = device.createImage(create_info);
    auto vk_image = create_result.value;
    device.destroyImage(vk_image);
    EXPECT_VK_SUCCESS(device.waitIdle());
  }
  EXPECT_VULKAN_VALIDATION_ERRORS_EQ(1);

  // In this case the |createImage()| command is valid. We should not see any new Vulkan validation
  // errors nor warnings here.
  {
    auto create_info = CorrectImageCreateInfo();
    auto create_result = device.createImage(create_info);
    auto vk_image = create_result.value;
    device.destroyImage(vk_image);
    EXPECT_VK_SUCCESS(device.waitIdle());
  }
  EXPECT_VULKAN_VALIDATION_ERRORS_EQ(1);

  // Suppress the debug reports check in |TearDown()|.
  REMOVE_VK_VALIDATION_DEBUG_UTILS_MESSAGES();
}

class ValidationLayerWithCustomHandler : public TestWithVkValidationLayer {
 public:
  ValidationLayerWithCustomHandler()
      : TestWithVkValidationLayer(
            {{[this](VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
                     VkDebugUtilsMessageTypeFlagsEXT message_types,
                     const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
                     void* user_data) -> bool {
                if (VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT & message_severity) {
                  ++count_errors_;
                }
                return false;
              },
              nullptr}}) {}
  int count_errors() const { return count_errors_; }

 private:
  int count_errors_ = 0;
};

VK_TEST_F(ValidationLayerWithCustomHandler, HandlerTest) {
  Escher* escher = GetEscher();
  auto device = escher->vk_device();
  {
    auto create_info = ErrorImageCreateInfo();
    auto create_result = device.createImage(create_info);
    auto vk_image = create_result.value;
    device.destroyImage(vk_image);
    EXPECT_VK_SUCCESS(device.waitIdle());
  }
  EXPECT_VULKAN_VALIDATION_ERRORS_EQ(1);
  EXPECT_EQ(count_errors(), 1);

  // In this case the createImage() command is valid. We should not see any Vulkan validation
  // errors nor warnings here.
  {
    auto create_info = CorrectImageCreateInfo();
    auto create_result = device.createImage(create_info);
    auto vk_image = create_result.value;
    device.destroyImage(vk_image);
    EXPECT_VK_SUCCESS(device.waitIdle());
  }
  // no new errors occurred.
  EXPECT_VULKAN_VALIDATION_ERRORS_EQ(1);
  EXPECT_EQ(count_errors(), 1);

  // Suppress the debug reports check in |TearDown()|.
  REMOVE_VK_VALIDATION_DEBUG_UTILS_MESSAGES();
}

}  // namespace test
}  // namespace escher
