# Copyright 2019 The ANGLE Project 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_overrides/angle.gni")

declare_args() {
  is_ggp = false

  # Extract native libs in ANGLE apk. Useful for flamegraph generation.
  angle_extract_native_libs = false

  # Display mode for ANGLE vulkan display, could be 'simple' or 'headless', default is 'simple'.
  angle_vulkan_display_mode = "simple"

  # Defaults to capture building to $root_out_dir/angle_libs/with_capture.
  # Switch on to build capture to $root_out_dir.
  angle_with_capture_by_default = false

  # Enables OpenCL support, off by default.
  angle_enable_cl = false
}

if (angle_has_build) {
  import("//build/config/dcheck_always_on.gni")
  import("//build/config/ozone.gni")
  import("//build/config/sanitizers/sanitizers.gni")
  import("//build/config/ui.gni")  # import the use_x11 variable
  import("//build_overrides/build.gni")
  import("//testing/test.gni")
  if (is_android) {
    import("//build/config/android/config.gni")
  }

  if (is_win) {
    import("//build/config/win/visual_studio_version.gni")
  }

  if (is_chromecast) {
    angle_vulkan_display_mode = "headless"
  }

  angle_use_x11 = use_x11 && !is_ggp
  angle_use_vulkan_display =
      is_linux && !use_x11 && !is_ggp && (!use_ozone || is_chromecast)
} else {
  declare_args() {
    is_ubsan = false
    is_tsan = false
    is_asan = false
    is_lsan = false
    build_with_chromium = false
    dcheck_always_on = false
    angle_use_x11 = (is_linux || is_chromeos) && !is_ggp
    use_ozone = false
    ozone_platform_gbm = false
    use_fuzzing_engine = false
    use_xcode_clang = false
    is_apple = is_mac || is_ios
  }

  declare_args() {
    angle_use_vulkan_display = is_linux && !angle_use_x11 && !is_ggp
  }
}

# Subdirectory to place data files (e.g. layer JSON files).
angle_data_dir = "angledata"

declare_args() {
  if (current_cpu == "arm64" || current_cpu == "x64" ||
      current_cpu == "mips64el" || current_cpu == "s390x" ||
      current_cpu == "ppc64") {
    angle_64bit_current_cpu = true
  } else if (current_cpu == "arm" || current_cpu == "x86" ||
             current_cpu == "mipsel" || current_cpu == "s390" ||
             current_cpu == "ppc") {
    angle_64bit_current_cpu = false
  } else {
    assert(false, "Unknown current CPU: $current_cpu")
  }
}

declare_args() {
  if (!is_android) {
    ndk_api_level_at_least_26 = false
  } else {
    ndk_api_level_at_least_26 =
        (!angle_64bit_current_cpu && android32_ndk_api_level >= 26) ||
        (angle_64bit_current_cpu && android64_ndk_api_level >= 26)
  }

  # Vulkan loader is statically linked on Mac. http://anglebug.com/4477
  angle_shared_libvulkan = !is_mac

  # There's no "is_winuwp" helper in BUILDCONFIG.gn, so we define one ourselves
  angle_is_winuwp = is_win && target_os == "winuwp"

  # Default to using "_angle" suffix on Android
  if (is_android) {
    angle_libs_suffix = "_angle"
  } else {
    angle_libs_suffix = ""
  }

  # Currently Windows on Arm doesn't support OpenGL or Vulkan.
  is_win_arm64 = is_win && target_cpu == "arm64"
}

declare_args() {
  # By default, ANGLE is using a thread pool for parallel compilation.
  # Activating the delegate worker results in posting the tasks using the
  # embedder API. In Chromium code base, it results in sending tasks to the
  # worker thread pool.
  angle_delegate_workers = build_with_chromium

  # True if we are building inside an ANGLE checkout.
  angle_standalone = !build_with_chromium

  angle_enable_d3d9 = is_win && !angle_is_winuwp
  angle_enable_d3d11 = is_win
  angle_enable_gl =
      (ozone_platform_gbm || !is_linux || (angle_use_x11 && !is_chromeos)) &&
      !is_fuchsia && !angle_is_winuwp && !is_ggp && !is_win_arm64

  angle_enable_vulkan =
      angle_has_build &&
      ((is_win && !angle_is_winuwp) ||
       (is_linux && (angle_use_x11 || angle_use_vulkan_display) &&
        !is_chromeos) || is_android || is_fuchsia || is_ggp || is_mac)

  # Disable null backend to save space for official build.
  angle_enable_null = !is_official_build
  angle_enable_gl_desktop = !is_android && !is_ios

  # http://anglebug.com/2634
  angle_enable_metal = is_mac

  # Enables the OpenCL pass-through back end
  angle_enable_cl_passthrough = angle_enable_cl
}

# OpenCL is not supported on Windows UWP, because the CL headers include DX9, which is not
# supported by UWP. A workaround might be possible if CL support on UWP is required.
assert(!angle_is_winuwp || !angle_enable_cl,
       "OpenCL is not supported on Windows UWP")

if (!angle_enable_cl) {
  angle_enable_cl_passthrough = false
}

declare_args() {
  # Currently SwiftShader's Vulkan front-end doesn't build on Android.
  # SwiftShader is not needed on Fuchsia because Vulkan is supported on all
  # devices that run Fuchsia.
  angle_enable_swiftshader =
      angle_enable_vulkan && !is_android && !is_fuchsia && !is_ggp

  angle_enable_hlsl = angle_enable_d3d9 || angle_enable_d3d11
  angle_enable_essl = angle_enable_gl || use_ozone
  angle_enable_glsl = angle_enable_gl || use_ozone
  angle_enable_trace = false
  angle_enable_trace_android_logcat = false

  # Disable the layers in ubsan builds because of really slow builds.
  # TODO(anglebug.com/4082) enable validation layers on mac for swiftshader
  # Vulkan Validation Layers require Android NDK API level 26, i.e. Oreo, due to
  # Vulkan Validation Layers compatibility issues, see http://crrev/c/1405714.
  # TODO(http://fxbug.dev/73208) Validation is temporarily disabled on Fuchsia.
  # Re-enable once the issue is resolved.
  angle_enable_vulkan_validation_layers =
      angle_enable_vulkan && !is_ubsan && !is_tsan && !is_asan &&
      (is_debug || dcheck_always_on) && !is_mac &&
      (!is_android || ndk_api_level_at_least_26) && !is_fuchsia

  # ISpriteVisual windows cannot be validated and can lead to crashes if an invalid window is
  # provided to ANGLE. Disable them for non-standalone ANGLE builds. crbug.com/1176118
  angle_enable_d3d11_compositor_native_window =
      angle_enable_d3d11 && angle_standalone

  # Disable overlay by default
  angle_enable_overlay = false

  # Disable performance counter output by default
  angle_enable_perf_counter_output = false

  # We should use EAGL (ES) on iOS except on Mac Catalyst on Intel CPUs, which uses CGL (desktop GL).
  angle_enable_eagl = angle_enable_gl && is_ios &&
                      !(target_environment == "catalyst" &&
                        (target_cpu == "x86" || target_cpu == "x64"))

  angle_vulkan_headers_dir =
      "$angle_root/third_party/vulkan-deps/vulkan-headers/src"
  angle_vulkan_loader_dir =
      "$angle_root/third_party/vulkan-deps/vulkan-loader/src"
  angle_vulkan_tools_dir =
      "$angle_root/third_party/vulkan-deps/vulkan-tools/src"
  angle_vulkan_validation_layers_dir =
      "$angle_root/third_party/vulkan-deps/vulkan-validation-layers/src"
}

declare_args() {
  # TODO(jdarpinian): Support enabling CGL and EAGL at the same time using the soft linking code. Also support disabling both for Metal-only builds.
  angle_enable_cgl = angle_enable_gl && !angle_enable_eagl && is_apple

  angle_has_histograms = angle_has_build
}

if (!defined(angle_zlib_compression_utils_dir)) {
  angle_zlib_compression_utils_dir = "//third_party/zlib/google"
}

angle_common_configs = [
  angle_root + ":angle_release_asserts_config",
  angle_root + ":constructor_and_destructor_warnings",
  angle_root + ":extra_warnings",
  angle_root + ":internal_config",
  angle_root + ":angle_uwp_env",
]

angle_remove_configs = []

if (angle_has_build) {
  angle_remove_configs += [ "//build/config/compiler:default_include_dirs" ]
}

if (angle_has_build && is_clang) {
  angle_remove_configs += [ "//build/config/clang:find_bad_constructs" ]
}

set_defaults("angle_executable") {
  configs = angle_common_configs
  public_configs = []
  suppressed_configs = angle_remove_configs
  data_deps = []
}

set_defaults("angle_shared_library") {
  configs = angle_common_configs
  public_configs = []
  suppressed_configs = angle_remove_configs
}

set_defaults("angle_source_set") {
  configs = angle_common_configs
  public_configs = []
  suppressed_configs = angle_remove_configs
}

set_defaults("angle_static_library") {
  configs = angle_common_configs
  public_configs = []
  suppressed_configs = angle_remove_configs
}

set_defaults("angle_test") {
  # Gtest itself can't pass all the strict warning filters.
  configs = angle_common_configs - [
              "$angle_root:constructor_and_destructor_warnings",
              "$angle_root:extra_warnings",
            ] + [ "$angle_root/src/tests:angle_maybe_has_histograms" ]

  public_configs = []
  public_deps = []
  sources = []
  data = []
  defines = []
  deps = []
  data_deps = []
  suppressed_configs = angle_remove_configs
}

template("angle_executable") {
  executable(target_name) {
    forward_variables_from(invoker,
                           "*",
                           [
                             "configs",
                             "suppressed_configs",
                             "visibility",
                           ])

    # Needed because visibility is global.
    forward_variables_from(invoker, [ "visibility" ])

    configs += invoker.configs
    configs -= invoker.suppressed_configs

    if (angle_has_build && is_win) {
      data_deps += [ "//build/win:runtime_libs" ]
    }
  }
}

template("angle_shared_library") {
  # On ios, define an ios_framework_bundle instead of a shared library.
  # ios_framework_bundle doesn't automatically link, so we have to create
  # a group that links and bundles the framework as well.
  target_type = "shared_library"
  internal_target_name = target_name
  if (is_ios) {
    target_type = "ios_framework_bundle"
    internal_target_name = target_name + "_framework"
  }
  target(target_type, internal_target_name) {
    forward_variables_from(invoker,
                           "*",
                           [
                             "configs",
                             "suppressed_configs",
                             "visibility",
                           ])

    # Needed because visibility is global.
    forward_variables_from(invoker, [ "visibility" ])

    configs += invoker.configs
    configs -= invoker.suppressed_configs

    public_configs += [ angle_root + ":shared_library_public_config" ]

    if (is_android) {
      configs += [ angle_root + ":build_id_config" ]
      configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
    }
    if (is_ios) {
      info_plist = "$angle_root/util/ios/Info.plist"

      # shared libraries are hidden inside ios_framework_bundle, but we include headers from them
      # Specifically, libGLESv1_CM includes headers from libGLESv2
      check_includes = false
    }
  }
  if (is_ios) {
    group(target_name) {
      forward_variables_from(invoker,
                             [
                               "testonly",
                               "visibility",
                             ])
      public_deps = [
        ":${internal_target_name}+bundle",
        ":${internal_target_name}+link",
      ]
    }
  }
}

template("angle_source_set") {
  source_set(target_name) {
    forward_variables_from(invoker,
                           "*",
                           [
                             "configs",
                             "suppressed_configs",
                             "visibility",
                           ])

    # Needed because visibility is global.
    forward_variables_from(invoker, [ "visibility" ])

    configs += invoker.configs
    configs -= invoker.suppressed_configs
  }
}

template("angle_static_library") {
  static_library(target_name) {
    forward_variables_from(invoker,
                           "*",
                           [
                             "configs",
                             "suppressed_configs",
                             "visibility",
                           ])

    # Needed because visibility is global.
    forward_variables_from(invoker, [ "visibility" ])

    configs += invoker.configs
    configs -= invoker.suppressed_configs
  }
}

if (angle_standalone || build_with_chromium) {
  template("angle_test") {
    test(target_name) {
      forward_variables_from(invoker,
                             "*",
                             [
                               "configs",
                               "data",
                               "public_deps",
                             ])

      configs += invoker.configs
      configs -= invoker.suppressed_configs

      if (is_ios) {
        # shared libraries are hidden inside ios_framework_bundle, but we include headers from them
        check_includes = false
      }

      public_deps = invoker.public_deps + [
                      "$angle_root:angle_common",
                      "$angle_root:includes",
                      "$angle_root/src/tests:angle_test_expectations",
                      "$angle_root/third_party/rapidjson:rapidjson",
                      "$angle_root/util:angle_test_utils",
                      "//testing/gmock",
                      "//testing/gtest",
                      "//third_party/googletest:gmock",
                      "//third_party/googletest:gtest",
                    ]

      data = invoker.data + [
               "$angle_root/scripts/run_gtest_angle_test.py",
               "//testing/scripts/common.py",
               "//testing/xvfb.py",
             ]

      sources += [
        "$angle_root/src/tests/test_utils/runner/HistogramWriter.h",
        "$angle_root/src/tests/test_utils/runner/TestSuite.cpp",
        "$angle_root/src/tests/test_utils/runner/TestSuite.h",
      ]

      if (angle_has_histograms) {
        sources +=
            [ "$angle_root/src/tests/test_utils/runner/HistogramWriter.cpp" ]
        deps += [
          "//third_party/catapult/tracing/tracing:histogram",
          "//third_party/catapult/tracing/tracing:reserved_infos",
        ]
      }

      if (is_mac && angle_enable_metal) {
        # On macOS, compiling Metal shader sometimes takes very long time due to internal caching
        # mechanism. This hooking library is a way to bypass this caching mechanism.
        data_deps += [ "$angle_root/src/libANGLE/renderer/metal/file_hooking:metal_shader_cache_file_hooking" ]
      }

      if ((is_linux && !is_chromeos) ||
          (build_with_chromium && is_chromeos_lacros && !is_chromeos_device)) {
        use_xvfb = true
      }

      if ((is_linux || is_chromeos) && !is_component_build) {
        # Set rpath to find shared libs in a non-component build.
        configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
      }

      if (is_android) {
        public_configs += [ "$angle_root:build_id_config" ]
        configs -= [ "//build/config/android:hide_all_but_jni" ]
        use_default_launcher = false
        generate_final_jni = false
        android_manifest_template = "$angle_root/src/tests/test_utils/runner/android/java/AndroidManifest.xml.jinja2"
        deps += [
          "$angle_root/src/tests:native_test_java",
          "$angle_root/src/tests:native_test_support_android",
        ]
      }
      if (is_ios) {
        # We use a special main function on iOS to initialize UIKit before the normal main runs.
        ldflags = [
          "-e",
          "_ios_main",
        ]
        sources += [ "$angle_root/util/ios/ios_main.mm" ]
      }

      if (angle_has_build && is_win) {
        data_deps += [ "//build/win:runtime_libs" ]
      }
    }
  }
}

# Used by a few targets that compile traces.
template("angle_trace_fixture") {
  _config_name = target_name + "_config"
  config(_config_name) {
    include_dirs = [ "$angle_root/src/libANGLE/capture" ]
  }
  angle_source_set(target_name) {
    testonly = true
    defines = [ "ANGLE_REPLAY_IMPLEMENTATION" ]
    suppressed_configs += [ "$angle_root:constructor_and_destructor_warnings" ]
    sources = [
      "$angle_root/src/libANGLE/capture/trace_fixture.cpp",
      "$angle_root/src/libANGLE/capture/trace_fixture.h",
      invoker.gl_header,
    ]
    public_deps = [ "$angle_root:includes" ]
    if (defined(invoker.public_deps)) {
      public_deps += invoker.public_deps
    }
    include_dirs = [ "." ]
    public_configs = [ ":${_config_name}" ]
    if (defined(invoker.public_configs)) {
      public_configs += invoker.public_configs
    }
    if (is_ios) {
      # shared libraries are hidden inside ios_framework_bundle, but we include headers from them
      check_includes = false
    }
  }
}

template("angle_trace") {
  _trace_name = invoker.trace_name
  _trace_dir = invoker.trace_dir
  _trace_ctx = invoker.trace_ctx
  _trace_prefix = "${_trace_dir}/${_trace_name}_capture_context${_trace_ctx}"
  angle_shared_library(target_name) {
    testonly = true

    # Similar to capture replay sample, use the file index for sources
    sources = [
                "${_trace_prefix}.cpp",
                "${_trace_prefix}.h",
              ] + invoker.sources

    data = [ "${_trace_prefix}.angledata.gz" ]
    defines = [ "ANGLE_REPLAY_IMPLEMENTATION" ]
    suppressed_configs += [ "$angle_root:constructor_and_destructor_warnings" ]

    deps = [
      "$angle_root:includes",
      invoker.fixture,
    ]

    if (is_android) {
      libs = [ "log" ]
    }

    # Disable optimization in the trace perf tests to avoid optimizing huge files.
    if (!is_debug) {
      suppressed_configs += [
        "//build/config/compiler:afdo",
        "//build/config/compiler:afdo_optimize_size",
        "//build/config/compiler:default_optimization",
        "//build/config/compiler/pgo:default_pgo_flags",
      ]
      configs += [ "//build/config/compiler:no_optimize" ]
    }

    include_dirs = [ "." ]

    if (defined(invoker.output_name)) {
      output_name = invoker.output_name
    }
  }

  angle_source_set(target_name + "_headers") {
    sources = [ "${_trace_prefix}.h" ]
  }
}
