From b8249ce389809c672015df64c95ee4868ec41212 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 20 May 2024 16:06:37 -0700 Subject: [PATCH] [Impeller] Refactor impeller.gni impeller.gni turned from a small include file with minor templates into a giant 1000 line mess of unrelated templates over time. Moves templates into their own "TU"s. Once this patch sticks, will document all the templates and flags. No change in functionality in this patch. Just moves templates around. --- ci/licenses_golden/excluded_files | 2 +- impeller/tools/args.gni | 62 ++ impeller/tools/compiler.gni | 291 ++++++ impeller/tools/component.gni | 58 ++ impeller/tools/embed_blob.gni | 47 + impeller/tools/impeller.gni | 946 +----------------- impeller/tools/metal_library.gni | 78 ++ ...uild_metal_library.py => metal_library.py} | 0 impeller/tools/scene.gni | 46 + impeller/tools/shader_archive.gni | 25 + impeller/tools/shaders.gni | 149 +++ impeller/tools/shaders_gles.gni | 91 ++ impeller/tools/shaders_mtl.gni | 78 ++ impeller/tools/shaders_vk.gni | 85 ++ 14 files changed, 1019 insertions(+), 939 deletions(-) create mode 100644 impeller/tools/args.gni create mode 100644 impeller/tools/compiler.gni create mode 100644 impeller/tools/component.gni create mode 100644 impeller/tools/embed_blob.gni create mode 100644 impeller/tools/metal_library.gni rename impeller/tools/{build_metal_library.py => metal_library.py} (100%) create mode 100644 impeller/tools/scene.gni create mode 100644 impeller/tools/shader_archive.gni create mode 100644 impeller/tools/shaders.gni create mode 100644 impeller/tools/shaders_gles.gni create mode 100644 impeller/tools/shaders_mtl.gni create mode 100644 impeller/tools/shaders_vk.gni diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 37cc6dec12598..9274336fa9e30 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -201,10 +201,10 @@ ../../../flutter/impeller/tessellator/tessellator_unittests.cc ../../../flutter/impeller/toolkit/android/README.md ../../../flutter/impeller/toolkit/android/toolkit_android_unittests.cc -../../../flutter/impeller/tools/build_metal_library.py ../../../flutter/impeller/tools/check_licenses.py ../../../flutter/impeller/tools/malioc_cores.py ../../../flutter/impeller/tools/malioc_diff.py +../../../flutter/impeller/tools/metal_library.py ../../../flutter/impeller/tools/xxd.py ../../../flutter/impeller/typographer/typographer_unittests.cc ../../../flutter/lib/gpu/analysis_options.yaml diff --git a/impeller/tools/args.gni b/impeller/tools/args.gni new file mode 100644 index 0000000000000..6c81b2da7b16a --- /dev/null +++ b/impeller/tools/args.gni @@ -0,0 +1,62 @@ +# Copyright 2013 The Flutter 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("//flutter/common/config.gni") +import("//flutter/testing/testing.gni") + +declare_args() { + impeller_debug = + flutter_runtime_mode == "debug" || flutter_runtime_mode == "profile" + + # Whether the runtime capture/playback system is enabled. + impeller_capture = flutter_runtime_mode == "debug" + + # Whether the Metal backend is enabled. + impeller_enable_metal = (is_mac || is_ios) && target_os != "fuchsia" + + # Whether the OpenGLES backend is enabled. + impeller_enable_opengles = (is_linux || is_win || is_android || is_mac || + enable_unittests) && target_os != "fuchsia" + + # Whether the Vulkan backend is enabled. + impeller_enable_vulkan = (is_linux || is_win || is_android || is_mac || + enable_unittests) && target_os != "fuchsia" + + # Whether to use a prebuilt impellerc. + # If this is the empty string, impellerc will be built. + # If it is non-empty, it should be the absolute path to impellerc. + impeller_use_prebuilt_impellerc = "" + + # Whether to use a prebuilt scenec. + # If this is the empty string, scenec will be built. + # If it is non-empty, it should be the absolute path to scenec. + impeller_use_prebuilt_scenec = "" + + # If enabled, all OpenGL calls will be traced. Because additional trace + # overhead may be substantial, this is not enabled by default. + impeller_trace_all_gl_calls = false + + # Enable experimental 3D scene rendering. + impeller_enable_3d = false + + # Enable to get trace statements for canvas usage. + impeller_trace_canvas = false +} + +# Arguments that are combinations of other arguments by default but which can +# be overridden by the user. + +declare_args() { + # Wether to build and include the validation layers. + impeller_enable_vulkan_validation_layers = + impeller_enable_vulkan && flutter_runtime_mode == "debug" && + target_cpu == "arm64" + + # Whether Impeller supports rendering on the platform. + impeller_supports_rendering = + impeller_enable_metal || impeller_enable_opengles || + impeller_enable_vulkan + + impeller_enable_compute = impeller_enable_vulkan || impeller_enable_metal +} diff --git a/impeller/tools/compiler.gni b/impeller/tools/compiler.gni new file mode 100644 index 0000000000000..3857b7c38f810 --- /dev/null +++ b/impeller/tools/compiler.gni @@ -0,0 +1,291 @@ +# Copyright 2013 The Flutter 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/compiled_action.gni") +import("//flutter/impeller/tools/args.gni") + +# Dispatches to the build or prebuilt impellerc depending on the value of +# the `impeller_use_prebuilt_impellerc` argument. +# * When the `single_invocation` argument is false, all variables are +# forwarded to `compiled_action_foreach` or `action_foreach`, which will +# invoke `impellerc` separately for each source. +# * When the `single_invocation` argument is true, `impellerc` is only +# invoked once via `compiled_action` or `action`. +template("_impellerc") { + if (invoker.single_invocation) { + if (impeller_use_prebuilt_impellerc == "") { + compiled_action(target_name) { + forward_variables_from(invoker, "*") + tool = "//flutter/impeller/compiler:impellerc" + } + } else { + action(target_name) { + forward_variables_from(invoker, "*", [ "args" ]) + script = "//build/gn_run_binary.py" + impellerc_path = + rebase_path(impeller_use_prebuilt_impellerc, root_build_dir) + args = [ impellerc_path ] + invoker.args + } + } + } else { + if (impeller_use_prebuilt_impellerc == "") { + compiled_action_foreach(target_name) { + forward_variables_from(invoker, "*") + tool = "//flutter/impeller/compiler:impellerc" + } + } else { + action_foreach(target_name) { + forward_variables_from(invoker, "*", [ "args" ]) + script = "//build/gn_run_binary.py" + impellerc_path = + rebase_path(impeller_use_prebuilt_impellerc, root_build_dir) + args = [ impellerc_path ] + invoker.args + } + } + } +} + +# Required: shaders The list of shaders inputs to compile. +# Required: shader_target_flags The target flag(s) to append. Valid options: +# --sksl +# --metal-ios +# --metal-desktop +# --opengl-es +# --opengl-desktop +# --vulkan +# --runtime-stage-metal +# --runtime-stage-gles +# --runtime-stage-vulkan +# Not required for --shader_bundle mode. +# Required: sl_file_extension The file extension to use for output files. +# Not required for --shader_bundle mode. +# Optional: iplr Causes --sl output to be in iplr/runtime +# stage flatbuffer format. +# Optional: shader_bundle Specifies a Flutter GPU shader bundle +# configuration. +# Required: shader_bundle_output Specifies the output filename of the shader +# bundle. This is only required if +# shader_bundle is supplied. +# Optional: defines Specifies a list of valueless macro +# definitions. +# Optional: intermediates_subdir Specifies the subdirectory in which to put +# intermediates. +# Optional: json Causes output format to be JSON instead of +# flatbuffer. +template("impellerc") { + assert(defined(invoker.shaders), "Impeller shaders must be specified.") + assert(defined(invoker.shader_target_flags) || defined(invoker.shader_bundle), + "The flag to impellerc for target selection must be specified.") + assert(defined(invoker.sl_file_extension) || defined(invoker.shader_bundle), + "The extension of the SL file must be specified (metal, glsl, etc..).") + if (defined(invoker.shader_bundle)) { + assert( + defined(invoker.shader_bundle_output), + "When shader_bundle is specified, shader_bundle_output must also be specified.") + } + + if (defined(invoker.shader_target_flags)) { + shader_target_flags = invoker.shader_target_flags + } else { + shader_target_flags = [] + } + + sksl = false + foreach(shader_target_flag, shader_target_flags) { + sksl = shader_target_flag == "--sksl" + } + iplr = false + if (defined(invoker.iplr) && invoker.iplr) { + iplr = invoker.iplr + } + json = false + if (defined(invoker.json) && invoker.json) { + json = invoker.json + } + + # Not needed on every path. + not_needed([ + "iplr", + "sksl", + "shader_bundle", + "shader_bundle_output", + ]) + + _impellerc(target_name) { + pool = "//build/toolchain:toolchain_pool" + shader_bundle = defined(invoker.shader_bundle) + + # When single_invocation is true, impellerc will be invoked exactly once. When it's + # false, impellerc be invoked for each of the source file entries (invoker.shaders). + single_invocation = shader_bundle + + if (defined(invoker.intermediates_subdir)) { + subdir = invoker.intermediates_subdir + generated_dir = "$target_gen_dir/$subdir" + } else { + generated_dir = "$target_gen_dir" + } + + shader_lib_dir = rebase_path("//flutter/impeller/compiler/shader_lib") + args = [ "--include=$shader_lib_dir" ] + shader_target_flags + + # When we're in single invocation mode, we can't use source enumeration. + if (!single_invocation) { + depfile_path = "$generated_dir/{{source_file_part}}.d" + depfile_intermediate_path = rebase_path(depfile_path, root_build_dir) + depfile = depfile_path + args += [ + "--input={{source}}", + "--include={{source_dir}}", + "--depfile=$depfile_intermediate_path", + ] + + if (defined(invoker.shader_target_flag)) { + args += [ "${invoker.shader_target_flag}" ] + } + } + + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + args += [ "--gles-language-version=$gles_language_version" ] + } + + if (defined(invoker.metal_version)) { + assert(is_mac || is_ios) + metal_version = invoker.metal_version + args += [ "--metal-version=$metal_version" ] + } + + if (defined(invoker.use_half_textures) && invoker.use_half_textures) { + args += [ "--use-half-textures" ] + } + if (defined(invoker.require_framebuffer_fetch) && + invoker.require_framebuffer_fetch) { + args += [ "--require-framebuffer-fetch" ] + } + + if (json) { + args += [ "--json" ] + } + + if (iplr) { + # When building in IPLR mode, the compiler may be executed twice + args += [ "--iplr" ] + } + + # The `sl_output` is the raw shader file output by the compiler. For --iplr + # and --shader-bundle, this is used as the filename for the flatbuffer to + # output. + + if (shader_bundle) { + # When a shader bundle is specified, don't bother supplying flags for + # the reflection state as these are ignored. In this mode, the compiler + # is invoked multiple times and the reflection state for each shader is + # written to the output flatbuffer. + sl_output = "$generated_dir/${invoker.shader_bundle_output}" + sl_output_path = rebase_path(sl_output, root_build_dir) + + args += [ + "--sl=$sl_output_path", + "--shader-bundle=${invoker.shader_bundle}", + ] + + outputs = [ sl_output ] + } else if (sksl) { + # When SkSL is selected as a `shader_target_flags`, don't generate + # C++ reflection state. Nothing needs to use it and it's likely invalid + # given the special cases when generating SkSL. + # Note that this configuration is orthogonal to the "--iplr" flag + sl_output = + "$generated_dir/{{source_file_part}}.${invoker.sl_file_extension}" + sl_output_path = rebase_path(sl_output, root_build_dir) + + spirv_intermediate = "$generated_dir/{{source_file_part}}.spirv" + spirv_intermediate_path = rebase_path(spirv_intermediate, root_build_dir) + args += [ + "--sl=$sl_output_path", + "--spirv=$spirv_intermediate_path", + ] + + outputs = [ sl_output ] + } else { + # The default branch. Here we just generate one shader along with all of + # its C++ reflection state. + + sl_output = + "$generated_dir/{{source_file_part}}.${invoker.sl_file_extension}" + sl_output_path = rebase_path(sl_output, root_build_dir) + + reflection_json_intermediate = "$generated_dir/{{source_file_part}}.json" + reflection_header_intermediate = "$generated_dir/{{source_file_part}}.h" + reflection_cc_intermediate = "$generated_dir/{{source_file_part}}.cc" + + spirv_intermediate = "$generated_dir/{{source_file_part}}.spirv" + spirv_intermediate_path = rebase_path(spirv_intermediate, root_build_dir) + reflection_json_path = + rebase_path(reflection_json_intermediate, root_build_dir) + reflection_header_path = + rebase_path(reflection_header_intermediate, root_build_dir) + reflection_cc_path = + rebase_path(reflection_cc_intermediate, root_build_dir) + + args += [ + "--sl=$sl_output_path", + "--spirv=$spirv_intermediate_path", + "--reflection-json=$reflection_json_path", + "--reflection-header=$reflection_header_path", + "--reflection-cc=$reflection_cc_path", + ] + + outputs = [ + sl_output, + reflection_header_intermediate, + reflection_cc_intermediate, + ] + } + + if (defined(invoker.defines)) { + foreach(def, invoker.defines) { + args += [ "--define=$def" ] + } + } + + if (single_invocation) { + inputs = invoker.shaders + } else { + sources = invoker.shaders + } + } +} + +template("impellerc_reflect") { + assert( + defined(invoker.impellerc_invocation), + "The target that specifies the ImpellerC invocation to reflect must be defined.") + + reflect_config = "reflect_$target_name" + config(reflect_config) { + include_dirs = [ get_path_info( + get_label_info("//flutter/impeller:impeller", "target_gen_dir"), + "dir") ] + } + + impellerc_invocation = invoker.impellerc_invocation + + source_set(target_name) { + public_configs = [ ":$reflect_config" ] + public = filter_include(get_target_outputs(impellerc_invocation), [ "*.h" ]) + sources = filter_include(get_target_outputs(impellerc_invocation), + [ + "*.h", + "*.cc", + "*.mm", + ]) + + deps = [ + "//flutter/impeller/core", + impellerc_invocation, + ] + } +} diff --git a/impeller/tools/component.gni b/impeller/tools/component.gni new file mode 100644 index 0000000000000..00df9f2ee5294 --- /dev/null +++ b/impeller/tools/component.gni @@ -0,0 +1,58 @@ +# Copyright 2013 The Flutter 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("//flutter/common/config.gni") +import("//flutter/testing/testing.gni") + +# ------------------------------------------------------------------------------ +# @brief Define an Impeller component. Components are different +# Impeller subsystems part of the umbrella framework. +# +# @param[optional] target_type The type of the component. This can be any of +# the target types supported by GN. Defaults to +# source_set. If Impeller is not supported on the +# target platform, this target is a no-op. +# +template("impeller_component") { + if (defined(invoker.testonly) && invoker.testonly && !enable_unittests) { + group(target_name) { + not_needed(invoker, "*") + } + } else { + target_type = "source_set" + if (defined(invoker.target_type)) { + target_type = invoker.target_type + } + target(target_type, target_name) { + forward_variables_from(invoker, "*") + + if (!defined(invoker.public_configs)) { + public_configs = [] + } + + public_configs += [ "//flutter/impeller:impeller_public_config" ] + + if (!defined(invoker.cflags)) { + cflags = [] + } + cflags += [ "-Wthread-safety-analysis" ] + + if (!defined(invoker.cflags_objc)) { + cflags_objc = [] + } + + if (is_ios || is_mac) { + cflags_objc += flutter_cflags_objc_arc + } + + if (!defined(invoker.cflags_objcc)) { + cflags_objcc = [] + } + + if (is_ios || is_mac) { + cflags_objcc += flutter_cflags_objcc_arc + } + } + } +} diff --git a/impeller/tools/embed_blob.gni b/impeller/tools/embed_blob.gni new file mode 100644 index 0000000000000..b895d395a832a --- /dev/null +++ b/impeller/tools/embed_blob.gni @@ -0,0 +1,47 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +template("embed_blob") { + assert(defined(invoker.symbol_name), "The symbol name must be specified.") + assert(defined(invoker.blob), "The blob file to embed must be specified") + assert(defined(invoker.hdr), + "The header file containing the symbol name must be specified.") + assert(defined(invoker.cc), + "The CC file containing the symbol data must be specified.") + assert(defined(invoker.deps), "The target dependencies must be specified") + + gen_blob_target_name = "gen_blob_$target_name" + action(gen_blob_target_name) { + inputs = [ invoker.blob ] + outputs = [ + invoker.hdr, + invoker.cc, + ] + args = [ + "--symbol-name", + invoker.symbol_name, + "--output-header", + rebase_path(invoker.hdr), + "--output-source", + rebase_path(invoker.cc), + "--source", + rebase_path(invoker.blob), + ] + script = "//flutter/impeller/tools/xxd.py" + deps = invoker.deps + } + + embed_config = "embed_$target_name" + config(embed_config) { + include_dirs = [ get_path_info( + get_label_info("//flutter/impeller:impeller", "target_gen_dir"), + "dir") ] + } + + source_set(target_name) { + public_configs = [ ":$embed_config" ] + sources = get_target_outputs(":$gen_blob_target_name") + deps = [ ":$gen_blob_target_name" ] + } +} diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 3db9152849533..1aabc809cd926 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -2,944 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/compiled_action.gni") -import("//flutter/common/config.gni") -import("//flutter/impeller/tools/malioc.gni") -import("//flutter/testing/testing.gni") +# Global configuration options for Impeller. +import("//flutter/impeller/tools/args.gni") -declare_args() { - impeller_debug = - flutter_runtime_mode == "debug" || flutter_runtime_mode == "profile" +# The common template used by all Impeller components. +import("//flutter/impeller/tools/component.gni") - # Whether the Metal backend is enabled. - impeller_enable_metal = (is_mac || is_ios) && target_os != "fuchsia" +# Templates for compiling, reflecting, and packaging shaders used by Impeller. +import("//flutter/impeller/tools/shaders.gni") - # Whether the OpenGLES backend is enabled. - impeller_enable_opengles = (is_linux || is_win || is_android || is_mac || - enable_unittests) && target_os != "fuchsia" - - # Whether the Vulkan backend is enabled. - impeller_enable_vulkan = (is_linux || is_win || is_android || is_mac || - enable_unittests) && target_os != "fuchsia" - - # Whether to use a prebuilt impellerc. - # If this is the empty string, impellerc will be built. - # If it is non-empty, it should be the absolute path to impellerc. - impeller_use_prebuilt_impellerc = "" - - # Whether to use a prebuilt scenec. - # If this is the empty string, scenec will be built. - # If it is non-empty, it should be the absolute path to scenec. - impeller_use_prebuilt_scenec = "" - - # If enabled, all OpenGL calls will be traced. Because additional trace - # overhead may be substantial, this is not enabled by default. - impeller_trace_all_gl_calls = false - - # Enable experimental 3D scene rendering. - impeller_enable_3d = false - - # Enable to get trace statements for canvas usage. - impeller_trace_canvas = false -} - -declare_args() { - # Wether to build and include the validation layers. - impeller_enable_vulkan_validation_layers = - impeller_enable_vulkan && flutter_runtime_mode == "debug" && - target_cpu == "arm64" - - # Whether Impeller supports rendering on the platform. - impeller_supports_rendering = - impeller_enable_metal || impeller_enable_opengles || - impeller_enable_vulkan - - impeller_enable_compute = impeller_enable_vulkan || impeller_enable_metal -} - -# ------------------------------------------------------------------------------ -# @brief Define an Impeller component. Components are different -# Impeller subsystems part of the umbrella framework. -# -# @param[optional] target_type The type of the component. This can be any of -# the target types supported by GN. Defaults to -# source_set. If Impeller is not supported on the -# target platform, this target is a no-op. -# -template("impeller_component") { - if (defined(invoker.testonly) && invoker.testonly && !enable_unittests) { - group(target_name) { - not_needed(invoker, "*") - } - } else { - target_type = "source_set" - if (defined(invoker.target_type)) { - target_type = invoker.target_type - } - target(target_type, target_name) { - forward_variables_from(invoker, "*") - - if (!defined(invoker.public_configs)) { - public_configs = [] - } - - public_configs += [ "//flutter/impeller:impeller_public_config" ] - - if (!defined(invoker.cflags)) { - cflags = [] - } - cflags += [ "-Wthread-safety-analysis" ] - - if (!defined(invoker.cflags_objc)) { - cflags_objc = [] - } - - if (is_ios || is_mac) { - cflags_objc += flutter_cflags_objc_arc - } - - if (!defined(invoker.cflags_objcc)) { - cflags_objcc = [] - } - - if (is_ios || is_mac) { - cflags_objcc += flutter_cflags_objcc_arc - } - } - } -} - -# ------------------------------------------------------------------------------ -# @brief Build a Metal Library. The output is a single file. Use -# get_target_outputs to get its location on build. -# -# @param[required] name The name of the Metal library. -# -# @param[required] sources The GLSL (4.60) sources to compiled into the Metal -# library. -# -# @param[required] metal_version The Metal language version to compile for. -# -template("metal_library") { - assert(is_ios || is_mac) - assert(defined(invoker.name), "Metal library name must be specified.") - assert(defined(invoker.sources), "Metal source files must be specified.") - assert(defined(invoker.metal_version), - "Metal language version must be specified.") - - metal_library_name = invoker.name - - action("$target_name") { - forward_variables_from(invoker, - "*", - [ - "inputs", - "outputs", - "script", - "depfile", - "args", - ]) - - inputs = invoker.sources - - metal_library_path = "$root_out_dir/shaders/$metal_library_name.metallib" - metal_library_symbols_path = - "$root_out_dir/shaders/$metal_library_name.metallibsym" - - outputs = [ - metal_library_path, - metal_library_symbols_path, - ] - - script = "//flutter/impeller/tools/build_metal_library.py" - - depfile = "$target_gen_dir/mtl/$metal_library_name.depfile" - - args = [ - "--output", - rebase_path(metal_library_path, root_out_dir), - "--depfile", - rebase_path(depfile), - "--metal-version=$metal_version", - ] - - if (is_ios) { - if (use_ios_simulator) { - args += [ "--platform=ios-simulator" ] - } else { - args += [ "--platform=ios" ] - } - } else if (is_mac) { - args += [ "--platform=mac" ] - } else { - assert(false, "Unsupported platform for generating Metal shaders.") - } - - foreach(source, invoker.sources) { - args += [ - "--source", - rebase_path(source, root_out_dir), - ] - } - } -} - -template("embed_blob") { - assert(defined(invoker.symbol_name), "The symbol name must be specified.") - assert(defined(invoker.blob), "The blob file to embed must be specified") - assert(defined(invoker.hdr), - "The header file containing the symbol name must be specified.") - assert(defined(invoker.cc), - "The CC file containing the symbol data must be specified.") - assert(defined(invoker.deps), "The target dependencies must be specified") - - gen_blob_target_name = "gen_blob_$target_name" - action(gen_blob_target_name) { - inputs = [ invoker.blob ] - outputs = [ - invoker.hdr, - invoker.cc, - ] - args = [ - "--symbol-name", - invoker.symbol_name, - "--output-header", - rebase_path(invoker.hdr), - "--output-source", - rebase_path(invoker.cc), - "--source", - rebase_path(invoker.blob), - ] - script = "//flutter/impeller/tools/xxd.py" - deps = invoker.deps - } - - embed_config = "embed_$target_name" - config(embed_config) { - include_dirs = [ get_path_info( - get_label_info("//flutter/impeller:impeller", "target_gen_dir"), - "dir") ] - } - - source_set(target_name) { - public_configs = [ ":$embed_config" ] - sources = get_target_outputs(":$gen_blob_target_name") - deps = [ ":$gen_blob_target_name" ] - } -} - -# Dispatches to the build or prebuilt impellerc depending on the value of -# the `impeller_use_prebuilt_impellerc` argument. -# * When the `single_invocation` argument is false, all variables are -# forwarded to `compiled_action_foreach` or `action_foreach`, which will -# invoke `impellerc` separately for each source. -# * When the `single_invocation` argument is true, `impellerc` is only -# invoked once via `compiled_action` or `action`. -template("_impellerc") { - if (invoker.single_invocation) { - if (impeller_use_prebuilt_impellerc == "") { - compiled_action(target_name) { - forward_variables_from(invoker, "*") - tool = "//flutter/impeller/compiler:impellerc" - } - } else { - action(target_name) { - forward_variables_from(invoker, "*", [ "args" ]) - script = "//build/gn_run_binary.py" - impellerc_path = - rebase_path(impeller_use_prebuilt_impellerc, root_build_dir) - args = [ impellerc_path ] + invoker.args - } - } - } else { - if (impeller_use_prebuilt_impellerc == "") { - compiled_action_foreach(target_name) { - forward_variables_from(invoker, "*") - tool = "//flutter/impeller/compiler:impellerc" - } - } else { - action_foreach(target_name) { - forward_variables_from(invoker, "*", [ "args" ]) - script = "//build/gn_run_binary.py" - impellerc_path = - rebase_path(impeller_use_prebuilt_impellerc, root_build_dir) - args = [ impellerc_path ] + invoker.args - } - } - } -} - -# Required: shaders The list of shaders inputs to compile. -# Required: shader_target_flags The target flag(s) to append. Valid options: -# --sksl -# --metal-ios -# --metal-desktop -# --opengl-es -# --opengl-desktop -# --vulkan -# --runtime-stage-metal -# --runtime-stage-gles -# --runtime-stage-vulkan -# Not required for --shader_bundle mode. -# Required: sl_file_extension The file extension to use for output files. -# Not required for --shader_bundle mode. -# Optional: iplr Causes --sl output to be in iplr/runtime -# stage flatbuffer format. -# Optional: shader_bundle Specifies a Flutter GPU shader bundle -# configuration. -# Required: shader_bundle_output Specifies the output filename of the shader -# bundle. This is only required if -# shader_bundle is supplied. -# Optional: defines Specifies a list of valueless macro -# definitions. -# Optional: intermediates_subdir Specifies the subdirectory in which to put -# intermediates. -# Optional: json Causes output format to be JSON instead of -# flatbuffer. -template("impellerc") { - assert(defined(invoker.shaders), "Impeller shaders must be specified.") - assert(defined(invoker.shader_target_flags) || defined(invoker.shader_bundle), - "The flag to impellerc for target selection must be specified.") - assert(defined(invoker.sl_file_extension) || defined(invoker.shader_bundle), - "The extension of the SL file must be specified (metal, glsl, etc..).") - if (defined(invoker.shader_bundle)) { - assert( - defined(invoker.shader_bundle_output), - "When shader_bundle is specified, shader_bundle_output must also be specified.") - } - - if (defined(invoker.shader_target_flags)) { - shader_target_flags = invoker.shader_target_flags - } else { - shader_target_flags = [] - } - - sksl = false - foreach(shader_target_flag, shader_target_flags) { - sksl = shader_target_flag == "--sksl" - } - iplr = false - if (defined(invoker.iplr) && invoker.iplr) { - iplr = invoker.iplr - } - json = false - if (defined(invoker.json) && invoker.json) { - json = invoker.json - } - - # Not needed on every path. - not_needed([ - "iplr", - "sksl", - "shader_bundle", - "shader_bundle_output", - ]) - - _impellerc(target_name) { - pool = "//build/toolchain:toolchain_pool" - shader_bundle = defined(invoker.shader_bundle) - - # When single_invocation is true, impellerc will be invoked exactly once. When it's - # false, impellerc be invoked for each of the source file entries (invoker.shaders). - single_invocation = shader_bundle - - if (defined(invoker.intermediates_subdir)) { - subdir = invoker.intermediates_subdir - generated_dir = "$target_gen_dir/$subdir" - } else { - generated_dir = "$target_gen_dir" - } - - shader_lib_dir = rebase_path("//flutter/impeller/compiler/shader_lib") - args = [ "--include=$shader_lib_dir" ] + shader_target_flags - - # When we're in single invocation mode, we can't use source enumeration. - if (!single_invocation) { - depfile_path = "$generated_dir/{{source_file_part}}.d" - depfile_intermediate_path = rebase_path(depfile_path, root_build_dir) - depfile = depfile_path - args += [ - "--input={{source}}", - "--include={{source_dir}}", - "--depfile=$depfile_intermediate_path", - ] - - if (defined(invoker.shader_target_flag)) { - args += [ "${invoker.shader_target_flag}" ] - } - } - - if (defined(invoker.gles_language_version)) { - gles_language_version = invoker.gles_language_version - args += [ "--gles-language-version=$gles_language_version" ] - } - - if (defined(invoker.metal_version)) { - assert(is_mac || is_ios) - metal_version = invoker.metal_version - args += [ "--metal-version=$metal_version" ] - } - - if (defined(invoker.use_half_textures) && invoker.use_half_textures) { - args += [ "--use-half-textures" ] - } - if (defined(invoker.require_framebuffer_fetch) && - invoker.require_framebuffer_fetch) { - args += [ "--require-framebuffer-fetch" ] - } - - if (json) { - args += [ "--json" ] - } - - if (iplr) { - # When building in IPLR mode, the compiler may be executed twice - args += [ "--iplr" ] - } - - # The `sl_output` is the raw shader file output by the compiler. For --iplr - # and --shader-bundle, this is used as the filename for the flatbuffer to - # output. - - if (shader_bundle) { - # When a shader bundle is specified, don't bother supplying flags for - # the reflection state as these are ignored. In this mode, the compiler - # is invoked multiple times and the reflection state for each shader is - # written to the output flatbuffer. - sl_output = "$generated_dir/${invoker.shader_bundle_output}" - sl_output_path = rebase_path(sl_output, root_build_dir) - - args += [ - "--sl=$sl_output_path", - "--shader-bundle=${invoker.shader_bundle}", - ] - - outputs = [ sl_output ] - } else if (sksl) { - # When SkSL is selected as a `shader_target_flags`, don't generate - # C++ reflection state. Nothing needs to use it and it's likely invalid - # given the special cases when generating SkSL. - # Note that this configuration is orthogonal to the "--iplr" flag - sl_output = - "$generated_dir/{{source_file_part}}.${invoker.sl_file_extension}" - sl_output_path = rebase_path(sl_output, root_build_dir) - - spirv_intermediate = "$generated_dir/{{source_file_part}}.spirv" - spirv_intermediate_path = rebase_path(spirv_intermediate, root_build_dir) - args += [ - "--sl=$sl_output_path", - "--spirv=$spirv_intermediate_path", - ] - - outputs = [ sl_output ] - } else { - # The default branch. Here we just generate one shader along with all of - # its C++ reflection state. - - sl_output = - "$generated_dir/{{source_file_part}}.${invoker.sl_file_extension}" - sl_output_path = rebase_path(sl_output, root_build_dir) - - reflection_json_intermediate = "$generated_dir/{{source_file_part}}.json" - reflection_header_intermediate = "$generated_dir/{{source_file_part}}.h" - reflection_cc_intermediate = "$generated_dir/{{source_file_part}}.cc" - - spirv_intermediate = "$generated_dir/{{source_file_part}}.spirv" - spirv_intermediate_path = rebase_path(spirv_intermediate, root_build_dir) - reflection_json_path = - rebase_path(reflection_json_intermediate, root_build_dir) - reflection_header_path = - rebase_path(reflection_header_intermediate, root_build_dir) - reflection_cc_path = - rebase_path(reflection_cc_intermediate, root_build_dir) - - args += [ - "--sl=$sl_output_path", - "--spirv=$spirv_intermediate_path", - "--reflection-json=$reflection_json_path", - "--reflection-header=$reflection_header_path", - "--reflection-cc=$reflection_cc_path", - ] - - outputs = [ - sl_output, - reflection_header_intermediate, - reflection_cc_intermediate, - ] - } - - if (defined(invoker.defines)) { - foreach(def, invoker.defines) { - args += [ "--define=$def" ] - } - } - - if (single_invocation) { - inputs = invoker.shaders - } else { - sources = invoker.shaders - } - } -} - -template("impellerc_reflect") { - assert( - defined(invoker.impellerc_invocation), - "The target that specifies the ImpellerC invocation to reflect must be defined.") - - reflect_config = "reflect_$target_name" - config(reflect_config) { - include_dirs = [ get_path_info( - get_label_info("//flutter/impeller:impeller", "target_gen_dir"), - "dir") ] - } - - impellerc_invocation = invoker.impellerc_invocation - - source_set(target_name) { - public_configs = [ ":$reflect_config" ] - public = filter_include(get_target_outputs(impellerc_invocation), [ "*.h" ]) - sources = filter_include(get_target_outputs(impellerc_invocation), - [ - "*.h", - "*.cc", - "*.mm", - ]) - - deps = [ - "//flutter/impeller/core", - impellerc_invocation, - ] - } -} - -template("_impeller_shaders_metal") { - assert(defined(invoker.shaders), "Impeller shaders must be specified.") - assert(defined(invoker.name), "Name of the shader library must be specified.") - - metal_version = "1.2" - if (defined(invoker.metal_version)) { - metal_version = invoker.metal_version - } - - use_half_textures = false - if (defined(invoker.use_half_textures) && invoker.use_half_textures) { - use_half_textures = invoker.use_half_textures - } - - shaders_base_name = string_join("", - [ - invoker.name, - "_shaders", - ]) - impellerc_mtl = "impellerc_$target_name" - impellerc(impellerc_mtl) { - shaders = invoker.shaders - metal_version = metal_version - sl_file_extension = "metal" - use_half_textures = use_half_textures - shader_target_flags = [] - defines = [ "IMPELLER_TARGET_METAL" ] - if (is_ios) { - shader_target_flags += [ "--metal-ios" ] - defines += [ "IMPELLER_TARGET_METAL_IOS" ] - } else if (is_mac) { - shader_target_flags = [ "--metal-desktop" ] - defines += [ "IMPELLER_TARGET_METAL_DESKTOP" ] - } else { - assert(false, "Metal not supported on this platform.") - } - } - - mtl_lib = "genlib_$target_name" - metal_library(mtl_lib) { - name = invoker.name - metal_version = metal_version - sources = - filter_include(get_target_outputs(":$impellerc_mtl"), [ "*.metal" ]) - deps = [ ":$impellerc_mtl" ] - } - - reflect_mtl = "reflect_$target_name" - impellerc_reflect(reflect_mtl) { - impellerc_invocation = ":$impellerc_mtl" - } - - embed_mtl_lib = "embed_$target_name" - embed_blob(embed_mtl_lib) { - metal_library_files = get_target_outputs(":$mtl_lib") - symbol_name = shaders_base_name - blob = metal_library_files[0] - hdr = "$target_gen_dir/mtl/$shaders_base_name.h" - cc = "$target_gen_dir/mtl/$shaders_base_name.cc" - deps = [ ":$mtl_lib" ] - } - - group(target_name) { - public_deps = [ - ":$embed_mtl_lib", - ":$reflect_mtl", - ] - } -} - -template("shader_archive") { - assert(defined(invoker.shaders), - "The shaders to build the library from must be specified.") - assert(defined(invoker.deps), "Target dependencies must be specified.") - - output_file = "$target_gen_dir/$target_name.shar" - compiled_action(target_name) { - tool = "//flutter/impeller/shader_archive:shader_archiver" - inputs = invoker.shaders - outputs = [ output_file ] - output_path_rebased = rebase_path(output_file, root_build_dir) - args = [ "--output=$output_path_rebased" ] - foreach(shader, invoker.shaders) { - shader_path = rebase_path(shader, root_build_dir) - args += [ "--input=$shader_path" ] - } - deps = invoker.deps - } -} - -template("_impeller_shaders_gles") { - assert(defined(invoker.shaders), "Impeller shaders must be specified.") - assert(defined(invoker.name), "Name of the shader library must be specified.") - assert(defined(invoker.analyze), "Whether to analyze must be specified.") - - require_framebuffer_fetch = false - if (defined(invoker.require_framebuffer_fetch) && - invoker.require_framebuffer_fetch) { - require_framebuffer_fetch = invoker.require_framebuffer_fetch - } - - shaders_base_name = string_join("", - [ - invoker.name, - "_shaders_gles", - ]) - impellerc_gles = "impellerc_$target_name" - impellerc(impellerc_gles) { - shaders = invoker.shaders - sl_file_extension = "gles" - require_framebuffer_fetch = require_framebuffer_fetch - if (defined(invoker.gles_language_version)) { - gles_language_version = invoker.gles_language_version - } - - # Metal reflectors generate a superset of information. - if (impeller_enable_metal || impeller_enable_vulkan) { - intermediates_subdir = "gles" - } - shader_target_flags = [ "--opengl-es" ] - - defines = [ "IMPELLER_TARGET_OPENGLES" ] - } - - gles_shaders = - filter_include(get_target_outputs(":$impellerc_gles"), [ "*.gles" ]) - - if (invoker.analyze) { - analyze_lib = "analyze_$target_name" - malioc_analyze_shaders(analyze_lib) { - shaders = gles_shaders - if (defined(invoker.gles_language_version)) { - gles_language_version = invoker.gles_language_version - } - deps = [ ":$impellerc_gles" ] - } - } - - gles_lib = "genlib_$target_name" - shader_archive(gles_lib) { - shaders = gles_shaders - deps = [ ":$impellerc_gles" ] - } - - reflect_gles = "reflect_$target_name" - impellerc_reflect(reflect_gles) { - impellerc_invocation = ":$impellerc_gles" - } - - embed_gles_lib = "embed_$target_name" - embed_blob(embed_gles_lib) { - gles_library_files = get_target_outputs(":$gles_lib") - symbol_name = shaders_base_name - blob = gles_library_files[0] - hdr = "$target_gen_dir/gles/$shaders_base_name.h" - cc = "$target_gen_dir/gles/$shaders_base_name.cc" - deps = [ ":$gles_lib" ] - } - - group(target_name) { - public_deps = [ ":$embed_gles_lib" ] - - if (invoker.analyze) { - public_deps += [ ":$analyze_lib" ] - } - - if (!impeller_enable_metal && !impeller_enable_vulkan) { - public_deps += [ ":$reflect_gles" ] - } - } -} - -template("_impeller_shaders_vk") { - assert(defined(invoker.shaders), "Impeller shaders must be specified.") - assert(defined(invoker.name), "Name of the shader library must be specified.") - assert(defined(invoker.analyze), "Whether to analyze must be specified.") - - shaders_base_name = string_join("", - [ - invoker.name, - "_shaders_vk", - ]) - impellerc_vk = "impellerc_$target_name" - impellerc(impellerc_vk) { - shaders = invoker.shaders - sl_file_extension = "vkspv" - - # Metal reflectors generate a superset of information. - if (impeller_enable_metal) { - if (defined(invoker.metal_version)) { - metal_version = invoker.metal_version - } - - intermediates_subdir = "vk" - } - shader_target_flags = [ "--vulkan" ] - - defines = [ "IMPELLER_TARGET_VULKAN" ] - } - - vk_shaders = - filter_include(get_target_outputs(":$impellerc_vk"), [ "*.vkspv" ]) - - if (invoker.analyze) { - analyze_lib = "analyze_$target_name" - malioc_analyze_shaders(analyze_lib) { - shaders = vk_shaders - if (defined(invoker.vulkan_language_version)) { - vulkan_language_version = invoker.vulkan_language_version - } - deps = [ ":$impellerc_vk" ] - } - } - - vk_lib = "genlib_$target_name" - shader_archive(vk_lib) { - shaders = vk_shaders - deps = [ ":$impellerc_vk" ] - } - - reflect_vk = "reflect_$target_name" - impellerc_reflect(reflect_vk) { - impellerc_invocation = ":$impellerc_vk" - } - - embed_vk_lib = "embed_$target_name" - embed_blob(embed_vk_lib) { - vk_library_files = get_target_outputs(":$vk_lib") - symbol_name = shaders_base_name - blob = vk_library_files[0] - hdr = "$target_gen_dir/vk/$shaders_base_name.h" - cc = "$target_gen_dir/vk/$shaders_base_name.cc" - deps = [ ":$vk_lib" ] - } - - group(target_name) { - public_deps = [ ":$embed_vk_lib" ] - - if (invoker.analyze) { - public_deps += [ ":$analyze_lib" ] - } - - if (!impeller_enable_metal) { - public_deps += [ ":$reflect_vk" ] - } - } -} - -# ------------------------------------------------------------------------------ -# @brief A target for precompiled shaders and the associated -# generated reflection library. -# -# @param[required] name -# -# The base name for the reflected C++ library. -# -# @param[required] shaders -# -# A list of GLSL shader files. -# -# @param[optional] analyze -# -# Whether to analyze shaders with malioc. Defaults to false. Shaders will -# only be analyzed if the GN argument "impeller_malioc_path" is defined. -# -# @param[optional] enable_opengles -# -# Whether to compile the shaders for the OpenGL ES backend. Defaults to the -# value of the GN argument "impeller_enable_opengles". -# -# @param[optional] gles_language_version -# -# The GLES version required by the shaders. -# -# @param[optional] metal_version -# -# The version of the Metal API required by the shaders. -# -# @param[optional] vulkan_language_version -# -# The SPIR-V version required by the shaders. -# -# @param[optional] use_half_textures -# -# Whether the metal shader is using half-precision textures and requires -# openGL semantics when compilig SPIR-V. -# -# @param[optional] require_framebuffer_fetch -# -# Whether to require the framebuffer fetch extension for GLES fragment shaders. -template("impeller_shaders") { - if (defined(invoker.metal_version)) { - metal_version = invoker.metal_version - } - - use_half_textures = false - if (defined(invoker.use_half_textures) && invoker.use_half_textures) { - use_half_textures = true - } - - require_framebuffer_fetch = false - if (defined(invoker.require_framebuffer_fetch) && - invoker.require_framebuffer_fetch) { - require_framebuffer_fetch = true - } - - not_needed([ - "metal_version", - "use_half_textures", - "require_framebuffer_fetch", - ]) - - enable_opengles = impeller_enable_opengles - if (defined(invoker.enable_opengles)) { - enable_opengles = invoker.enable_opengles - } - - if (impeller_enable_metal) { - if (!defined(metal_version)) { - metal_version = "1.2" - } - not_needed(invoker, [ "analyze" ]) - mtl_shaders = "mtl_$target_name" - _impeller_shaders_metal(mtl_shaders) { - name = invoker.name - shaders = invoker.shaders - metal_version = metal_version - use_half_textures = use_half_textures - } - } - - if (enable_opengles) { - analyze = true - if (defined(invoker.analyze) && !invoker.analyze) { - analyze = false - } - gles_shaders = "gles_$target_name" - _impeller_shaders_gles(gles_shaders) { - name = invoker.name - require_framebuffer_fetch = require_framebuffer_fetch - if (defined(invoker.gles_language_version)) { - gles_language_version = invoker.gles_language_version - } - if (defined(invoker.gles_exclusions)) { - shaders = invoker.shaders - invoker.gles_exclusions - } else { - shaders = invoker.shaders - } - analyze = analyze - } - } - - if (impeller_enable_vulkan) { - analyze = true - if (defined(invoker.analyze) && !invoker.analyze) { - analyze = false - } - vk_shaders = "vk_$target_name" - _impeller_shaders_vk(vk_shaders) { - name = invoker.name - if (defined(invoker.vulkan_language_version)) { - vulkan_language_version = invoker.vulkan_language_version - } - shaders = invoker.shaders - analyze = analyze - } - } - - if (!impeller_supports_rendering) { - not_needed(invoker, "*") - } - - group(target_name) { - public_deps = [] - if (impeller_enable_metal) { - public_deps += [ ":$mtl_shaders" ] - } - - if (enable_opengles) { - public_deps += [ ":$gles_shaders" ] - } - - if (impeller_enable_vulkan) { - public_deps += [ ":$vk_shaders" ] - } - } -} - -# Dispatches to the build or prebuilt scenec depending on the value of -# the impeller_use_prebuilt_scenec argument. Forwards all variables to -# compiled_action_foreach or action_foreach as appropriate. -template("_scenec") { - if (impeller_use_prebuilt_scenec == "") { - compiled_action_foreach(target_name) { - forward_variables_from(invoker, "*") - tool = "//flutter/impeller/scene/importer:scenec" - } - } else { - action_foreach(target_name) { - forward_variables_from(invoker, "*", [ "args" ]) - script = "//build/gn_run_binary.py" - scenec_path = rebase_path(impeller_use_prebuilt_scenec, root_build_dir) - args = [ scenec_path ] + invoker.args - } - } -} - -template("scenec") { - assert(defined(invoker.geometry), "Geometry input files must be specified.") - assert(defined(invoker.type), - "The type of geometry to be parsed (gltf, etc..).") - - _scenec(target_name) { - sources = invoker.geometry - generated_dir = "$target_gen_dir" - - input_type = invoker.type - args = [ - "--input={{source}}", - "--input-type=$input_type", - ] - - output = "$generated_dir/{{source_file_part}}.ipscene" - output_path = rebase_path(output, root_build_dir) - - args += [ "--output=$output_path" ] - - outputs = [ output ] - } -} +# Templates for the experimental 3D renderer. +import("//flutter/impeller/tools/scene.gni") diff --git a/impeller/tools/metal_library.gni b/impeller/tools/metal_library.gni new file mode 100644 index 0000000000000..26bac51ccd12d --- /dev/null +++ b/impeller/tools/metal_library.gni @@ -0,0 +1,78 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# ------------------------------------------------------------------------------ +# @brief Build a Metal Library. The output is a single file. Use +# get_target_outputs to get its location on build. +# +# @param[required] name The name of the Metal library. +# +# @param[required] sources The GLSL (4.60) sources to compiled into the Metal +# library. +# +# @param[required] metal_version The Metal language version to compile for. +# +template("metal_library") { + assert(is_ios || is_mac) + assert(defined(invoker.name), "Metal library name must be specified.") + assert(defined(invoker.sources), "Metal source files must be specified.") + assert(defined(invoker.metal_version), + "Metal language version must be specified.") + + metal_library_name = invoker.name + + action("$target_name") { + forward_variables_from(invoker, + "*", + [ + "inputs", + "outputs", + "script", + "depfile", + "args", + ]) + + inputs = invoker.sources + + metal_library_path = "$root_out_dir/shaders/$metal_library_name.metallib" + metal_library_symbols_path = + "$root_out_dir/shaders/$metal_library_name.metallibsym" + + outputs = [ + metal_library_path, + metal_library_symbols_path, + ] + + script = "//flutter/impeller/tools/metal_library.py" + + depfile = "$target_gen_dir/mtl/$metal_library_name.depfile" + + args = [ + "--output", + rebase_path(metal_library_path, root_out_dir), + "--depfile", + rebase_path(depfile), + "--metal-version=$metal_version", + ] + + if (is_ios) { + if (use_ios_simulator) { + args += [ "--platform=ios-simulator" ] + } else { + args += [ "--platform=ios" ] + } + } else if (is_mac) { + args += [ "--platform=mac" ] + } else { + assert(false, "Unsupported platform for generating Metal shaders.") + } + + foreach(source, invoker.sources) { + args += [ + "--source", + rebase_path(source, root_out_dir), + ] + } + } +} diff --git a/impeller/tools/build_metal_library.py b/impeller/tools/metal_library.py similarity index 100% rename from impeller/tools/build_metal_library.py rename to impeller/tools/metal_library.py diff --git a/impeller/tools/scene.gni b/impeller/tools/scene.gni new file mode 100644 index 0000000000000..447c835a3be3a --- /dev/null +++ b/impeller/tools/scene.gni @@ -0,0 +1,46 @@ +# Dispatches to the build or prebuilt scenec depending on the value of +# the impeller_use_prebuilt_scenec argument. Forwards all variables to +# compiled_action_foreach or action_foreach as appropriate. + +import("//build/compiled_action.gni") +import("//flutter/impeller/tools/args.gni") + +template("_scenec") { + if (impeller_use_prebuilt_scenec == "") { + compiled_action_foreach(target_name) { + forward_variables_from(invoker, "*") + tool = "//flutter/impeller/scene/importer:scenec" + } + } else { + action_foreach(target_name) { + forward_variables_from(invoker, "*", [ "args" ]) + script = "//build/gn_run_binary.py" + scenec_path = rebase_path(impeller_use_prebuilt_scenec, root_build_dir) + args = [ scenec_path ] + invoker.args + } + } +} + +template("scenec") { + assert(defined(invoker.geometry), "Geometry input files must be specified.") + assert(defined(invoker.type), + "The type of geometry to be parsed (gltf, etc..).") + + _scenec(target_name) { + sources = invoker.geometry + generated_dir = "$target_gen_dir" + + input_type = invoker.type + args = [ + "--input={{source}}", + "--input-type=$input_type", + ] + + output = "$generated_dir/{{source_file_part}}.ipscene" + output_path = rebase_path(output, root_build_dir) + + args += [ "--output=$output_path" ] + + outputs = [ output ] + } +} diff --git a/impeller/tools/shader_archive.gni b/impeller/tools/shader_archive.gni new file mode 100644 index 0000000000000..84bedb50f0200 --- /dev/null +++ b/impeller/tools/shader_archive.gni @@ -0,0 +1,25 @@ +# Copyright 2013 The Flutter 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/compiled_action.gni") + +template("shader_archive") { + assert(defined(invoker.shaders), + "The shaders to build the library from must be specified.") + assert(defined(invoker.deps), "Target dependencies must be specified.") + + output_file = "$target_gen_dir/$target_name.shar" + compiled_action(target_name) { + tool = "//flutter/impeller/shader_archive:shader_archiver" + inputs = invoker.shaders + outputs = [ output_file ] + output_path_rebased = rebase_path(output_file, root_build_dir) + args = [ "--output=$output_path_rebased" ] + foreach(shader, invoker.shaders) { + shader_path = rebase_path(shader, root_build_dir) + args += [ "--input=$shader_path" ] + } + deps = invoker.deps + } +} diff --git a/impeller/tools/shaders.gni b/impeller/tools/shaders.gni new file mode 100644 index 0000000000000..e0bd24183dc03 --- /dev/null +++ b/impeller/tools/shaders.gni @@ -0,0 +1,149 @@ +# Copyright 2013 The Flutter 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("//flutter/impeller/tools/args.gni") +import("//flutter/impeller/tools/shader_archive.gni") +import("//flutter/impeller/tools/shaders_gles.gni") +import("//flutter/impeller/tools/shaders_mtl.gni") +import("//flutter/impeller/tools/shaders_vk.gni") + +# ------------------------------------------------------------------------------ +# @brief A target for precompiled shaders and the associated +# generated reflection library. +# +# @param[required] name +# +# The base name for the reflected C++ library. +# +# @param[required] shaders +# +# A list of GLSL shader files. +# +# @param[optional] analyze +# +# Whether to analyze shaders with malioc. Defaults to false. Shaders will +# only be analyzed if the GN argument "impeller_malioc_path" is defined. +# +# @param[optional] enable_opengles +# +# Whether to compile the shaders for the OpenGL ES backend. Defaults to the +# value of the GN argument "impeller_enable_opengles". +# +# @param[optional] gles_language_version +# +# The GLES version required by the shaders. +# +# @param[optional] metal_version +# +# The version of the Metal API required by the shaders. +# +# @param[optional] vulkan_language_version +# +# The SPIR-V version required by the shaders. +# +# @param[optional] use_half_textures +# +# Whether the metal shader is using half-precision textures and requires +# openGL semantics when compilig SPIR-V. +# +# @param[optional] require_framebuffer_fetch +# +# Whether to require the framebuffer fetch extension for GLES fragment shaders. +template("impeller_shaders") { + if (defined(invoker.metal_version)) { + metal_version = invoker.metal_version + } + + use_half_textures = false + if (defined(invoker.use_half_textures) && invoker.use_half_textures) { + use_half_textures = true + } + + require_framebuffer_fetch = false + if (defined(invoker.require_framebuffer_fetch) && + invoker.require_framebuffer_fetch) { + require_framebuffer_fetch = true + } + + not_needed([ + "metal_version", + "use_half_textures", + "require_framebuffer_fetch", + ]) + + enable_opengles = impeller_enable_opengles + if (defined(invoker.enable_opengles)) { + enable_opengles = invoker.enable_opengles + } + + if (impeller_enable_metal) { + if (!defined(metal_version)) { + metal_version = "1.2" + } + not_needed(invoker, [ "analyze" ]) + mtl_shaders = "mtl_$target_name" + impeller_shaders_metal(mtl_shaders) { + name = invoker.name + shaders = invoker.shaders + metal_version = metal_version + use_half_textures = use_half_textures + } + } + + if (enable_opengles) { + analyze = true + if (defined(invoker.analyze) && !invoker.analyze) { + analyze = false + } + gles_shaders = "gles_$target_name" + impeller_shaders_gles(gles_shaders) { + name = invoker.name + require_framebuffer_fetch = require_framebuffer_fetch + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } + if (defined(invoker.gles_exclusions)) { + shaders = invoker.shaders - invoker.gles_exclusions + } else { + shaders = invoker.shaders + } + analyze = analyze + } + } + + if (impeller_enable_vulkan) { + analyze = true + if (defined(invoker.analyze) && !invoker.analyze) { + analyze = false + } + vk_shaders = "vk_$target_name" + impeller_shaders_vk(vk_shaders) { + name = invoker.name + if (defined(invoker.vulkan_language_version)) { + vulkan_language_version = invoker.vulkan_language_version + } + shaders = invoker.shaders + analyze = analyze + } + } + + if (!impeller_supports_rendering) { + not_needed(invoker, "*") + } + + group(target_name) { + public_deps = [] + if (impeller_enable_metal) { + public_deps += [ ":$mtl_shaders" ] + } + + if (enable_opengles) { + public_deps += [ ":$gles_shaders" ] + } + + if (impeller_enable_vulkan) { + public_deps += [ ":$vk_shaders" ] + } + } +} diff --git a/impeller/tools/shaders_gles.gni b/impeller/tools/shaders_gles.gni new file mode 100644 index 0000000000000..903be3fedb5bd --- /dev/null +++ b/impeller/tools/shaders_gles.gni @@ -0,0 +1,91 @@ +# Copyright 2013 The Flutter 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("//flutter/impeller/tools/args.gni") +import("//flutter/impeller/tools/compiler.gni") +import("//flutter/impeller/tools/embed_blob.gni") +import("//flutter/impeller/tools/malioc.gni") +import("//flutter/impeller/tools/shader_archive.gni") + +template("impeller_shaders_gles") { + assert(defined(invoker.shaders), "Impeller shaders must be specified.") + assert(defined(invoker.name), "Name of the shader library must be specified.") + assert(defined(invoker.analyze), "Whether to analyze must be specified.") + + require_framebuffer_fetch = false + if (defined(invoker.require_framebuffer_fetch) && + invoker.require_framebuffer_fetch) { + require_framebuffer_fetch = invoker.require_framebuffer_fetch + } + + shaders_base_name = string_join("", + [ + invoker.name, + "_shaders_gles", + ]) + impellerc_gles = "impellerc_$target_name" + impellerc(impellerc_gles) { + shaders = invoker.shaders + sl_file_extension = "gles" + require_framebuffer_fetch = require_framebuffer_fetch + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } + + # Metal reflectors generate a superset of information. + if (impeller_enable_metal || impeller_enable_vulkan) { + intermediates_subdir = "gles" + } + shader_target_flags = [ "--opengl-es" ] + + defines = [ "IMPELLER_TARGET_OPENGLES" ] + } + + gles_shaders = + filter_include(get_target_outputs(":$impellerc_gles"), [ "*.gles" ]) + + if (invoker.analyze) { + analyze_lib = "analyze_$target_name" + malioc_analyze_shaders(analyze_lib) { + shaders = gles_shaders + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } + deps = [ ":$impellerc_gles" ] + } + } + + gles_lib = "genlib_$target_name" + shader_archive(gles_lib) { + shaders = gles_shaders + deps = [ ":$impellerc_gles" ] + } + + reflect_gles = "reflect_$target_name" + impellerc_reflect(reflect_gles) { + impellerc_invocation = ":$impellerc_gles" + } + + embed_gles_lib = "embed_$target_name" + embed_blob(embed_gles_lib) { + gles_library_files = get_target_outputs(":$gles_lib") + symbol_name = shaders_base_name + blob = gles_library_files[0] + hdr = "$target_gen_dir/gles/$shaders_base_name.h" + cc = "$target_gen_dir/gles/$shaders_base_name.cc" + deps = [ ":$gles_lib" ] + } + + group(target_name) { + public_deps = [ ":$embed_gles_lib" ] + + if (invoker.analyze) { + public_deps += [ ":$analyze_lib" ] + } + + if (!impeller_enable_metal && !impeller_enable_vulkan) { + public_deps += [ ":$reflect_gles" ] + } + } +} diff --git a/impeller/tools/shaders_mtl.gni b/impeller/tools/shaders_mtl.gni new file mode 100644 index 0000000000000..b5fd1303a6986 --- /dev/null +++ b/impeller/tools/shaders_mtl.gni @@ -0,0 +1,78 @@ +# Copyright 2013 The Flutter 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("//flutter/impeller/tools/args.gni") +import("//flutter/impeller/tools/compiler.gni") +import("//flutter/impeller/tools/embed_blob.gni") +import("//flutter/impeller/tools/metal_library.gni") + +template("impeller_shaders_metal") { + assert(defined(invoker.shaders), "Impeller shaders must be specified.") + assert(defined(invoker.name), "Name of the shader library must be specified.") + + metal_version = "1.2" + if (defined(invoker.metal_version)) { + metal_version = invoker.metal_version + } + + use_half_textures = false + if (defined(invoker.use_half_textures) && invoker.use_half_textures) { + use_half_textures = invoker.use_half_textures + } + + shaders_base_name = string_join("", + [ + invoker.name, + "_shaders", + ]) + impellerc_mtl = "impellerc_$target_name" + impellerc(impellerc_mtl) { + shaders = invoker.shaders + metal_version = metal_version + sl_file_extension = "metal" + use_half_textures = use_half_textures + shader_target_flags = [] + defines = [ "IMPELLER_TARGET_METAL" ] + if (is_ios) { + shader_target_flags += [ "--metal-ios" ] + defines += [ "IMPELLER_TARGET_METAL_IOS" ] + } else if (is_mac) { + shader_target_flags = [ "--metal-desktop" ] + defines += [ "IMPELLER_TARGET_METAL_DESKTOP" ] + } else { + assert(false, "Metal not supported on this platform.") + } + } + + mtl_lib = "genlib_$target_name" + metal_library(mtl_lib) { + name = invoker.name + metal_version = metal_version + sources = + filter_include(get_target_outputs(":$impellerc_mtl"), [ "*.metal" ]) + deps = [ ":$impellerc_mtl" ] + } + + reflect_mtl = "reflect_$target_name" + impellerc_reflect(reflect_mtl) { + impellerc_invocation = ":$impellerc_mtl" + } + + embed_mtl_lib = "embed_$target_name" + embed_blob(embed_mtl_lib) { + metal_library_files = get_target_outputs(":$mtl_lib") + symbol_name = shaders_base_name + blob = metal_library_files[0] + hdr = "$target_gen_dir/mtl/$shaders_base_name.h" + cc = "$target_gen_dir/mtl/$shaders_base_name.cc" + deps = [ ":$mtl_lib" ] + } + + group(target_name) { + public_deps = [ + ":$embed_mtl_lib", + ":$reflect_mtl", + ] + } +} diff --git a/impeller/tools/shaders_vk.gni b/impeller/tools/shaders_vk.gni new file mode 100644 index 0000000000000..d424a32cbdda9 --- /dev/null +++ b/impeller/tools/shaders_vk.gni @@ -0,0 +1,85 @@ +# Copyright 2013 The Flutter 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("//flutter/impeller/tools/args.gni") +import("//flutter/impeller/tools/compiler.gni") +import("//flutter/impeller/tools/embed_blob.gni") +import("//flutter/impeller/tools/malioc.gni") +import("//flutter/impeller/tools/shader_archive.gni") + +template("impeller_shaders_vk") { + assert(defined(invoker.shaders), "Impeller shaders must be specified.") + assert(defined(invoker.name), "Name of the shader library must be specified.") + assert(defined(invoker.analyze), "Whether to analyze must be specified.") + + shaders_base_name = string_join("", + [ + invoker.name, + "_shaders_vk", + ]) + impellerc_vk = "impellerc_$target_name" + impellerc(impellerc_vk) { + shaders = invoker.shaders + sl_file_extension = "vkspv" + + # Metal reflectors generate a superset of information. + if (impeller_enable_metal) { + if (defined(invoker.metal_version)) { + metal_version = invoker.metal_version + } + + intermediates_subdir = "vk" + } + shader_target_flags = [ "--vulkan" ] + + defines = [ "IMPELLER_TARGET_VULKAN" ] + } + + vk_shaders = + filter_include(get_target_outputs(":$impellerc_vk"), [ "*.vkspv" ]) + + if (invoker.analyze) { + analyze_lib = "analyze_$target_name" + malioc_analyze_shaders(analyze_lib) { + shaders = vk_shaders + if (defined(invoker.vulkan_language_version)) { + vulkan_language_version = invoker.vulkan_language_version + } + deps = [ ":$impellerc_vk" ] + } + } + + vk_lib = "genlib_$target_name" + shader_archive(vk_lib) { + shaders = vk_shaders + deps = [ ":$impellerc_vk" ] + } + + reflect_vk = "reflect_$target_name" + impellerc_reflect(reflect_vk) { + impellerc_invocation = ":$impellerc_vk" + } + + embed_vk_lib = "embed_$target_name" + embed_blob(embed_vk_lib) { + vk_library_files = get_target_outputs(":$vk_lib") + symbol_name = shaders_base_name + blob = vk_library_files[0] + hdr = "$target_gen_dir/vk/$shaders_base_name.h" + cc = "$target_gen_dir/vk/$shaders_base_name.cc" + deps = [ ":$vk_lib" ] + } + + group(target_name) { + public_deps = [ ":$embed_vk_lib" ] + + if (invoker.analyze) { + public_deps += [ ":$analyze_lib" ] + } + + if (!impeller_enable_metal) { + public_deps += [ ":$reflect_vk" ] + } + } +}