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" ] + } + } +}