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

import("dav1d_generated.gni")

import("//build/config/compiler/compiler.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//third_party/nasm/nasm_assemble.gni")

# MemorySanitizer can't handle assembly, https://crbug.com/928357.
enable_nasm = (current_cpu == "x86" || current_cpu == "x64") && !is_msan

if (is_win) {
  platform_config_root = "config/win/$current_cpu"
} else if (is_msan) {
  assert(current_cpu == "x64" && (is_linux || is_chromeos),
         "Only Linux X64 MSAN is supported")
  platform_config_root = "config/linux-noasm/$current_cpu"
} else if (current_cpu == "loong64" || current_cpu == "mipsel" ||
           current_cpu == "mips64el" || current_cpu == "ppc64") {
  platform_config_root = "config/linux-noasm/generic"
} else if (is_apple) {
  if (current_cpu == "arm64e") {
    platform_config_root = "config/apple/arm64"
  } else {
    platform_config_root = "config/apple/$current_cpu"
  }
} else {
  platform_config_root = "config/linux/$current_cpu"
}

# Clang LTO doesn't respect stack alignment and clang-cl doesn't support setting
# the stack alignment, so we must use the platform's default alignment in those
# cases; https://crbug.com/928743.
if (enable_nasm) {
  if (use_thin_lto || is_win) {
    needs_stack_alignment = false
    # The defaults are stack_alignment=4 for x86 and stack_alignment=16 for x64.
  } else {
    # The compiler flags, as well as the stack alignment values, all mirror
    # upstream's meson.build setup:
    # https://chromium.googlesource.com/external/github.com/videolan/dav1d/+/master/meson.build
    needs_stack_alignment = true
    if (current_cpu == "x64" || is_linux || is_apple) {
      stack_alignment = 16
    } else {
      stack_alignment = 4
    }
  }
}

config("public_dav1d_config") {
  include_dirs = [ "version" ]

  # Disable internal dav1d logs in the official build to save storage.
  if (is_official_build) {
    defines = [ "CONFIG_LOG=0" ]
  } else {
    defines = [ "CONFIG_LOG=1" ]
  }

  if (!is_android && !is_apple && !is_win) {
    defines += [
      "HAVE_PTHREAD_GETAFFINITY_NP=1",
      "HAVE_PTHREAD_SETAFFINITY_NP=1",
    ]
  }

  # Don't let dav1d export any symbols. Otherwise the verify_order step on macOS
  # can fail since these exports end up in the final Chromium binary.
  defines += [ "DAV1D_API=" ]
}

config("dav1d_config") {
  configs = [ ":public_dav1d_config" ]
  include_dirs = [
    "libdav1d",
    "libdav1d/include",
    "libdav1d/include/dav1d",
    platform_config_root,
  ]
  if (is_win && !is_clang) {
    include_dirs += [ "libdav1d/include/compat/msvc" ]
  }
}

dav1d_copts = [
  "-D_FILE_OFFSET_BITS=64",
  "-D_POSIX_C_SOURCE=200112L",
]

if (is_win) {
  if (!is_clang) {
    dav1d_copts += [
      "/wd4028",  # parameter different from declaration
      "/wd4090",  # broken with arrays of pointers
      "/wd4996",  # use of POSIX functions
      "/wd5287",  # operands are different enum types
    ]
  }
} else {
  dav1d_copts += [ "-std=c99" ]
  if (is_apple) {
    dav1d_copts += [ "-D_DARWIN_C_SOURCE" ]
  }
  if (is_linux || is_chromeos || is_android || current_os == "aix") {
    if (!is_clang) {
      dav1d_copts += [ "-D_GNU_SOURCE" ]
    }
  }
}

if (is_clang && (current_cpu == "arm" || current_cpu == "arm64" ||
                 current_cpu == "arm64e")) {
  if (is_win) {
    dav1d_copts += [ "/clang:-fno-align-functions" ]
  } else {
    dav1d_copts += [ "-fno-align-functions" ]
  }
}

if (enable_nasm) {
  nasm_assemble("dav1d_asm") {
    sources = x86_asm_sources

    inputs = [
      "$platform_config_root/config.asm",
      "libdav1d/src/ext/x86/x86inc.asm",

      # This is added here in addition to sources as it is included from some
      # other files. And in such case, we need to use inputs to teach GN that
      # some actions depend on this file indirectly.
      "libdav1d/src/x86/filmgrain_common.asm",
    ]

    include_dirs = [
      "libdav1d/src/",
      platform_config_root,
    ]

    nasm_flags = [
      "-P",
      rebase_path("$platform_config_root/config.asm", root_build_dir),
    ]

    defines = []
    if (needs_stack_alignment) {
      defines += [ "STACK_ALIGNMENT=$stack_alignment" ]
    }

    # Necessary to ensure macOS symbols end up with a _ prefix.
    if (is_apple) {
      defines += [ "PREFIX" ]
    }
  }
}

source_set("dav1d_headers") {
  configs -= [ "//build/config/compiler:chromium_code" ]
  configs += [
    "//build/config/compiler:no_chromium_code",
    ":dav1d_config",
  ]

  sources = c_headers
}

static_library("dav1d_8bit") {
  configs -= [ "//build/config/compiler:chromium_code" ]
  configs += [
    "//build/config/compiler:no_chromium_code",
    ":dav1d_config",
  ]

  sources = template_sources
  if (current_cpu == "x86" || current_cpu == "x64") {
    sources += x86_template_sources
  } else if (current_cpu == "arm") {
    sources += arm_template_sources
  } else if (current_cpu == "arm64" || current_cpu == "arm64e") {
    sources += arm_template_sources
  }

  cflags = dav1d_copts
  cflags += [ "-DBITDEPTH=8" ]

  deps = [ ":dav1d_headers" ]
}

static_library("dav1d_10bit") {
  configs -= [
    "//build/config/compiler:chromium_code",

    # Disable coverage for the 10 bit version to avoid confusing the
    # instrumentation about which version of the library is being run.
    # dav1d_10 bit was selected for this, as it's less used than dav1d_8bit,
    # which still has coverage enabled. See crbug.com/1030350.
    "//build/config/coverage:default_coverage",
  ]
  configs += [
    "//build/config/compiler:no_chromium_code",
    ":dav1d_config",
  ]

  sources = template_sources
  if (current_cpu == "x86" || current_cpu == "x64") {
    sources += x86_template_sources
  } else if (current_cpu == "arm") {
    sources += arm_template_sources
  } else if (current_cpu == "arm64" || current_cpu == "arm64e") {
    sources += arm_template_sources
  }

  cflags = dav1d_copts
  cflags += [ "-DBITDEPTH=16" ]

  deps = [ ":dav1d_headers" ]
}

if (current_cpu == "x86" || current_cpu == "x64") {
  static_library("dav1d_x86") {
    sources = [
      "libdav1d/src/x86/cpu.c",
      "libdav1d/src/x86/cpu.h",
    ]

    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [
      "//build/config/compiler:no_chromium_code",
      ":dav1d_config",
    ]
    cflags = dav1d_copts

    deps = [ ":dav1d_headers" ]
    allow_circular_includes_from = [ ":dav1d_headers" ]
  }
} else if (current_cpu == "arm" || current_cpu == "arm64" ||
           current_cpu == "arm64e") {
  static_library("dav1d_arm") {
    sources = [
      "libdav1d/src/arm/cpu.c",
      "libdav1d/src/arm/cpu.h",
    ]

    # These are not template based so should only be built once.
    if (current_cpu == "arm") {
      sources += arm32_asm_sources
    } else if (current_cpu == "arm64" || current_cpu == "arm64e") {
      sources += arm64_asm_sources
    }

    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [
      "//build/config/compiler:no_chromium_code",
      ":dav1d_config",
    ]

    # Necessary to ensure macOS symbols end up with a _ prefix.
    if (is_apple) {
      defines = [ "PREFIX" ]
    }

    cflags = dav1d_copts

    deps = [ ":dav1d_headers" ]
    allow_circular_includes_from = [ ":dav1d_headers" ]
  }
} else if (current_cpu == "riscv64") {
  static_library("dav1d_riscv") {
    sources = [
                "config/linux/riscv64/cpu-renamed.c",
                "libdav1d/src/riscv/cpu.h",
              ] + riscv64_asm_sources

    configs -= [ "//build/config/compiler:chromium_code" ]
    configs += [
      "//build/config/compiler:no_chromium_code",
      ":dav1d_config",
    ]

    cflags = dav1d_copts

    deps = [ ":dav1d_headers" ]
    allow_circular_includes_from = [ ":dav1d_headers" ]
  }
}

static_library("dav1d") {
  sources = c_sources
  if (is_win) {
    sources += [ "libdav1d/src/win32/thread.c" ]
  }

  configs -= [ "//build/config/compiler:chromium_code" ]
  configs += [
    "//build/config/compiler:no_chromium_code",
    ":dav1d_config",
  ]
  cflags = dav1d_copts

  deps = [
    ":dav1d_10bit",
    ":dav1d_8bit",
    ":dav1d_headers",
  ]

  public_configs = [ ":public_dav1d_config" ]

  if (current_cpu == "x86" || current_cpu == "x64") {
    deps += [ ":dav1d_x86" ]
    if (enable_nasm) {
      deps += [ ":dav1d_asm" ]
    }
  } else if (current_cpu == "arm" || current_cpu == "arm64" ||
             current_cpu == "arm64e") {
    deps += [ ":dav1d_arm" ]
  } else if (current_cpu == "riscv64") {
    deps += [ ":dav1d_riscv" ]
  }
}
