|  | # 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. | 
|  |  | 
|  | set(EM_BUILD_GEN_DIR "${DAWN_BUILD_GEN_DIR}/src/emdawnwebgpu") | 
|  |  | 
|  | DawnJSONGenerator( | 
|  | TARGET "emdawnwebgpu_headers" | 
|  | PRINT_NAME "Dawn WebGPU Emscripten headers" | 
|  | OUTPUT_HEADERS EMDAWNWEBGPU_HEADERS_GEN_HEADERS | 
|  | ) | 
|  | add_custom_target(emdawnwebgpu_headers_gen | 
|  | DEPENDS ${EMDAWNWEBGPU_HEADERS_GEN_HEADERS} | 
|  | ) | 
|  | # Also copy the webgpu_glfw.h file. | 
|  | add_custom_command(TARGET emdawnwebgpu_headers_gen POST_BUILD | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${DAWN_INCLUDE_DIR}/webgpu/webgpu_glfw.h" | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/" | 
|  | ) | 
|  |  | 
|  | DawnJSONGenerator( | 
|  | TARGET "emdawnwebgpu_js" | 
|  | PRINT_NAME "Dawn WebGPU Emscripten JS files" | 
|  | OUTPUT_JSONS EMDAWNWEBGPU_STRUCT_INFO_JSON_GEN_SOURCES | 
|  | OUTPUT_JS EMDAWNWEBGPU_JS_GEN_SOURCES | 
|  | ) | 
|  | add_custom_target(emdawnwebgpu_js_gen | 
|  | DEPENDS ${EMDAWNWEBGPU_STRUCT_INFO_JSON_GEN_SOURCES} ${EMDAWNWEBGPU_JS_GEN_SOURCES} | 
|  | ) | 
|  |  | 
|  | # 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 (EMSCRIPTEN) | 
|  | set(EM_SRC_DIR "${DAWN_SRC_DIR}/emdawnwebgpu") | 
|  |  | 
|  | function(webgpu_gen_struct_info) | 
|  | cmake_parse_arguments(PARSE_ARGV 0 arg | 
|  | "" | 
|  | "OUTPUT_JSON;WASM64" | 
|  | "" | 
|  | ) | 
|  | if (arg_UNPARSED_ARGUMENTS) | 
|  | message(FATAL_ERROR | 
|  | "Unparsed arguments for webgpu_gen_struct_info: " | 
|  | "${arg_UNPARSED_ARGUMENTS}") | 
|  | endif() | 
|  |  | 
|  | # Note this requires Emscripten 4.0.3+ (prior to that it was located | 
|  | # at tools/maint/gen_struct_info.py). | 
|  | set(ARGS | 
|  | ${Python3_EXECUTABLE} | 
|  | "${EMSCRIPTEN_ROOT_PATH}/tools/gen_struct_info.py" | 
|  | -q | 
|  | "${EM_BUILD_GEN_DIR}/struct_info_webgpu.json" | 
|  | "-I=${EM_BUILD_GEN_DIR}/include" | 
|  | ) | 
|  |  | 
|  | set(PRINT_NAME) | 
|  | if (${arg_WASM64}) | 
|  | set(PRINT_NAME "webgpu_generated_struct_info64.json") | 
|  | list(APPEND ARGS "--wasm64") | 
|  | else() | 
|  | set(PRINT_NAME "webgpu_generated_struct_info32.json") | 
|  | endif() | 
|  | set(OUTPUT "${EM_BUILD_GEN_DIR}/${PRINT_NAME}") | 
|  | set(${arg_OUTPUT_JSON} "${OUTPUT}" PARENT_SCOPE) | 
|  | list(APPEND ARGS "-o=${OUTPUT}") | 
|  |  | 
|  | add_custom_command( | 
|  | COMMAND ${ARGS} | 
|  | OUTPUT ${OUTPUT} | 
|  | COMMENT "Dawn Emscripten: Generating ${PRINT_NAME}." | 
|  | DEPENDS | 
|  | "${EMSCRIPTEN_ROOT_PATH}/tools/gen_struct_info.py" | 
|  | ${EMDAWNWEBGPU_HEADERS_GEN_HEADERS}  # for webgpu.h | 
|  | ${EMDAWNWEBGPU_STRUCT_INFO_JSON_GEN_SOURCES}  # for struct_info_webgpu.json | 
|  | ) | 
|  |  | 
|  | # Prior to CMake 3.20 the GENERATED property is local to a directory which means that putting | 
|  | # generated headers in INTERFACE properties causes dependent targets to complain that they | 
|  | # cannot find the file. (because they don't see it as generated and want to check is is | 
|  | # actually on the filesystem). | 
|  | # Work around this by generating the files once if they aren't present at configuration time. | 
|  | if (NOT EXISTS ${OUTPUT}) | 
|  | message(STATUS "Dawn: Generating initial versions of files for ${PRINT_NAME}.") | 
|  | execute_process(COMMAND ${ARGS} RESULT_VARIABLE RET) | 
|  | if (NOT RET EQUAL 0) | 
|  | message(FATAL_ERROR "Dawn: Failed to generate the initial version of files for ${PRINT_NAME}. Base args are '${ARGS}'.") | 
|  | endif() | 
|  | endif() | 
|  | endfunction() | 
|  |  | 
|  | message(STATUS "Dawn: Configuring Emscripten gen_struct_info for WebGPU.") | 
|  |  | 
|  | webgpu_gen_struct_info( | 
|  | OUTPUT_JSON WEBGPU_STRUCT_INFO_GEN32 | 
|  | WASM64 OFF | 
|  | ) | 
|  | webgpu_gen_struct_info( | 
|  | OUTPUT_JSON WEBGPU_STRUCT_INFO_GEN64 | 
|  | WASM64 ON | 
|  | ) | 
|  |  | 
|  | # TODO(crbug.com/346806934): Consider using CMake builtin `cat` as per https://stackoverflow.com/a/62362885, | 
|  | # especially if we are to remove the GN build where concat.py is needed. | 
|  | function(webgpu_gen_struct_info_js) | 
|  | cmake_parse_arguments(PARSE_ARGV 0 arg | 
|  | "" | 
|  | "OUTPUT_JS" | 
|  | "" | 
|  | ) | 
|  | if (arg_UNPARSED_ARGUMENTS) | 
|  | message(FATAL_ERROR | 
|  | "Unparsed arguments for webgpu_gen_struct_info_js: " | 
|  | "${arg_UNPARSED_ARGUMENTS}") | 
|  | endif() | 
|  |  | 
|  | set(PRINT_NAME library_webgpu_generated_struct_info.js) | 
|  | set(OUTPUT "${EM_BUILD_GEN_DIR}/${PRINT_NAME}") | 
|  | set(SRCS | 
|  | "${EM_SRC_DIR}/snippets/library_webgpu_struct_info_part1.txt" | 
|  | "${WEBGPU_STRUCT_INFO_GEN32}" | 
|  | "${EM_SRC_DIR}/snippets/library_webgpu_struct_info_part2.txt" | 
|  | "${WEBGPU_STRUCT_INFO_GEN64}" | 
|  | "${EM_SRC_DIR}/snippets/library_webgpu_struct_info_part3.txt" | 
|  | ) | 
|  | set(ARGS | 
|  | ${Python3_EXECUTABLE} | 
|  | "${EM_SRC_DIR}/concat.py" | 
|  | "${OUTPUT}" | 
|  | ${SRCS} | 
|  | ) | 
|  | set(${arg_OUTPUT_JS} "${OUTPUT}" PARENT_SCOPE) | 
|  |  | 
|  | add_custom_command( | 
|  | COMMAND ${ARGS} | 
|  | OUTPUT ${OUTPUT} | 
|  | COMMENT "Dawn Emscripten: Generating ${PRINT_NAME}." | 
|  | DEPENDS | 
|  | "${EM_SRC_DIR}/concat.py" | 
|  | ${SRCS} | 
|  | ) | 
|  |  | 
|  | # Prior to CMake 3.20 the GENERATED property is local to a directory which means that putting | 
|  | # generated headers in INTERFACE properties causes dependent targets to complain that they | 
|  | # cannot find the file. (because they don't see it as generated and want to check is is | 
|  | # actually on the filesystem). | 
|  | # Work around this by generating the files once if they aren't present at configuration time. | 
|  | if (NOT EXISTS ${OUTPUT}) | 
|  | message(STATUS "Dawn: Generating initial versions of files for ${PRINT_NAME}.") | 
|  | execute_process(COMMAND ${ARGS} RESULT_VARIABLE RET) | 
|  | if (NOT RET EQUAL 0) | 
|  | message(FATAL_ERROR "Dawn: Failed to generate the initial version of files for ${PRINT_NAME}. Base args are '${ARGS}'.") | 
|  | endif() | 
|  | endif() | 
|  | endfunction() | 
|  |  | 
|  | webgpu_gen_struct_info_js( | 
|  | OUTPUT_JS EMDAWNWEBGPU_STRUCT_INFO_JS | 
|  | ) | 
|  |  | 
|  | # Include dir, and dependency on the generated files in the include dir. | 
|  | add_library(emdawnwebgpu_c_include INTERFACE) | 
|  | target_include_directories(emdawnwebgpu_c_include BEFORE INTERFACE | 
|  | "${EM_BUILD_GEN_DIR}/include" | 
|  | ) | 
|  | add_dependencies(emdawnwebgpu_c_include emdawnwebgpu_headers_gen) | 
|  |  | 
|  | dawn_add_library( | 
|  | emdawnwebgpu_c | 
|  | ENABLE_EMSCRIPTEN | 
|  | HEADERS | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu.h" | 
|  | SOURCES | 
|  | "${DAWN_EMDAWNWEBGPU_DIR}/pkg/webgpu/src/webgpu.cpp" | 
|  | DEPENDS | 
|  | emdawnwebgpu_c_include | 
|  | ) | 
|  | target_link_options(emdawnwebgpu_c INTERFACE | 
|  | # IMPORTANT: If changing these dependencies, update EMDAWNWEBGPU_C_ALL_FILE_DEPS too. | 
|  | "--js-library=${EM_BUILD_GEN_DIR}/library_webgpu_enum_tables.js" | 
|  | "--js-library=${EM_BUILD_GEN_DIR}/library_webgpu_generated_sig_info.js" | 
|  | "--js-library=${EM_BUILD_GEN_DIR}/library_webgpu_generated_struct_info.js" | 
|  | "--js-library=${DAWN_EMDAWNWEBGPU_DIR}/pkg/webgpu/src/library_webgpu.js" | 
|  | "--closure-args=--externs=${DAWN_EMDAWNWEBGPU_DIR}/pkg/webgpu/src/webgpu-externs.js" | 
|  | ) | 
|  |  | 
|  | # Dependencies from emdawnwebgpu_c to the files referenced in the linker flags. | 
|  | # - These are used as both file-level dependencies (defining *when* to rebuild) and | 
|  | #   target-level dependencies (defining *how* to rebuild). | 
|  | set(EMDAWNWEBGPU_C_GENERATED_FILE_DEPS | 
|  | "${EMDAWNWEBGPU_JS_GEN_SOURCES}" | 
|  | "${EMDAWNWEBGPU_STRUCT_INFO_JS}" | 
|  | ) | 
|  | # - There are also source files, which are used only as file-level dependencies. | 
|  | set(EMDAWNWEBGPU_C_ALL_FILE_DEPS | 
|  | "${EMDAWNWEBGPU_C_GENERATED_FILE_DEPS}" | 
|  | "${DAWN_EMDAWNWEBGPU_DIR}/pkg/webgpu/src/library_webgpu.js" | 
|  | "${DAWN_EMDAWNWEBGPU_DIR}/pkg/webgpu/src/webgpu-externs.js" | 
|  | ) | 
|  | add_custom_target(emdawnwebgpu_config_generated_deps | 
|  | DEPENDS "${EMDAWNWEBGPU_C_GENERATED_FILE_DEPS}" | 
|  | ) | 
|  | add_dependencies(emdawnwebgpu_c emdawnwebgpu_config_generated_deps) | 
|  | set_target_properties(emdawnwebgpu_c PROPERTIES | 
|  | # This defines file-level dependencies of the linker (intended for "linker scripts"). | 
|  | INTERFACE_LINK_DEPENDS "${EMDAWNWEBGPU_C_ALL_FILE_DEPS}" | 
|  | ) | 
|  |  | 
|  | dawn_add_library( | 
|  | emdawnwebgpu_cpp | 
|  | ENABLE_EMSCRIPTEN | 
|  | HEADER_ONLY | 
|  | HEADERS | 
|  | "${EM_BUILD_GEN_DIR}/include/dawn/webgpu_cpp_print.h" | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu_cpp.h" | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu_cpp_chained_struct.h" | 
|  | "${DAWN_INCLUDE_DIR}/webgpu/webgpu_enum_class_bitmasks.h" | 
|  | DEPENDS | 
|  | emdawnwebgpu_c | 
|  | ) | 
|  |  | 
|  | add_custom_target(emdawnwebgpu_pkg | 
|  | DEPENDS | 
|  | # This will compile webgpu.cpp, which is unnecessary because we package webgpu.cpp as a | 
|  | # source file, but it's simpler than specifying all the generator dependencies again. | 
|  | emdawnwebgpu_c | 
|  | ) | 
|  |  | 
|  | add_custom_command(TARGET emdawnwebgpu_pkg POST_BUILD | 
|  | # Copy files from src/emdawnwebgpu/pkg and third_party/emdawnwebgpu/pkg | 
|  | COMMAND ${CMAKE_COMMAND} -E copy_directory | 
|  | "${DAWN_EMDAWNWEBGPU_DIR}/pkg/" | 
|  | "${EM_SRC_DIR}/pkg/" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/" | 
|  | COMMAND ${CMAKE_COMMAND} -E make_directory | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu/include/webgpu/" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu_cpp/include/webgpu/" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu_cpp/include/dawn/" | 
|  |  | 
|  | # Copy webgpu_enum_class_bitmasks.h | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${DAWN_INCLUDE_DIR}/webgpu/webgpu_enum_class_bitmasks.h" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu_cpp/include/webgpu/" | 
|  |  | 
|  | # Copy webgpu_glfw.h | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu_glfw.h" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu/include/webgpu/" | 
|  |  | 
|  | # Copy generated files | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${EM_BUILD_GEN_DIR}/library_webgpu_enum_tables.js" | 
|  | "${EM_BUILD_GEN_DIR}/library_webgpu_generated_struct_info.js" | 
|  | "${EM_BUILD_GEN_DIR}/library_webgpu_generated_sig_info.js" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu/src/" | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu.h" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu/include/webgpu/" | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu_cpp.h" | 
|  | "${EM_BUILD_GEN_DIR}/include/webgpu/webgpu_cpp_chained_struct.h" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu_cpp/include/webgpu/" | 
|  | COMMAND ${CMAKE_COMMAND} -E copy | 
|  | "${EM_BUILD_GEN_DIR}/include/dawn/webgpu_cpp_print.h" | 
|  | "${CMAKE_BINARY_DIR}/emdawnwebgpu_pkg/webgpu_cpp/include/dawn/" | 
|  | ) | 
|  |  | 
|  | if (${DAWN_BUILD_TESTS}) | 
|  | set(emdawnwebgpu_test_sources | 
|  | "tests/FuturesTests.cpp" | 
|  | ) | 
|  | set(emdawnwebgpu_test_deps | 
|  | dawn::dawn_wgpu_utils | 
|  | emdawnwebgpu_cpp | 
|  | gmock_main | 
|  | ) | 
|  |  | 
|  | add_executable(emdawnwebgpu_tests_asyncify ${emdawnwebgpu_test_sources}) | 
|  | set_target_properties(emdawnwebgpu_tests_asyncify PROPERTIES | 
|  | SUFFIX ".html") | 
|  | target_link_libraries( | 
|  | emdawnwebgpu_tests_asyncify | 
|  | PUBLIC | 
|  | ${emdawnwebgpu_test_deps} | 
|  | ) | 
|  | target_link_options(emdawnwebgpu_tests_asyncify PUBLIC | 
|  | # We need Asyncify or JSPI for Future tests. | 
|  | "-sASYNCIFY=1" | 
|  | ) | 
|  |  | 
|  | add_executable(emdawnwebgpu_tests_jspi ${emdawnwebgpu_test_sources}) | 
|  | set_target_properties(emdawnwebgpu_tests_jspi PROPERTIES | 
|  | SUFFIX ".html") | 
|  | target_link_libraries( | 
|  | emdawnwebgpu_tests_jspi | 
|  | PUBLIC | 
|  | ${emdawnwebgpu_test_deps} | 
|  | ) | 
|  | target_link_options(emdawnwebgpu_tests_jspi PUBLIC | 
|  | # We need Asyncify or JSPI for Future tests. | 
|  | "-sJSPI=1" | 
|  | ) | 
|  |  | 
|  | DawnJSONGenerator( | 
|  | TARGET "emdawnwebgpu_link_test_cpp" | 
|  | PRINT_NAME "emdawnwebgpu LinkTest.cpp" | 
|  | OUTPUT_SOURCES EMDAWNWEBGPU_LINK_TEST_CPP_SOURCES | 
|  | ) | 
|  | add_executable(emdawnwebgpu_link_test | 
|  | ${EMDAWNWEBGPU_LINK_TEST_CPP_SOURCES} | 
|  | ) | 
|  | # The test is just that this links, not that it runs (it doesn't do | 
|  | # anything interesting), so just build to .js. Since it has a main() | 
|  | # function, this is the same as building to .html, but skipping the | 
|  | # .html file. It _is_ runnable if invoked via <script> or `node`. | 
|  | set_target_properties(emdawnwebgpu_link_test PROPERTIES | 
|  | SUFFIX ".js") | 
|  | target_link_options(emdawnwebgpu_link_test | 
|  | PRIVATE | 
|  | --closure=1 | 
|  | ) | 
|  | target_link_libraries( | 
|  | emdawnwebgpu_link_test | 
|  | PUBLIC | 
|  | emdawnwebgpu_c | 
|  | ) | 
|  | endif() | 
|  | endif() |