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

#include "flutter/fml/hash_combine.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/device_holder_vk.h"
#include "impeller/renderer/backend/vulkan/sampler_vk.h"

namespace impeller {

YUVConversionVK::YUVConversionVK(const vk::Device& device,
                                 const YUVConversionDescriptorVK& chain)
    : chain_(chain) {
  auto conversion = device.createSamplerYcbcrConversionUnique(chain_.get());
  if (conversion.result != vk::Result::eSuccess) {
    VALIDATION_LOG << "Could not create YUV conversion: "
                   << vk::to_string(conversion.result);
    return;
  }
  conversion_ = std::move(conversion.value);
}

YUVConversionVK::~YUVConversionVK() = default;

bool YUVConversionVK::IsValid() const {
  return conversion_ && !!conversion_.get();
}

vk::SamplerYcbcrConversion YUVConversionVK::GetConversion() const {
  return conversion_ ? conversion_.get()
                     : static_cast<vk::SamplerYcbcrConversion>(VK_NULL_HANDLE);
}

const YUVConversionDescriptorVK& YUVConversionVK::GetDescriptor() const {
  return chain_;
}

std::size_t YUVConversionDescriptorVKHash::operator()(
    const YUVConversionDescriptorVK& desc) const {
  // Hashers in Vulkan HPP hash the pNext member which isn't what we want for
  // these to be stable.
  const auto& conv = desc.get();

  std::size_t hash = fml::HashCombine(conv.format,                      //
                                      conv.ycbcrModel,                  //
                                      conv.ycbcrRange,                  //
                                      conv.components.r,                //
                                      conv.components.g,                //
                                      conv.components.b,                //
                                      conv.components.a,                //
                                      conv.xChromaOffset,               //
                                      conv.yChromaOffset,               //
                                      conv.chromaFilter,                //
                                      conv.forceExplicitReconstruction  //
  );
#if FML_OS_ANDROID
  const auto external_format = desc.get<vk::ExternalFormatANDROID>();
  fml::HashCombineSeed(hash, external_format.externalFormat);
#endif  // FML_OS_ANDROID

  return hash;
};

bool YUVConversionDescriptorVKEqual::operator()(
    const YUVConversionDescriptorVK& lhs_desc,
    const YUVConversionDescriptorVK& rhs_desc) const {
  // Default equality checks in Vulkan HPP checks pNext member members by
  // pointer which isn't what we want.
  {
    const auto& lhs = lhs_desc.get();
    const auto& rhs = rhs_desc.get();

    if (lhs.format != rhs.format ||                                         //
        lhs.ycbcrModel != rhs.ycbcrModel ||                                 //
        lhs.ycbcrRange != rhs.ycbcrRange ||                                 //
        lhs.components.r != rhs.components.r ||                             //
        lhs.components.g != rhs.components.g ||                             //
        lhs.components.b != rhs.components.b ||                             //
        lhs.components.a != rhs.components.a ||                             //
        lhs.xChromaOffset != rhs.xChromaOffset ||                           //
        lhs.yChromaOffset != rhs.yChromaOffset ||                           //
        lhs.chromaFilter != rhs.chromaFilter ||                             //
        lhs.forceExplicitReconstruction != rhs.forceExplicitReconstruction  //
    ) {
      return false;
    }
  }
#if FML_OS_ANDROID
  {
    const auto lhs = lhs_desc.get<vk::ExternalFormatANDROID>();
    const auto rhs = rhs_desc.get<vk::ExternalFormatANDROID>();
    return lhs.externalFormat == rhs.externalFormat;
  }
#else   // FML_OS_ANDROID
  return true;
#endif  // FML_OS_ANDROID
}

ImmutableSamplerKeyVK::ImmutableSamplerKeyVK(const SamplerVK& sampler)
    : sampler(sampler.GetDescriptor()) {
  if (const auto& conversion = sampler.GetYUVConversion()) {
    yuv_conversion = conversion->GetDescriptor();
  }
}

bool ImmutableSamplerKeyVK::IsEqual(const ImmutableSamplerKeyVK& other) const {
  return sampler.IsEqual(other.sampler) &&
         YUVConversionDescriptorVKEqual{}(yuv_conversion, other.yuv_conversion);
}

std::size_t ImmutableSamplerKeyVK::GetHash() const {
  return fml::HashCombine(sampler.GetHash(),
                          YUVConversionDescriptorVKHash{}(yuv_conversion));
}

}  // namespace impeller
