// 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/entity/contents/runtime_effect_contents.h"

#include <future>
#include <memory>

#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/core/runtime_types.h"
#include "impeller/core/shader_types.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/runtime_effect.vert.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/pipeline_library.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/shader_function.h"

namespace impeller {

void RuntimeEffectContents::SetRuntimeStage(
    std::shared_ptr<RuntimeStage> runtime_stage) {
  runtime_stage_ = std::move(runtime_stage);
}

void RuntimeEffectContents::SetUniformData(
    std::shared_ptr<std::vector<uint8_t>> uniform_data) {
  uniform_data_ = std::move(uniform_data);
}

void RuntimeEffectContents::SetTextureInputs(
    std::vector<TextureInput> texture_inputs) {
  texture_inputs_ = std::move(texture_inputs);
}

bool RuntimeEffectContents::CanInheritOpacity(const Entity& entity) const {
  return false;
}

static ShaderType GetShaderType(RuntimeUniformType type) {
  switch (type) {
    case kSampledImage:
      return ShaderType::kSampledImage;
    case kFloat:
      return ShaderType::kFloat;
    case kStruct:
      return ShaderType::kStruct;
  }
}

static std::shared_ptr<ShaderMetadata> MakeShaderMetadata(
    const RuntimeUniformDescription& uniform) {
  auto metadata = std::make_shared<ShaderMetadata>();
  metadata->name = uniform.name;
  metadata->members.emplace_back(ShaderStructMemberMetadata{
      .type = GetShaderType(uniform.type),
      .size = uniform.GetSize(),
      .byte_length = uniform.bit_width / 8,
  });

  return metadata;
}

bool RuntimeEffectContents::Render(const ContentContext& renderer,
                                   const Entity& entity,
                                   RenderPass& pass) const {
  const std::shared_ptr<Context>& context = renderer.GetContext();
  const std::shared_ptr<ShaderLibrary>& library = context->GetShaderLibrary();

  //--------------------------------------------------------------------------
  /// Get or register shader.
  ///

  // TODO(113719): Register the shader function earlier.

  std::shared_ptr<const ShaderFunction> function = library->GetFunction(
      runtime_stage_->GetEntrypoint(), ShaderStage::kFragment);

  //--------------------------------------------------------------------------
  /// Resolve geometry and content context options.
  ///

  auto geometry_result =
      GetGeometry()->GetPositionBuffer(renderer, entity, pass);
  auto options = OptionsFromPassAndEntity(pass, entity);
  if (geometry_result.prevent_overdraw) {
    options.stencil_compare = CompareFunction::kEqual;
    options.stencil_operation = StencilOperation::kIncrementClamp;
  }
  options.primitive_type = geometry_result.type;

  if (function && runtime_stage_->IsDirty()) {
    renderer.ClearCachedRuntimeEffectPipeline(runtime_stage_->GetEntrypoint());
    context->GetPipelineLibrary()->RemovePipelinesWithEntryPoint(function);
    library->UnregisterFunction(runtime_stage_->GetEntrypoint(),
                                ShaderStage::kFragment);

    function = nullptr;
  }

  if (!function) {
    std::promise<bool> promise;
    auto future = promise.get_future();

    library->RegisterFunction(
        runtime_stage_->GetEntrypoint(),
        ToShaderStage(runtime_stage_->GetShaderStage()),
        runtime_stage_->GetCodeMapping(),
        fml::MakeCopyable([promise = std::move(promise)](bool result) mutable {
          promise.set_value(result);
        }));

    if (!future.get()) {
      VALIDATION_LOG << "Failed to build runtime effect (entry point: "
                     << runtime_stage_->GetEntrypoint() << ")";
      return false;
    }

    function = library->GetFunction(runtime_stage_->GetEntrypoint(),
                                    ShaderStage::kFragment);
    if (!function) {
      VALIDATION_LOG
          << "Failed to fetch runtime effect function immediately after "
             "registering it (entry point: "
          << runtime_stage_->GetEntrypoint() << ")";
      return false;
    }

    runtime_stage_->SetClean();
  }

  //--------------------------------------------------------------------------
  /// Set up the command. Defer setting up the pipeline until the descriptor set
  /// layouts are known from the uniforms.
  ///

  const std::shared_ptr<const Capabilities>& caps = context->GetCapabilities();
  const auto color_attachment_format = caps->GetDefaultColorFormat();
  const auto stencil_attachment_format = caps->GetDefaultStencilFormat();

  using VS = RuntimeEffectVertexShader;

  pass.SetCommandLabel("RuntimeEffectContents");
  pass.SetStencilReference(entity.GetClipDepth());
  pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));

  //--------------------------------------------------------------------------
  /// Vertex stage uniforms.
  ///

  VS::FrameInfo frame_info;
  frame_info.mvp = geometry_result.transform;
  VS::BindFrameInfo(pass,
                    renderer.GetTransientsBuffer().EmplaceUniform(frame_info));

  //--------------------------------------------------------------------------
  /// Fragment stage uniforms.
  ///

  size_t minimum_sampler_index = 100000000;
  size_t buffer_index = 0;
  size_t buffer_offset = 0;

  std::vector<DescriptorSetLayout> descriptor_set_layouts;

  for (const auto& uniform : runtime_stage_->GetUniforms()) {
    std::shared_ptr<ShaderMetadata> metadata = MakeShaderMetadata(uniform);

    switch (uniform.type) {
      case kSampledImage: {
        // Sampler uniforms are ordered in the IPLR according to their
        // declaration and the uniform location reflects the correct offset to
        // be mapped to - except that it may include all proceeding float
        // uniforms. For example, a float sampler that comes after 4 float
        // uniforms may have a location of 4. To convert to the actual offset we
        // need to find the largest location assigned to a float uniform and
        // then subtract this from all uniform locations. This is more or less
        // the same operation we previously performed in the shader compiler.
        minimum_sampler_index =
            std::min(minimum_sampler_index, uniform.location);
        break;
      }
      case kFloat: {
        FML_DCHECK(renderer.GetContext()->GetBackendType() !=
                   Context::BackendType::kVulkan)
            << "Uniform " << uniform.name
            << " had unexpected type kFloat for Vulkan backend.";
        size_t alignment =
            std::max(uniform.bit_width / 8, DefaultUniformAlignment());
        auto buffer_view = renderer.GetTransientsBuffer().Emplace(
            uniform_data_->data() + buffer_offset, uniform.GetSize(),
            alignment);

        ShaderUniformSlot uniform_slot;
        uniform_slot.name = uniform.name.c_str();
        uniform_slot.ext_res_0 = uniform.location;
        pass.BindResource(ShaderStage::kFragment, uniform_slot, metadata,
                          buffer_view);
        buffer_index++;
        buffer_offset += uniform.GetSize();
        break;
      }
      case kStruct: {
        FML_DCHECK(renderer.GetContext()->GetBackendType() ==
                   Context::BackendType::kVulkan);
        descriptor_set_layouts.emplace_back(DescriptorSetLayout{
            static_cast<uint32_t>(uniform.location),
            DescriptorType::kUniformBuffer,
            ShaderStage::kFragment,
        });
        ShaderUniformSlot uniform_slot;
        uniform_slot.name = uniform.name.c_str();
        uniform_slot.binding = uniform.location;

        std::vector<float> uniform_buffer;
        uniform_buffer.reserve(uniform.struct_layout.size());
        size_t uniform_byte_index = 0u;
        for (const auto& byte_type : uniform.struct_layout) {
          if (byte_type == 0) {
            uniform_buffer.push_back(0.f);
          } else if (byte_type == 1) {
            uniform_buffer.push_back(reinterpret_cast<float*>(
                uniform_data_->data())[uniform_byte_index++]);
          } else {
            FML_UNREACHABLE();
          }
        }

        size_t alignment = std::max(sizeof(float) * uniform_buffer.size(),
                                    DefaultUniformAlignment());

        auto buffer_view = renderer.GetTransientsBuffer().Emplace(
            reinterpret_cast<const void*>(uniform_buffer.data()),
            sizeof(float) * uniform_buffer.size(), alignment);
        pass.BindResource(ShaderStage::kFragment, uniform_slot,
                          ShaderMetadata{}, buffer_view);
      }
    }
  }

  size_t sampler_index = 0;
  for (const auto& uniform : runtime_stage_->GetUniforms()) {
    std::shared_ptr<ShaderMetadata> metadata = MakeShaderMetadata(uniform);

    switch (uniform.type) {
      case kSampledImage: {
        FML_DCHECK(sampler_index < texture_inputs_.size());
        auto& input = texture_inputs_[sampler_index];

        auto sampler =
            context->GetSamplerLibrary()->GetSampler(input.sampler_descriptor);

        SampledImageSlot image_slot;
        image_slot.name = uniform.name.c_str();

        uint32_t sampler_binding_location = 0u;
        if (!descriptor_set_layouts.empty()) {
          sampler_binding_location = descriptor_set_layouts.back().binding + 1;
        }

        descriptor_set_layouts.emplace_back(DescriptorSetLayout{
            sampler_binding_location,
            DescriptorType::kSampledImage,
            ShaderStage::kFragment,
        });

        image_slot.binding = sampler_binding_location;
        image_slot.texture_index = uniform.location - minimum_sampler_index;
        pass.BindResource(ShaderStage::kFragment, image_slot, *metadata,
                          input.texture, sampler);

        sampler_index++;
        break;
      }
      default:
        continue;
    }
  }

  /// Now that the descriptor set layouts are known, get the pipeline.
  auto create_callback =
      [&]() -> std::shared_ptr<Pipeline<PipelineDescriptor>> {
    PipelineDescriptor desc;
    desc.SetLabel("Runtime Stage");
    desc.AddStageEntrypoint(
        library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
    desc.AddStageEntrypoint(library->GetFunction(
        runtime_stage_->GetEntrypoint(), ShaderStage::kFragment));
    auto vertex_descriptor = std::make_shared<VertexDescriptor>();
    vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs,
                                      VS::kInterleavedBufferLayout);
    vertex_descriptor->RegisterDescriptorSetLayouts(VS::kDescriptorSetLayouts);
    vertex_descriptor->RegisterDescriptorSetLayouts(
        descriptor_set_layouts.data(), descriptor_set_layouts.size());
    desc.SetVertexDescriptor(std::move(vertex_descriptor));
    desc.SetColorAttachmentDescriptor(
        0u, {.format = color_attachment_format, .blending_enabled = true});

    StencilAttachmentDescriptor stencil0;
    stencil0.stencil_compare = CompareFunction::kEqual;
    desc.SetStencilAttachmentDescriptors(stencil0);
    desc.SetStencilPixelFormat(stencil_attachment_format);

    options.ApplyToPipelineDescriptor(desc);
    auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
    if (!pipeline) {
      VALIDATION_LOG << "Failed to get or create runtime effect pipeline.";
      return nullptr;
    }

    return pipeline;
  };

  pass.SetPipeline(renderer.GetCachedRuntimeEffectPipeline(
      runtime_stage_->GetEntrypoint(), options, create_callback));

  if (!pass.Draw().ok()) {
    return false;
  }

  if (geometry_result.prevent_overdraw) {
    auto restore = ClipRestoreContents();
    restore.SetRestoreCoverage(GetCoverage(entity));
    return restore.Render(renderer, entity, pass);
  }
  return true;
}

}  // namespace impeller
