[emscripten] Compile emdawnwebgpu port with -sSHARED_MEMORY

When linking using -sSHARED_MEMORY (which means the heap is a
SharedArrayBuffer - it's implied by -pthread or other flags),
emdawnwebgpu's webgpu.cpp also needs to be compiled with that flag.

Asides:
- Switch webgpu.cpp to C++20.
- Remove the underscore from lib_emdawnwebgpu -> libemdawnwebgpu, to
  make it more consistent with typical library names.

No-Try: true
Fixed: 420406098
Change-Id: I1668295212da03f145bdef5db85c8cf013969df3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/244075
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/emdawnwebgpu/pkg/README.md b/src/emdawnwebgpu/pkg/README.md
index d344c64..0a7af93 100644
--- a/src/emdawnwebgpu/pkg/README.md
+++ b/src/emdawnwebgpu/pkg/README.md
@@ -17,7 +17,7 @@
 
 First, start with either:
 
-- A "remote" port file `emdawnwebgpu-v*.port.py` (requires Emscripten 4.0.10+).
+- A "remote" port file `emdawnwebgpu-v*.remoteport.py` (requires Emscripten 4.0.10+).
 - An `emdawnwebgpu_pkg` containing a local port file `emdawnwebgpu.port.py`.
   (Either from a pre-built zip release, or from a Dawn build output directory.)
 
@@ -26,7 +26,7 @@
 Pass the following flag to `emcc`, during both compile and link, to set the
 include paths and link the implementation:
 
-    --use-port=path/to/emdawnwebgpu*.port.py
+    --use-port=path/to/emdawnwebgpu_port_or_remoteport_file.py
 
 If (and only if) using Emscripten before 4.0.7, also pass this flag during link:
 
@@ -37,7 +37,9 @@
 Options can be set by appending `:key1=value:key2=value` to `--use-port`.
 For information about port options, run:
 
-    emcc --use-port=path/to/emdawnwebgpu*.port.py:help
+    emcc --use-port=emdawnwebgpu:help
+    emcc --use-port=path/to/emdawnwebgpu.port.py:help
+    emcc --use-port=path/to/emdawnwebgpu-*.remoteport.py:help
 
 ### C++ bindings
 
@@ -46,12 +48,14 @@
 for any reason (you have custom bindings, you're using a pinned snapshot of
 `webgpu_cpp.h`, etc.), you can set the option `cpp_bindings=false`:
 
-    --use-port=path/to/emdawnwebgpu*.port.py:cpp_bindings=false
+    --use-port=emdawnwebgpu:cpp_bindings=false
+    --use-port=path/to/emdawnwebgpu.port.py:cpp_bindings=false
+    --use-port=path/to/emdawnwebgpu-*.remoteport.py:cpp_bindings=false
 
 ## Embuilder
 
 If your build process needs a separate step to build the port before linking,
-use Emscripten's `embuilder` (with `opt_level` set explicitly):
+use Emscripten's `embuilder`.
 
-    embuilder build path/to/emdawnwebgpu*.port.py:opt_level=0
-    embuilder build path/to/emdawnwebgpu*.port.py:opt_level=2
+Under `embuilder`, some options cannot be set automatically, so they must be
+set manually. See `OPTIONS` in `emdawnwebgpu.port.py` for details.
diff --git a/src/emdawnwebgpu/pkg/emdawnwebgpu.port.py b/src/emdawnwebgpu/pkg/emdawnwebgpu.port.py
index 3af52aa..b80ee18 100644
--- a/src/emdawnwebgpu/pkg/emdawnwebgpu.port.py
+++ b/src/emdawnwebgpu/pkg/emdawnwebgpu.port.py
@@ -36,20 +36,31 @@
 
 LICENSE = "Some files: BSD 3-Clause License. Other files: Emscripten's license (available under both MIT License and University of Illinois/NCSA Open Source License)"
 
-# User options, e.g. --use-port=path/to/emdawnwebgpu.port.py:cpp_bindings=false
+# User options. (See README.md for how to use these.)
 OPTIONS = {
     'cpp_bindings':
     "Add the include path for Dawn-like <webgpu/webgpu_cpp.h> C++ bindings. Default: true.",
+
+    # The following options are generally not needed, as they are automatically
+    # derived from the linker flags. However, if using embuilder, these must be
+    # used as they are the only way to control these options
+    # (https://github.com/emscripten-core/emscripten/issues/24421). For example:
+    #
+    #     embuilder build path/to/port/file.py:opt_level=2:shared_memory=true
     'opt_level':
     "Optimization (-O) level for the bindings' Wasm layer. Default: choose based on -sASSERTIONS.",
+    'shared_memory':
+    "Enable -sSHARED_MEMORY. Default: choose based on whether linker has -sSHARED_MEMORY enabled.",
 }
 _VALID_OPTION_VALUES = {
     'cpp_bindings': ['true', 'false'],
     'opt_level': ['auto', '0', '2'],
+    'shared_memory': ['auto', 'true', 'false'],
 }
-_opts: Dict[str, Union[Optional[str], bool]] = {
-    'cpp_bindings': True,
+_opts: Dict[str, Optional[str]] = {
+    'cpp_bindings': 'true',
     'opt_level': 'auto',
+    'shared_memory': 'auto',
 }
 
 
@@ -91,8 +102,6 @@
         error_handler(
             f'[{option}] can be {list(_VALID_OPTION_VALUES[option])}, got [{value}]'
         )
-    if isinstance(_opts[option], bool):
-        value = value == 'true'
     return value
 
 
@@ -106,34 +115,44 @@
     # It's important that these take precedent over Emscripten's builtin
     # system/include/, which also currently has webgpu headers.
     args = ['-isystem', _c_include_dir]
-    if _opts['cpp_bindings']:
+    if _opts['cpp_bindings'] == 'true':
         args += ['-isystem', _cpp_include_dir]
     return args
 
 
 # Hooks that affect linker invocations
 
-
-# If not explicitly set, use -O0 when linking with -sASSERTIONS builds, and -O2
-# otherwise. (ASSERTIONS implicitly affects library_webgpu.js, so it makes sense
-# for it to control this too - debuggability is most useful with assertions.)
-# Emscripten automatically handles necessary compile flags (LTO, PIC, wasm64).
-def _compute_opt_level_flag(settings):
-    value = _opts['opt_level']
-    if value == 'auto':
-        value = '0' if settings.ASSERTIONS else '2'
-    return f'-O{value}'
-
-
-# Compute the library compile flags, either `-O0` or `-O2 -DNDEBUG` (see above).
-# NDEBUG affects <assert.h> and is used in `webgpu.cpp`.
 def _compute_library_compile_flags(settings):
-    opt_level_flag = _compute_opt_level_flag(settings)
-    flags = [opt_level_flag]
+    # Emscripten automatically handles many necessary compile flags (LTO, PIC,
+    # wasm64). The ones it does not handle are handled below.
+    lib_name_suffix = ''
+    flags = []
+
+    # If not explicitly set, use -O0 when linking with -sASSERTIONS builds, and
+    # -O2 otherwise. (ASSERTIONS implicitly affects library_webgpu.js, so it
+    # makes sense for it to control this too - debuggability is most useful with
+    # assertions.)
+    opt_level = _opts['opt_level']
+    if opt_level == 'auto':
+        opt_level = '0' if settings.ASSERTIONS else '2'
+    lib_name_suffix += f'-O{opt_level}'
+    flags.append(f'-O{opt_level}')
     # Set NDEBUG if -O0 (similar to emcc's defaulting of -sASSERTIONS from -O).
-    if opt_level_flag != '-O0':
+    if opt_level != '0':
         flags.append('-DNDEBUG')
-    return flags
+
+    # If not explicitly set, inherit -sSHARED_MEMORY from the linker invocation.
+    # This affects how std::atomic<> is compiled. (It may be fine to link a
+    # -sSHARED_MEMORY=1 object into a -sSHARED_MEMORY=0 executable, but it still
+    # emits unnecessary atomic operations, so we prefer not to do that.)
+    shared_memory = _opts['shared_memory']
+    if shared_memory == 'auto':
+        shared_memory = 'true' if settings.SHARED_MEMORY else 'false'
+    if shared_memory == 'true':
+        lib_name_suffix += '-shared_memory'
+        flags.append('-sSHARED_MEMORY')
+
+    return (lib_name_suffix, flags)
 
 
 # Create a unique lib name for this version of the port and compile flags.
@@ -149,8 +168,8 @@
     for filename in _files_affecting_port_build:
         add(open(filename, 'rb').read())
 
-    opt_level_flag = _compute_opt_level_flag(settings)
-    return f'lib_emdawnwebgpu-{hash_value:08x}{opt_level_flag}.a'
+    (lib_name_suffix, _) = _compute_library_compile_flags(settings)
+    return f'libemdawnwebgpu-{hash_value:08x}{lib_name_suffix}.a'
 
 
 def linker_setup(ports, settings):
@@ -184,8 +203,8 @@
         # compiled webgpu.cpp (which also includes webgpu/webgpu.h).
         includes = [_c_include_dir]
         # Always use -g. The linker can remove debug symbols in release builds.
-        flags = ['-g', '-std=c++17', '-fno-exceptions']
-        flags += _compute_library_compile_flags(settings)
+        (_, flags) = _compute_library_compile_flags(settings)
+        flags += ['-g', '-std=c++20', '-fno-exceptions']
 
         # IMPORTANT: Keep `_files_affecting_port_build` in sync with this.
         ports.build_port(_src_dir,