-
Notifications
You must be signed in to change notification settings - Fork 8
Open
Description
Hi @kainino0x
I saw your response about "misusing" the port system for your needs at the moment. I understand that this is experimental. I also want to help because I think using webgpu as a proper port is the right way to go (down the line).
Here is the port that I wrote (and you are more than welcome to reuse if you so wish):
# note that the file must be called emdawnwebgpu.py (<port_name>.py)
import os
from typing import Union, Dict, Optional
TAG = 'v2025.04.12-03.06.48'
HASH = 'd5627fb822317a8573ad133100a15917517ad44ca39c6927b4dd37b3a3476082a077f8474dcde348bb42a4058c92b9c25beeffb5bd71b83c44df93efea48c1cf'
ZIP_URL = f'https://github.com/kainino0x/dawn/releases/download/{TAG}/emdawnwebgpu_pkg-{TAG}.zip'
# contrib port information (required)
URL = 'https://dawn.googlesource.com/dawn'
DESCRIPTION = 'Dawn is an open-source and cross-platform implementation of the WebGPU standard'
LICENSE = 'BSD 3-Clause License'
VALID_OPTION_VALUES = {
'enableCPPBindings': ['true', 'false'],
'optimizationLevel': ['0', '1', '2', '3', 'g', 's', 'z'] # all -OX possibilities
}
OPTIONS = {
'enableCPPBindings': 'A boolean to enable CPP bindings (disabled by default)',
'optimizationLevel': f'Optimization level: {VALID_OPTION_VALUES["optimizationLevel"]} (default to 2)',
}
# user options (from --use-port)
opts: Dict[str, Union[Optional[str], bool]] = {
'enableCPPBindings': False,
'optimizationLevel': '2'
}
port_name = 'emdawnwebgpu'
def get_lib_name(settings):
return f'lib_{port_name}_{TAG}-O{opts["optimizationLevel"]}.a'
def get_root_path(ports):
return os.path.join(ports.get_dir(), port_name, 'emdawnwebgpu_pkg')
def get_include_path(ports):
return os.path.join(get_root_path(ports), 'webgpu', 'include')
def get_cpp_include_path(ports):
return os.path.join(get_root_path(ports), 'webgpu_cpp', 'include')
def get_source_path(ports):
return os.path.join(get_root_path(ports), 'webgpu', 'src')
def get(ports, settings, shared):
# get the port
ports.fetch_project(port_name, ZIP_URL, sha512hash=HASH)
def create(final):
source_path = get_source_path(ports)
include_path = get_include_path(ports)
includes = [include_path]
srcs = ['webgpu.cpp']
flags = ['-std=c++17', '-fno-exceptions']
flags.append(f'-O{opts["optimizationLevel"]}')
ports.build_port(source_path, final, port_name, includes=includes, srcs=srcs, flags=flags)
lib = shared.cache.get_lib(get_lib_name(settings), create, what='port')
if os.path.getmtime(lib) < os.path.getmtime(__file__):
clear(ports, settings, shared)
lib = shared.cache.get_lib(get_lib_name(settings), create, what='port')
return [lib]
def clear(ports, settings, shared):
shared.cache.erase_lib(get_lib_name(settings))
def linker_setup(ports, settings):
if settings.USE_WEBGPU:
raise Exception('dawn may not be used with -sUSE_WEBGPU=1')
src_dir = get_source_path(ports)
settings.JS_LIBRARIES += [
os.path.join(src_dir, 'library_webgpu_enum_tables.js'),
os.path.join(src_dir, 'library_webgpu_generated_struct_info.js'),
os.path.join(src_dir, 'library_webgpu_generated_sig_info.js'),
os.path.join(src_dir, 'library_webgpu.js'),
]
# TODO(crbug.com/371024051): Emscripten needs a way for us to pass
# --closure-args too.
def process_args(ports):
# It's important that these take precedent over Emscripten's builtin
# system/include/, which also currently as webgpu headers.
args = ['-isystem', get_include_path(ports)]
if opts['enableCPPBindings']:
args += ['-isystem', get_cpp_include_path(ports)]
return args
def check_option(option, value, error_handler):
if value not in VALID_OPTION_VALUES[option]:
error_handler(f'[{option}] can be {list(VALID_OPTION_VALUES[option])}, got [{value}]')
if isinstance(opts[option], bool):
value = value == 'true'
return value
def check_required_option(option, value, error_handler):
if opts[option] is not None and opts[option] != value:
error_handler(f'[{option}] is already set with incompatible value [{opts[option]}]')
return check_option(option, value, error_handler)
def handle_options(options, error_handler):
for option, value in options.items():
value = value.lower()
opts[option] = check_option(option, value, error_handler)
if __name__ == "__main__":
print(f'''# To compute checksums run this
curl -sfL {ZIP_URL} | shasum -a 512
''')
You use it this way (with the main.cpp
file from this repository)
> mkdir /tmp/dawn
> emcc -sASYNCIFY=1 -sASYNCIFY_STACK_SIZE=65536 -sEXPORTED_RUNTIME_METHODS=ccall --use-port=emdawnwebgpu.py:enableCPPBindings=true main_dawn.cpp -o /tmp/dawn/index.html
A few points:
- by using port options, you do not need 2 separate ports: enabling cpp bindings is an option (and it is false by default)
- the port file downloads the zip file and does what needs to be done => from a user point of view you only need the port file (not the zip file)
- this means that the port file is outside the zip file (and could be also an artifact generated part of your CI)
- I can host this port file in my emscripten-ports project for the time being for people who just wants to use the port without having to download the zip file
- It is my strong opinion that this port file should become a contrib port in Emscripten once -sUSE_WEBGPU is deprecated so that people can simply install Emscripten and do
emcc --use-port=contrib.dawn
. Updating the port file on Emscripten usually becomes simply updating the version/hash and that would be fine to do when Dawn has "stable" releases
Metadata
Metadata
Assignees
Labels
No labels