# wgpu-native WebGPU Implementation Configuration if(TARGET mbgl-vendor-wgpu) return() endif() if(NOT MLN_WITH_WEBGPU) return() endif() message(STATUS "Configuring wgpu-native WebGPU implementation") set(_mln_wgpu_source_dir "${PROJECT_SOURCE_DIR}/vendor/wgpu-native") if ("${MLN_WEBGPU_IMPL_FFI_BUNDLED_WEBGPU_HEADER}" STREQUAL "") set(WEBGPU_H_DIR ${_mln_wgpu_source_dir}/ffi/webgpu-headers) else() set(WEBGPU_H_DIR ${MLN_WEBGPU_IMPL_WEBGPU_HEADER_DIR}) endif() # Check if wgpu-native exists if(NOT EXISTS "${WEBGPU_H_DIR}/webgpu.h") message(FATAL_ERROR "wgpu-native not found at ${_mln_wgpu_source_dir}. " "Please ensure the wgpu-native submodule is initialized: " "git submodule update --init --recursive vendor/wgpu-native") endif() # wgpu-native provides pre-built binaries or can be built from source # We'll look for prebuilt binaries first, then fall back to building from source # Platform-specific library names and paths if(APPLE) if(CMAKE_SYSTEM_NAME STREQUAL "iOS") include("${CMAKE_CURRENT_LIST_DIR}/wgpu.ios.cmake") else() if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") set(_wgpu_lib_arch "aarch64-apple-darwin") else() set(_wgpu_lib_arch "x86_64-apple-darwin") endif() endif() set(_wgpu_lib_name "libwgpu_native.a") elseif(ANDROID) include("${CMAKE_CURRENT_LIST_DIR}/wgpu.android.cmake") elseif(WIN32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_wgpu_lib_arch "x86_64-pc-windows-msvc") else() set(_wgpu_lib_arch "i686-pc-windows-msvc") endif() set(_wgpu_lib_name "wgpu_native.lib") else() # Linux if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64") set(_wgpu_lib_arch "aarch64-unknown-linux-gnu") else() set(_wgpu_lib_arch "x86_64-unknown-linux-gnu") endif() set(_wgpu_lib_name "libwgpu_native.a") endif() # Look for prebuilt wgpu-native library # Search platform-specific path first to prefer cross-compiled libraries set(_wgpu_lib_search_paths "${_mln_wgpu_source_dir}/target/${_wgpu_lib_arch}/release" ) if(CMAKE_SYSTEM_NAME STREQUAL "iOS") mln_wgpu_ios_append_search_paths(_wgpu_lib_search_paths) endif() list(APPEND _wgpu_lib_search_paths "${_mln_wgpu_source_dir}/target/release" "${_mln_wgpu_source_dir}/lib" "${_mln_wgpu_source_dir}/build/release" ) # Resolve the exact archive/import library filename emitted by wgpu-native. macro(mln_wgpu_find_exact_library out_var out_description) foreach(_search_path ${_wgpu_lib_search_paths}) if(EXISTS "${_search_path}/${_wgpu_lib_name}") set(${out_var} "${_search_path}/${_wgpu_lib_name}" CACHE FILEPATH "${out_description}") break() endif() endforeach() endmacro() # On Android/iOS, use manual path search since find_library may not work with cross-compilation toolchains if (NOT MLN_WEBGPU_IMPL_FFI) macro(mln_wgpu_find_library) if(ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "iOS") mln_wgpu_find_exact_library(WGPU_LIBRARY "wgpu-native library") else() find_library(WGPU_LIBRARY NAMES wgpu_native libwgpu_native PATHS ${_wgpu_lib_search_paths} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH ) endif() endmacro() mln_wgpu_find_library() mln_wgpu_find_exact_library(WGPU_STATIC_LIBRARY "wgpu-native static library") endif() if(NOT MLN_WEBGPU_IMPL_FFI AND (NOT WGPU_LIBRARY OR MLN_WGPU_NATIVE_VERSION)) # Use a specific version of WGPU. This is required when to a rust application # which uses wgpu directly instead of wgpu-native if (MLN_WGPU_NATIVE_VERSION) execute_process( COMMAND git checkout ${MLN_WGPU_NATIVE_VERSION} WORKING_DIRECTORY ${_mln_wgpu_source_dir} RESULT_VARIABLE _git_checkout_wgpu_result OUTPUT_VARIABLE _git_checkout_wgpu_output ERROR_VARIABLE _git_checkout_wgpu_error ) if(NOT _git_checkout_wgpu_result EQUAL 0) message(FATAL_ERROR "Failed to checkout wgpu-native version '${MLN_WGPU_NATIVE_VERSION}': ${_git_checkout_wgpu_error}\n") endif() endif() message(STATUS "Pre-built wgpu-native library not found, attempting to build from source...") # Check if cargo is available find_program(CARGO_EXECUTABLE cargo) if(NOT CARGO_EXECUTABLE) message(FATAL_ERROR "wgpu-native library not found and cargo is not available to build it. " "Please either:\n" " 1. Install Rust and cargo (https://rustup.rs/), or\n" " 2. Download pre-built wgpu-native binaries from https://github.com/gfx-rs/wgpu-native/releases\n" " and place them in ${_mln_wgpu_source_dir}/target/release/") endif() # Build wgpu-native using cargo message(STATUS "Building wgpu-native with cargo (this may take a few minutes)...") # For cross-compilation targets (iOS, Android), pass --target and platform-specific features set(_cargo_extra_args "") if(_wgpu_lib_arch AND NOT _wgpu_lib_arch MATCHES "apple-darwin$") list(APPEND _cargo_extra_args --target ${_wgpu_lib_arch}) endif() if(_wgpu_cargo_features) list(APPEND _cargo_extra_args ${_wgpu_cargo_features}) endif() set(_cargo_env_prefix "") if(CMAKE_SYSTEM_NAME STREQUAL "iOS") mln_wgpu_ios_setup_cargo_env(_cargo_env_prefix) endif() execute_process( COMMAND ${_cargo_env_prefix} ${CARGO_EXECUTABLE} build --release ${_cargo_extra_args} WORKING_DIRECTORY ${_mln_wgpu_source_dir} RESULT_VARIABLE _cargo_result OUTPUT_VARIABLE _cargo_output ERROR_VARIABLE _cargo_error ) if(NOT _cargo_result EQUAL 0) message(FATAL_ERROR "Failed to build wgpu-native:\n${_cargo_error}\n" "You can try building manually:\n" " cd ${_mln_wgpu_source_dir} && cargo build --release") endif() # Try to find the library again mln_wgpu_find_library() mln_wgpu_find_exact_library(WGPU_STATIC_LIBRARY "wgpu-native static library") if(NOT WGPU_LIBRARY) message(FATAL_ERROR "Failed to locate wgpu-native library after building") endif() message(STATUS "Successfully built wgpu-native: ${WGPU_LIBRARY}") else() message(STATUS "Found wgpu-native library: ${WGPU_LIBRARY}") endif() if(WGPU_STATIC_LIBRARY) message(STATUS "Found wgpu-native static library: ${WGPU_STATIC_LIBRARY}") elseif(MLN_CREATE_AMALGAMATION) message(FATAL_ERROR "MLN_CREATE_AMALGAMATION=ON requires a static wgpu-native library, " "but none was found in: ${_wgpu_lib_search_paths}") endif() # Create compatibility shims for Dawn header paths if they don't exist set(_webgpu-cpp-output_dir "${CMAKE_CURRENT_BINARY_DIR}/webgpu-cpp") set(_compat_shim_dir "${_webgpu-cpp-output_dir}/webgpu") set(_compat_shim_header "${_compat_shim_dir}/webgpu_cpp.h") set(_compat_shim_webgpu_h "${_compat_shim_dir}/webgpu.h") set(_compat_shim_wgpu_h "${_compat_shim_dir}/wgpu.h") file(MAKE_DIRECTORY "${_compat_shim_dir}") # Generate WebGPU-Cpp wrapper if needed set(_webgpu_cpp_header "${_webgpu-cpp-output_dir}/webgpu.hpp") if(NOT EXISTS "${_webgpu_cpp_header}") message(STATUS "Generating WebGPU-Cpp wrapper...") # Check if Python 3 is available find_program(PYTHON_EXECUTABLE python3 python) if(NOT PYTHON_EXECUTABLE) message(FATAL_ERROR "Python is required to generate WebGPU-Cpp wrapper. " "Please install Python 3.") endif() # Run the generator script using the local webgpu.h from wgpu-native execute_process( COMMAND ${PYTHON_EXECUTABLE} generate.py --use-init-macros --header ${WEBGPU_H_DIR}/webgpu.h --output ${_webgpu_cpp_header} WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/vendor/webgpu-cpp" RESULT_VARIABLE _gen_result OUTPUT_VARIABLE _gen_output ERROR_VARIABLE _gen_error ) if(NOT _gen_result EQUAL 0) message(FATAL_ERROR "Failed to generate WebGPU-Cpp wrapper:\n${_gen_error}") endif() message(STATUS "Successfully generated WebGPU-Cpp wrapper") endif() if(NOT EXISTS "${_compat_shim_header}") message(STATUS "Creating WebGPU-Cpp compatibility shim...") file(WRITE "${_compat_shim_header}" "#pragma once // Compatibility shim for Dawn header paths // This file allows MapLibre code to use #include // for both Dawn and wgpu-native backends // Include the WebGPU-Cpp wrapper // TODO: remove this workaround as soon as https://github.com/eliemichel/WebGPU-Cpp/issues/35 is fixed #ifndef _NULLABLE #define _NULLABLE WGPU_NULLABLE #endif #include \"${_webgpu_cpp_header}\" #undef _NULLABLE ") message(STATUS "Successfully created WebGPU-Cpp compatibility shim") endif() if(NOT EXISTS "${_compat_shim_webgpu_h}") message(STATUS "Creating webgpu.h compatibility shim...") file(WRITE "${_compat_shim_webgpu_h}" "#pragma once // Compatibility shim for Dawn header paths // This file allows MapLibre code to use #include // for both Dawn and wgpu-native backends // Include the actual webgpu.h header #include ") message(STATUS "Successfully created webgpu.h compatibility shim") endif() # Also create wgpu.h shim for wgpu-native specific includes if(NOT EXISTS "${_compat_shim_wgpu_h}") message(STATUS "Creating wgpu.h compatibility shim...") file(WRITE "${_compat_shim_wgpu_h}" "#pragma once // Compatibility shim for wgpu-native specific header // This file allows MapLibre code to use #include // for both Dawn and wgpu-native backends // Include the actual wgpu.h header #include ") message(STATUS "Successfully created wgpu.h compatibility shim") endif() # Create interface library add_library(mbgl-vendor-wgpu INTERFACE) # For the ffi we don't link the wgpu library, because we link in the final stage with the rust wgpu version target_link_libraries(mbgl-vendor-wgpu INTERFACE ${WGPU_LIBRARY}) # Add include directories for webgpu.h, wgpu.h, and C++ wrapper target_include_directories(mbgl-vendor-wgpu SYSTEM INTERFACE ${_webgpu-cpp-output_dir} # For webgpu.hpp webgpu/webgpu_cpp.h compatibility shim ${WEBGPU_H_DIR} ${_mln_wgpu_source_dir}/ffi # wgpu.h ) # Platform-specific system libraries that wgpu-native needs if (NOT MLN_WEBGPU_IMPL_FFI) if(APPLE) target_link_libraries(mbgl-vendor-wgpu INTERFACE "-framework Foundation" "-framework QuartzCore" "-framework Metal" ) elseif(WIN32) target_link_libraries(mbgl-vendor-wgpu INTERFACE d3d12 dxgi d3dcompiler ws2_32 userenv bcrypt ntdll ) elseif(ANDROID) mln_wgpu_android_link_library(mbgl-vendor-wgpu) else() # Linux # wgpu-native on Linux might need these depending on the build configuration find_package(Threads REQUIRED) target_link_libraries(mbgl-vendor-wgpu INTERFACE Threads::Threads ${CMAKE_DL_LIBS} ) endif() endif() # Suppress warnings from wgpu headers if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") target_compile_options(mbgl-vendor-wgpu INTERFACE -Wno-strict-aliasing -Wno-error=strict-aliasing ) endif() if (NOT MLN_WEBGPU_IMPL_FFI) set_target_properties( mbgl-vendor-wgpu PROPERTIES INTERFACE_MAPLIBRE_NAME "wgpu-native" INTERFACE_MAPLIBRE_URL "https://github.com/gfx-rs/wgpu-native" INTERFACE_MAPLIBRE_AUTHOR "gfx-rs developers" INTERFACE_MAPLIBRE_LICENSE "${PROJECT_SOURCE_DIR}/vendor/wgpu-native/LICENSE.MIT" ) else() set_target_properties( mbgl-vendor-wgpu PROPERTIES INTERFACE_MAPLIBRE_NAME "wgpu-ffi" INTERFACE_MAPLIBRE_URL "https://github.com/maplibre/maplibre-native" INTERFACE_MAPLIBRE_AUTHOR "Maplibre Contributors" INTERFACE_MAPLIBRE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE.md" ) endif()