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

#include <cstring>
#include <vector>

#include "impeller/base/validation.h"
#include "impeller/renderer/backend/gles/device_buffer_gles.h"
#include "impeller/renderer/backend/gles/formats_gles.h"
#include "impeller/renderer/backend/gles/sampler_gles.h"
#include "impeller/renderer/backend/gles/texture_gles.h"

namespace impeller {

BufferBindingsGLES::BufferBindingsGLES() = default;

BufferBindingsGLES::~BufferBindingsGLES() = default;

bool BufferBindingsGLES::RegisterVertexStageInput(
    const ProcTableGLES& gl,
    const std::vector<ShaderStageIOSlot>& p_inputs,
    const std::vector<ShaderStageBufferLayout>& layouts) {
  std::vector<VertexAttribPointer> vertex_attrib_arrays;
  for (auto i = 0u; i < p_inputs.size(); i++) {
    const auto& input = p_inputs[i];
    const auto& layout = layouts[input.binding];
    VertexAttribPointer attrib;
    attrib.index = input.location;
    // Component counts must be 1, 2, 3 or 4. Do that validation now.
    if (input.vec_size < 1u || input.vec_size > 4u) {
      return false;
    }
    attrib.size = input.vec_size;
    auto type = ToVertexAttribType(input.type);
    if (!type.has_value()) {
      return false;
    }
    attrib.type = type.value();
    attrib.normalized = GL_FALSE;
    attrib.offset = input.offset;
    attrib.stride = layout.stride;
    vertex_attrib_arrays.emplace_back(attrib);
  }
  vertex_attrib_arrays_ = std::move(vertex_attrib_arrays);
  return true;
}

static std::string NormalizeUniformKey(const std::string& key) {
  std::string result;
  result.reserve(key.length());
  for (char ch : key) {
    if (ch != '_') {
      result.push_back(toupper(ch));
    }
  }
  return result;
}

static std::string CreateUniformMemberKey(const std::string& struct_name,
                                          const std::string& member,
                                          bool is_array) {
  std::string result;
  result.reserve(struct_name.length() + member.length() + (is_array ? 4 : 1));
  result += struct_name;
  if (!member.empty()) {
    result += '.';
    result += member;
  }
  if (is_array) {
    result += "[0]";
  }
  return NormalizeUniformKey(result);
}

static std::string CreateUniformMemberKey(
    const std::string& non_struct_member) {
  return NormalizeUniformKey(non_struct_member);
}

bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl,
                                              GLuint program) {
  if (!gl.IsProgram(program)) {
    return false;
  }
  GLint max_name_size = 0;
  gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_size);

  GLint uniform_count = 0;
  gl.GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_count);

  // Query the Program for all active uniform locations, and
  // record this via normalized key.
  for (GLint i = 0; i < uniform_count; i++) {
    std::vector<GLchar> name;
    name.resize(max_name_size);
    GLsizei written_count = 0u;
    GLint uniform_var_size = 0u;
    GLenum uniform_type = GL_FLOAT;
    // Note: Active uniforms are defined as uniforms that may have an impact on
    //       the output of the shader. Drivers are allowed to (and often do)
    //       optimize out unused uniforms.
    gl.GetActiveUniform(program,            // program
                        i,                  // index
                        max_name_size,      // buffer_size
                        &written_count,     // length
                        &uniform_var_size,  // size
                        &uniform_type,      // type
                        name.data()         // name
    );
    auto location = gl.GetUniformLocation(program, name.data());
    if (location == -1) {
      VALIDATION_LOG << "Could not query the location of an active uniform.";
      return false;
    }
    if (written_count <= 0) {
      VALIDATION_LOG << "Uniform name could not be read for active uniform.";
      return false;
    }
    uniform_locations_[NormalizeUniformKey(std::string{
        name.data(), static_cast<size_t>(written_count)})] = location;
  }
  return true;
}

bool BufferBindingsGLES::BindVertexAttributes(const ProcTableGLES& gl,
                                              size_t vertex_offset) const {
  for (const auto& array : vertex_attrib_arrays_) {
    gl.EnableVertexAttribArray(array.index);
    gl.VertexAttribPointer(array.index,       // index
                           array.size,        // size (must be 1, 2, 3, or 4)
                           array.type,        // type
                           array.normalized,  // normalized
                           array.stride,      // stride
                           reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
                               vertex_offset + array.offset))  // pointer
    );
  }

  return true;
}

bool BufferBindingsGLES::BindUniformData(const ProcTableGLES& gl,
                                         Allocator& transients_allocator,
                                         const Bindings& vertex_bindings,
                                         const Bindings& fragment_bindings) {
  for (const auto& buffer : vertex_bindings.buffers) {
    if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) {
      return false;
    }
  }
  for (const auto& buffer : fragment_bindings.buffers) {
    if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) {
      return false;
    }
  }

  std::optional<size_t> next_unit_index =
      BindTextures(gl, vertex_bindings, ShaderStage::kVertex);
  if (!next_unit_index.has_value()) {
    return false;
  }

  if (!BindTextures(gl, fragment_bindings, ShaderStage::kFragment,
                    *next_unit_index)
           .has_value()) {
    return false;
  }

  return true;
}

bool BufferBindingsGLES::UnbindVertexAttributes(const ProcTableGLES& gl) const {
  for (const auto& array : vertex_attrib_arrays_) {
    gl.DisableVertexAttribArray(array.index);
  }
  return true;
}

GLint BufferBindingsGLES::ComputeTextureLocation(
    const ShaderMetadata* metadata) {
  auto location = binding_map_.find(metadata->name);
  if (location != binding_map_.end()) {
    return location->second[0];
  }
  auto& locations = binding_map_[metadata->name] = {};
  auto computed_location =
      uniform_locations_.find(CreateUniformMemberKey(metadata->name));
  if (computed_location == uniform_locations_.end()) {
    locations.push_back(-1);
  } else {
    locations.push_back(computed_location->second);
  }
  return locations[0];
}

const std::vector<GLint>& BufferBindingsGLES::ComputeUniformLocations(
    const ShaderMetadata* metadata) {
  auto location = binding_map_.find(metadata->name);
  if (location != binding_map_.end()) {
    return location->second;
  }

  // For each metadata member, look up the binding location and record
  // it in the binding map.
  auto& locations = binding_map_[metadata->name] = {};
  for (const auto& member : metadata->members) {
    if (member.type == ShaderType::kVoid) {
      // Void types are used for padding. We are obviously not going to find
      // mappings for these. Keep going.
      locations.push_back(-1);
      continue;
    }

    size_t element_count = member.array_elements.value_or(1);
    const auto member_key =
        CreateUniformMemberKey(metadata->name, member.name, element_count > 1);
    const auto computed_location = uniform_locations_.find(member_key);
    if (computed_location == uniform_locations_.end()) {
      // Uniform was not active.
      locations.push_back(-1);
      continue;
    }
    locations.push_back(computed_location->second);
  }
  return locations;
}

bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl,
                                           Allocator& transients_allocator,
                                           const BufferResource& buffer) {
  const auto* metadata = buffer.GetMetadata();
  auto device_buffer =
      buffer.resource.buffer->GetDeviceBuffer(transients_allocator);
  if (!device_buffer) {
    VALIDATION_LOG << "Device buffer not found.";
    return false;
  }
  const auto& device_buffer_gles = DeviceBufferGLES::Cast(*device_buffer);
  const uint8_t* buffer_ptr =
      device_buffer_gles.GetBufferData() + buffer.resource.range.offset;

  if (metadata->members.empty()) {
    VALIDATION_LOG << "Uniform buffer had no members. This is currently "
                      "unsupported in the OpenGL ES backend. Use a uniform "
                      "buffer block.";
    return false;
  }

  const auto& locations = ComputeUniformLocations(metadata);
  for (auto i = 0u; i < metadata->members.size(); i++) {
    const auto& member = metadata->members[i];
    auto location = locations[i];
    // Void type or inactive uniform.
    if (location == -1) {
      continue;
    }

    size_t element_count = member.array_elements.value_or(1);
    size_t element_stride = member.byte_length / element_count;
    auto* buffer_data =
        reinterpret_cast<const GLfloat*>(buffer_ptr + member.offset);

    std::vector<uint8_t> array_element_buffer;
    if (element_count > 1) {
      // When binding uniform arrays, the elements must be contiguous. Copy
      // the uniforms to a temp buffer to eliminate any padding needed by the
      // other backends.
      array_element_buffer.resize(member.size * element_count);
      for (size_t element_i = 0; element_i < element_count; element_i++) {
        std::memcpy(array_element_buffer.data() + element_i * member.size,
                    reinterpret_cast<const char*>(buffer_data) +
                        element_i * element_stride,
                    member.size);
      }
      buffer_data =
          reinterpret_cast<const GLfloat*>(array_element_buffer.data());
    }

    switch (member.type) {
      case ShaderType::kFloat:
        switch (member.size) {
          case sizeof(Matrix):
            gl.UniformMatrix4fv(location,       // location
                                element_count,  // count
                                GL_FALSE,       // normalize
                                buffer_data     // data
            );
            continue;
          case sizeof(Vector4):
            gl.Uniform4fv(location,       // location
                          element_count,  // count
                          buffer_data     // data
            );
            continue;
          case sizeof(Vector3):
            gl.Uniform3fv(location,       // location
                          element_count,  // count
                          buffer_data     // data
            );
            continue;
          case sizeof(Vector2):
            gl.Uniform2fv(location,       // location
                          element_count,  // count
                          buffer_data     // data
            );
            continue;
          case sizeof(Scalar):
            gl.Uniform1fv(location,       // location
                          element_count,  // count
                          buffer_data     // data
            );
            continue;
        }
        VALIDATION_LOG << "Size " << member.size
                       << " could not be mapped ShaderType::kFloat for key: "
                       << member.name;
      case ShaderType::kBoolean:
      case ShaderType::kSignedByte:
      case ShaderType::kUnsignedByte:
      case ShaderType::kSignedShort:
      case ShaderType::kUnsignedShort:
      case ShaderType::kSignedInt:
      case ShaderType::kUnsignedInt:
      case ShaderType::kSignedInt64:
      case ShaderType::kUnsignedInt64:
      case ShaderType::kAtomicCounter:
      case ShaderType::kUnknown:
      case ShaderType::kVoid:
      case ShaderType::kHalfFloat:
      case ShaderType::kDouble:
      case ShaderType::kStruct:
      case ShaderType::kImage:
      case ShaderType::kSampledImage:
      case ShaderType::kSampler:
        VALIDATION_LOG << "Could not bind uniform buffer data for key: "
                       << member.name;
        return false;
    }
  }
  return true;
}

std::optional<size_t> BufferBindingsGLES::BindTextures(
    const ProcTableGLES& gl,
    const Bindings& bindings,
    ShaderStage stage,
    size_t unit_start_index) {
  size_t active_index = unit_start_index;
  for (const auto& data : bindings.sampled_images) {
    const auto& texture_gles = TextureGLES::Cast(*data.texture.resource);
    if (data.texture.GetMetadata() == nullptr) {
      VALIDATION_LOG << "No metadata found for texture binding.";
      return std::nullopt;
    }

    auto location = ComputeTextureLocation(data.texture.GetMetadata());
    if (location == -1) {
      return std::nullopt;
    }

    //--------------------------------------------------------------------------
    /// Set the active texture unit.
    ///
    if (active_index >= gl.GetCapabilities()->GetMaxTextureUnits(stage)) {
      VALIDATION_LOG << "Texture units specified exceed the capabilities for "
                        "this shader stage.";
      return std::nullopt;
    }
    gl.ActiveTexture(GL_TEXTURE0 + active_index);

    //--------------------------------------------------------------------------
    /// Bind the texture.
    ///
    if (!texture_gles.Bind()) {
      return std::nullopt;
    }

    //--------------------------------------------------------------------------
    /// If there is a sampler for the texture at the same index, configure the
    /// bound texture using that sampler.
    ///
    const auto& sampler_gles = SamplerGLES::Cast(*data.sampler);
    if (!sampler_gles.ConfigureBoundTexture(texture_gles, gl)) {
      return std::nullopt;
    }

    //--------------------------------------------------------------------------
    /// Set the texture uniform location.
    ///
    gl.Uniform1i(location, active_index);

    //--------------------------------------------------------------------------
    /// Bump up the active index at binding.
    ///
    active_index++;
  }
  return active_index;
}

}  // namespace impeller
