blob: 3cf42d96a60e10218af06ae311fb0c5949eea1f0 [file] [log] [blame]
# Copyright 2019 The Fuchsia 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("../../../../gn/glsl_shader_rules.gni")
_hotsort_dir = "${graphics_compute_dir}/hotsort"
#
# Generates a "HotSort target", which contains a compiled compute kernel to
# perform sorting of 32-bit or 64-bit integers, highly optimized for a given
# GPU architecture.
#
# To use a hotsort target in your code, do the following:
#
# 1) Declare a hotsort_target(<target_name>) target in your BUILD.gn
# that sets the appropriate configuration parameters (see below).
#
# 2) Add <target_name> to your source file's GN target deps variable.
#
# 3) In your source file, #include "<target_name>/hs_target.h", a
# special auto-generated header that defines a single variable
# declared as:
#
# extern struct hotsort_vk_target const * const <target_name>;
#
# NOTE: This GN template ensures that anything that depends on this
# GN target will have the right include_dirs set to do so.
#
# 4) Pass the <target_name> address to hotsort_vk_create().
#
#
# Variables:
#
# The following variable names are optional and used to select various
# configuration parameters sent to hotsort_gen. Their description comes from
# comments in the 'hotsort_gen' sources, but should be clarified in the future.
#
# vendor: vendor name. Used to pick the default configuration file from
# hotsort/platforms/vk/targets/configs/${vendor}/
# type_dwords: number of 32-bit words per sort entry.
# warp_lanes: Number of independent ALU cores (CUDA lanes) per
# processing element (CUDA warp).
# thread_regs: Number of registers to use per thread (lane?).
# smem_min: Minimum amount of memory that can be allocated (??)
# smem_quantum: smem quantum amount (??)
# smem_bs: ??
# smem_bc: ??
# warps_per_group: Max warps in a workgroup/cta/thread block (??)
# warps_max: Max warps that can fit in a multiprocessor (??)
# warps_min: blocks using smem barriers must have at least this many warps.
# warps_mod: the number of warps necessary to load balance horizontal
# merging.
# thread_xtra: ??
# merge_flip_lo: ??
# merge_flip_hi: ??
# merge_half_lo: ??
# merge_half_hi: ??
# merge_flip_warps: ??
# merge_half_warps: ??
# glsl_bindings: A string containing four comma-separated unsigned integers,
# related to GLSL in/out bindings (??)
# autotune: Set to true to enable auto-tuning of some parameters (??).
#
# The following variables are still supported for legacy reasons.
#
# hotsort_target_name:
# A name that conveys the configuration of the generated HotSort
# algorithm. If not provided, defaults to the short name of
# ${target_name}.
#
# hotsort_target_config_files:
# An optional list of additional configuration files, which will be added
# to the vendor-specific configuration file determined from the "vendor"
# variable (see below).
#
# hotsort_target_dump:
# Boolean, if true the generated GN target is a group that references a
# target binary produced by the host toolchain. Otherwise, a source set is
# produced on the current toolchain.
#
# hotsort_target_args:
# Extra arguments passed to the 'hotsort_gen' HotSort algorithm code
# generator.
#
template("hotsort_target") {
# Order of operations below:
#
# 1. Determine what compute shaders will be generated by the
# hotsort_gen executable.
#
# 2. Generate compute shaders and supporting files with the
# hotsort_gen executable.
#
# 3. Compile compute shaders to SPIR-V modules.
#
# 4. Optimize SPIR-V modules.
#
# 5. Remap SPIR-V modules.
#
# 6. Return the target as either:
# - a source set
# - a binary image produced by the host toolchain
#
# NOTE: If $hotsort_target_name is provided, the generated HotSort target
# and its artifacts are output to the root of $target_gen_dir. Otherwise,
# the outputs are found in $target_gen_dir/$target_name.
#
if (defined(invoker.hotsort_target_name)) {
_hs_target_name = invoker.hotsort_target_name
_hs_output_dir = "${target_gen_dir}"
} else {
_hs_target_name = get_label_info(target_name, "name")
_hs_output_dir = "${target_gen_dir}/${_hs_target_name}"
}
_hs_public_include_dirs = target_gen_dir
#
# Either dump a binary or produce a source set
#
_hs_target_dump =
defined(invoker.hotsort_target_dump) && invoker.hotsort_target_dump
#
# prefix target args with implicit args
#
_hs_target_gen_args = [
# Select glsl platform (what hotsort_gen calls an 'arch').
"-a",
"glsl",
# hotsort_gen output directory.
"-o",
rebase_path(_hs_output_dir, root_build_dir),
]
# Generate the hotsort_gen command line arguments from our GN variables.
_gen_args = []
if (defined(invoker.type_dwords)) {
_gen_args += [
"-t",
"${invoker.type_dwords}",
]
}
if (defined(invoker.warp_lanes)) {
_gen_args += [
"-w",
"${invoker.warp_lanes}",
]
}
if (defined(invoker.thread_regs)) {
_gen_args += [
"-r",
"${invoker.thread_regs}",
]
}
if (defined(invoker.smem_min)) {
_gen_args += [
"-g",
"${invoker.smem_min}",
]
}
if (defined(invoker.smem_quantum)) {
_gen_args += [
"-G",
"${invoker.smem_quantum}",
]
}
if (defined(invoker.smem_bs)) {
_gen_args += [
"-s",
"${invoker.smem_bs}",
]
}
if (defined(invoker.smem_bc)) {
_gen_args += [
"-S",
"${invoker.smem_bc}",
]
}
if (defined(invoker.warps_per_group)) {
_gen_args += [
"-b",
"${invoker.warps_per_group}",
]
}
if (defined(invoker.warps_max)) {
_gen_args += [
"-B",
"${invoker.warps_max}",
]
}
if (defined(invoker.warps_min)) {
_gen_args += [
"-m",
"${invoker.warps_min}",
]
}
if (defined(invoker.warps_mod)) {
_gen_args += [
"-M",
"${invoker.warps_mod}",
]
}
if (defined(invoker.thread_xtra)) {
_gen_args += [
"-x",
"${invoker.thread_xtra}",
]
}
if (defined(invoker.merge_flip_lo)) {
_gen_args += [
"-f",
"${invoker.merge_flip_lo}",
]
}
if (defined(invoker.merge_flip_hi)) {
_gen_args += [
"-F",
"${invoker.merge_flip_hi}",
]
}
if (defined(invoker.merge_half_lo)) {
_gen_args += [
"-c",
"${invoker.merge_half_lo}",
]
}
if (defined(invoker.merge_half_hi)) {
_gen_args += [
"-C",
"${invoker.merge_half_hi}",
]
}
if (defined(invoker.merge_flip_warps)) {
_gen_args += [
"-p",
"${invoker.merge_flip_warps}",
]
}
if (defined(invoker.merge_half_warps)) {
_gen_args += [
"-P",
"${invoker.merge_half_warps}",
]
}
if (defined(invoker.glsl_bindings)) {
# NOTE: Parameter is a string
_gen_args += [
"-L",
invoker.glsl_bindings,
]
}
if (defined(invoker.autotune) && invoker.autotune) {
# NOTE: Parameter is a boolean
_gen_args += [ "-z" ]
}
_hs_target_gen_args += _gen_args
# Legacy support
if (defined(invoker.hotsort_target_args)) {
_hs_target_gen_args += invoker.hotsort_target_args
}
#
# define generated sources, includes and deps
#
_hs_target_gen_includes_public = [ "${_hs_output_dir}/hs_target.h" ]
_hs_target_gen_includes =
[ "${_hs_output_dir}/hs_config.h" ] + _hs_target_gen_includes_public
_hs_target_gen_sources = [ "${_hs_output_dir}/" + _hs_target_name + ".c" ]
_hs_target_gen_inlines = [ "${_hs_output_dir}/hs_modules.inl" ]
#
# define source set sources
#
_hs_target_include_dirs = [
_hs_output_dir,
"${_hotsort_dir}/platforms/vk/targets",
"${_hotsort_dir}/platforms/vk",
]
_hs_target_sources =
_hs_target_gen_includes + _hs_target_gen_sources + _hs_target_gen_inlines
#
# generated compute shaders
#
_hs_comp_names =
exec_script("${_hotsort_dir}/platforms/vk/targets/hotsort_comp_names.py",
_hs_target_gen_args,
"list lines")
_hs_comp_sources =
process_file_template(_hs_comp_names,
"${_hs_output_dir}/comp/{{source_file_part}}")
#
# generate the .comp shaders
#
# Note that hs_modules.txt should match names returned by script
#
_gen_comp_target_name = "gen_comp_${_hs_target_name}"
compiled_action(_gen_comp_target_name) {
tool = "${_hotsort_dir}/hotsort_gen"
outputs =
_hs_comp_sources + _hs_target_gen_sources + _hs_target_gen_includes
args = [
"-D",
_hs_target_name,
] + _hs_target_gen_args
}
#
# copy any configuration files to the target directory
#
_gen_config_dir =
"${_hotsort_dir}/platforms/vk/targets/configs/${invoker.vendor}"
_gen_config_files = [ "${_gen_config_dir}/hs_glsl_macros_config.h" ]
if (defined(invoker.hotsort_target_config_files)) {
_gen_config_files += invoker.hotsort_target_config_files
}
_gen_copy_target_name = "gen_copy_${_hs_target_name}"
copy(_gen_copy_target_name) {
sources = _gen_config_files
outputs = [
"${_hs_output_dir}/{{source_file_part}}",
]
}
#
# compile the .comp shaders to SPIR-V modules
#
_gen_spv_target_name = "gen_spv_${_hs_target_name}"
graphics_compute_compile_glsl_shader_foreach(_gen_spv_target_name) {
# Ensure we only keep the .comp files as sources for this step.
set_sources_assignment_filter([
"*.h",
"*.c",
])
sources = get_target_outputs(":${_gen_comp_target_name}")
inputs = [ "${_hotsort_dir}/platforms/vk/targets/hs_glsl_macros.h" ] +
_hs_target_gen_includes +
get_target_outputs(":${_gen_copy_target_name}")
output_dir = _hs_output_dir
args = [
"--target-env",
"vulkan1.1",
]
include_dirs = _hs_target_include_dirs
deps = [
":${_gen_comp_target_name}",
":${_gen_copy_target_name}",
]
}
#
# dump the modules as uint32_t literals
#
_gen_modules_target_name = "gen_modules_${_hs_target_name}"
compiled_action(_gen_modules_target_name) {
tool = "${_hotsort_dir}/platforms/vk/targets:hotsort_modules_to_literals"
inputs = get_target_outputs(":${_gen_spv_target_name}")
outputs = _hs_target_gen_inlines
args = rebase_path(outputs, root_build_dir) +
rebase_path(inputs, root_build_dir)
deps = [
":${_gen_spv_target_name}",
]
}
#
# either dump a binary or return a source set
#
if (_hs_target_dump) {
#
# executable for dumping a binary image of target
#
_hs_target_dump_name = "hotsort_dump_" + invoker.hotsort_target_name
executable(_hs_target_dump_name) {
defines = [ "HS_DUMP" ]
sources = _hs_target_gen_sources
include_dirs = _hs_target_include_dirs
deps = [
"${_gen_comp_target_name}",
]
}
#
# dump a binary image of target
#
_gen_bin_target_name = "gen_bin_${_hs_target_name}"
compiled_action(_gen_bin_target_name) {
tool = ":$_hs_target_dump_name"
sources = _hs_target_sources
outputs = [
"${_hs_output_dir}/hs_target.bin",
]
args = rebase_path(outputs, root_build_dir)
public_deps = [
":$_hs_target_dump_name",
]
}
#
# dummy group invokes $host_toolchain
#
group(target_name) {
public_deps = [
":${_gen_bin_target_name}($host_toolchain)",
]
}
} else {
#
# target is a source set
#
_config_name = "${target_name}_public_config"
config(_config_name) {
include_dirs = [ _hs_public_include_dirs ]
}
source_set(target_name) {
public = [
"${_hs_output_dir}/hs_target.h",
]
sources = _hs_target_sources
include_dirs = _hs_target_include_dirs
public_configs = [ ":${_config_name}" ]
deps = [
":${_gen_comp_target_name}",
":${_gen_modules_target_name}",
":${_gen_spv_target_name}",
]
}
}
}