blob: f5216537b4a6f2fda035de11684ac7a3049beed1 [file] [log] [blame]
# Copyright 2021 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("//build/components.gni")
import("//build/zircon/c_utils.gni")
import("//src/graphics/lib/compute/gn/glsl_shader_rules.gni")
#
# Generates a SPIR-V target archive by performing the following steps:
#
# 1. Compile the target archive data.
# 2. Dump the data .rodata sections to a binary.
# 3. Compile all compute shaders.
# 4. Archive the data binaries followed by the SPIR-V modules.
#
# There are two templates that produce different outputs and target
# types but have identical inputs.
#
# 1. A Fuchsia-only run-time loadable target archive binary file:
#
# target_archive_resource(target_name)
#
# 2. A compile-time linkable target archive:
#
# target_archive_linkable(target_name)
#
# Upon completion, the root of $target_gen_dir contains all outputs.
#
# Multiple subdirectories in the $target_gen_dir contain the compute
# shaders and successive stages of processed SPIR-V modules.
#
# The following variables can be defined by the invoker:
#
# - "target_archive_name" : Explicit name of the target archive
# - "struct_sources" : C sources defining structured data
# - "struct_include_dirs" : C include dirs
# - "shader_sources" : GLSL shader sources (e.g. `.comp`)
# - "shader_inputs" : GLSL source dependencies
# - "shader_include_dirs" : GLSL include dirs
# - "binary_sources" : Binary sources
# - "binary_deps" : Binary dependency labels
# - "defines" : Defines passed to both C and GLSL sources
# - "gen_debug_shaders" : generate debug shaders
# - "skip_spirv_opt" : skip the `spirv-opt` pass
#
# The archive is built by appending the binaries in order:
# - The C sources data in their original listed order
# - The SPIR-V modules produced from the GLSL shader sources.
#
# TODO: Only one data source is supported at this time. A new script
# or a `toolchain_utils_action_foreach` would be required.
#
#
# Basic target archive template
#
template("target_archive") {
#
# Is an explicit target archive name defined?
#
if (defined(invoker.target_archive_name)) {
_target_archive_name = invoker.target_archive_name
} else {
_target_archive_name = target_name
}
#
# Define template internal names
#
main_target = target_name
_target_archive_dir = "${target_gen_dir}/${_target_archive_name}"
_target_archive_name_part = "${_target_archive_dir}/${_target_archive_name}"
_target_archive_file_ar = _target_archive_name_part + ".ar"
_target_archive_file_h = _target_archive_name_part + ".h"
_target_archive_file_S = _target_archive_name_part + ".S"
_target_archive_outputs = [
_target_archive_file_ar,
_target_archive_file_h,
_target_archive_file_S,
]
_target_archive_deps = []
#
# Compile the sources
#
if (defined(invoker.struct_sources) && invoker.struct_sources != []) {
_struct_sources_executable = "_target_archive.$target_name.executable"
_struct_sources_image = "_target_archive.$target_name.image"
# This executable is not a tool to be used outside the build
metadata = {
tool_barrier = []
}
# First build a tiny executable that is specially linked to use no normal
# startup or library code so it contains just the definitions from
# struct_sources, rooted at the `kRodata` symbol.
executable(_struct_sources_executable) {
visibility = [ ":*" ]
forward_variables_from(invoker,
[
"defines",
"testonly",
])
sources = invoker.struct_sources
if (defined(invoker.struct_include_dirs)) {
include_dirs = invoker.struct_include_dirs
}
configs += [
"//src/graphics/lib/compute/tools/target_archive:struct_sources.config",
]
}
# Now extract the raw binary image from that executable into a file.
# The resulting binary contains just the `kRodata` variable's contents.
image_binary(_struct_sources_image) {
visibility = [ ":$main_target" ]
forward_variables_from(invoker, [ "testonly" ])
deps = [ ":$_struct_sources_executable" ]
output_name = _target_archive_name
}
_target_archive_deps += [ ":$_struct_sources_image" ]
}
#
# Compile the .comp shaders to SPIR-V modules and perform multiple
# post-processing passes.
#
_spirv_modules = _target_archive_name + "_spirv_modules"
if (defined(invoker.shader_sources) && invoker.shader_sources != []) {
graphics_compute_compile_glsl_shader_foreach(_spirv_modules) {
output_dir = _target_archive_dir
args = [
"--target-env",
"vulkan1.2",
]
sources = invoker.shader_sources
if (defined(invoker.shader_inputs)) {
inputs = invoker.shader_inputs
}
if (defined(invoker.shader_include_dirs)) {
include_dirs = invoker.shader_include_dirs
}
forward_variables_from(invoker,
[
"defines",
"gen_debug_shaders",
"skip_spirv_opt",
])
}
_target_archive_deps += [ ":$_spirv_modules" ]
}
#
# Build a target archive from a target binary and SPIR-V modules.
#
# If it exists, the target binary is listed first.
#
compiled_action(main_target) {
tool = "//src/graphics/lib/compute/tools/target_archive"
outputs = _target_archive_outputs
deps = _target_archive_deps
sources = []
foreach(label, deps) {
sources += get_target_outputs(label)
}
if (defined(invoker.binary_deps)) {
deps += invoker.binary_deps
}
if (defined(invoker.binary_sources)) {
sources += invoker.binary_sources
}
args = [ _target_archive_name ] + #
rebase_path([ _target_archive_name_part ], root_build_dir) + #
rebase_path(sources, root_build_dir) #
}
}
#
# Create a loadable target archive
#
# This is primarily a Fuchsia-only target.
#
template("target_archive_resource") {
#
# Create the target archive
#
_internal = target_name + "_internal"
target_archive(_internal) {
target_archive_name = invoker.target_name
forward_variables_from(invoker,
[
"struct_sources",
"struct_include_dirs",
"shader_sources",
"shader_inputs",
"shader_include_dirs",
"binary_sources",
"binary_deps",
"defines",
"gen_debug_shaders",
"skip_spirv_opt",
])
}
if (is_fuchsia) {
#
# Declare a Fuchsia resource
#
resource(target_name) {
sources = filter_include(get_target_outputs(":${_internal}"), [ "*.ar" ])
outputs = [ "data/targets/{{source_file_part}}" ]
deps = [ ":${_internal}" ]
}
} else {
#
# Force generation of the outputs
#
group(target_name) {
deps = [ ":${_internal}" ]
}
}
}
#
# Create a linkable target archive.
#
template("target_archive_linkable") {
#
# Create the target archive
#
_internal = target_name + "_internal"
target_archive(_internal) {
target_archive_name = invoker.target_name
forward_variables_from(invoker,
[
"struct_sources",
"struct_include_dirs",
"shader_sources",
"shader_inputs",
"shader_include_dirs",
"binary_sources",
"binary_deps",
"defines",
"gen_debug_shaders",
"skip_spirv_opt",
])
}
_config = target_name + "_config"
config(_config) {
include_dirs = [
"${target_gen_dir}/${invoker.target_name}",
"//src/graphics/lib/compute/tools/target_archive/include",
]
}
source_set(target_name) {
public_configs = [ ":${_config}" ]
inputs = filter_include(get_target_outputs(":${_internal}"), [ "*.ar" ])
public = filter_include(get_target_outputs(":${_internal}"), [ "*.h" ])
sources = filter_include(get_target_outputs(":${_internal}"),
[
"*.S",
"*.h",
])
sources += [ "//src/graphics/lib/compute/tools/target_archive/include/target_archive/target_archive.h" ]
deps = [ ":${_internal}" ]
}
}