# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//build/config/arm.gni")
import("//build/config/android/config.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/shim_headers.gni")
import("//third_party/libvpx/libvpx_srcs.gni")
import("//third_party/yasm/yasm_assemble.gni")

declare_args() {
  use_system_libvpx = false
}

# Sets the architecture name for building libvpx.
if (current_cpu == "x86") {
  cpu_arch_full = "ia32"
} else if (current_cpu == "x64") {
  if (is_msan) {
    cpu_arch_full = "generic"
  } else {
    cpu_arch_full = "x64"
  }
} else if (current_cpu == "arm") {
  if (arm_use_neon) {
    cpu_arch_full = "arm-neon"
  } else if (is_android) {
    cpu_arch_full = "arm-neon-cpu-detect"
  } else {
    cpu_arch_full = "arm"
  }
} else {
  cpu_arch_full = current_cpu
}

if (is_nacl) {
  platform_include_dir = "source/config/nacl"
} else {
  # The mac configurations are currently a relic. They were useful when
  # x86inc.asm did not work for MACH_O but now the build is identical to the
  # linux config. iOS for arm on the other hand needs an apple-specific twist in
  # vpx_config.asm
  if (is_ios && current_cpu == "arm") {
    os_category = current_os
  } else if (is_posix || is_fuchsia) {
    # Should cover linux, fuchsia, mac, and the ios simulator.
    os_category = "linux"
  } else {  # This should only match windows.
    os_category = current_os
  }
  platform_include_dir = "source/config/$os_category/$cpu_arch_full"
}

libvpx_include_dirs = [
  "source/config",
  platform_include_dir,
  "source/libvpx",
]

config("libvpx_config") {
  include_dirs = libvpx_include_dirs

  # gn orders flags on a target before flags from configs. The default config
  # adds -Wall, and these flags have to be after -Wall -- so they need to come
  # from a config and can't be on the target directly.
  if (is_clang) {
    cflags = [
      # libvpx heavily relies on implicit enum casting.
      "-Wno-conversion",

      # libvpx does `if ((a == b))` in some places.
      "-Wno-parentheses-equality",

      # libvpx has many static functions in header, which trigger this warning.
      "-Wno-unused-function",
    ]

    # Fixes a mac / ios simulator link error for vpx_scaled_2d:
    # Undefined symbols for architecture x86_64:
    # "_vpx_scaled_2d", referenced from:
    # _vp9_scale_and_extend_frame_c in libvpx.a(vp9_frame_scale.o)
    # (maybe you meant: _vpx_scaled_2d_ssse3)
    # ld: symbol(s) not found for architecture x86_64
    if (is_mac || (is_ios && (current_cpu == "x86" || current_cpu == "x64"))) {
      cflags += [ "-fno-common" ]
    }
  } else if (!is_win) {
    cflags = [
      "-Wno-unused-function",
      "-Wno-sign-compare",
    ]
  }
}

# This config is applied to targets that depend on libvpx.
config("libvpx_external_config") {
  include_dirs = [ "source/libvpx" ]
}

if (current_cpu == "x86" || (current_cpu == "x64" && !is_msan)) {
  yasm_assemble("libvpx_yasm") {
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_assembly
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_assembly
    }

    defines = [ "CHROMIUM" ]
    if (is_android) {
      # On Android, define __ANDROID__ to use alternative standard library
      # functions.
      defines += [ "__ANDROID__" ]
    }
    include_dirs = libvpx_include_dirs
  }
}

if (current_cpu == "x86" || (current_cpu == "x64" && !is_msan)) {
  # The following targets are deliberately source_set rather than
  # static_library. The :libvpx target exposes these intrinsic implementations
  # via global function pointer symbols, which hides the object dependency at
  # link time. On Mac, this results in undefined references to the intrinsic
  # symbols.

  source_set("libvpx_intrinsics_mmx") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (!is_win) {
      cflags = [ "-mmmx" ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_mmx
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_mmx
    }
  }

  source_set("libvpx_intrinsics_sse2") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (!is_win || is_clang) {
      cflags = [ "-msse2" ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_sse2
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_sse2
    }
  }

  source_set("libvpx_intrinsics_ssse3") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (!is_win || is_clang) {
      cflags = [ "-mssse3" ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_ssse3
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_ssse3
    }
  }

  source_set("libvpx_intrinsics_sse4_1") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (!is_win || is_clang) {
      cflags = [ "-msse4.1" ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_sse4_1
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_sse4_1
    }
  }

  source_set("libvpx_intrinsics_avx") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (is_win) {
      cflags = [ "/arch:AVX" ]
    } else {
      cflags = [ "-mavx" ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_avx
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_avx
    }
  }

  source_set("libvpx_intrinsics_avx2") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (is_win) {
      cflags = [ "/arch:AVX2" ]
    } else {
      cflags = [ "-mavx2" ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_avx2
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_avx2
    }
  }

  source_set("libvpx_intrinsics_avx512") {
    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [ "//build/config/compiler:no_chromium_code" ]
    configs += [ ":libvpx_config" ]
    if (is_win) {
      # clang-cl does not accept this flag.
      # https://bugs.chromium.org/p/chromium/issues/detail?id=783370
      cflags = [ "/arch:AVX512" ]
    } else {
      cflags = [
        "-mavx512f",
        "-mavx512cd",
        "-mavx512bw",
        "-mavx512dq",
        "-mavx512vl",
      ]
    }
    if (current_cpu == "x86") {
      sources = libvpx_srcs_x86_avx512
    } else if (current_cpu == "x64") {
      sources = libvpx_srcs_x86_64_avx512
    }
  }
}

if (cpu_arch_full == "arm-neon-cpu-detect") {
  static_library("libvpx_intrinsics_neon") {
    configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
    configs += [ ":libvpx_config" ]
    cflags = [ "-mfpu=neon" ]
    sources = libvpx_srcs_arm_neon_cpu_detect_neon
  }
}

if (current_cpu == "arm") {
  if (cpu_arch_full == "arm-neon") {
    arm_assembly_sources = libvpx_srcs_arm_neon_assembly
  } else if (cpu_arch_full == "arm-neon-cpu-detect") {
    arm_assembly_sources = libvpx_srcs_arm_neon_cpu_detect_assembly
  } else {
    arm_assembly_sources = libvpx_srcs_arm_assembly
  }
}

# Converts ARM assembly files to GAS style.
if (current_cpu == "arm" && arm_assembly_sources != []) {
  action_foreach("convert_arm_assembly") {
    script = "//third_party/libvpx/run_perl.py"
    sources = arm_assembly_sources
    gen_file =
        get_label_info("//third_party/libvpx/source/libvpx", "root_gen_dir") +
        "/{{source_root_relative_dir}}/{{source_file_part}}.S"
    outputs = [
      gen_file,
    ]
    if (is_ios) {
      ads2gas_script =
          "//third_party/libvpx/source/libvpx/build/make/ads2gas_apple.pl"
    } else {
      ads2gas_script =
          "//third_party/libvpx/source/libvpx/build/make/ads2gas.pl"
    }
    args = [
      "-s",
      rebase_path(ads2gas_script, root_build_dir),
      "-i",
      "{{source}}",
      "-o",
      rebase_path(gen_file),
    ]
  }

  static_library("libvpx_assembly_arm") {
    sources = get_target_outputs(":convert_arm_assembly")
    configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
    configs += [ ":libvpx_config" ]
    if (cpu_arch_full == "arm-neon" || cpu_arch_full == "arm-neon-cpu-detect") {
      asmflags = [ "-mfpu=neon" ]

      # allow asm files to include generated sources which match the source
      # tree layout, e.g., vpx_dsp/arm/...
      include_dirs = [ get_label_info("//third_party/libvpx/source/libvpx",
                                      "target_gen_dir") ]
    }
    deps = [
      ":convert_arm_assembly",
    ]
  }
}

static_library("bundled_libvpx") {
  if (!is_debug && is_win) {
    configs -= [ "//build/config/compiler:default_optimization" ]
    configs += [ "//build/config/compiler:optimize_max" ]
  }

  if (is_nacl) {
    sources = libvpx_srcs_generic
  } else if (current_cpu == "x86") {
    sources = libvpx_srcs_x86
  } else if (current_cpu == "x64") {
    if (is_msan) {
      sources = libvpx_srcs_generic
    } else {
      sources = libvpx_srcs_x86_64
    }
  } else if (current_cpu == "mipsel" || current_cpu == "mips64el") {
    sources = libvpx_srcs_mips
  } else if (current_cpu == "arm") {
    if (arm_use_neon) {
      sources = libvpx_srcs_arm_neon
    } else if (is_android) {
      sources = libvpx_srcs_arm_neon_cpu_detect
    } else {
      sources = libvpx_srcs_arm
    }
  } else if (current_cpu == "arm64") {
    configs -= [ "//build/config/compiler:default_symbols" ]
    configs += [ "//build/config/compiler:no_symbols" ]
    sources = libvpx_srcs_arm64
  }

  configs -= [ "//build/config/compiler:chromium_code" ]
  configs += [ "//build/config/compiler:no_chromium_code" ]
  configs += [ ":libvpx_config" ]
  deps = []
  if (current_cpu == "x86" || (current_cpu == "x64" && !is_msan)) {
    deps += [
      ":libvpx_intrinsics_avx",
      ":libvpx_intrinsics_avx2",
      ":libvpx_intrinsics_avx512",
      ":libvpx_intrinsics_mmx",
      ":libvpx_intrinsics_sse2",
      ":libvpx_intrinsics_sse4_1",
      ":libvpx_intrinsics_ssse3",
      ":libvpx_yasm",
    ]
  }
  if (cpu_arch_full == "arm-neon-cpu-detect") {
    deps += [ ":libvpx_intrinsics_neon" ]
  }
  if (is_android) {
    deps += [ "//third_party/android_tools:cpu_features" ]
  }
  if (current_cpu == "arm" && arm_assembly_sources != []) {
    deps += [ ":libvpx_assembly_arm" ]
  }

  public_configs = [ ":libvpx_external_config" ]
}

if (use_system_libvpx) {
  pkg_config("system_libvpx") {
    packages = [ "vpx" ]
  }
}

shim_headers("libvpx_shim") {
  root_path = "source/libvpx/vpx"
  prefix = "vpx/"
  headers = [
    "vp8.h",
    "vp8cx.h",
    "vp8dx.h",
    "vpx_codec.h",
    "vpx_decoder.h",
    "vpx_encoder.h",
    "vpx_frame_buffer.h",
    "vpx_image.h",
    "vpx_integer.h",
  ]
}

group("libvpx") {
  if (use_system_libvpx) {
    deps = [ ":libvpx_shim" ]
    public_configs = [ ":system_libvpx" ]
  } else {
    public_deps = [ ":bundled_libvpx" ]
  }
}
