blob: a086df4542b13dc0c96a843b265046efebf555b8 [file] [log] [blame] [edit]
# Copyright 2024 The Dawn & Tint Authors
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import("../../scripts/dawn_overrides_with_defaults.gni")
import("${dawn_root}/generator/dawn_generator.gni")
dawn_json_generator("emdawnwebgpu_headers_gen") {
target = "emdawnwebgpu_headers"
outputs = [
"src/emdawnwebgpu/include/dawn/webgpu_cpp_print.h",
"src/emdawnwebgpu/include/webgpu/webgpu.h",
"src/emdawnwebgpu/include/webgpu/webgpu_cpp.h",
"src/emdawnwebgpu/include/webgpu/webgpu_cpp_chained_struct.h",
]
}
source_set("emdawnwebgpu_headers") {
all_dependent_configs = [ "${dawn_root}/include/dawn:public" ]
public_deps = [ ":emdawnwebgpu_headers_gen" ]
sources = get_target_outputs(":emdawnwebgpu_headers_gen")
}
dawn_json_generator("emdawnwebgpu_js_gen") {
target = "emdawnwebgpu_js"
outputs = [
"src/emdawnwebgpu/struct_info_webgpu.json",
"src/emdawnwebgpu/library_webgpu_enum_tables.js",
"src/emdawnwebgpu/library_webgpu_generated_sig_info.js",
]
}
# When Emscripten is available, we can use one of its helper scripts to generate
# the struct info needed for our bindings fork (third_party/emdawnwebgpu).
# Those helpers, and their tree of generated dependencies, are:
#
# - library_webgpu_generated_struct_info.js
# is constructed by concatenating:
# - Some glue "snippets" from txt files
# - webgpu_generated_struct_info{32,64}.json
# which are generated using an Emscripten tool "gen_struct_info.py", from:
# - webgpu.h (generated from dawn.json)
# - struct_info_webgpu.json (generated from dawn.json)
#
# The bindings also require the following helpers (generated above):
#
# - library_webgpu_enum_tables.js
# - library_webgpu_generated_sig_info.js
# which we generate directly instead of using "gen_sig_info.py"
if (is_wasm) {
template("webgpu_gen_struct_info") {
action(target_name) {
forward_variables_from(invoker, "*")
deps = [
":emdawnwebgpu_headers_gen", # for webgpu.h
":emdawnwebgpu_js_gen", # for struct_info_webgpu.json
]
script = dawn_emscripten_dir + "/tools/gen_struct_info.py"
args = [
"-q", # quiet
rebase_path(sources[0], root_build_dir), # input file
"-o=" + rebase_path(outputs[0], root_build_dir), # output file
# Include dir where webgpu/webgpu.h can be found
"-I=" + rebase_path(target_gen_dir, root_build_dir) + "/include",
]
if (wasm64) {
args += [ "--wasm64" ]
}
}
}
webgpu_gen_struct_info("webgpu_generated_struct_info32") {
sources = [ "${target_gen_dir}/struct_info_webgpu.json" ]
outputs = [ "${target_gen_dir}/webgpu_generated_struct_info32.json" ]
wasm64 = false
}
webgpu_gen_struct_info("webgpu_generated_struct_info64") {
sources = [ "${target_gen_dir}/struct_info_webgpu.json" ]
outputs = [ "${target_gen_dir}/webgpu_generated_struct_info64.json" ]
wasm64 = true
}
action("library_webgpu_generated_struct_info") {
deps = [
":webgpu_generated_struct_info32",
":webgpu_generated_struct_info64",
]
source_files = [
# The order of these files is important.
"snippets/library_webgpu_struct_info_part1.txt",
"${target_gen_dir}/webgpu_generated_struct_info32.json",
"snippets/library_webgpu_struct_info_part2.txt",
"${target_gen_dir}/webgpu_generated_struct_info64.json",
"snippets/library_webgpu_struct_info_part3.txt",
]
sources = source_files
outputs = [ "${target_gen_dir}/library_webgpu_generated_struct_info.js" ]
script = "concat.py"
args = []
foreach(source, [ outputs[0] ] + sources) {
args += [ rebase_path(source, root_build_dir) ]
}
}
# NOTE: Do not use this directly, because it will not add dependencies on the
# the included files. Use :emdawnwebgpu instead.
config("emdawnwebgpu_config") {
include_dirs = [
# Include directory where webgpu/webgpu{,_cpp}.h can be found.
# This needs to take precedent over Emscripten's built-in include
# directory which also has these files (at an older revision).
"${target_gen_dir}/include",
]
ldflags = [
# These will be processed in order; library_webgpu.js must come after
# the generated files, because it depends on them.
# (It will assert this, and also that -sUSE_WEBGPU is not enabled.)
"--js-library=" +
rebase_path("${target_gen_dir}/library_webgpu_enum_tables.js"),
"--js-library=" + rebase_path(
"${target_gen_dir}/library_webgpu_generated_struct_info.js"),
"--js-library=" +
rebase_path("${target_gen_dir}/library_webgpu_generated_sig_info.js"),
"--js-library=" + rebase_path(
"../../third_party/emdawnwebgpu/pkg/webgpu/src/library_webgpu.js"),
# Closure externs to avoid minifying WebGPU API symbols
"--closure-args=--externs=" + rebase_path(
"../../third_party/emdawnwebgpu/pkg/webgpu/src/webgpu-externs.js"),
]
}
# Dawn's WebGPU bindings for Emscripten. These don't actually use Dawn at all,
# but generating them in Dawn lets us keep them in sync more easily.
# When included in Emscripten they attempt to delete Emscripten's built-in
# implementation and replace it with ours.
#
# This can be built as a standalone target to generate all the files needed
# to feed into a separate project that is built using Emscripten.
# Reference emdawnwebgpu_config for how to actually do that.
#
# EXPERIMENTALLY, this should also be usable as a dependency of a gn-native
# Wasm build target, as an alternative to -sUSE_WEBGPU=1 which uses
# Emscripten's built-in WebGPU bindings. This has not been well-tested.
source_set("emdawnwebgpu") {
public_configs = [ ":emdawnwebgpu_config" ]
deps = [
":emdawnwebgpu_headers_gen",
":emdawnwebgpu_js_gen",
":library_webgpu_generated_struct_info",
]
sources = get_target_outputs(":emdawnwebgpu_headers_gen") +
[ "../../third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp" ]
inputs = [
# TODO(crbug.com/371024051): Changing these files doesn't seem to trigger a relink. Why?
"../../third_party/emdawnwebgpu/pkg/webgpu/src/library_webgpu.js",
]
}
# Tests
group("tests") {
testonly = true
deps = [
":emdawnwebgpu",
":emdawnwebgpu_link_test",
":emdawnwebgpu_tests_asyncify",
":emdawnwebgpu_tests_jspi",
]
}
config("emdawnwebgpu_base_test_config") {
cflags = []
ldflags = [ "-Wno-limited-postlink-optimizations" ]
# If possible, always build with Closure, even in debug, for its static
# analysis checks and to test the externs. On Mac, first check whether
# Closure Compiler works, as it requires either Rosetta 2 or Java to be
# installed. Dawn bots don't have either of those.
use_closure = true
if (host_os == "mac") {
use_closure = exec_script("../../third_party/gn/emsdk/can-use-closure.py",
[],
"value")
}
if (use_closure) {
ldflags += [ "--closure=1" ]
} else {
print("WARNING: building without Closure Compiler")
}
# is_asan and is_ubsan are never true when using the Emscripten toolchain,
# so force enable them for all builds. (If this is fixed in sanitizers.gni,
# then remove this, but turn on -sSAFE_HEAP for non-ASAN debug builds.)
# Note this makes GN builds unsuitable for testing code size.
cflags += [
"-fsanitize=address",
"-fsanitize=undefined",
]
ldflags += [
"-fsanitize=address",
"-fsanitize=undefined",
]
}
source_set("emdawnwebgpu_tests") {
testonly = true
public_configs = [ ":emdawnwebgpu_base_test_config" ]
public_deps = [
":emdawnwebgpu",
"../dawn/tests:gmock_main",
]
sources = [
"tests/FuturesTests.cpp",
"tests/SpotTests.cpp",
]
}
executable("emdawnwebgpu_tests_asyncify") {
testonly = true
deps = [ ":emdawnwebgpu_tests" ]
ldflags = [
"-sASYNCIFY=1",
"-sASYNCIFY_STACK_SIZE=10000", # Needed when building with ASAN.
]
}
executable("emdawnwebgpu_tests_jspi") {
testonly = true
deps = [ ":emdawnwebgpu_tests" ]
ldflags = [
"-Wno-experimental", # -sJSPI is experimental.
"-sJSPI",
]
}
# A "sample" that makes real (bogus) API calls to serve as a basic code size test.
dawn_json_generator("emdawnwebgpu_link_test_cpp_gen") {
target = "emdawnwebgpu_link_test_cpp"
outputs = [ "src/emdawnwebgpu/LinkTest.cpp" ]
}
executable("emdawnwebgpu_link_test") {
# The test is just that this links, not that it runs (it will just
# crash), so just build to .js. Since it has a main() function, this is
# the same as building to .html, but skipping the .html file.
output_extension = "js"
testonly = true
configs += [ ":emdawnwebgpu_base_test_config" ]
deps = [
":emdawnwebgpu",
":emdawnwebgpu_link_test_cpp_gen",
]
sources = get_target_outputs(":emdawnwebgpu_link_test_cpp_gen")
}
}