Merge remote-tracking branch 'tint/main' into HEAD

Integrates Tint repo into Dawn

KIs:
- Building docs for Tint is turned off, because it fails due to lack
  of annotations in Dawn source files.
- Dawn CQ needs to be updated to run Tint specific tests
- Significant post-merge cleanup needed

R=bclayton,cwallez
BUG=dawn:1339

Change-Id: I6c9714a0030934edd6c51f3cac4684dcd59d1ea3
diff --git a/.clang-format b/.clang-format
index 2fb833a..ff58eea 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,2 +1,20 @@
 # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
 BasedOnStyle: Chromium
+Standard: Cpp11
+
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 100
+
+# Use 4 space indents
+IndentWidth: 4
+ObjCBlockIndentWidth: 4
+AccessModifierOffset: -2
+
+CompactNamespaces: true
+
+# This should result in only one indentation level with compacted namespaces
+NamespaceIndentation: All
+
+# Use this option once clang-format 6 is out.
+IndentPPDirectives: AfterHash
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..d31b156
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+*     text=auto
+*.sh  eol=lf
+*.gn  eol=lf
+*.gni eol=lf
diff --git a/.gitignore b/.gitignore
index 19bafab..42d8414 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,31 +1,123 @@
-.cipd
-.DS_Store
-.gclient
-.gclient_entries
-.vs
+*.pyc
+
+# Directories added by gclient sync and the GN build
+/.cipd
+/.gclient
+/.gclient_entries
+/build
+/buildtools
+/testing
+/third_party/abseil-cpp/
+/third_party/angle
+/third_party/benchmark
+/third_party/binutils
+/third_party/catapult
+/third_party/clang-format
+/third_party/cpplint
+/third_party/glfw
+/third_party/googletest
+/third_party/gpuweb
+/third_party/gpuweb-cts
+/third_party/jinja2
+/third_party/jsoncpp
+/third_party/llvm-build
+/third_party/markupsafe
+/third_party/node
+/third_party/node-addon-api
+/third_party/node-api-headers
+/third_party/protobuf
+/third_party/swiftshader
+/third_party/vulkan-deps
+/third_party/vulkan_memory_allocator
+/third_party/webgpu-cts
+/third_party/zlib
+/tools/clang
+/tools/cmake
+/tools/golang
+/tools/memory
+/out
+
+# Modified from https://www.gitignore.io/api/vim,macos,linux,emacs,windows,sublimetext,visualstudio,visualstudiocode,intellij
+
+### Emacs ###
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+### Linux ###
+.fuse_hidden*
+.directory
+.Trash-*
+.nfs*
+
+### macOS ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+._*
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### SublimeText ###
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+*.sublime-workspace
+*.sublime-project
+sftp-config.json
+GitHub.sublime-settings
+
+### Vim ###
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-v][a-z]
+[._]sw[a-p]
+Session.vim
+.netrwhist
+tags
+
+### VisualStudio ###
+.vs/*
+
+### VisualStudioCode ###
 .vscode/*
 !.vscode/tasks.json
+
+### Windows ###
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+Desktop.ini
+$RECYCLE.BIN/
+
+### Intellij ###
 .idea
+
+### Dawn node tools binaries
+src/dawn/node/tools/bin/
+
+### Cached node transpiled tools
+/.node_transpile_work_dir
+
+# Misc inherited from Tint
+/test.wgsl
 coverage.summary
 default.profraw
 lcov.info
-
-/buildtools
 /cmake-build-*/
-/out
 /testing
-/third_party/clang-format
-/third_party/catapult
-/third_party/cpplint
-/third_party/benchmark
-/third_party/binutils
-/third_party/googletest
-/third_party/gpuweb-cts
-/third_party/llvm-build
-/third_party/protobuf
-/third_party/vulkan-deps
-/tools/clang
-/tools/bin
-
-/build*/
-/test.wgsl
diff --git a/.gn b/.gn
index 2bc6b1c..3860440 100644
--- a/.gn
+++ b/.gn
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors
+# Copyright 2018 The Dawn Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,4 +17,33 @@
 # Use Python3 to run scripts. On Windows this will use python.exe or python.bat
 script_executable = "python3"
 
-check_targets = [ "//*" ]
+default_args = {
+  clang_use_chrome_plugins = false
+
+  # Override the mac version so standalone Dawn compiles with at least 10.11
+  # which allows us to not skip the -Wunguarded-availability warning and get
+  # proper warnings for use of APIs that are 10.12 and above (even if
+  # Chromium is still on 10.10).
+  mac_deployment_target = "10.11.0"
+  mac_min_system_version = "10.11.0"
+
+  angle_enable_abseil = false
+  angle_standalone = false
+  angle_build_all = false
+  angle_has_rapidjson = false
+  angle_vulkan_headers_dir = "//third_party/vulkan-deps/vulkan-headers/src"
+  angle_vulkan_loader_dir = "//third_party/vulkan-deps/vulkan-loader/src"
+  angle_vulkan_tools_dir = "//third_party/vulkan-deps/vulkan-tools/src"
+  angle_vulkan_validation_layers_dir =
+      "//third_party/vulkan-deps/vulkan-validation-layers/src"
+
+  vma_vulkan_headers_dir = "//third_party/vulkan-deps/vulkan-headers/src"
+}
+
+check_targets = [
+  # Everything in BUILD.gn
+  "//:*",
+
+  # Everything in third_party/BUILD.gn
+  "//third_party/:*",
+]
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index f584277..9d72ed9 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -10,46 +10,42 @@
     // ${cwd}: the current working directory of the spawned process
     "version": "2.0.0",
     "tasks": [
+        // Invokes ninja in the 'out/active' directory, which is created with
+        // the 'gn gen' task (see below).
         {
-            "label": "make",
+            "label": "build",
             "group": {
                 "kind": "build",
                 "isDefault": true
             },
             "type": "shell",
-            "osx": {
-                "command": "sh",
-                "args": [
-                    "-c",
-                    "cmake --build . && echo Done"
-                ],
-                "options": {
-                    "cwd": "${workspaceRoot}/build",
-                },
-            },
             "linux": {
                 "command": "sh",
                 "args": [
                     "-c",
-                    "cmake --build . && echo Done"
-                ],
-                "options": {
-                    "cwd": "${workspaceRoot}/build",
-                },
-            },
-            "windows": {
-                // Invokes ninja in the 'out/active' directory, which is created
-                // with the 'generate' task (see below).
-                "command": "/C",
-                "args": [
                     "ninja && echo Done"
                 ],
+            },
+            "osx": {
+                "command": "sh",
+                "args": [
+                    "-c",
+                    "ninja && echo Done"
+                ],
+            },
+            "windows": {
+                "command": "/C",
+                "args": [
+                    "ninja && echo Done",
+                ],
                 "options": {
-                    "cwd": "${workspaceRoot}/out/active",
                     "shell": {
                         "executable": "cmd"
-                    }
-                },
+                    },
+                }
+            },
+            "options": {
+                "cwd": "${workspaceRoot}/out/active",
             },
             "presentation": {
                 "echo": false,
@@ -72,36 +68,28 @@
                 }
             }
         },
+        // Generates a GN build directory at 'out/<build-type>' with the
+        // is_debug argument set to to true iff the build-type is Debug.
+        // A symbolic link to this build directory is created at 'out/active'
+        // which is used to track the active build directory.
         {
-            "label": "configure",
+            "label": "gn gen",
             "type": "shell",
-            "osx": {
-                "command": "cmake",
-                "args": [
-                    "..",
-                    "-GNinja",
-                    "-DCMAKE_BUILD_TYPE=${input:buildType}",
-                ],
-                "options": {
-                    "cwd": "${workspaceRoot}/build"
-                },
-            },
             "linux": {
-                "command": "cmake",
+                "command": "sh",
                 "args": [
-                    "..",
-                    "-GNinja",
-                    "-DCMAKE_BUILD_TYPE=${input:buildType}",
+                    "-c",
+                    "gn gen 'out/${input:buildType}' --args=is_debug=$(if [ '${input:buildType}' = 'Debug' ]; then echo 'true'; else echo 'false'; fi) && (rm -fr out/active || true) && ln -s ${input:buildType} out/active",
                 ],
-                "options": {
-                    "cwd": "${workspaceRoot}/build"
-                },
+            },
+            "osx": {
+                "command": "sh",
+                "args": [
+                    "-c",
+                    "gn gen 'out/${input:buildType}' --args=is_debug=$(if [ '${input:buildType}' = 'Debug' ]; then echo 'true'; else echo 'false'; fi) && (rm -fr out/active || true) && ln -s ${input:buildType} out/active",
+                ],
             },
             "windows": {
-                // Generates a GN build directory at 'out/<build-type>' with the
-                // is_debug argument set to true iff the build-type is Debug.
-                // A symbolic link to this build directory is created at 'out/active'
-                // which is used to track the active build directory.
                 "command": "/C",
                 "args": [
                     "(IF \"${input:buildType}\" == \"Debug\" ( gn gen \"out\\${input:buildType}\" --args=is_debug=true ) ELSE ( gn gen \"out\\${input:buildType}\" --args=is_debug=false )) && (IF EXIST \"out\\active\" rmdir \"out\\active\" /q /s) && (mklink /j \"out\\active\" \"out\\${input:buildType}\")",
@@ -109,13 +97,52 @@
                 "options": {
                     "shell": {
                         "executable": "cmd"
-                    }
-                },
+                    },
+                }
+            },
+            "options": {
+                "cwd": "${workspaceRoot}"
             },
             "problemMatcher": [],
         },
+        // Rebases the current branch on to origin/main and then calls
+        // `gclient sync`.
         {
-            "label": "Push branch for review",
+            "label": "sync",
+            "type": "shell",
+            "linux": {
+                "command": "sh",
+                "args": [
+                    "-c",
+                    "git fetch origin && git rebase origin/main && gclient sync && echo Done"
+                ],
+            },
+            "osx": {
+                "command": "sh",
+                "args": [
+                    "-c",
+                    "git fetch origin && git rebase origin/main && gclient sync && echo Done"
+                ],
+            },
+            "windows": {
+                "command": "/C",
+                "args": [
+                    "git fetch origin && git rebase origin/main && gclient sync && echo Done",
+                ],
+                "options": {
+                    "shell": {
+                        "executable": "cmd"
+                    },
+                }
+            },
+            "options": {
+                "cwd": "${workspaceRoot}"
+            },
+            "problemMatcher": [],
+        },
+        // Pushes the changes at HEAD to gerrit for review
+        {
+            "label": "push",
             "type": "shell",
             "command": "git",
             "args": [
@@ -136,8 +163,6 @@
             "options": [
                 "Debug",
                 "Release",
-                "MinSizeRel",
-                "RelWithDebInfo",
             ],
             "default": "Debug",
             "description": "The type of build",
diff --git a/AUTHORS b/AUTHORS
index a66d09e..bded374 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,8 +1,7 @@
-# This is the list of the Tint authors for copyright purposes.
+# This is the list of Dawn & Tint authors for copyright purposes.
 #
 # This does not necessarily list everyone who has contributed code, since in
 # some cases, their employer may be the copyright holder.  To see the full list
 # of contributors, see the revision history in source control.
-
 Google LLC
 Vasyl Teliman
diff --git a/AUTHORS.dawn b/AUTHORS.dawn
new file mode 100644
index 0000000..32a6c3c
--- /dev/null
+++ b/AUTHORS.dawn
@@ -0,0 +1,6 @@
+# This is the list of Dawn authors for copyright purposes.
+#
+# This does not necessarily list everyone who has contributed code, since in
+# some cases, their employer may be the copyright holder.  To see the full list
+# of contributors, see the revision history in source control.
+Google Inc.
diff --git a/AUTHORS.tint b/AUTHORS.tint
new file mode 100644
index 0000000..a66d09e
--- /dev/null
+++ b/AUTHORS.tint
@@ -0,0 +1,8 @@
+# This is the list of the Tint authors for copyright purposes.
+#
+# This does not necessarily list everyone who has contributed code, since in
+# some cases, their employer may be the copyright holder.  To see the full list
+# of contributors, see the revision history in source control.
+
+Google LLC
+Vasyl Teliman
diff --git a/BUILD.gn b/BUILD.gn
index f73c1da..c33776d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors
+# Copyright 2018 The Dawn Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,13 +12,29 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import("scripts/dawn_overrides_with_defaults.gni")
+
+group("all") {
+  testonly = true
+  deps = [
+    "src/dawn/fuzzers",
+    "src/dawn/native:webgpu_dawn",
+    "src/dawn/tests",
+    "src/fuzzers/dawn:dawn_fuzzers",
+    "src/tint/fuzzers",
+    "src/tint:libtint",
+    "test/tint:tint_unittests",
+  ]
+  if (dawn_standalone) {
+    deps += [
+      "samples/dawn:samples",
+      "src/tint/cmd:tint",
+    ]
+  }
+}
+
 # This target is built when no specific target is specified on the command line.
 group("default") {
   testonly = true
-  deps = [
-    "src/tint:libtint",
-    "src/tint/cmd:tint",
-    "src/tint/fuzzers",
-    "test/tint:tint_unittests",
-  ]
+  deps = [ ":all" ]
 }
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 17a7ec5..f125476 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors.
+# Copyright 2022 The Dawn & Tint Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -14,8 +14,22 @@
 
 cmake_minimum_required(VERSION 3.10.2)
 
-project(tint)
+# When upgrading to CMake 3.11 we can remove DAWN_DUMMY_FILE because source-less add_library
+# becomes available.
+# When upgrading to CMake 3.12 we should add CONFIGURE_DEPENDS to DawnGenerator to rerun CMake in
+# case any of the generator files changes. We should also remove the CACHE "" FORCE stuff to
+# override options in third_party dependencies. We can also add the HOMEPAGE_URL
+# entry to the project `HOMEPAGE_URL "https://dawn.googlesource.com/dawn"`
+
+project(
+    Dawn
+    DESCRIPTION "Dawn, a WebGPU implementation"
+    LANGUAGES C CXX
+)
 enable_testing()
+
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
 set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 set(CMAKE_CXX_STANDARD 17)
@@ -26,20 +40,17 @@
   set(CMAKE_BUILD_TYPE "Debug")
 endif()
 
-# TINT_IS_SUBPROJECT is 1 if added via add_subdirectory() from another project.
-get_directory_property(TINT_IS_SUBPROJECT PARENT_DIRECTORY)
-if(TINT_IS_SUBPROJECT)
-  set(TINT_IS_SUBPROJECT 1)
+set(DAWN_BUILD_GEN_DIR "${Dawn_BINARY_DIR}/gen")
+set(DAWN_GENERATOR_DIR "${Dawn_SOURCE_DIR}/generator")
+set(DAWN_SRC_DIR "${Dawn_SOURCE_DIR}/src")
+set(DAWN_INCLUDE_DIR "${Dawn_SOURCE_DIR}/include")
+set(DAWN_TEMPLATE_DIR "${DAWN_GENERATOR_DIR}/templates")
 
-  # If tint is used as a subproject, default to disabling the building of
-  # documentation and tests. These are unlikely to be desirable, but can be
-  # enabled.
-  set(TINT_BUILD_DOCS_DEFAULT OFF)
-  set(TINT_BUILD_TESTS_DEFAULT OFF)
-else()
-  set(TINT_BUILD_DOCS_DEFAULT ON)
-  set(TINT_BUILD_TESTS_DEFAULT ON)
-endif()
+set(DAWN_DUMMY_FILE "${DAWN_SRC_DIR}/Dummy.cpp")
+
+################################################################################
+# Configuration options
+################################################################################
 
 # option_if_not_defined(name description default)
 # Behaves like:
@@ -65,7 +76,159 @@
     endif()
 endfunction()
 
-set_if_not_defined(TINT_THIRD_PARTY_DIR "${tint_SOURCE_DIR}/third_party" "Directory in which to find third-party dependencies.")
+# Default values for the backend-enabling options
+set(ENABLE_D3D12 OFF)
+set(ENABLE_METAL OFF)
+set(ENABLE_OPENGLES OFF)
+set(ENABLE_DESKTOP_GL OFF)
+set(ENABLE_VULKAN OFF)
+set(USE_X11 OFF)
+set(BUILD_SAMPLES OFF)
+if (WIN32)
+    set(ENABLE_D3D12 ON)
+    if (NOT WINDOWS_STORE)
+        # Enable Vulkan in win32 compilation only
+        # since UWP only supports d3d
+        set(ENABLE_VULKAN ON)
+    endif()
+elseif(APPLE)
+    set(ENABLE_METAL ON)
+elseif(ANDROID)
+    set(ENABLE_VULKAN ON)
+    set(ENABLE_OPENGLES ON)
+elseif(UNIX)
+    set(ENABLE_OPENGLES ON)
+    set(ENABLE_DESKTOP_GL ON)
+    set(ENABLE_VULKAN ON)
+    set(USE_X11 ON)
+endif()
+
+# GLFW is not supported in UWP
+if ((WIN32 AND NOT WINDOWS_STORE) OR UNIX AND NOT ANDROID)
+    set(DAWN_SUPPORTS_GLFW_FOR_WINDOWING ON)
+endif()
+
+# Current examples are depend on GLFW
+if (DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
+    set(BUILD_SAMPLES ON)
+endif()
+
+option_if_not_defined(DAWN_ENABLE_D3D12 "Enable compilation of the D3D12 backend" ${ENABLE_D3D12})
+option_if_not_defined(DAWN_ENABLE_METAL "Enable compilation of the Metal backend" ${ENABLE_METAL})
+option_if_not_defined(DAWN_ENABLE_NULL "Enable compilation of the Null backend" ON)
+option_if_not_defined(DAWN_ENABLE_DESKTOP_GL "Enable compilation of the OpenGL backend" ${ENABLE_DESKTOP_GL})
+option_if_not_defined(DAWN_ENABLE_OPENGLES "Enable compilation of the OpenGL ES backend" ${ENABLE_OPENGLES})
+option_if_not_defined(DAWN_ENABLE_VULKAN "Enable compilation of the Vulkan backend" ${ENABLE_VULKAN})
+option_if_not_defined(DAWN_ALWAYS_ASSERT "Enable assertions on all build types" OFF)
+option_if_not_defined(DAWN_USE_X11 "Enable support for X11 surface" ${USE_X11})
+
+option_if_not_defined(DAWN_BUILD_SAMPLES "Enables building Dawn's samples" ${BUILD_SAMPLES})
+option_if_not_defined(DAWN_BUILD_NODE_BINDINGS "Enables building Dawn's NodeJS bindings" OFF)
+
+option_if_not_defined(DAWN_ENABLE_PIC "Build with Position-Independent-Code enabled" OFF)
+
+set_if_not_defined(DAWN_THIRD_PARTY_DIR "${Dawn_SOURCE_DIR}/third_party" "Directory in which to find third-party dependencies.")
+
+# Recommended setting for compability with future abseil releases.
+set(ABSL_PROPAGATE_CXX_STD ON)
+
+set_if_not_defined(DAWN_ABSEIL_DIR "${DAWN_THIRD_PARTY_DIR}/abseil-cpp" "Directory in which to find Abseil")
+set_if_not_defined(DAWN_GLFW_DIR "${DAWN_THIRD_PARTY_DIR}/glfw" "Directory in which to find GLFW")
+set_if_not_defined(DAWN_JINJA2_DIR "${DAWN_THIRD_PARTY_DIR}/jinja2" "Directory in which to find Jinja2")
+set_if_not_defined(DAWN_SPIRV_HEADERS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-headers/src" "Directory in which to find SPIRV-Headers")
+set_if_not_defined(DAWN_SPIRV_TOOLS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-tools/src" "Directory in which to find SPIRV-Tools")
+set_if_not_defined(DAWN_TINT_DIR "${Dawn_SOURCE_DIR}" "Directory in which to find Tint")
+set_if_not_defined(DAWN_VULKAN_HEADERS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/vulkan-headers/src" "Directory in which to find Vulkan-Headers")
+
+# Dependencies for DAWN_BUILD_NODE_BINDINGS
+set_if_not_defined(NODE_ADDON_API_DIR "${DAWN_THIRD_PARTY_DIR}/node-addon-api" "Directory in which to find node-addon-api")
+set_if_not_defined(NODE_API_HEADERS_DIR "${DAWN_THIRD_PARTY_DIR}/node-api-headers" "Directory in which to find node-api-headers")
+set_if_not_defined(WEBGPU_IDL_PATH "${DAWN_THIRD_PARTY_DIR}/gpuweb/webgpu.idl" "Path to the webgpu.idl definition file")
+set_if_not_defined(GO_EXECUTABLE "go" "Golang executable for running the IDL generator")
+
+# Much of the backend code is shared among desktop OpenGL and OpenGL ES
+if (${DAWN_ENABLE_DESKTOP_GL} OR ${DAWN_ENABLE_OPENGLES})
+    set(DAWN_ENABLE_OPENGL ON)
+endif()
+
+if(DAWN_ENABLE_PIC)
+    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+endif()
+
+################################################################################
+# Dawn's public and internal "configs"
+################################################################################
+
+# The public config contains only the include paths for the Dawn headers.
+add_library(dawn_public_config INTERFACE)
+target_include_directories(dawn_public_config INTERFACE
+    "${DAWN_INCLUDE_DIR}"
+    "${DAWN_BUILD_GEN_DIR}/include"
+)
+
+# The internal config conatins additional path but includes the dawn_public_config include paths
+add_library(dawn_internal_config INTERFACE)
+target_include_directories(dawn_internal_config INTERFACE
+    "${DAWN_SRC_DIR}"
+    "${DAWN_BUILD_GEN_DIR}/src"
+)
+target_link_libraries(dawn_internal_config INTERFACE dawn_public_config)
+
+# Compile definitions for the internal config
+if (DAWN_ALWAYS_ASSERT OR $<CONFIG:Debug>)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_ASSERTS")
+endif()
+if (DAWN_ENABLE_D3D12)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_D3D12")
+endif()
+if (DAWN_ENABLE_METAL)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_METAL")
+endif()
+if (DAWN_ENABLE_NULL)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_NULL")
+endif()
+if (DAWN_ENABLE_DESKTOP_GL)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_DESKTOP_GL")
+endif()
+if (DAWN_ENABLE_OPENGLES)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_OPENGLES")
+endif()
+if (DAWN_ENABLE_OPENGL)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_OPENGL")
+endif()
+if (DAWN_ENABLE_VULKAN)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_VULKAN")
+endif()
+if (DAWN_USE_X11)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_USE_X11")
+endif()
+if (WIN32)
+    target_compile_definitions(dawn_internal_config INTERFACE "NOMINMAX" "WIN32_LEAN_AND_MEAN")
+endif()
+
+set(CMAKE_CXX_STANDARD "17")
+
+################################################################################
+# Tint
+################################################################################
+
+# TINT_IS_SUBPROJECT is 1 if added via add_subdirectory() from another project.
+get_directory_property(TINT_IS_SUBPROJECT PARENT_DIRECTORY)
+if(TINT_IS_SUBPROJECT)
+  set(TINT_IS_SUBPROJECT 1)
+
+  # If tint is used as a subproject, default to disabling the building of
+  # documentation and tests. These are unlikely to be desirable, but can be
+  # enabled.
+  set(TINT_BUILD_DOCS_DEFAULT OFF)
+  set(TINT_BUILD_TESTS_DEFAULT OFF)
+else()
+  set(TINT_BUILD_DOCS_DEFAULT ON)
+  set(TINT_BUILD_TESTS_DEFAULT ON)
+endif()
+
+# Forcing building docs off right now, since currently this will try to build docs for both Tint & Dawn, and Dawn isn't annotated yet.
+set(TINT_BUILD_DOCS_DEFAULT OFF)
 
 option_if_not_defined(TINT_BUILD_SAMPLES "Build samples" ON)
 option_if_not_defined(TINT_BUILD_DOCS "Build documentation" ${TINT_BUILD_DOCS_DEFAULT})
@@ -200,7 +363,7 @@
 endif()
 
 if (${TINT_BUILD_SPV_READER})
-  include_directories("${TINT_THIRD_PARTY_DIR}/vulkan-deps/spirv-tools/src/include")
+  include_directories("${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-tools/include")
 endif()
 
 if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))
@@ -264,7 +427,7 @@
 
   if (${TINT_BUILD_SPV_READER} OR ${TINT_BUILD_SPV_WRITER})
     target_include_directories(${TARGET} PUBLIC
-        "${TINT_THIRD_PARTY_DIR}/vulkan-deps/spirv-headers/src/include")
+        "${DAWN_THIRD_PARTY_DIR}/spirv-headers/include")
   endif()
 
   target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SPV_READER=$<BOOL:${TINT_BUILD_SPV_READER}>)
@@ -388,8 +551,25 @@
   endif()
 endfunction()
 
+################################################################################
+# Run on all subdirectories
+################################################################################
+
 add_subdirectory(third_party)
 add_subdirectory(src/tint)
+add_subdirectory(generator)
+add_subdirectory(src/dawn)
+
+################################################################################
+# Samples
+################################################################################
+
+if (DAWN_BUILD_SAMPLES)
+    #TODO(dawn:269): Add this once implementation-based swapchains are removed.
+    #add_subdirectory(src/utils)
+    add_subdirectory(samples/dawn)
+endif()
+
 if (TINT_BUILD_SAMPLES)
   add_subdirectory(src/tint/cmd)
 endif()
diff --git a/DEPS b/DEPS
index 7bf1906..0c13f63 100644
--- a/DEPS
+++ b/DEPS
@@ -8,100 +8,257 @@
 
 vars = {
   'chromium_git': 'https://chromium.googlesource.com',
+  'dawn_git': 'https://dawn.googlesource.com',
+  'github_git': 'https://github.com',
+  'swiftshader_git': 'https://swiftshader.googlesource.com',
 
-  'tint_gn_revision': 'git_revision:281ba2c91861b10fec7407c4b6172ec3d4661243',
+  'dawn_standalone': True,
+  'dawn_node': False, # Also fetches dependencies required for building NodeJS bindings.
+  'dawn_cmake_version': 'version:3.13.5',
+  'dawn_cmake_win32_sha1': 'b106d66bcdc8a71ea2cdf5446091327bfdb1bcd7',
+  'dawn_gn_version': 'git_revision:bd99dbf98cbdefe18a4128189665c5761263bcfb',
+  'dawn_go_version': 'version:1.16',
 
-  # We don't use location metadata in our test isolates.
+  'node_darwin_arm64_sha': '31859fc1fa0994a95f44f09c367d6ff63607cfde',
+  'node_darwin_x64_sha': '16dfd094763b71988933a31735f9dea966f9abd6',
+  'node_linux_x64_sha': 'ab9544e24e752d3d17f335fb7b2055062e582d11',
+  'node_win_x64_sha': '5ef847033c517c499f56f9d136d159b663bab717',
+
+  # GN variable required by //testing that will be output in the gclient_args.gni
   'generate_location_tags': False,
 }
 
 deps = {
-  'third_party/gpuweb-cts': {
-    'url': '{chromium_git}/external/github.com/gpuweb/cts@b0291fd966b55a5efc496772555b94842bde1085',
-  },
-
-  'third_party/vulkan-deps': {
-    'url': '{chromium_git}/vulkan-deps@20efc30b0c6fe3c9bbd4f8ed6335593ee51391b0',
-  },
-
   # Dependencies required to use GN/Clang in standalone
   'build': {
-    'url': '{chromium_git}/chromium/src/build@555c8b467c21e2c4b22d00e87e3faa0431df9ac2',
+    'url': '{chromium_git}/chromium/src/build@c7876b5a44308b94074287939244bc562007de69',
+    'condition': 'dawn_standalone',
   },
-
   'buildtools': {
-    'url': '{chromium_git}/chromium/src/buildtools@f78b4b9f33bd8ef9944d5ce643daff1c31880189',
+    'url': '{chromium_git}/chromium/src/buildtools@e1471b21ee9c6765ee95e9db0c76fe997ccad35c',
+    'condition': 'dawn_standalone',
   },
-
-  'tools/clang': {
-    'url': '{chromium_git}/chromium/src/tools/clang@8b7330592cb85ba09505a6be7bacabd0ad6160a3',
-  },
-
   'buildtools/clang_format/script': {
-    'url': '{chromium_git}/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@2271e89c145a5e27d6c110b6a1113c057a8301a3',
+    'url': '{chromium_git}/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@99803d74e35962f63a775f29477882afd4d57d94',
+    'condition': 'dawn_standalone',
   },
-
   'buildtools/linux64': {
     'packages': [{
       'package': 'gn/gn/linux-amd64',
-      'version': Var('tint_gn_revision'),
+      'version': Var('dawn_gn_version'),
     }],
     'dep_type': 'cipd',
-    'condition': 'host_os == "linux"',
+    'condition': 'dawn_standalone and host_os == "linux"',
   },
   'buildtools/mac': {
     'packages': [{
       'package': 'gn/gn/mac-${{arch}}',
-      'version': Var('tint_gn_revision'),
+      'version': Var('dawn_gn_version'),
     }],
     'dep_type': 'cipd',
-    'condition': 'host_os == "mac"',
+    'condition': 'dawn_standalone and host_os == "mac"',
   },
   'buildtools/win': {
     'packages': [{
       'package': 'gn/gn/windows-amd64',
-      'version': Var('tint_gn_revision'),
+      'version': Var('dawn_gn_version'),
     }],
     'dep_type': 'cipd',
-    'condition': 'host_os == "win"',
+    'condition': 'dawn_standalone and host_os == "win"',
   },
 
   'buildtools/third_party/libc++/trunk': {
     'url': '{chromium_git}/external/github.com/llvm/llvm-project/libcxx.git@79a2e924d96e2fc1e4b937c42efd08898fa472d7',
+    'condition': 'dawn_standalone',
   },
 
   'buildtools/third_party/libc++abi/trunk': {
-    'url': '{chromium_git}/external/github.com/llvm/llvm-project/libcxxabi.git@2715a6c0de8dac4c7674934a6b3d30ba0c685271',
+    'url': '{chromium_git}/external/github.com/llvm/llvm-project/libcxxabi.git@edde7bbc4049ae4a32257d9f16451312c763c601',
+    'condition': 'dawn_standalone',
   },
 
-  # Dependencies required for testing
+  'tools/clang': {
+    'url': '{chromium_git}/chromium/src/tools/clang@df9b14e26c163dd8e2c0ab081e2689f038ae7141',
+    'condition': 'dawn_standalone',
+  },
+  'tools/clang/dsymutil': {
+    'packages': [{
+      'package': 'chromium/llvm-build-tools/dsymutil',
+      'version': 'M56jPzDv1620Rnm__jTMYS62Zi8rxHVq7yw0qeBFEgkC',
+    }],
+    'condition': 'dawn_standalone and (checkout_mac or checkout_ios)',
+    'dep_type': 'cipd',
+  },
+
+  # Testing, GTest and GMock
   'testing': {
     'url': '{chromium_git}/chromium/src/testing@d485ae97b7900c1fb7edfbe2901ae5adcb120865',
+    'condition': 'dawn_standalone',
   },
-
+  'third_party/googletest': {
+    'url': '{chromium_git}/external/github.com/google/googletest@6b74da4757a549563d7c37c8fae3e704662a043b',
+    'condition': 'dawn_standalone',
+  },
+  # This is a dependency of //testing
   'third_party/catapult': {
     'url': '{chromium_git}/catapult.git@fa35beefb3429605035f98211ddb8750dee6a13d',
+    'condition': 'dawn_standalone',
   },
 
+  # Jinja2 and MarkupSafe for the code generator
+  'third_party/jinja2': {
+    'url': '{chromium_git}/chromium/src/third_party/jinja2@ee69aa00ee8536f61db6a451f3858745cf587de6',
+    'condition': 'dawn_standalone',
+  },
+  'third_party/markupsafe': {
+    'url': '{chromium_git}/chromium/src/third_party/markupsafe@0944e71f4b2cb9a871bcbe353f95e889b64a611a',
+    'condition': 'dawn_standalone',
+  },
+
+  # GLFW for tests and samples
+  'third_party/glfw': {
+    'url': '{chromium_git}/external/github.com/glfw/glfw@94773111300fee0453844a4c9407af7e880b4df8',
+    'condition': 'dawn_standalone',
+  },
+
+  'third_party/vulkan_memory_allocator': {
+    'url': '{chromium_git}/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator@5e49f57a6e71a026a54eb42e366de09a4142d24e',
+    'condition': 'dawn_standalone',
+  },
+
+  'third_party/angle': {
+    'url': '{chromium_git}/angle/angle@152616eedcfded69cab516e093efd3a98190fa5b',
+    'condition': 'dawn_standalone',
+  },
+
+  'third_party/swiftshader': {
+    'url': '{swiftshader_git}/SwiftShader@9c16e141823e93c2d6ad05b94165cc18ffda6ffe',
+    'condition': 'dawn_standalone',
+  },
+
+  'third_party/vulkan-deps': {
+    'url': '{chromium_git}/vulkan-deps@746dd371204b5b582e0ed0365909fefa4b0ef0fa',
+    'condition': 'dawn_standalone',
+  },
+
+  'third_party/zlib': {
+    'url': '{chromium_git}/chromium/src/third_party/zlib@c29ee8c9c3824ca013479bf8115035527967fe02',
+    'condition': 'dawn_standalone',
+  },
+
+  'third_party/abseil-cpp': {
+    'url': '{chromium_git}/chromium/src/third_party/abseil-cpp@789af048b388657987c59d4da406859034fe310f',
+    'condition': 'dawn_standalone',
+  },
+
+  # WebGPU CTS - not used directly by Dawn, only transitively by Chromium.
+  'third_party/webgpu-cts': {
+    'url': '{chromium_git}/external/github.com/gpuweb/cts@87e74a93e0c046b30a798667f19a449fc99ddb5d',
+    'condition': 'build_with_chromium',
+  },
+
+  # Dependencies required to build / run Dawn NodeJS bindings
+  'third_party/node-api-headers': {
+    'url': '{github_git}/nodejs/node-api-headers.git@d68505e4055ecb630e14c26c32e5c2c65e179bba',
+    'condition': 'dawn_node',
+  },
+  'third_party/node-addon-api': {
+    'url': '{github_git}/nodejs/node-addon-api.git@4a3de56c3e4ed0031635a2f642b27efeeed00add',
+    'condition': 'dawn_node',
+  },
+  'third_party/gpuweb': {
+    'url': '{github_git}/gpuweb/gpuweb.git@881403b5fda2d9ac9ffc5daa24e34738205bf155',
+    'condition': 'dawn_node',
+  },
+  'third_party/gpuweb-cts': {
+    'url': '{chromium_git}/external/github.com/gpuweb/cts@b0291fd966b55a5efc496772555b94842bde1085',
+    'condition': 'dawn_standalone',
+  },
+
+  'tools/golang': {
+    'condition': 'dawn_node',
+    'packages': [{
+      'package': 'infra/3pp/tools/go/${{platform}}',
+      'version': Var('dawn_go_version'),
+    }],
+    'dep_type': 'cipd',
+  },
+
+  'tools/cmake': {
+    'condition': 'dawn_node and (host_os == "mac" or host_os == "linux")',
+    'packages': [{
+      'package': 'infra/3pp/tools/cmake/${{platform}}',
+      'version': Var('dawn_cmake_version'),
+    }],
+    'dep_type': 'cipd',
+  },
+
+  # Misc dependencies inherited from Tint
   'third_party/benchmark': {
     'url': '{chromium_git}/external/github.com/google/benchmark.git@e991355c02b93fe17713efe04cbc2e278e00fdbd',
+    'condition': 'dawn_standalone',
   },
-
-  'third_party/googletest': {
-    'url': '{chromium_git}/external/github.com/google/googletest.git@6b74da4757a549563d7c37c8fae3e704662a043b',
-  },
-
   'third_party/protobuf': {
     'url': '{chromium_git}/external/github.com/protocolbuffers/protobuf.git@fde7cf7358ec7cd69e8db9be4f1fa6a5c431386a',
+    'condition': 'dawn_standalone',
   },
 }
 
 hooks = [
+  # Pull the compilers and system libraries for hermetic builds
+  {
+    'name': 'sysroot_x86',
+    'pattern': '.',
+    'condition': 'dawn_standalone and checkout_linux and (checkout_x86 or checkout_x64)',
+    'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py',
+               '--arch=x86'],
+  },
+  {
+    'name': 'sysroot_x64',
+    'pattern': '.',
+    'condition': 'dawn_standalone and checkout_linux and checkout_x64',
+    'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py',
+               '--arch=x64'],
+  },
+  {
+    # Update the Mac toolchain if possible, this makes builders use "hermetic XCode" which is
+    # is more consistent (only changes when rolling build/) and is cached.
+    'name': 'mac_toolchain',
+    'pattern': '.',
+    'condition': 'dawn_standalone and checkout_mac',
+    'action': ['python3', 'build/mac_toolchain.py'],
+  },
+  {
+    # Update the Windows toolchain if necessary. Must run before 'clang' below.
+    'name': 'win_toolchain',
+    'pattern': '.',
+    'condition': 'dawn_standalone and checkout_win',
+    'action': ['python3', 'build/vs_toolchain.py', 'update', '--force'],
+  },
+  {
+    # Note: On Win, this should run after win_toolchain, as it may use it.
+    'name': 'clang',
+    'pattern': '.',
+    'action': ['python3', 'tools/clang/scripts/update.py'],
+    'condition': 'dawn_standalone',
+  },
+  {
+    # Pull rc binaries using checked-in hashes.
+    'name': 'rc_win',
+    'pattern': '.',
+    'condition': 'dawn_standalone and checkout_win and host_os == "win"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--no_auth',
+                '--bucket', 'chromium-browser-clang/rc',
+                '-s', 'build/toolchain/win/rc/win/rc.exe.sha1',
+    ],
+  },
   # Pull clang-format binaries using checked-in hashes.
   {
     'name': 'clang_format_win',
     'pattern': '.',
-    'condition': 'host_os == "win"',
+    'condition': 'dawn_standalone and host_os == "win"',
     'action': [ 'download_from_google_storage',
                 '--no_resume',
                 '--platform=win32',
@@ -113,7 +270,7 @@
   {
     'name': 'clang_format_mac',
     'pattern': '.',
-    'condition': 'host_os == "mac"',
+    'condition': 'dawn_standalone and host_os == "mac"',
     'action': [ 'download_from_google_storage',
                 '--no_resume',
                 '--platform=darwin',
@@ -125,7 +282,7 @@
   {
     'name': 'clang_format_linux',
     'pattern': '.',
-    'condition': 'host_os == "linux"',
+    'condition': 'dawn_standalone and host_os == "linux"',
     'action': [ 'download_from_google_storage',
                 '--no_resume',
                 '--platform=linux*',
@@ -134,7 +291,6 @@
                 '-s', 'buildtools/linux64/clang-format.sha1',
     ],
   },
-
   # Pull the compilers and system libraries for hermetic builds
   {
     'name': 'sysroot_x86',
@@ -186,15 +342,90 @@
   {
     'name': 'lastchange',
     'pattern': '.',
+    'condition': 'dawn_standalone',
     'action': ['python3', 'build/util/lastchange.py',
                '-o', 'build/util/LASTCHANGE'],
   },
+  # TODO(https://crbug.com/1180257): Use CIPD for CMake on Windows.
+  {
+    'name': 'cmake_win32',
+    'pattern': '.',
+    'condition': 'dawn_node and host_os == "win"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=win32',
+                '--no_auth',
+                '--bucket', 'chromium-tools',
+                Var('dawn_cmake_win32_sha1'),
+                '-o', 'tools/cmake-win32.zip'
+    ],
+  },
+  {
+    'name': 'cmake_win32_extract',
+    'pattern': '.',
+    'condition': 'dawn_node and host_os == "win"',
+    'action': [ 'python3',
+                'scripts/extract.py',
+                'tools/cmake-win32.zip',
+                'tools/cmake-win32/',
+    ],
+  },
+
+  # Node binaries, when dawn_node is enabled
+  {
+    'name': 'node_linux64',
+    'pattern': '.',
+    'condition': 'dawn_node and host_os == "linux"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--extract',
+                '--no_auth',
+                '--bucket', 'chromium-nodejs/16.13.0',
+                Var('node_linux_x64_sha'),
+                '-o', 'third_party/node/node-linux-x64.tar.gz',
+    ],
+  },
+  {
+    'name': 'node_mac',
+    'pattern': '.',
+    'condition': 'dawn_node and host_os == "mac"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--extract',
+                '--no_auth',
+                '--bucket', 'chromium-nodejs/16.13.0',
+                Var('node_darwin_x64_sha'),
+                '-o', 'third_party/node/node-darwin-x64.tar.gz',
+    ],
+  },
+  {
+    'name': 'node_mac_arm64',
+    'pattern': '.',
+    'condition': 'dawn_node and host_os == "mac"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--extract',
+                '--no_auth',
+                '--bucket', 'chromium-nodejs/16.13.0',
+                Var('node_darwin_arm64_sha'),
+                '-o', 'third_party/node/node-darwin-arm64.tar.gz',
+    ],
+  },
+  {
+    'name': 'node_win',
+    'pattern': '.',
+    'condition': 'dawn_node and host_os == "win"',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--no_auth',
+                '--bucket', 'chromium-nodejs/16.13.0',
+                Var('node_win_x64_sha'),
+                '-o', 'third_party/node/node.exe',
+    ],
+  },
+
 ]
 
 recursedeps = [
-  # buildtools provides clang_format, libc++, and libc++abi
-  'buildtools',
-  # vulkan-deps provides spirv-headers, spirv-tools & gslang
-  # It also provides other Vulkan tools that Tint doesn't use
   'third_party/vulkan-deps',
 ]
diff --git a/DIR_METADATA b/DIR_METADATA
new file mode 100644
index 0000000..0ca8187
--- /dev/null
+++ b/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>GPU>Dawn"
+}
diff --git a/LICENSE b/LICENSE
index d645695..14b77bd 100644
--- a/LICENSE
+++ b/LICENSE
@@ -3,9 +3,9 @@
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/
 
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-   1. Definitions.
+    1. Definitions.
 
       "License" shall mean the terms and conditions for use, reproduction,
       and distribution as defined by Sections 1 through 9 of this document.
@@ -64,14 +64,14 @@
       on behalf of whom a Contribution has been received by Licensor and
       subsequently incorporated within the Work.
 
-   2. Grant of Copyright License. Subject to the terms and conditions of
+    2. Grant of Copyright License. Subject to the terms and conditions of
       this License, each Contributor hereby grants to You a perpetual,
       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
       copyright license to reproduce, prepare Derivative Works of,
       publicly display, publicly perform, sublicense, and distribute the
       Work and such Derivative Works in Source or Object form.
 
-   3. Grant of Patent License. Subject to the terms and conditions of
+    3. Grant of Patent License. Subject to the terms and conditions of
       this License, each Contributor hereby grants to You a perpetual,
       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
       (except as stated in this section) patent license to make, have made,
@@ -87,7 +87,7 @@
       granted to You under this License for that Work shall terminate
       as of the date such litigation is filed.
 
-   4. Redistribution. You may reproduce and distribute copies of the
+    4. Redistribution. You may reproduce and distribute copies of the
       Work or Derivative Works thereof in any medium, with or without
       modifications, and in Source or Object form, provided that You
       meet the following conditions:
@@ -128,7 +128,7 @@
       reproduction, and distribution of the Work otherwise complies with
       the conditions stated in this License.
 
-   5. Submission of Contributions. Unless You explicitly state otherwise,
+    5. Submission of Contributions. Unless You explicitly state otherwise,
       any Contribution intentionally submitted for inclusion in the Work
       by You to the Licensor shall be under the terms and conditions of
       this License, without any additional terms or conditions.
@@ -136,12 +136,12 @@
       the terms of any separate license agreement you may have executed
       with Licensor regarding such Contributions.
 
-   6. Trademarks. This License does not grant permission to use the trade
+    6. Trademarks. This License does not grant permission to use the trade
       names, trademarks, service marks, or product names of the Licensor,
       except as required for reasonable and customary use in describing the
       origin of the Work and reproducing the content of the NOTICE file.
 
-   7. Disclaimer of Warranty. Unless required by applicable law or
+    7. Disclaimer of Warranty. Unless required by applicable law or
       agreed to in writing, Licensor provides the Work (and each
       Contributor provides its Contributions) on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
@@ -151,7 +151,7 @@
       appropriateness of using or redistributing the Work and assume any
       risks associated with Your exercise of permissions under this License.
 
-   8. Limitation of Liability. In no event and under no legal theory,
+    8. Limitation of Liability. In no event and under no legal theory,
       whether in tort (including negligence), contract, or otherwise,
       unless required by applicable law (such as deliberate and grossly
       negligent acts) or agreed to in writing, shall any Contributor be
@@ -163,7 +163,7 @@
       other commercial damages or losses), even if such Contributor
       has been advised of the possibility of such damages.
 
-   9. Accepting Warranty or Additional Liability. While redistributing
+    9. Accepting Warranty or Additional Liability. While redistributing
       the Work or Derivative Works thereof, You may choose to offer,
       and charge a fee for, acceptance of support, warranty, indemnity,
       or other liability obligations and/or rights consistent with this
@@ -174,9 +174,9 @@
       incurred by, or claims asserted against, such Contributor by reason
       of your accepting any such warranty or additional liability.
 
-   END OF TERMS AND CONDITIONS
+    END OF TERMS AND CONDITIONS
 
-   APPENDIX: How to apply the Apache License to your work.
+    APPENDIX: How to apply the Apache License to your work.
 
       To apply the Apache License to your work, attach the following
       boilerplate notice, with the fields enclosed by brackets "[]"
@@ -187,16 +187,49 @@
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright [yyyy] [name of copyright owner]
+    Copyright [yyyy] [name of copyright owner]
 
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
 
        http://www.apache.org/licenses/LICENSE-2.0
 
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+----------
+The following license is exclusively used by the template generated header files.
+
+BSD 3-Clause License
+
+Copyright (c) 2019, "WebGPU native" developers
+All rights reserved.
+
+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.
diff --git a/OWNERS b/OWNERS
index 18239af..a7cef5e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,16 @@
+cwallez@chromium.org
+enga@chromium.org
+jiawei.shao@intel.com
+
+# Backup reviewers if needed.
+bclayton@google.com
+kainino@chromium.org
+
+per-file dawn.json=kainino@chromium.org
+per-file DEPS=*
+per-file README.md=file://docs/dawn/OWNERS
+
+# Tint specific OWNERS
 amaiorano@google.com
 bclayton@chromium.org
 bclayton@google.com
diff --git a/OWNERS.dawn b/OWNERS.dawn
new file mode 100644
index 0000000..1856f30
--- /dev/null
+++ b/OWNERS.dawn
@@ -0,0 +1,11 @@
+cwallez@chromium.org
+enga@chromium.org
+jiawei.shao@intel.com
+
+# Backup reviewers if needed.
+bclayton@google.com
+kainino@chromium.org
+
+per-file dawn.json=kainino@chromium.org
+per-file DEPS=*
+per-file README.md=file://docs/dawn/OWNERS
diff --git a/OWNERS.tint b/OWNERS.tint
new file mode 100644
index 0000000..18239af
--- /dev/null
+++ b/OWNERS.tint
@@ -0,0 +1,7 @@
+amaiorano@google.com
+bclayton@chromium.org
+bclayton@google.com
+cwallez@chromium.org
+dneto@google.com
+jrprice@google.com
+rharrison@chromium.org
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
old mode 100755
new mode 100644
index 97623c1..968a27c
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors
+# Copyright 2022 The Dawn & Tint Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -11,42 +11,12 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-"""Presubmit script for Tint.
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
 
 import re
 
 USE_PYTHON3 = True
 
-
-def _LicenseHeader(input_api):
-    """Returns the license header regexp."""
-    # Accept any year number from 2019 to the current year
-    current_year = int(input_api.time.strftime('%Y'))
-    allowed_years = (str(s) for s in reversed(xrange(2019, current_year + 1)))
-    years_re = '(' + '|'.join(allowed_years) + ')'
-    license_header = (
-        r'.*? Copyright( \(c\))? %(year)s The Tint [Aa]uthors\n '
-        r'.*?\n'
-        r'.*? Licensed under the Apache License, Version 2.0 (the "License");\n'
-        r'.*? you may not use this file except in compliance with the License.\n'
-        r'.*? You may obtain a copy of the License at\n'
-        r'.*?\n'
-        r'.*?     http://www.apache.org/licenses/LICENSE-2.0\n'
-        r'.*?\n'
-        r'.*? Unless required by applicable law or agreed to in writing, software\n'
-        r'.*? distributed under the License is distributed on an "AS IS" BASIS,\n'
-        r'.*? WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
-        r'.*? See the License for the specific language governing permissions and\n'
-        r'.*? limitations under the License.\n') % {
-            'year': years_re,
-        }
-    return license_header
-
-
-REGEXES = [
+NONINCLUSIVE_REGEXES = [
     r"(?i)black[-_]?list",
     r"(?i)white[-_]?list",
     r"(?i)gr[ea]y[-_]?list",
@@ -97,18 +67,19 @@
     r"(?i)red[-_]?line",
 ]
 
-REGEX_LIST = []
-for reg in REGEXES:
-    REGEX_LIST.append(re.compile(reg))
+NONINCLUSIVE_REGEX_LIST = []
+for reg in NONINCLUSIVE_REGEXES:
+    NONINCLUSIVE_REGEX_LIST.append(re.compile(reg))
 
-def CheckNonInclusiveLanguage(input_api, output_api, source_file_filter=None):
+
+def _CheckNonInclusiveLanguage(input_api, output_api, source_file_filter=None):
     """Checks the files for non-inclusive language."""
 
     matches = []
     for f in input_api.AffectedFiles(include_deletes=False,
                                      file_filter=source_file_filter):
         for line_num, line in f.ChangedContents():
-            for reg in REGEX_LIST:
+            for reg in NONINCLUSIVE_REGEX_LIST:
                 match = reg.search(line)
                 if match:
                     matches.append(
@@ -124,44 +95,53 @@
     return []
 
 
-def CheckChange(input_api, output_api):
+def _NonInclusiveFileFilter(file):
+    filter_list = [
+        "PRESUBMIT.py",  # Non-inclusive language check data
+        "docs/tint/spirv-input-output-variables.md",  # External URL
+        "test/tint/samples/compute_boids.wgsl ",  # External URL
+    ]
+    return file in filter_list
+
+
+def _DoCommonChecks(input_api, output_api):
     results = []
-
-    results += input_api.canned_checks.CheckChangeHasDescription(
-        input_api, output_api)
-    results += input_api.canned_checks.CheckPatchFormatted(input_api,
-                                                           output_api,
-                                                           check_python=True)
-    results += input_api.canned_checks.CheckGNFormatted(input_api, output_api)
-    results += input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
-        input_api, output_api)
-    results += input_api.canned_checks.CheckChangeHasNoTabs(
-        input_api, output_api)
-    results += input_api.canned_checks.CheckChangeTodoHasOwner(
-        input_api, output_api)
-    results += input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
-        input_api, output_api)
-    results += input_api.canned_checks.CheckDoNotSubmit(input_api, output_api)
-    results += input_api.canned_checks.CheckChangeLintsClean(input_api,
-                                                             output_api,
-                                                             lint_filters="")
-
-    def NonInclusiveFileFilter(file):
-        filter_list = [
-            "docs/tint/spirv-input-output-variables.md",  # External URL
-            "test/tint/samples/compute_boids.wgsl ",  # External URL
-        ]
-        return file in filter_list
-
-    results += CheckNonInclusiveLanguage(input_api, output_api,
-                                         NonInclusiveFileFilter)
-
+    results.extend(
+        input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckPatchFormatted(input_api,
+                                                    output_api,
+                                                    check_python=True))
+    results.extend(
+        input_api.canned_checks.CheckChangeHasDescription(
+            input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckGNFormatted(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
+            input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckChangeTodoHasOwner(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
+            input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckDoNotSubmit(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckChangeLintsClean(input_api,
+                                                      output_api,
+                                                      lint_filters=""))
+    results.extend(
+        _CheckNonInclusiveLanguage(input_api, output_api,
+                                   _NonInclusiveFileFilter))
     return results
 
 
 def CheckChangeOnUpload(input_api, output_api):
-    return CheckChange(input_api, output_api)
+    return _DoCommonChecks(input_api, output_api)
 
 
 def CheckChangeOnCommit(input_api, output_api):
-    return CheckChange(input_api, output_api)
+    return _DoCommonChecks(input_api, output_api)
diff --git a/PRESUBMIT.py.dawn b/PRESUBMIT.py.dawn
new file mode 100644
index 0000000..899e0e2
--- /dev/null
+++ b/PRESUBMIT.py.dawn
@@ -0,0 +1,38 @@
+# Copyright 2018 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import platform
+import subprocess
+
+USE_PYTHON3 = True
+
+
+def _DoCommonChecks(input_api, output_api):
+    results = []
+    results.extend(
+        input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckPatchFormatted(input_api,
+                                                    output_api,
+                                                    check_python=True))
+    return results
+
+
+def CheckChangeOnUpload(input_api, output_api):
+    return _DoCommonChecks(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+    return _DoCommonChecks(input_api, output_api)
diff --git a/PRESUBMIT.py.tint b/PRESUBMIT.py.tint
new file mode 100755
index 0000000..97623c1
--- /dev/null
+++ b/PRESUBMIT.py.tint
@@ -0,0 +1,167 @@
+# Copyright 2020 The Tint Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Presubmit script for Tint.
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+import re
+
+USE_PYTHON3 = True
+
+
+def _LicenseHeader(input_api):
+    """Returns the license header regexp."""
+    # Accept any year number from 2019 to the current year
+    current_year = int(input_api.time.strftime('%Y'))
+    allowed_years = (str(s) for s in reversed(xrange(2019, current_year + 1)))
+    years_re = '(' + '|'.join(allowed_years) + ')'
+    license_header = (
+        r'.*? Copyright( \(c\))? %(year)s The Tint [Aa]uthors\n '
+        r'.*?\n'
+        r'.*? Licensed under the Apache License, Version 2.0 (the "License");\n'
+        r'.*? you may not use this file except in compliance with the License.\n'
+        r'.*? You may obtain a copy of the License at\n'
+        r'.*?\n'
+        r'.*?     http://www.apache.org/licenses/LICENSE-2.0\n'
+        r'.*?\n'
+        r'.*? Unless required by applicable law or agreed to in writing, software\n'
+        r'.*? distributed under the License is distributed on an "AS IS" BASIS,\n'
+        r'.*? WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
+        r'.*? See the License for the specific language governing permissions and\n'
+        r'.*? limitations under the License.\n') % {
+            'year': years_re,
+        }
+    return license_header
+
+
+REGEXES = [
+    r"(?i)black[-_]?list",
+    r"(?i)white[-_]?list",
+    r"(?i)gr[ea]y[-_]?list",
+    r"(?i)(first class citizen)",
+    r"(?i)black[-_]?hat",
+    r"(?i)white[-_]?hat",
+    r"(?i)gr[ea]y[-_]?hat",
+    r"(?i)master",
+    r"(?i)slave",
+    r"(?i)\bhim\b",
+    r"(?i)\bhis\b",
+    r"(?i)\bshe\b",
+    r"(?i)\bher\b",
+    r"(?i)\bguys\b",
+    r"(?i)\bhers\b",
+    r"(?i)\bman\b",
+    r"(?i)\bwoman\b",
+    r"(?i)\she\s",
+    r"(?i)\she$",
+    r"(?i)^he\s",
+    r"(?i)^he$",
+    r"(?i)\she['|\u2019]d\s",
+    r"(?i)\she['|\u2019]d$",
+    r"(?i)^he['|\u2019]d\s",
+    r"(?i)^he['|\u2019]d$",
+    r"(?i)\she['|\u2019]s\s",
+    r"(?i)\she['|\u2019]s$",
+    r"(?i)^he['|\u2019]s\s",
+    r"(?i)^he['|\u2019]s$",
+    r"(?i)\she['|\u2019]ll\s",
+    r"(?i)\she['|\u2019]ll$",
+    r"(?i)^he['|\u2019]ll\s",
+    r"(?i)^he['|\u2019]ll$",
+    r"(?i)grandfather",
+    r"(?i)\bmitm\b",
+    r"(?i)\bcrazy\b",
+    r"(?i)\binsane\b",
+    r"(?i)\bblind\sto\b",
+    r"(?i)\bflying\sblind\b",
+    r"(?i)\bblind\seye\b",
+    r"(?i)\bcripple\b",
+    r"(?i)\bcrippled\b",
+    r"(?i)\bdumb\b",
+    r"(?i)\bdummy\b",
+    r"(?i)\bparanoid\b",
+    r"(?i)\bsane\b",
+    r"(?i)\bsanity\b",
+    r"(?i)red[-_]?line",
+]
+
+REGEX_LIST = []
+for reg in REGEXES:
+    REGEX_LIST.append(re.compile(reg))
+
+def CheckNonInclusiveLanguage(input_api, output_api, source_file_filter=None):
+    """Checks the files for non-inclusive language."""
+
+    matches = []
+    for f in input_api.AffectedFiles(include_deletes=False,
+                                     file_filter=source_file_filter):
+        for line_num, line in f.ChangedContents():
+            for reg in REGEX_LIST:
+                match = reg.search(line)
+                if match:
+                    matches.append(
+                        "{} ({}): found non-inclusive language: {}".format(
+                            f.LocalPath(), line_num, match.group(0)))
+
+    if len(matches):
+        return [
+            output_api.PresubmitPromptWarning('Non-inclusive language found:',
+                                              items=matches)
+        ]
+
+    return []
+
+
+def CheckChange(input_api, output_api):
+    results = []
+
+    results += input_api.canned_checks.CheckChangeHasDescription(
+        input_api, output_api)
+    results += input_api.canned_checks.CheckPatchFormatted(input_api,
+                                                           output_api,
+                                                           check_python=True)
+    results += input_api.canned_checks.CheckGNFormatted(input_api, output_api)
+    results += input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
+        input_api, output_api)
+    results += input_api.canned_checks.CheckChangeHasNoTabs(
+        input_api, output_api)
+    results += input_api.canned_checks.CheckChangeTodoHasOwner(
+        input_api, output_api)
+    results += input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
+        input_api, output_api)
+    results += input_api.canned_checks.CheckDoNotSubmit(input_api, output_api)
+    results += input_api.canned_checks.CheckChangeLintsClean(input_api,
+                                                             output_api,
+                                                             lint_filters="")
+
+    def NonInclusiveFileFilter(file):
+        filter_list = [
+            "docs/tint/spirv-input-output-variables.md",  # External URL
+            "test/tint/samples/compute_boids.wgsl ",  # External URL
+        ]
+        return file in filter_list
+
+    results += CheckNonInclusiveLanguage(input_api, output_api,
+                                         NonInclusiveFileFilter)
+
+    return results
+
+
+def CheckChangeOnUpload(input_api, output_api):
+    return CheckChange(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+    return CheckChange(input_api, output_api)
diff --git a/README.chromium b/README.chromium
new file mode 100644
index 0000000..e14cc8b
--- /dev/null
+++ b/README.chromium
@@ -0,0 +1,12 @@
+Name: Dawn
+Short Name: dawn
+URL: https://dawn.googlesource.com/dawn
+License: Apache 2.0
+License File: LICENSE
+Security Critical: yes
+
+Description:
+Dawn is an implementation of the WebGPU standard exposed through a C/C++
+interface. It provides implementations on top of native graphics APIs like
+D3D12, Metal and Vulkan, as well as a client-server implementation to remote
+WebGPU outside sandboxed context like Chromium's render processes.
diff --git a/README.md b/README.md
index fbe6cfb..a430410 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,56 @@
+![Dawn's logo: a sun rising behind a stylized mountain inspired by the WebGPU logo. The text "Dawn" is written below it.](docs/imgs/dawn_logo.png "Dawn's logo")
+
+# Dawn, a WebGPU implementation
+
+Dawn is an open-source and cross-platform implementation of the work-in-progress [WebGPU](https://webgpu.dev) standard.
+More precisely it implements [`webgpu.h`](https://github.com/webgpu-native/webgpu-headers/blob/master/webgpu.h) that is a one-to-one mapping with the WebGPU IDL.
+Dawn is meant to be integrated as part of a larger system and is the underlying implementation of WebGPU in Chromium.
+
+Dawn provides several WebGPU building blocks:
+ - **WebGPU C/C++ headers** that applications and other building blocks use.
+   - The `webgpu.h` version that Dawn implements.
+   - A C++ wrapper for the `webgpu.h`.
+ - **A "native" implementation of WebGPU** using platforms' GPU APIs:
+   - **D3D12** on Windows 10
+   - **Metal** on macOS and iOS
+   - **Vulkan** on Windows, Linux, ChromeOS, Android and Fuchsia
+   - OpenGL as best effort where available
+ - **A client-server implementation of WebGPU** for applications that are in a sandbox without access to native drivers
+
+Helpful links:
+
+ - [Dawn's bug tracker](https://bugs.chromium.org/p/dawn/issues/entry) if you find issues with Dawn.
+ - [Dawn's mailing list](https://groups.google.com/forum/#!members/dawn-graphics) for other discussions related to Dawn.
+ - [Dawn's source code](https://dawn.googlesource.com/dawn)
+ - [Dawn's Matrix chatroom](https://matrix.to/#/#webgpu-dawn:matrix.org) for live discussion around contributing or using Dawn.
+ - [WebGPU's Matrix chatroom](https://matrix.to/#/#WebGPU:matrix.org)
+
+## Documentation table of content
+
+Developer documentation:
+
+ - [Dawn overview](docs/dawn/overview.md)
+ - [Building Dawn](docs/dawn/building.md)
+ - [Contributing to Dawn](docs/dawn/contributing.md)
+ - [Testing Dawn](docs/dawn/testing.md)
+ - [Debugging Dawn](docs/dawn/debugging.md)
+ - [Dawn's infrastructure](docs/dawn/infra.md)
+ - [Dawn errors](docs/dawn/errors.md)
+
+User documentation: (TODO, figure out what overlaps with the webgpu.h docs)
+
+## Status
+
+(TODO)
+
+## License
+
+Apache 2.0 Public License, please see [LICENSE](/LICENSE).
+
+## Disclaimer
+
+This is not an officially supported Google product.
+
 # Tint
 
 Tint is a compiler for the WebGPU Shader Language (WGSL).
diff --git a/README.md.dawn b/README.md.dawn
new file mode 100644
index 0000000..1871388
--- /dev/null
+++ b/README.md.dawn
@@ -0,0 +1,52 @@
+![Dawn's logo: a sun rising behind a stylized mountain inspired by the WebGPU logo. The text "Dawn" is written below it.](docs/imgs/dawn_logo.png "Dawn's logo")
+
+# Dawn, a WebGPU implementation
+
+Dawn is an open-source and cross-platform implementation of the work-in-progress [WebGPU](https://webgpu.dev) standard.
+More precisely it implements [`webgpu.h`](https://github.com/webgpu-native/webgpu-headers/blob/master/webgpu.h) that is a one-to-one mapping with the WebGPU IDL.
+Dawn is meant to be integrated as part of a larger system and is the underlying implementation of WebGPU in Chromium.
+
+Dawn provides several WebGPU building blocks:
+ - **WebGPU C/C++ headers** that applications and other building blocks use.
+   - The `webgpu.h` version that Dawn implements.
+   - A C++ wrapper for the `webgpu.h`.
+ - **A "native" implementation of WebGPU** using platforms' GPU APIs:
+   - **D3D12** on Windows 10
+   - **Metal** on macOS and iOS
+   - **Vulkan** on Windows, Linux, ChromeOS, Android and Fuchsia
+   - OpenGL as best effort where available
+ - **A client-server implementation of WebGPU** for applications that are in a sandbox without access to native drivers
+
+Helpful links:
+
+ - [Dawn's bug tracker](https://bugs.chromium.org/p/dawn/issues/entry) if you find issues with Dawn.
+ - [Dawn's mailing list](https://groups.google.com/forum/#!members/dawn-graphics) for other discussions related to Dawn.
+ - [Dawn's source code](https://dawn.googlesource.com/dawn)
+ - [Dawn's Matrix chatroom](https://matrix.to/#/#webgpu-dawn:matrix.org) for live discussion around contributing or using Dawn.
+ - [WebGPU's Matrix chatroom](https://matrix.to/#/#WebGPU:matrix.org)
+
+## Documentation table of content
+
+Developer documentation:
+
+ - [Dawn overview](docs/dawn/overview.md)
+ - [Building Dawn](docs/dawn/building.md)
+ - [Contributing to Dawn](docs/dawn/contributing.md)
+ - [Testing Dawn](docs/dawn/testing.md)
+ - [Debugging Dawn](docs/dawn/debugging.md)
+ - [Dawn's infrastructure](docs/dawn/infra.md)
+ - [Dawn errors](docs/dawn/errors.md)
+
+User documentation: (TODO, figure out what overlaps with the webgpu.h docs)
+
+## Status
+
+(TODO)
+
+## License
+
+Apache 2.0 Public License, please see [LICENSE](/LICENSE).
+
+## Disclaimer
+
+This is not an officially supported Google product.
diff --git a/README.md.tint b/README.md.tint
new file mode 100644
index 0000000..fbe6cfb
--- /dev/null
+++ b/README.md.tint
@@ -0,0 +1,106 @@
+# Tint
+
+Tint is a compiler for the WebGPU Shader Language (WGSL).
+
+This is not an officially supported Google product.
+
+## Requirements
+ * Git
+ * CMake (3.10.2 or later)
+ * Ninja (or other build tool)
+ * Python, for fetching dependencies
+ * [depot_tools] in your path
+
+## Build options
+ * `TINT_BUILD_SPV_READER` : enable the SPIR-V input reader (off by default)
+ * `TINT_BUILD_WGSL_READER` : enable the WGSL input reader (on by default)
+ * `TINT_BUILD_SPV_WRITER` : enable the SPIR-V output writer (on by default)
+ * `TINT_BUILD_WGSL_WRITER` : enable the WGSL output writer (on by default)
+ * `TINT_BUILD_FUZZERS` : enable building fuzzzers (off by default)
+
+## Building
+Tint uses Chromium dependency management so you need to install [depot_tools]
+and add it to your PATH.
+
+[depot_tools]: http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up
+
+### Getting source & dependencies
+
+```sh
+# Clone the repo as "tint"
+git clone https://dawn.googlesource.com/tint tint
+cd tint
+
+# Bootstrap the gclient configuration
+cp standalone.gclient .gclient
+
+# Fetch external dependencies and toolchains with gclient
+gclient sync
+```
+
+### Compiling using CMake + Ninja
+```sh
+mkdir -p out/Debug
+cd out/Debug
+cmake -GNinja ../..
+ninja # or autoninja
+```
+
+### Compiling using CMake + make
+```sh
+mkdir -p out/Debug
+cd out/Debug
+cmake ../..
+make # -j N for N-way parallel build
+```
+
+### Compiling using gn + ninja
+```sh
+mkdir -p out/Debug
+gn gen out/Debug
+autoninja -C out/Debug
+```
+
+### Fuzzers on MacOS
+If you are attempting fuzz, using `TINT_BUILD_FUZZERS=ON`, the version of llvm
+in the XCode SDK does not have the needed libfuzzer functionality included.
+
+The build error that you will see from using the XCode SDK will look something
+like this:
+```
+ld: file not found:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/11.0.0/lib/darwin/libclang_rt.fuzzer_osx.a
+```
+
+The solution to this problem is to use a full version llvm, like what you would
+get via homebrew, `brew install llvm`, and use something like `CC=<path to full
+clang> cmake ..` to setup a build using that toolchain.
+
+### Checking [chromium-style] issues in CMake builds
+The gn based work flow uses the Chromium toolchain for building in anticipation
+of integration of Tint into Chromium based projects. This toolchain has
+additional plugins for checking for style issues, which are marked with
+[chromium-style] in log messages. This means that this toolchain is more strict
+then the default clang toolchain.
+
+In the future we will have a CQ that will build this work flow and flag issues
+automatically. Until that is in place, to avoid causing breakages you can run
+the [chromium-style] checks using the CMake based work flows. This requires
+setting `CC` to the version of clang checked out by `gclient sync` and setting
+the `TINT_CHECK_CHROMIUM_STYLE` to `ON`.
+
+```sh
+mkdir -p out/style
+cd out/style
+cmake ../..
+CC=../../third_party/llvm-build/Release+Asserts/bin/clang cmake -DTINT_CHECK_CHROMIUM_STYLE=ON ../../ # add -GNinja for ninja builds
+```
+
+## Issues
+Please file any issues or feature requests at
+https://bugs.chromium.org/p/tint/issues/entry
+
+## Contributing
+Please see the CONTRIBUTING and CODE_OF_CONDUCT files on how to contribute to
+Tint.
+
+Tint has a process for supporting [experimental extensions](docs/tint/experimental_extensions.md).
diff --git a/build_overrides/angle.gni b/build_overrides/angle.gni
new file mode 100644
index 0000000..85d4d95
--- /dev/null
+++ b/build_overrides/angle.gni
@@ -0,0 +1,26 @@
+# Copyright 2020 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Override for angle_root
+angle_root = "//third_party/angle"
+
+# True if ANGLE can access build/, testing/ and other Chrome folders.
+angle_has_build = true
+
+# Paths to ANGLE dependencies in Dawn
+angle_glslang_dir = "//third_party/vulkan-deps/glslang/src"
+angle_spirv_cross_dir = "//third_party/vulkan-deps/spirv-cross/src"
+angle_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src"
+angle_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src"
+angle_vulkan_memory_allocator_dir = "//third_party/vulkan_memory_allocator"
diff --git a/build_overrides/build.gni b/build_overrides/build.gni
index 11ce9f4..8717867 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors.
+# Copyright 2022 The Dawn Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -13,10 +13,10 @@
 # limitations under the License.
 
 declare_args() {
-  # Tell Tint and dependencies to not do Chromium-specific things
+  # Tell Dawn and dependencies to not do Chromium-specific things
   build_with_chromium = false
 
-  # In standalone Tint builds, don't try to use the hermetic install of Xcode
+  # In standalone Dawn builds, don't try to use the hermetic install of Xcode
   # that Chromium uses
   use_system_xcode = ""
 
diff --git a/build_overrides/dawn.gni b/build_overrides/dawn.gni
new file mode 100644
index 0000000..87e1ded
--- /dev/null
+++ b/build_overrides/dawn.gni
@@ -0,0 +1,39 @@
+# Copyright 2018 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# These are variables that are overridable by projects that include Dawn.
+# The values in this file are the defaults for when we are building from
+# Dawn's repository.
+
+# Whether we are building from Dawn's repository.
+# MUST be unset in other projects (will default to false).
+dawn_standalone = true
+
+# True if Dawn can access build/, testing/ and other Chrome folders.
+dawn_has_build = true
+
+# Defaults for these are set again in dawn_overrides_with_defaults.gni so that
+# users of Dawn don't have to set dirs if they happen to use the same as Dawn.
+
+# The paths to Dawn's dependencies
+dawn_abseil_dir = "//third_party/abseil-cpp"
+dawn_angle_dir = "//third_party/angle"
+dawn_jinja2_dir = "//third_party/jinja2"
+dawn_glfw_dir = "//third_party/glfw"
+dawn_googletest_dir = "//third_party/googletest"
+dawn_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src"
+dawn_swiftshader_dir = "//third_party/swiftshader"
+dawn_vulkan_loader_dir = "//third_party/vulkan-deps/vulkan-loader/src"
+dawn_vulkan_validation_layers_dir =
+    "//third_party/vulkan-deps/vulkan-validation-layers/src"
diff --git a/build_overrides/glslang.gni b/build_overrides/glslang.gni
index 80a30c9..69d968d 100644
--- a/build_overrides/glslang.gni
+++ b/build_overrides/glslang.gni
@@ -1,4 +1,4 @@
-# Copyright 2021 The Dawn Authors
+# Copyright 2018 The Dawn Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/build_overrides/spirv_tools.gni b/build_overrides/spirv_tools.gni
index 13bffc5..48e7b11 100644
--- a/build_overrides/spirv_tools.gni
+++ b/build_overrides/spirv_tools.gni
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors
+# Copyright 2018 The Dawn Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# We are building inside Tint
+# We are building inside Dawn
 spirv_tools_standalone = false
 
-# Paths to SPIRV-Tools dependencies in Tint
+# Paths to SPIRV-Tools dependencies in Dawn
 spirv_tools_googletest_dir = "//third_party/googletest"
 spirv_tools_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src"
diff --git a/build_overrides/swiftshader.gni b/build_overrides/swiftshader.gni
new file mode 100644
index 0000000..dc3579b
--- /dev/null
+++ b/build_overrides/swiftshader.gni
@@ -0,0 +1,23 @@
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# We are building SwiftShader inside Dawn
+swiftshader_standalone = false
+
+# Path to SwiftShader
+swiftshader_dir = "//third_party/swiftshader"
+
+# Forward to ozone_platform_x11 when inside Dawn's repository
+import("../scripts/dawn_features.gni")
+ozone_platform_x11 = dawn_use_x11
diff --git a/build_overrides/tint.gni b/build_overrides/tint.gni
index fdcc866..8349998 100644
--- a/build_overrides/tint.gni
+++ b/build_overrides/tint.gni
@@ -1,4 +1,4 @@
-# Copyright 2020 The Tint Authors.
+# Copyright 2020 The Dawn Authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,4 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# This file contains Tint-related overrides.
+tint_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src"
+tint_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src"
+
+tint_build_spv_reader = true
+tint_build_spv_writer = true
+tint_build_wgsl_reader = true
+tint_build_wgsl_writer = true
diff --git a/build_overrides/vulkan_common.gni b/build_overrides/vulkan_common.gni
new file mode 100644
index 0000000..9a883e7
--- /dev/null
+++ b/build_overrides/vulkan_common.gni
@@ -0,0 +1,19 @@
+# Copyright 2021 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+vulkan_headers_dir = "//third_party/vulkan-deps/vulkan-headers/src"
+
+# Subdirectories for generated files
+vulkan_data_subdir = "vulkandata"
+vulkan_gen_subdir = ""
diff --git a/build_overrides/vulkan_headers.gni b/build_overrides/vulkan_headers.gni
new file mode 100644
index 0000000..4c0047a
--- /dev/null
+++ b/build_overrides/vulkan_headers.gni
@@ -0,0 +1,17 @@
+# Copyright 2020 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Fake the vulkan_use_x11 when inside Dawn's repository
+import("../scripts/dawn_features.gni")
+vulkan_use_x11 = dawn_use_x11
diff --git a/build_overrides/vulkan_loader.gni b/build_overrides/vulkan_loader.gni
new file mode 100644
index 0000000..6f6eaf0
--- /dev/null
+++ b/build_overrides/vulkan_loader.gni
@@ -0,0 +1,17 @@
+# Copyright 2020 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/vulkan_common.gni")
+
+vulkan_loader_shared = !is_mac
diff --git a/build_overrides/vulkan_tools.gni b/build_overrides/vulkan_tools.gni
new file mode 100644
index 0000000..7bd4d99
--- /dev/null
+++ b/build_overrides/vulkan_tools.gni
@@ -0,0 +1,15 @@
+# Copyright 2021 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/vulkan_common.gni")
diff --git a/build_overrides/vulkan_validation_layers.gni b/build_overrides/vulkan_validation_layers.gni
new file mode 100644
index 0000000..9463e66
--- /dev/null
+++ b/build_overrides/vulkan_validation_layers.gni
@@ -0,0 +1,25 @@
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/vulkan_common.gni")
+
+# These are variables that are overridable by projects that include Dawn.
+# The values in this file are the defaults for when we are building from
+# Dawn's repository.
+vvl_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src"
+vvl_glslang_dir = "//third_party/vulkan-deps/glslang/src"
+
+# Forward to ozone_platform_x11 when inside Dawn's repository
+import("../scripts/dawn_features.gni")
+ozone_platform_x11 = dawn_use_x11
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 0000000..10cc2bf
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,5 @@
+# This file is used by git cl to get repository specific information.
+GERRIT_HOST: True
+CODE_REVIEW_SERVER: https://dawn-review.googlesource.com
+GERRIT_SQUASH_UPLOADS: False
+TRYSERVER_GERRIT_URL: https://dawn-review.googlesource.com
diff --git a/dawn.json b/dawn.json
new file mode 100644
index 0000000..3578858
--- /dev/null
+++ b/dawn.json
@@ -0,0 +1,2848 @@
+{
+    "_comment": [
+        "Copyright 2017 The Dawn Authors",
+        "",
+        "Licensed under the Apache License, Version 2.0 (the \"License\");",
+        "you may not use this file except in compliance with the License.",
+        "You may obtain a copy of the License at",
+        "",
+        "    http://www.apache.org/licenses/LICENSE-2.0",
+        "",
+        "Unless required by applicable law or agreed to in writing, software",
+        "distributed under the License is distributed on an \"AS IS\" BASIS,",
+        "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
+        "See the License for the specific language governing permissions and",
+        "limitations under the License."
+    ],
+
+    "_doc": "See docs/dawn/codegen.md",
+
+    "_metadata": {
+        "api": "WebGPU",
+        "c_prefix": "WGPU",
+        "namespace": "wgpu",
+        "proc_table_prefix": "Dawn",
+        "native_namespace": "dawn native",
+        "copyright_year": "2019"
+    },
+
+    "create instance": {
+        "category": "function",
+        "returns": "instance",
+        "args": [
+            {"name": "descriptor", "type": "instance descriptor", "annotation": "const*", "optional": true}
+        ]
+    },
+    "proc": {
+        "category": "function pointer",
+        "returns": "void",
+        "args": []
+    },
+    "get proc address": {
+        "category": "function",
+        "returns": "proc",
+        "args": [
+            {"name": "device", "type": "device"},
+            {"name": "proc name", "type": "char", "annotation": "const*"}
+        ]
+    },
+
+    "request adapter options": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "compatible surface", "type": "surface", "optional": true},
+            {"name": "power preference", "type": "power preference", "default": "undefined"},
+            {"name": "force fallback adapter", "type": "bool", "default": "false"}
+        ]
+    },
+    "request adapter status": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "unavailable"},
+            {"value": 2, "name": "error"},
+            {"value": 3, "name": "unknown"}
+        ]
+    },
+    "request adapter callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "request adapter status"},
+            {"name": "adapter", "type": "adapter"},
+            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "adapter": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "get limits",
+                "returns": "bool",
+                "args": [
+                    {"name": "limits", "type": "supported limits", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "get properties",
+                "args": [
+                    {"name": "properties", "type": "adapter properties", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "has feature",
+                "returns": "bool",
+                "args": [
+                    {"name": "feature", "type": "feature name"}
+                ]
+            },
+            {
+                "name": "enumerate features",
+                "returns": "size_t",
+                "args": [
+                    {"name": "features", "type": "feature name", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "request device",
+                "args": [
+                    {"name": "descriptor", "type": "device descriptor", "annotation": "const*"},
+                    {"name": "callback", "type": "request device callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "create device",
+                "tags": ["dawn"],
+                "returns": "device",
+                "args": [
+                    {"name": "descriptor", "type": "device descriptor", "annotation": "const*", "optional": "true"}
+                ]
+            }
+        ]
+    },
+    "adapter properties": {
+        "category": "structure",
+        "extensible": "out",
+        "members": [
+            {"name": "vendor ID", "type": "uint32_t"},
+            {"name": "device ID", "type": "uint32_t"},
+            {"name": "name", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "driver description", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "adapter type", "type": "adapter type"},
+            {"name": "backend type", "type": "backend type"}
+        ]
+    },
+    "adapter type": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "discrete GPU"},
+            {"value": 1, "name": "integrated GPU"},
+            {"value": 2, "name": "CPU"},
+            {"value": 3, "name": "unknown"}
+        ]
+    },
+    "device descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "required features count", "type": "uint32_t", "default": 0},
+            {"name": "required features", "type": "feature name", "annotation": "const*", "length": "required features count", "default": "nullptr"},
+            {"name": "required limits", "type": "required limits", "annotation": "const*", "optional": true},
+            {"name": "default queue", "type": "queue descriptor", "tags": ["upstream"]}
+        ]
+    },
+    "dawn toggles device descriptor": {
+        "tags": ["dawn", "native"],
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "force enabled toggles count", "type": "uint32_t", "default": 0},
+            {"name": "force enabled toggles", "type": "char", "annotation": "const*const*", "length": "force enabled toggles count"},
+            {"name": "force disabled toggles count", "type": "uint32_t", "default": 0},
+            {"name": "force disabled toggles", "type": "char", "annotation": "const*const*", "length": "force disabled toggles count"}
+        ]
+    },
+    "dawn cache device descriptor" : {
+        "tags": ["dawn", "native"],
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "isolation key", "type": "char", "annotation": "const*", "length": "strlen", "default": "\"\""}
+        ]
+    },
+    "address mode": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "repeat"},
+            {"value": 1, "name": "mirror repeat"},
+            {"value": 2, "name": "clamp to edge"}
+        ]
+    },
+    "backend type": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "null"},
+            {"value": 1, "name": "WebGPU"},
+            {"value": 2, "name": "D3D11"},
+            {"value": 3, "name": "D3D12"},
+            {"value": 4, "name": "metal"},
+            {"value": 5, "name": "vulkan"},
+            {"value": 6, "name": "openGL"},
+            {"value": 7, "name": "openGLES"}
+        ]
+    },
+    "bind group": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "bind group entry": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "binding", "type": "uint32_t"},
+            {"name": "buffer", "type": "buffer", "optional": true},
+            {"name": "offset", "type": "uint64_t", "default": "0"},
+            {"name": "size", "type": "uint64_t"},
+            {"name": "sampler", "type": "sampler", "optional": true},
+            {"name": "texture view", "type": "texture view", "optional": true}
+        ]
+    },
+    "bind group descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "layout", "type": "bind group layout"},
+            {"name": "entry count", "type": "uint32_t"},
+            {"name": "entries", "type": "bind group entry", "annotation": "const*", "length": "entry count"}
+        ]
+    },
+    "bind group layout": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+
+    "buffer binding type": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
+            {"value": 1, "name": "uniform"},
+            {"value": 2, "name": "storage"},
+            {"value": 3, "name": "read only storage"}
+        ]
+    },
+    "buffer binding layout": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "type", "type": "buffer binding type", "default": "undefined"},
+            {"name": "has dynamic offset", "type": "bool", "default": "false"},
+            {"name": "min binding size", "type": "uint64_t", "default": "0"}
+        ]
+    },
+
+    "sampler binding type": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
+            {"value": 1, "name": "filtering"},
+            {"value": 2, "name": "non filtering"},
+            {"value": 3, "name": "comparison"}
+        ]
+    },
+    "sampler binding layout": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "type", "type": "sampler binding type", "default": "undefined"}
+        ]
+    },
+
+    "texture sample type": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
+            {"value": 1, "name": "float"},
+            {"value": 2, "name": "unfilterable float"},
+            {"value": 3, "name": "depth"},
+            {"value": 4, "name": "sint"},
+            {"value": 5, "name": "uint"}
+        ]
+    },
+    "texture binding layout": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "sample type", "type": "texture sample type", "default": "undefined"},
+            {"name": "view dimension", "type": "texture view dimension", "default": "undefined"},
+            {"name": "multisampled", "type": "bool", "default": "false"}
+        ]
+    },
+
+    "external texture binding entry": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn"],
+        "members": [
+            {"name": "external texture", "type": "external texture"}
+        ]
+    },
+
+    "external texture binding layout": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn"],
+        "members": []
+    },
+
+    "storage texture access": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
+            {"value": 1, "name": "write only"}
+        ]
+    },
+    "storage texture binding layout": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "access", "type": "storage texture access", "default": "undefined"},
+            {"name": "format", "type": "texture format", "default": "undefined"},
+            {"name": "view dimension", "type": "texture view dimension", "default": "undefined"}
+        ]
+    },
+
+    "bind group layout entry": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "binding", "type": "uint32_t"},
+            {"name": "visibility", "type": "shader stage"},
+            {"name": "buffer", "type": "buffer binding layout"},
+            {"name": "sampler", "type": "sampler binding layout"},
+            {"name": "texture", "type": "texture binding layout"},
+            {"name": "storage texture", "type": "storage texture binding layout"}
+        ]
+    },
+    "bind group layout descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "entry count", "type": "uint32_t"},
+            {"name": "entries", "type": "bind group layout entry", "annotation": "const*", "length": "entry count"}
+        ]
+    },
+    "blend component": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "operation", "type": "blend operation", "default": "add"},
+            {"name": "src factor", "type": "blend factor", "default": "one"},
+            {"name": "dst factor", "type": "blend factor", "default": "zero"}
+        ]
+    },
+    "blend factor": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "zero"},
+            {"value": 1, "name": "one"},
+            {"value": 2, "name": "src"},
+            {"value": 3, "name": "one minus src"},
+            {"value": 4, "name": "src alpha"},
+            {"value": 5, "name": "one minus src alpha"},
+            {"value": 6, "name": "dst"},
+            {"value": 7, "name": "one minus dst"},
+            {"value": 8, "name": "dst alpha"},
+            {"value": 9, "name": "one minus dst alpha"},
+            {"value": 10, "name": "src alpha saturated"},
+            {"value": 11, "name": "constant"},
+            {"value": 12, "name": "one minus constant"}
+        ]
+    },
+    "blend operation": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "add"},
+            {"value": 1, "name": "subtract"},
+            {"value": 2, "name": "reverse subtract"},
+            {"value": 3, "name": "min"},
+            {"value": 4, "name": "max"}
+        ]
+    },
+    "bool": {
+        "category": "native"
+    },
+    "buffer": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "map async",
+                "args": [
+                    {"name": "mode", "type": "map mode"},
+                    {"name": "offset", "type": "size_t"},
+                    {"name": "size", "type": "size_t"},
+                    {"name": "callback", "type": "buffer map callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "get mapped range",
+                "returns": "void *",
+                "args": [
+                    {"name": "offset", "type": "size_t", "default": 0},
+                    {"name": "size", "type": "size_t", "default": 0}
+                ]
+            },
+            {
+                "name": "get const mapped range",
+                "returns": "void const *",
+                "args": [
+                    {"name": "offset", "type": "size_t", "default": 0},
+                    {"name": "size", "type": "size_t", "default": 0}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "unmap"
+            },
+            {
+                "name": "destroy"
+            }
+        ]
+    },
+    "buffer descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "usage", "type": "buffer usage"},
+            {"name": "size", "type": "uint64_t"},
+            {"name": "mapped at creation", "type": "bool", "default": "false"}
+        ]
+    },
+    "buffer map callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "buffer map async status"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "buffer map async status": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "unknown"},
+            {"value": 3, "name": "device lost"},
+            {"value": 4, "name": "destroyed before callback"},
+            {"value": 5, "name": "unmapped before callback"}
+        ]
+    },
+    "buffer usage": {
+        "category": "bitmask",
+        "values": [
+            {"value": 0, "name": "none"},
+            {"value": 1, "name": "map read"},
+            {"value": 2, "name": "map write"},
+            {"value": 4, "name": "copy src"},
+            {"value": 8, "name": "copy dst"},
+            {"value": 16, "name": "index"},
+            {"value": 32, "name": "vertex"},
+            {"value": 64, "name": "uniform"},
+            {"value": 128, "name": "storage"},
+            {"value": 256, "name": "indirect"},
+            {"value": 512, "name": "query resolve"}
+        ]
+    },
+    "char": {
+        "category": "native"
+    },
+    "color": {
+        "category": "structure",
+        "members": [
+            {"name": "r", "type": "double"},
+            {"name": "g", "type": "double"},
+            {"name": "b", "type": "double"},
+            {"name": "a", "type": "double"}
+        ]
+    },
+    "color write mask": {
+        "category": "bitmask",
+        "values": [
+            {"value": 0, "name": "none"},
+            {"value": 1, "name": "red"},
+            {"value": 2, "name": "green"},
+            {"value": 4, "name": "blue"},
+            {"value": 8, "name": "alpha"},
+            {"value": 15, "name": "all"}
+        ]
+    },
+    "constant entry": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "key", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "value", "type": "double"}
+        ]
+    },
+    "command buffer": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "command buffer descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}
+        ]
+    },
+    "command encoder": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "finish",
+                "returns": "command buffer",
+                "args": [
+                    {"name": "descriptor", "type": "command buffer descriptor", "annotation": "const*", "optional": true}
+                ]
+            },
+            {
+                "name": "begin compute pass",
+                "returns": "compute pass encoder",
+                "args": [
+                    {"name": "descriptor", "type": "compute pass descriptor", "annotation": "const*", "optional": true}
+                ]
+            },
+            {
+                "name": "begin render pass",
+                "returns": "render pass encoder",
+                "args": [
+                    {"name": "descriptor", "type": "render pass descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "copy buffer to buffer",
+                "args": [
+                    {"name": "source", "type": "buffer"},
+                    {"name": "source offset", "type": "uint64_t"},
+                    {"name": "destination", "type": "buffer"},
+                    {"name": "destination offset", "type": "uint64_t"},
+                    {"name": "size", "type": "uint64_t"}
+                ]
+            },
+            {
+                "name": "copy buffer to texture",
+                "args": [
+                    {"name": "source", "type": "image copy buffer", "annotation": "const*"},
+                    {"name": "destination", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "copy size", "type": "extent 3D", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "copy texture to buffer",
+                "args": [
+                    {"name": "source", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "destination", "type": "image copy buffer", "annotation": "const*"},
+                    {"name": "copy size", "type": "extent 3D", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "copy texture to texture",
+                "args": [
+                    {"name": "source", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "destination", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "copy size", "type": "extent 3D", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "copy texture to texture internal",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "source", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "destination", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "copy size", "type": "extent 3D", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "clear buffer",
+                "args": [
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "offset", "type": "uint64_t", "default": 0},
+                    {"name": "size", "type": "uint64_t", "default": "WGPU_WHOLE_SIZE"}
+                ]
+            },
+            {
+                "name": "inject validation error",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "insert debug marker",
+                "args": [
+                    {"name": "marker label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "pop debug group",
+                "args": []
+            },
+            {
+                "name": "push debug group",
+                "args": [
+                    {"name": "group label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "resolve query set",
+                "args": [
+                    {"name": "query set", "type": "query set"},
+                    {"name": "first query", "type": "uint32_t"},
+                    {"name": "query count", "type": "uint32_t"},
+                    {"name": "destination", "type": "buffer"},
+                    {"name": "destination offset", "type": "uint64_t"}
+                ]
+            },
+            {
+                "name": "write buffer",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "buffer offset", "type": "uint64_t"},
+                    {"name": "data", "type": "uint8_t", "annotation": "const*", "length": "size"},
+                    {"name": "size", "type": "uint64_t"}
+                ]
+            },
+            {
+                "name": "write timestamp",
+                "args": [
+                    {"name": "query set", "type": "query set"},
+                    {"name": "query index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "command encoder descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}
+        ]
+    },
+    "compare function": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
+            {"value": 1, "name": "never"},
+            {"value": 2, "name": "less"},
+            {"value": 3, "name": "less equal"},
+            {"value": 4, "name": "greater"},
+            {"value": 5, "name": "greater equal"},
+            {"value": 6, "name": "equal"},
+            {"value": 7, "name": "not equal"},
+            {"value": 8, "name": "always"}
+        ]
+    },
+    "compilation info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "message count", "type": "uint32_t"},
+            {"name": "messages", "type": "compilation message", "annotation": "const*", "length": "message count"}
+        ]
+    },
+    "compilation info callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "compilation info request status"},
+            {"name": "compilation info", "type": "compilation info", "annotation": "const*"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "compilation info request status": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "device lost"},
+            {"value": 3, "name": "unknown"}
+        ]
+    },
+    "compilation message": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "type", "type": "compilation message type"},
+            {"name": "line num", "type": "uint64_t"},
+            {"name": "line pos", "type": "uint64_t"},
+            {"name": "offset", "type": "uint64_t"},
+            {"name": "length", "type": "uint64_t"}
+        ]
+    },
+    "compilation message type": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "error"},
+            {"value": 1, "name": "warning"},
+            {"value": 2, "name": "info"}
+        ]
+    },
+    "compute pass descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "timestamp write count", "type": "uint32_t", "default": 0},
+            {"name": "timestamp writes", "type": "compute pass timestamp write", "annotation": "const*", "length": "timestamp write count"}
+        ]
+    },
+    "compute pass encoder": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "insert debug marker",
+                "args": [
+                    {"name": "marker label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "pop debug group",
+                "args": []
+            },
+            {
+                "name": "push debug group",
+                "args": [
+                    {"name": "group label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "set pipeline",
+                "args": [
+                    {"name": "pipeline", "type": "compute pipeline"}
+                ]
+            },
+            {
+                "name": "set bind group",
+                "args": [
+                    {"name": "group index", "type": "uint32_t"},
+                    {"name": "group", "type": "bind group"},
+                    {"name": "dynamic offset count", "type": "uint32_t", "default": "0"},
+                    {"name": "dynamic offsets", "type": "uint32_t", "annotation": "const*", "length": "dynamic offset count", "default": "nullptr"}
+                ]
+            },
+            {
+                "name": "write timestamp",
+                "tags": ["emscripten", "dawn"],
+                "args": [
+                    {"name": "query set", "type": "query set"},
+                    {"name": "query index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "begin pipeline statistics query",
+                "tags": ["upstream", "emscripten"],
+                "args": [
+                    {"name": "query set", "type": "query set"},
+                    {"name": "query index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "dispatch",
+                "args": [
+                    {"name": "workgroupCountX", "type": "uint32_t"},
+                    {"name": "workgroupCountY", "type": "uint32_t", "default": "1"},
+                    {"name": "workgroupCountZ", "type": "uint32_t", "default": "1"}
+                ]
+            },
+            {
+                "name": "dispatch indirect",
+                "args": [
+                  {"name": "indirect buffer", "type": "buffer"},
+                  {"name": "indirect offset", "type": "uint64_t"}
+                ]
+            },
+            {
+                "name": "end"
+            },
+            {
+                "name": "end pass",
+                "tags": ["deprecated"]
+            },
+            {
+                "name": "end pipeline statistics query",
+                "tags": ["upstream", "emscripten"]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "compute pass timestamp location": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "beginning"},
+            {"value": 1, "name": "end"}
+        ]
+    },
+    "compute pass timestamp write": {
+        "category": "structure",
+        "members": [
+            {"name": "query set", "type": "query set"},
+            {"name": "query index", "type": "uint32_t"},
+            {"name": "location", "type": "compute pass timestamp location"}
+        ]
+    },
+    "compute pipeline": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "get bind group layout",
+                "returns": "bind group layout",
+                "args": [
+                    {"name": "group index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "compute pipeline descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "layout", "type": "pipeline layout", "optional": true},
+            {"name": "compute", "type": "programmable stage descriptor"}
+        ]
+    },
+    "alpha mode": {
+        "category": "enum",
+        "tags": ["dawn"],
+        "values": [
+            {"value": 0, "name": "premultiplied"},
+            {"value": 1, "name": "unpremultiplied"}
+        ]
+    },
+    "copy texture for browser options": {
+        "category": "structure",
+        "extensible": "in",
+        "tags": ["dawn"],
+        "_TODO": "support number as length input",
+        "members": [
+            {"name": "flip y", "type": "bool", "default": "false"},
+            {"name": "needs color space conversion", "type": "bool", "default": "false"},
+            {"name": "src alpha mode", "type": "alpha mode", "default": "unpremultiplied"},
+            {"name": "src transfer function parameters", "type": "float", "annotation": "const*",
+                     "length": 7, "optional": true},
+            {"name": "conversion matrix", "type": "float", "annotation": "const*",
+                     "length": 9, "optional": true},
+            {"name": "dst transfer function parameters", "type": "float", "annotation": "const*",
+                     "length": 7, "optional": true},
+            {"name": "dst alpha mode", "type": "alpha mode", "default": "unpremultiplied"}
+        ]
+    },
+    "create compute pipeline async callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "create pipeline async status"},
+            {"name": "pipeline", "type": "compute pipeline"},
+            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "create pipeline async status": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "device lost"},
+            {"value": 3, "name": "device destroyed"},
+            {"value": 4, "name": "unknown"}
+        ]
+    },
+    "create render pipeline async callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "create pipeline async status"},
+            {"name": "pipeline", "type": "render pipeline"},
+            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "cull mode": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "none"},
+            {"value": 1, "name": "front"},
+            {"value": 2, "name": "back"}
+        ]
+    },
+    "device": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "create bind group",
+                "returns": "bind group",
+                "args": [
+                    {"name": "descriptor", "type": "bind group descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create bind group layout",
+                "returns": "bind group layout",
+                "args": [
+                    {"name": "descriptor", "type": "bind group layout descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create buffer",
+                "returns": "buffer",
+                "args": [
+                    {"name": "descriptor", "type": "buffer descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create error buffer",
+                "returns": "buffer",
+                "tags": ["dawn"]
+            },
+            {
+                "name": "create command encoder",
+                "returns": "command encoder",
+                "args": [
+                    {"name": "descriptor", "type": "command encoder descriptor", "annotation": "const*", "optional": true}
+                ]
+            },
+            {
+                "name": "create compute pipeline",
+                "returns": "compute pipeline",
+                "args": [
+                    {"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create compute pipeline async",
+                "returns": "void",
+                "args": [
+                    {"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"},
+                    {"name": "callback", "type": "create compute pipeline async callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "create external texture",
+                "returns": "external texture",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "external texture descriptor", "type": "external texture descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create pipeline layout",
+                "returns": "pipeline layout",
+                "args": [
+                    {"name": "descriptor", "type": "pipeline layout descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create query set",
+                "returns": "query set",
+                "args": [
+                    {"name": "descriptor", "type": "query set descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create render pipeline async",
+                "returns": "void",
+                "args": [
+                    {"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"},
+                    {"name": "callback", "type": "create render pipeline async callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "create render bundle encoder",
+                "returns": "render bundle encoder",
+                "args": [
+                    {"name": "descriptor", "type": "render bundle encoder descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create render pipeline",
+                "returns": "render pipeline",
+                "args": [
+                    {"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create sampler",
+                "returns": "sampler",
+                "args": [
+                    {"name": "descriptor", "type": "sampler descriptor", "annotation": "const*", "optional": true}
+                ]
+            },
+            {
+                "name": "create shader module",
+                "returns": "shader module",
+                "args": [
+                    {"name": "descriptor", "type": "shader module descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create swap chain",
+                "returns": "swap chain",
+                "args": [
+                    {"name": "surface", "type": "surface", "optional": true},
+                    {"name": "descriptor", "type": "swap chain descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "create texture",
+                "returns": "texture",
+                "args": [
+                    {"name": "descriptor", "type": "texture descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "destroy"
+            },
+            {
+                "name": "get limits",
+                "returns": "bool",
+                "args": [
+                    {"name": "limits", "type": "supported limits", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "has feature",
+                "returns": "bool",
+                "args": [
+                    {"name": "feature", "type": "feature name"}
+                ]
+            },
+            {
+                "name": "enumerate features",
+                "returns": "size_t",
+                "args": [
+                    {"name": "features", "type": "feature name", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "get queue",
+                "returns": "queue"
+            },
+            {
+                "name": "inject error",
+                "args": [
+                    {"name": "type", "type": "error type"},
+                    {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
+                ],
+                "tags": ["dawn"]
+            },
+            {
+                "name": "lose for testing",
+                "tags": ["dawn"]
+            },
+            {
+                "name": "tick",
+                "tags": ["dawn"]
+            },
+            {
+                "name": "set uncaptured error callback",
+                "args": [
+                    {"name": "callback", "type": "error callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "set logging callback",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "callback", "type": "logging callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "set device lost callback",
+                "args": [
+                    {"name": "callback", "type": "device lost callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "push error scope",
+                "args": [
+                    {"name": "filter", "type": "error filter"}
+                ]
+            },
+            {
+                "name": "pop error scope",
+                "returns": "bool",
+                "args": [
+                    {"name": "callback", "type": "error callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            }
+        ]
+    },
+    "device lost callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "reason", "type": "device lost reason"},
+            {"name": "message", "type": "char", "annotation": "const*"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "device lost reason": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "destroyed"}
+        ]
+    },
+    "device properties": {
+        "category": "structure",
+        "extensible": false,
+        "tags": ["dawn"],
+        "members": [
+            {"name": "device ID", "type": "uint32_t"},
+            {"name": "vendor ID", "type": "uint32_t"},
+            {"name": "adapter type", "type": "adapter type"},
+            {"name": "texture compression BC", "type": "bool", "default": "false"},
+            {"name": "texture compression ETC2", "type": "bool", "default": "false"},
+            {"name": "texture compression ASTC", "type": "bool", "default": "false"},
+            {"name": "shader float16", "type": "bool", "default": "false"},
+            {"name": "pipeline statistics query", "type": "bool", "default": "false"},
+            {"name": "timestamp query", "type": "bool", "default": "false"},
+            {"name": "multi planar formats", "type": "bool", "default": "false"},
+            {"name": "depth clamping", "type": "bool", "default": "false"},
+            {"name": "depth24 unorm stencil8", "type": "bool", "default": "false"},
+            {"name": "depth32 float stencil8", "type": "bool", "default": "false"},
+            {"name": "invalid feature", "type": "bool", "default": "false"},
+            {"name": "dawn internal usages", "type": "bool", "default": "false"},
+            {"name": "dawn native", "type": "bool", "default": "false"},
+            {"name": "limits", "type": "supported limits"}
+        ]
+    },
+    "double": {
+        "category": "native"
+    },
+    "error callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "type", "type": "error type"},
+            {"name": "message", "type": "char", "annotation": "const*"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "limits": {
+        "category": "structure",
+        "members": [
+            {"name": "max texture dimension 1D", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max texture dimension 2D", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max texture dimension 3D", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max texture array layers", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max bind groups", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max dynamic uniform buffers per pipeline layout", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max dynamic storage buffers per pipeline layout", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max sampled textures per shader stage", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max samplers per shader stage", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max storage buffers per shader stage", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max storage textures per shader stage", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max uniform buffers per shader stage", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max uniform buffer binding size", "type": "uint64_t", "default": "WGPU_LIMIT_U64_UNDEFINED"},
+            {"name": "max storage buffer binding size", "type": "uint64_t", "default": "WGPU_LIMIT_U64_UNDEFINED"},
+            {"name": "min uniform buffer offset alignment", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "min storage buffer offset alignment", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max vertex buffers", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max vertex attributes", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max vertex buffer array stride", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max inter stage shader components", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max compute workgroup storage size", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max compute invocations per workgroup", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max compute workgroup size x", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max compute workgroup size y", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max compute workgroup size z", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
+            {"name": "max compute workgroups per dimension", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"}
+        ]
+    },
+    "required limits": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "limits", "type": "limits"}
+        ]
+    },
+    "supported limits": {
+        "category": "structure",
+        "extensible": "out",
+        "members": [
+            {"name": "limits", "type": "limits"}
+        ]
+    },
+    "logging callback": {
+        "category": "function pointer",
+        "tags": ["dawn"],
+        "args": [
+            {"name": "type", "type": "logging type"},
+            {"name": "message", "type": "char", "annotation": "const*"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "error filter": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "validation"},
+            {"value": 1, "name": "out of memory"}
+        ]
+    },
+    "error type": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "no error"},
+            {"value": 1, "name": "validation"},
+            {"value": 2, "name": "out of memory"},
+            {"value": 3, "name": "unknown"},
+            {"value": 4, "name": "device lost"}
+        ]
+    },
+    "logging type": {
+        "category": "enum",
+        "tags": ["dawn"],
+        "values": [
+            {"value": 0, "name": "verbose"},
+            {"value": 1, "name": "info"},
+            {"value": 2, "name": "warning"},
+            {"value": 3, "name": "error"}
+        ]
+    },
+    "extent 3D": {
+        "category": "structure",
+        "members": [
+            {"name": "width", "type": "uint32_t"},
+            {"name": "height", "type": "uint32_t", "default": 1},
+            {"name": "depth or array layers", "type": "uint32_t", "default": 1}
+        ]
+    },
+    "external texture": {
+        "category": "object",
+        "tags": ["dawn"],
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "destroy",
+                "returns": "void"
+            }
+        ]
+    },
+    "external texture descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "tags": ["dawn"],
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "plane 0", "type": "texture view"},
+            {"name": "plane 1", "type": "texture view", "optional": true},
+            {"name": "color space", "type": "predefined color space", "default": "srgb"}
+        ]
+    },
+    "feature name": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "depth clip control", "tags": ["upstream", "emscripten"]},
+            {"value": 2, "name": "depth24 unorm stencil8"},
+            {"value": 3, "name": "depth32 float stencil8"},
+            {"value": 4, "name": "timestamp query"},
+            {"value": 5, "name": "pipeline statistics query"},
+            {"value": 6, "name": "texture compression BC"},
+            {"value": 7, "name": "texture compression ETC2"},
+            {"value": 8, "name": "texture compression ASTC"},
+            {"value": 9, "name": "indirect first instance"},
+            {"value": 1000, "name": "depth clamping", "tags": ["emscripten", "dawn"]},
+            {"value": 1001, "name": "dawn shader float 16", "tags": ["dawn"]},
+            {"value": 1002, "name": "dawn internal usages", "tags": ["dawn"]},
+            {"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]},
+            {"value": 1004, "name": "dawn native", "tags": ["dawn", "native"]}
+        ]
+    },
+    "filter mode": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "nearest"},
+            {"value": 1, "name": "linear"}
+        ]
+    },
+    "float": {
+        "category": "native"
+    },
+    "front face": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "CCW"},
+            {"value": 1, "name": "CW"}
+        ]
+    },
+    "image copy buffer": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "layout", "type": "texture data layout"},
+            {"name": "buffer", "type": "buffer"}
+        ]
+    },
+    "image copy texture": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "texture", "type": "texture"},
+            {"name": "mip level", "type": "uint32_t", "default": "0"},
+            {"name": "origin", "type": "origin 3D"},
+            {"name": "aspect", "type": "texture aspect", "default": "all"}
+        ]
+    },
+    "index format": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "uint16"},
+            {"value": 2, "name": "uint32"}
+        ]
+    },
+    "instance": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "create surface",
+                "returns": "surface",
+                "args": [
+                    {"name": "descriptor", "type": "surface descriptor", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "process events",
+                "tags": ["upstream", "emscripten"]
+            },
+            {
+                "name": "request adapter",
+                "args": [
+                    {"name": "options", "type": "request adapter options", "annotation": "const*"},
+                    {"name": "callback", "type": "request adapter callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            }
+        ]
+    },
+    "instance descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": []
+    },
+    "dawn instance descriptor": {
+        "tags": ["dawn", "native"],
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "additional runtime search paths count", "type": "uint32_t", "default": 0},
+            {"name": "additional runtime search paths", "type": "char", "annotation": "const*const*", "length": "additional runtime search paths count"}
+        ]
+    },
+    "vertex attribute": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "format", "type": "vertex format"},
+            {"name": "offset", "type": "uint64_t"},
+            {"name": "shader location", "type": "uint32_t"}
+        ]
+    },
+    "vertex buffer layout": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "array stride", "type": "uint64_t"},
+            {"name": "step mode", "type": "vertex step mode", "default": "vertex"},
+            {"name": "attribute count", "type": "uint32_t"},
+            {"name": "attributes", "type": "vertex attribute", "annotation": "const*", "length": "attribute count"}
+        ]
+    },
+    "vertex step mode": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "vertex"},
+            {"value": 1, "name": "instance"}
+        ]
+    },
+    "load op": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "clear"},
+            {"value": 2, "name": "load"}
+        ]
+    },
+    "map mode": {
+        "category": "bitmask",
+        "values": [
+            {"value": 0, "name": "none"},
+            {"value": 1, "name": "read"},
+            {"value": 2, "name": "write"}
+        ]
+    },
+    "mipmap filter mode": {
+        "category": "enum",
+        "tags": ["upstream"],
+        "values": [
+            {"value": 0, "name": "nearest"},
+            {"value": 1, "name": "linear"}
+        ]
+    },
+    "store op": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "store"},
+            {"value": 2, "name": "discard"}
+        ]
+    },
+    "origin 3D": {
+        "category": "structure",
+        "members": [
+            {"name": "x", "type": "uint32_t", "default": "0"},
+            {"name": "y", "type": "uint32_t", "default": "0"},
+            {"name": "z", "type": "uint32_t", "default": "0"}
+        ]
+    },
+    "pipeline layout": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "pipeline layout descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "bind group layout count", "type": "uint32_t"},
+            {"name": "bind group layouts", "type": "bind group layout", "annotation": "const*", "length": "bind group layout count"}
+        ]
+    },
+    "pipeline statistic name": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "vertex shader invocations"},
+            {"value": 1, "name": "clipper invocations"},
+            {"value": 2, "name": "clipper primitives out"},
+            {"value": 3, "name": "fragment shader invocations"},
+            {"value": 4, "name": "compute shader invocations"}
+        ]
+    },
+    "power preference": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "low power"},
+            {"value": 2, "name": "high performance"}
+        ]
+    },
+    "predefined color space": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "jsrepr": "undefined"},
+            {"value": 1, "name": "srgb"}
+        ]
+    },
+    "present mode": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "immediate"},
+            {"value": 1, "name": "mailbox"},
+            {"value": 2, "name": "fifo"}
+        ]
+    },
+    "programmable stage descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "module", "type": "shader module"},
+            {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "constant count", "type": "uint32_t", "default": 0},
+            {"name": "constants", "type": "constant entry", "annotation": "const*", "length": "constant count"}
+        ]
+    },
+    "primitive topology": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "point list"},
+            {"value": 1, "name": "line list"},
+            {"value": 2, "name": "line strip"},
+            {"value": 3, "name": "triangle list"},
+            {"value": 4, "name": "triangle strip"}
+        ]
+    },
+    "query set": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "destroy"
+            }
+        ]
+    },
+    "query set descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "type", "type": "query type"},
+            {"name": "count", "type": "uint32_t"},
+            {"name": "pipeline statistics", "type": "pipeline statistic name", "annotation": "const*", "length": "pipeline statistics count"},
+            {"name": "pipeline statistics count", "type": "uint32_t", "default": "0"}
+        ]
+    },
+    "query type": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "occlusion"},
+            {"value": 1, "name": "pipeline statistics"},
+            {"value": 2, "name": "timestamp"}
+        ]
+    },
+    "queue": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "submit",
+                "args": [
+                    {"name": "command count", "type": "uint32_t"},
+                    {"name": "commands", "type": "command buffer", "annotation": "const*", "length": "command count"}
+                ]
+            },
+            {
+                "name": "on submitted work done",
+                "tags": ["dawn", "emscripten"],
+                "args": [
+                    {"name": "signal value", "type": "uint64_t"},
+                    {"name": "callback", "type": "queue work done callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "on submitted work done",
+                "tags": ["upstream"],
+                "args": [
+                    {"name": "callback", "type": "queue work done callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "write buffer",
+                "args": [
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "buffer offset", "type": "uint64_t"},
+                    {"name": "data", "type": "void", "annotation": "const*", "length": "size"},
+                    {"name": "size", "type": "size_t"}
+                ]
+            },
+            {
+                "name": "write texture",
+                "args": [
+                    {"name": "destination", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "data", "type": "void", "annotation": "const*", "length": "data size"},
+                    {"name": "data size", "type": "size_t"},
+                    {"name": "data layout", "type": "texture data layout", "annotation": "const*"},
+                    {"name": "write size", "type": "extent 3D", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "copy texture for browser",
+                "extensible": "in",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "source", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "destination", "type": "image copy texture", "annotation": "const*"},
+                    {"name": "copy size", "type": "extent 3D", "annotation": "const*"},
+                    {"name": "options", "type": "copy texture for browser options", "annotation": "const*"}
+                ]
+            }
+        ]
+    },
+    "queue descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "tags": ["upstream"],
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}
+        ]
+    },
+    "queue work done callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "queue work done status"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "queue work done status": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "unknown"},
+            {"value": 3, "name": "device lost"}
+        ]
+    },
+
+    "render bundle": {
+        "category": "object"
+    },
+
+    "render bundle encoder": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set pipeline",
+                "args": [
+                    {"name": "pipeline", "type": "render pipeline"}
+                ]
+            },
+            {
+                "name": "set bind group",
+                "args": [
+                    {"name": "group index", "type": "uint32_t"},
+                    {"name": "group", "type": "bind group"},
+                    {"name": "dynamic offset count", "type": "uint32_t", "default": "0"},
+                    {"name": "dynamic offsets", "type": "uint32_t", "annotation": "const*", "length": "dynamic offset count", "default": "nullptr"}
+                ]
+            },
+            {
+                "name": "draw",
+                "args": [
+                    {"name": "vertex count", "type": "uint32_t"},
+                    {"name": "instance count", "type": "uint32_t", "default": "1"},
+                    {"name": "first vertex", "type": "uint32_t", "default": "0"},
+                    {"name": "first instance", "type": "uint32_t",  "default": "0"}
+                ]
+            },
+            {
+                "name": "draw indexed",
+                "args": [
+                    {"name": "index count", "type": "uint32_t"},
+                    {"name": "instance count", "type": "uint32_t", "default": "1"},
+                    {"name": "first index", "type": "uint32_t", "default": "0"},
+                    {"name": "base vertex", "type": "int32_t", "default": "0"},
+                    {"name": "first instance", "type": "uint32_t", "default": "0"}
+                ]
+            },
+            {
+              "name": "draw indirect",
+              "args": [
+                    {"name": "indirect buffer", "type": "buffer"},
+                    {"name": "indirect offset", "type": "uint64_t"}
+              ]
+            },
+            {
+              "name": "draw indexed indirect",
+              "args": [
+                    {"name": "indirect buffer", "type": "buffer"},
+                    {"name": "indirect offset", "type": "uint64_t"}
+              ]
+            },
+            {
+                "name": "insert debug marker",
+                "args": [
+                    {"name": "marker label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "pop debug group",
+                "args": []
+            },
+            {
+                "name": "push debug group",
+                "args": [
+                    {"name": "group label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "set vertex buffer",
+                "args": [
+                    {"name": "slot", "type": "uint32_t"},
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "offset", "type": "uint64_t", "default": "0"},
+                    {"name": "size", "type": "uint64_t", "default": "WGPU_WHOLE_SIZE"}
+                ]
+            },
+            {
+                "name": "set index buffer",
+                "args": [
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "format", "type": "index format"},
+                    {"name": "offset", "type": "uint64_t", "default": "0"},
+                    {"name": "size", "type": "uint64_t", "default": "WGPU_WHOLE_SIZE"}
+                ]
+            },
+            {
+                "name": "finish",
+                "returns": "render bundle",
+                "args": [
+                    {"name": "descriptor", "type": "render bundle descriptor", "annotation": "const*", "optional": true}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+
+    "render bundle descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}
+        ]
+    },
+
+    "render bundle encoder descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "color formats count", "type": "uint32_t"},
+            {"name": "color formats", "type": "texture format", "annotation": "const*", "length": "color formats count"},
+            {"name": "depth stencil format", "type": "texture format", "default": "undefined"},
+            {"name": "sample count", "type": "uint32_t", "default": "1"},
+            {"name": "depth read only", "type": "bool", "default": "false"},
+            {"name": "stencil read only", "type": "bool", "default": "false"}
+        ]
+    },
+
+    "render pass color attachment": {
+        "category": "structure",
+        "members": [
+            {"name": "view", "type": "texture view", "optional": true},
+            {"name": "resolve target", "type": "texture view", "optional": true},
+            {"name": "load op", "type": "load op"},
+            {"name": "store op", "type": "store op"},
+            {"name": "clear color", "type": "color", "default": "{ NAN, NAN, NAN, NAN }", "tags": ["deprecated"]},
+            {"name": "clear value", "type": "color"}
+        ]
+    },
+
+    "render pass depth stencil attachment": {
+        "category": "structure",
+        "members": [
+            {"name": "view", "type": "texture view"},
+            {"name": "depth load op", "type": "load op", "default": "undefined"},
+            {"name": "depth store op", "type": "store op", "default": "undefined"},
+            {"name": "clear depth", "type": "float", "default": "NAN", "tags": ["deprecated"]},
+            {"name": "depth clear value", "type": "float", "default": "0"},
+            {"name": "depth read only", "type": "bool", "default": "false"},
+            {"name": "stencil load op", "type": "load op", "default": "undefined"},
+            {"name": "stencil store op", "type": "store op", "default": "undefined"},
+            {"name": "clear stencil", "type": "uint32_t", "default": "0", "tags": ["deprecated"]},
+            {"name": "stencil clear value", "type": "uint32_t", "default": "0"},
+            {"name": "stencil read only", "type": "bool", "default": "false"}
+        ]
+    },
+
+    "render pass descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "color attachment count", "type": "uint32_t"},
+            {"name": "color attachments", "type": "render pass color attachment", "annotation": "const*", "length": "color attachment count"},
+            {"name": "depth stencil attachment", "type": "render pass depth stencil attachment", "annotation": "const*", "optional": true},
+            {"name": "occlusion query set", "type": "query set", "optional": true},
+            {"name": "timestamp write count", "type": "uint32_t", "default": 0},
+            {"name": "timestamp writes", "type": "render pass timestamp write", "annotation": "const*", "length": "timestamp write count"}
+        ]
+    },
+    "render pass encoder": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set pipeline",
+                "args": [
+                    {"name": "pipeline", "type": "render pipeline"}
+                ]
+            },
+            {
+                "name": "set bind group",
+                "args": [
+                    {"name": "group index", "type": "uint32_t"},
+                    {"name": "group", "type": "bind group"},
+                    {"name": "dynamic offset count", "type": "uint32_t", "default": "0"},
+                    {"name": "dynamic offsets", "type": "uint32_t", "annotation": "const*", "length": "dynamic offset count", "default": "nullptr"}
+                ]
+            },
+            {
+                "name": "draw",
+                "args": [
+                    {"name": "vertex count", "type": "uint32_t"},
+                    {"name": "instance count", "type": "uint32_t", "default": "1"},
+                    {"name": "first vertex", "type": "uint32_t", "default": "0"},
+                    {"name": "first instance", "type": "uint32_t",  "default": "0"}
+                ]
+            },
+            {
+                "name": "draw indexed",
+                "args": [
+                    {"name": "index count", "type": "uint32_t"},
+                    {"name": "instance count", "type": "uint32_t", "default": "1"},
+                    {"name": "first index", "type": "uint32_t", "default": "0"},
+                    {"name": "base vertex", "type": "int32_t", "default": "0"},
+                    {"name": "first instance", "type": "uint32_t", "default": "0"}
+                ]
+            },
+            {
+              "name": "draw indirect",
+              "args": [
+                    {"name": "indirect buffer", "type": "buffer"},
+                    {"name": "indirect offset", "type": "uint64_t"}
+              ]
+            },
+            {
+              "name": "draw indexed indirect",
+              "args": [
+                    {"name": "indirect buffer", "type": "buffer"},
+                    {"name": "indirect offset", "type": "uint64_t"}
+              ]
+            },
+            {
+              "name": "execute bundles",
+              "args": [
+                  {"name": "bundles count", "type": "uint32_t"},
+                  {"name": "bundles", "type": "render bundle", "annotation": "const*", "length": "bundles count"}
+              ]
+            },
+            {
+                "name": "insert debug marker",
+                "args": [
+                    {"name": "marker label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "pop debug group",
+                "args": []
+            },
+            {
+                "name": "push debug group",
+                "args": [
+                    {"name": "group label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "set stencil reference",
+                "args": [
+                    {"name": "reference", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "set blend constant",
+                "args": [
+                    {"name": "color", "type": "color", "annotation": "const*"}
+                ]
+            },
+            {
+                "name": "set viewport",
+                "args": [
+                    {"name": "x", "type": "float"},
+                    {"name": "y", "type": "float"},
+                    {"name": "width", "type": "float"},
+                    {"name": "height", "type": "float"},
+                    {"name": "min depth", "type": "float"},
+                    {"name": "max depth", "type": "float"}
+                ]
+            },
+            {
+                "name": "set scissor rect",
+                "args": [
+                    {"name": "x", "type": "uint32_t"},
+                    {"name": "y", "type": "uint32_t"},
+                    {"name": "width", "type": "uint32_t"},
+                    {"name": "height", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "set vertex buffer",
+                "args": [
+                    {"name": "slot", "type": "uint32_t"},
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "offset", "type": "uint64_t", "default": "0"},
+                    {"name": "size", "type": "uint64_t", "default": "WGPU_WHOLE_SIZE"}
+                ]
+            },
+            {
+                "name": "set index buffer",
+                "args": [
+                    {"name": "buffer", "type": "buffer"},
+                    {"name": "format", "type": "index format"},
+                    {"name": "offset", "type": "uint64_t", "default": "0"},
+                    {"name": "size", "type": "uint64_t", "default": "WGPU_WHOLE_SIZE"}
+                ]
+            },
+            {
+                "name": "begin occlusion query",
+                "args": [
+                    {"name": "query index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "begin pipeline statistics query",
+                "tags": ["upstream", "emscripten"],
+                "args": [
+                    {"name": "query set", "type": "query set"},
+                    {"name": "query index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "end occlusion query"
+            },
+            {
+                "name": "write timestamp",
+                "tags": ["emscripten", "dawn"],
+                "args": [
+                    {"name": "query set", "type": "query set"},
+                    {"name": "query index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "end"
+            },
+            {
+                "name": "end pass",
+                "tags": ["deprecated"]
+            },
+            {
+                "name": "end pipeline statistics query",
+                "tags": ["upstream", "emscripten"]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "render pass timestamp location": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "beginning"},
+            {"value": 1, "name": "end"}
+        ]
+    },
+    "render pass timestamp write": {
+        "category": "structure",
+        "members": [
+            {"name": "query set", "type": "query set"},
+            {"name": "query index", "type": "uint32_t"},
+            {"name": "location", "type": "render pass timestamp location"}
+        ]
+    },
+    "render pipeline": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "get bind group layout",
+                "returns": "bind group layout",
+                "args": [
+                    {"name": "group index", "type": "uint32_t"}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+
+        ]
+    },
+
+    "request device callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "request device status"},
+            {"name": "device", "type": "device"},
+            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+
+    "request device status": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "unknown"}
+        ]
+    },
+
+    "vertex state": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "module", "type": "shader module"},
+            {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "constant count", "type": "uint32_t", "default": 0},
+            {"name": "constants", "type": "constant entry", "annotation": "const*", "length": "constant count"},
+            {"name": "buffer count", "type": "uint32_t", "default": 0},
+            {"name": "buffers", "type": "vertex buffer layout", "annotation": "const*", "length": "buffer count"}
+        ]
+    },
+
+    "primitive state": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "topology", "type": "primitive topology", "default": "triangle list"},
+            {"name": "strip index format", "type": "index format", "default": "undefined"},
+            {"name": "front face", "type": "front face", "default": "CCW"},
+            {"name": "cull mode", "type": "cull mode", "default": "none"}
+        ]
+    },
+
+    "primitive depth clamping state": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn", "emscripten"],
+        "members": [
+            {"name": "clamp depth", "type": "bool", "default": "false"}
+        ]
+    },
+
+    "primitive depth clip control": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["upstream", "emscripten"],
+        "members": [
+            {"name": "unclipped depth", "type": "bool", "default": "false"}
+        ]
+    },
+
+    "depth stencil state": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "format", "type": "texture format"},
+            {"name": "depth write enabled", "type": "bool", "default": "false"},
+            {"name": "depth compare", "type": "compare function", "default": "always"},
+            {"name": "stencil front", "type": "stencil face state"},
+            {"name": "stencil back", "type": "stencil face state"},
+            {"name": "stencil read mask", "type": "uint32_t", "default": "0xFFFFFFFF"},
+            {"name": "stencil write mask", "type": "uint32_t", "default": "0xFFFFFFFF"},
+            {"name": "depth bias", "type": "int32_t", "default": "0"},
+            {"name": "depth bias slope scale", "type": "float", "default": "0.0f"},
+            {"name": "depth bias clamp", "type": "float", "default": "0.0f"}
+        ]
+    },
+
+    "multisample state": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "count", "type": "uint32_t", "default": "1"},
+            {"name": "mask", "type": "uint32_t", "default": "0xFFFFFFFF"},
+            {"name": "alpha to coverage enabled", "type": "bool", "default": "false"}
+        ]
+    },
+
+    "fragment state": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "module", "type": "shader module"},
+            {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "constant count", "type": "uint32_t", "default": 0},
+            {"name": "constants", "type": "constant entry", "annotation": "const*", "length": "constant count"},
+            {"name": "target count", "type": "uint32_t"},
+            {"name": "targets", "type": "color target state", "annotation": "const*", "length": "target count"}
+        ]
+    },
+    "color target state": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "format", "type": "texture format"},
+            {"name": "blend", "type": "blend state", "annotation": "const*", "optional": true},
+            {"name": "write mask", "type": "color write mask", "default": "all"}
+        ]
+    },
+    "blend state": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "color", "type": "blend component"},
+            {"name": "alpha", "type": "blend component"}
+        ]
+    },
+
+    "render pipeline descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "layout", "type": "pipeline layout", "optional": true},
+            {"name": "vertex", "type": "vertex state"},
+            {"name": "primitive", "type": "primitive state"},
+            {"name": "depth stencil", "type": "depth stencil state", "annotation": "const*", "optional": true},
+            {"name": "multisample", "type": "multisample state"},
+            {"name": "fragment", "type": "fragment state", "annotation": "const*", "optional": true}
+        ]
+    },
+
+    "sampler": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "sampler descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "address mode u", "type": "address mode", "default": "clamp to edge"},
+            {"name": "address mode v", "type": "address mode", "default": "clamp to edge"},
+            {"name": "address mode w", "type": "address mode", "default": "clamp to edge"},
+            {"name": "mag filter", "type": "filter mode", "default": "nearest"},
+            {"name": "min filter", "type": "filter mode", "default": "nearest"},
+            {"name": "mipmap filter", "type": "filter mode", "default": "nearest", "tags": ["dawn", "emscripten"]},
+            {"name": "mipmap filter", "type": "mipmap filter mode", "default": "nearest", "tags": ["upstream"]},
+            {"name": "lod min clamp", "type": "float", "default": "0.0f"},
+            {"name": "lod max clamp", "type": "float", "default": "1000.0f"},
+            {"name": "compare", "type": "compare function", "default": "undefined"},
+            {"name": "max anisotropy", "type": "uint16_t", "default": "1"}
+        ]
+    },
+    "shader module": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "get compilation info",
+                "args": [
+                    {"name": "callback", "type": "compilation info callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "shader module descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "hint count", "type": "uint32_t", "default": 0, "tags": ["upstream"]},
+            {"name": "hints", "type": "shader module compilation hint", "annotation": "const*", "length": "hint count", "tags": ["upstream"]}
+        ]
+    },
+    "shader module compilation hint": {
+        "category": "structure",
+        "extensible": "in",
+        "tags": ["upstream"],
+        "members": [
+            {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"},
+            {"name": "layout", "type": "pipeline layout"}
+        ]
+    },
+    "shader module SPIRV descriptor": {
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "code size", "type": "uint32_t"},
+            {"name": "code", "type": "uint32_t", "annotation": "const*", "length": "code size"}
+        ]
+    },
+    "shader module WGSL descriptor": {
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "source", "type": "char", "annotation": "const*", "length": "strlen", "tags": ["dawn", "emscripten"]},
+            {"name": "code", "type": "char", "annotation": "const*", "length": "strlen", "tags": ["upstream"]}
+        ]
+    },
+    "shader stage": {
+        "category": "bitmask",
+        "values": [
+            {"value": 0, "name": "none"},
+            {"value": 1, "name": "vertex"},
+            {"value": 2, "name": "fragment"},
+            {"value": 4, "name": "compute"}
+        ]
+    },
+    "stencil operation": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "keep"},
+            {"value": 1, "name": "zero"},
+            {"value": 2, "name": "replace"},
+            {"value": 3, "name": "invert"},
+            {"value": 4, "name": "increment clamp"},
+            {"value": 5, "name": "decrement clamp"},
+            {"value": 6, "name": "increment wrap"},
+            {"value": 7, "name": "decrement wrap"}
+        ]
+    },
+    "stencil face state": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "compare", "type": "compare function", "default": "always"},
+            {"name": "fail op", "type": "stencil operation", "default": "keep"},
+            {"name": "depth fail op", "type": "stencil operation", "default": "keep"},
+            {"name": "pass op", "type": "stencil operation", "default": "keep"}
+        ]
+    },
+    "surface": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "get preferred format",
+                "returns": "texture format",
+                "tags": ["upstream", "emscripten"],
+                "args": [
+                    {"name": "adapter", "type": "adapter"}
+                ]
+            }
+        ]
+    },
+    "surface descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}
+        ]
+    },
+    "surface descriptor from android native window": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["native"],
+        "members": [
+            {"name": "window", "type": "void", "annotation": "*"}
+        ]
+    },
+    "surface descriptor from canvas HTML selector": {
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "selector", "type": "char", "annotation": "const*", "length": "strlen"}
+        ]
+    },
+    "surface descriptor from metal layer": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["native"],
+        "members": [
+            {"name": "layer", "type": "void", "annotation": "*"}
+        ]
+    },
+    "surface descriptor from windows HWND": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["native"],
+        "members": [
+            {"name": "hinstance", "type": "void", "annotation": "*"},
+            {"name": "hwnd", "type": "void", "annotation": "*"}
+        ]
+    },
+    "surface descriptor from xcb window": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["upstream"],
+        "members": [
+            {"name": "connection", "type": "void", "annotation": "*"},
+            {"name": "window", "type": "uint32_t"}
+        ]
+    },
+    "surface descriptor from xlib window": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["native"],
+        "members": [
+            {"name": "display", "type": "void", "annotation": "*"},
+            {"name": "window", "type": "uint32_t"}
+        ]
+    },
+    "surface descriptor from wayland surface": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["native"],
+        "members": [
+            {"name": "display", "type": "void", "annotation": "*"},
+            {"name": "surface", "type": "void", "annotation": "*"}
+        ]
+    },
+    "surface descriptor from windows core window": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn"],
+        "members": [
+            {"name": "core window", "type": "void", "annotation": "*"}
+        ]
+    },
+    "surface descriptor from windows swap chain panel": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn"],
+        "members": [
+            {"name": "swap chain panel", "type": "void", "annotation": "*"}
+        ]
+    },
+    "swap chain": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "configure",
+                "tags": ["dawn"],
+                "args": [
+                    {"name": "format", "type": "texture format"},
+                    {"name": "allowed usage", "type": "texture usage"},
+                    {"name": "width", "type": "uint32_t"},
+                    {"name": "height", "type": "uint32_t"}
+                ]
+            },
+            {"name": "get current texture view", "returns": "texture view"},
+            {"name": "present"}
+        ]
+    },
+    "swap chain descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "usage", "type": "texture usage"},
+            {"name": "format", "type": "texture format"},
+            {"name": "width", "type": "uint32_t"},
+            {"name": "height", "type": "uint32_t"},
+            {"name": "present mode", "type": "present mode"},
+            {"name": "implementation", "type": "uint64_t", "default": 0, "tags": ["deprecated"]}
+        ]
+    },
+    "s type": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 0, "name": "invalid", "valid": false},
+            {"value": 1, "name": "surface descriptor from metal layer", "tags": ["native"]},
+            {"value": 2, "name": "surface descriptor from windows HWND", "tags": ["native"]},
+            {"value": 3, "name": "surface descriptor from xlib window", "tags": ["native"]},
+            {"value": 4, "name": "surface descriptor from canvas HTML selector"},
+            {"value": 5, "name": "shader module SPIRV descriptor"},
+            {"value": 6, "name": "shader module WGSL descriptor"},
+            {"value": 7, "name": "primitive depth clip control", "tags": ["upstream", "emscripten"]},
+            {"value": 8, "name": "surface descriptor from wayland surface", "tags": ["native"]},
+            {"value": 9, "name": "surface descriptor from android native window", "tags": ["native"]},
+            {"value": 10, "name": "surface descriptor from xcb window", "tags": ["upstream"]},
+            {"value": 11, "name": "surface descriptor from windows core window", "tags": ["dawn"]},
+            {"value": 12, "name": "external texture binding entry", "tags": ["dawn"]},
+            {"value": 13, "name": "external texture binding layout", "tags": ["dawn"]},
+            {"value": 14, "name": "surface descriptor from windows swap chain panel", "tags": ["dawn"]},
+            {"value": 1000, "name": "dawn texture internal usage descriptor", "tags": ["dawn"]},
+            {"value": 1001, "name": "primitive depth clamping state", "tags": ["dawn", "emscripten"]},
+            {"value": 1002, "name": "dawn toggles device descriptor", "tags": ["dawn", "native"]},
+            {"value": 1003, "name": "dawn encoder internal usage descriptor", "tags": ["dawn"]},
+            {"value": 1004, "name": "dawn instance descriptor", "tags": ["dawn", "native"]},
+            {"value": 1005, "name": "dawn cache device descriptor", "tags": ["dawn", "native"]}
+        ]
+    },
+    "texture": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "create view",
+                "returns": "texture view",
+                "args": [
+                    {"name": "descriptor", "type": "texture view descriptor", "annotation": "const*", "optional": true}
+                ]
+            },
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            },
+            {
+                "name": "destroy"
+            }
+        ]
+    },
+    "texture aspect": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "all"},
+            {"value": 1, "name": "stencil only"},
+            {"value": 2, "name": "depth only"},
+            {"value": 3, "name": "plane 0 only", "tags": ["dawn"]},
+            {"value": 4, "name": "plane 1 only", "tags": ["dawn"]}
+        ]
+    },
+    "texture component type": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "float"},
+            {"value": 1, "name": "sint"},
+            {"value": 2, "name": "uint"},
+            {"value": 3, "name": "depth comparison"}
+        ]
+    },
+    "texture data layout": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "offset", "type": "uint64_t", "default": 0},
+            {"name": "bytes per row", "type": "uint32_t", "default": "WGPU_COPY_STRIDE_UNDEFINED"},
+            {"name": "rows per image", "type": "uint32_t", "default": "WGPU_COPY_STRIDE_UNDEFINED"}
+        ]
+    },
+    "texture descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "usage", "type": "texture usage"},
+            {"name": "dimension", "type": "texture dimension", "default": "2D"},
+            {"name": "size", "type": "extent 3D"},
+            {"name": "format", "type": "texture format"},
+            {"name": "mip level count", "type": "uint32_t", "default": 1},
+            {"name": "sample count", "type": "uint32_t", "default": 1},
+            {"name": "view format count", "type": "uint32_t", "default": 0},
+            {"name": "view formats", "type": "texture format", "annotation": "const*", "length": "view format count"}
+        ]
+    },
+    "texture dimension": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "1D"},
+            {"value": 1, "name": "2D"},
+            {"value": 2, "name": "3D"}
+        ]
+    },
+    "texture format": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "valid": false, "jsrepr": "undefined"},
+
+            {"value": 1, "name": "R8 unorm"},
+            {"value": 2, "name": "R8 snorm"},
+            {"value": 3, "name": "R8 uint"},
+            {"value": 4, "name": "R8 sint"},
+
+            {"value": 5, "name": "R16 uint"},
+            {"value": 6, "name": "R16 sint"},
+            {"value": 7, "name": "R16 float"},
+            {"value": 8, "name": "RG8 unorm"},
+            {"value": 9, "name": "RG8 snorm"},
+            {"value": 10, "name": "RG8 uint"},
+            {"value": 11, "name": "RG8 sint"},
+
+            {"value": 12, "name": "R32 float"},
+            {"value": 13, "name": "R32 uint"},
+            {"value": 14, "name": "R32 sint"},
+            {"value": 15, "name": "RG16 uint"},
+            {"value": 16, "name": "RG16 sint"},
+            {"value": 17, "name": "RG16 float"},
+            {"value": 18, "name": "RGBA8 unorm"},
+            {"value": 19, "name": "RGBA8 unorm srgb"},
+            {"value": 20, "name": "RGBA8 snorm"},
+            {"value": 21, "name": "RGBA8 uint"},
+            {"value": 22, "name": "RGBA8 sint"},
+            {"value": 23, "name": "BGRA8 unorm"},
+            {"value": 24, "name": "BGRA8 unorm srgb"},
+            {"value": 25, "name": "RGB10 A2 unorm"},
+            {"value": 26, "name": "RG11 B10 ufloat"},
+            {"value": 27, "name": "RGB9 E5 ufloat"},
+
+            {"value": 28, "name": "RG32 float"},
+            {"value": 29, "name": "RG32 uint"},
+            {"value": 30, "name": "RG32 sint"},
+            {"value": 31, "name": "RGBA16 uint"},
+            {"value": 32, "name": "RGBA16 sint"},
+            {"value": 33, "name": "RGBA16 float"},
+
+            {"value": 34, "name": "RGBA32 float"},
+            {"value": 35, "name": "RGBA32 uint"},
+            {"value": 36, "name": "RGBA32 sint"},
+
+            {"value": 37, "name": "stencil8"},
+            {"value": 38, "name": "depth16 unorm"},
+            {"value": 39, "name": "depth24 plus"},
+            {"value": 40, "name": "depth24 plus stencil8"},
+            {"value": 41, "name": "depth24 unorm stencil8"},
+            {"value": 42, "name": "depth32 float"},
+            {"value": 43, "name": "depth32 float stencil8"},
+
+            {"value": 44, "name": "BC1 RGBA unorm",         "jsrepr": "'bc1-rgba-unorm'"},
+            {"value": 45, "name": "BC1 RGBA unorm srgb",    "jsrepr": "'bc1-rgba-unorm-srgb'"},
+            {"value": 46, "name": "BC2 RGBA unorm",         "jsrepr": "'bc2-rgba-unorm'"},
+            {"value": 47, "name": "BC2 RGBA unorm srgb",    "jsrepr": "'bc2-rgba-unorm-srgb'"},
+            {"value": 48, "name": "BC3 RGBA unorm",         "jsrepr": "'bc3-rgba-unorm'"},
+            {"value": 49, "name": "BC3 RGBA unorm srgb",    "jsrepr": "'bc3-rgba-unorm-srgb'"},
+            {"value": 50, "name": "BC4 R unorm",            "jsrepr": "'bc4-r-unorm'"},
+            {"value": 51, "name": "BC4 R snorm",            "jsrepr": "'bc4-r-snorm'"},
+            {"value": 52, "name": "BC5 RG unorm",           "jsrepr": "'bc5-rg-unorm'"},
+            {"value": 53, "name": "BC5 RG snorm",           "jsrepr": "'bc5-rg-snorm'"},
+            {"value": 54, "name": "BC6H RGB ufloat",        "jsrepr": "'bc6h-rgb-ufloat'"},
+            {"value": 55, "name": "BC6H RGB float",         "jsrepr": "'bc6h-rgb-float'"},
+            {"value": 56, "name": "BC7 RGBA unorm",         "jsrepr": "'bc7-rgba-unorm'"},
+            {"value": 57, "name": "BC7 RGBA unorm srgb",    "jsrepr": "'bc7-rgba-unorm-srgb'"},
+
+            {"value": 58, "name": "ETC2 RGB8 unorm",        "jsrepr": "'etc2-rgb8unorm'"},
+            {"value": 59, "name": "ETC2 RGB8 unorm srgb",   "jsrepr": "'etc2-rgb8unorm-srgb'"},
+            {"value": 60, "name": "ETC2 RGB8A1 unorm",      "jsrepr": "'etc2-rgb8a1unorm'"},
+            {"value": 61, "name": "ETC2 RGB8A1 unorm srgb", "jsrepr": "'etc2-rgb8a1unorm-srgb'"},
+            {"value": 62, "name": "ETC2 RGBA8 unorm",       "jsrepr": "'etc2-rgba8unorm'"},
+            {"value": 63, "name": "ETC2 RGBA8 unorm srgb",  "jsrepr": "'etc2-rgba8unorm-srgb'"},
+            {"value": 64, "name": "EAC R11 unorm",          "jsrepr": "'eac-r11unorm'"},
+            {"value": 65, "name": "EAC R11 snorm",          "jsrepr": "'eac-r11snorm'"},
+            {"value": 66, "name": "EAC RG11 unorm",         "jsrepr": "'eac-rg11unorm'"},
+            {"value": 67, "name": "EAC RG11 snorm",         "jsrepr": "'eac-rg11snorm'"},
+
+            {"value": 68, "name": "ASTC 4x4 unorm",         "jsrepr": "'astc-4x4-unorm'"},
+            {"value": 69, "name": "ASTC 4x4 unorm srgb",    "jsrepr": "'astc-4x4-unorm-srgb'"},
+            {"value": 70, "name": "ASTC 5x4 unorm",         "jsrepr": "'astc-5x4-unorm'"},
+            {"value": 71, "name": "ASTC 5x4 unorm srgb",    "jsrepr": "'astc-5x4-unorm-srgb'"},
+            {"value": 72, "name": "ASTC 5x5 unorm",         "jsrepr": "'astc-5x5-unorm'"},
+            {"value": 73, "name": "ASTC 5x5 unorm srgb",    "jsrepr": "'astc-5x5-unorm-srgb'"},
+            {"value": 74, "name": "ASTC 6x5 unorm",         "jsrepr": "'astc-6x5-unorm'"},
+            {"value": 75, "name": "ASTC 6x5 unorm srgb",    "jsrepr": "'astc-6x5-unorm-srgb'"},
+            {"value": 76, "name": "ASTC 6x6 unorm",         "jsrepr": "'astc-6x6-unorm'"},
+            {"value": 77, "name": "ASTC 6x6 unorm srgb",    "jsrepr": "'astc-6x6-unorm-srgb'"},
+            {"value": 78, "name": "ASTC 8x5 unorm",         "jsrepr": "'astc-8x5-unorm'"},
+            {"value": 79, "name": "ASTC 8x5 unorm srgb",    "jsrepr": "'astc-8x5-unorm-srgb'"},
+            {"value": 80, "name": "ASTC 8x6 unorm",         "jsrepr": "'astc-8x6-unorm'"},
+            {"value": 81, "name": "ASTC 8x6 unorm srgb",    "jsrepr": "'astc-8x6-unorm-srgb'"},
+            {"value": 82, "name": "ASTC 8x8 unorm",         "jsrepr": "'astc-8x8-unorm'"},
+            {"value": 83, "name": "ASTC 8x8 unorm srgb",    "jsrepr": "'astc-8x8-unorm-srgb'"},
+            {"value": 84, "name": "ASTC 10x5 unorm",        "jsrepr": "'astc-10x5-unorm'"},
+            {"value": 85, "name": "ASTC 10x5 unorm srgb",   "jsrepr": "'astc-10x5-unorm-srgb'"},
+            {"value": 86, "name": "ASTC 10x6 unorm",        "jsrepr": "'astc-10x6-unorm'"},
+            {"value": 87, "name": "ASTC 10x6 unorm srgb",   "jsrepr": "'astc-10x6-unorm-srgb'"},
+            {"value": 88, "name": "ASTC 10x8 unorm",        "jsrepr": "'astc-10x8-unorm'"},
+            {"value": 89, "name": "ASTC 10x8 unorm srgb",   "jsrepr": "'astc-10x8-unorm-srgb'"},
+            {"value": 90, "name": "ASTC 10x10 unorm",       "jsrepr": "'astc-10x10-unorm'"},
+            {"value": 91, "name": "ASTC 10x10 unorm srgb",  "jsrepr": "'astc-10x10-unorm-srgb'"},
+            {"value": 92, "name": "ASTC 12x10 unorm",       "jsrepr": "'astc-12x10-unorm'"},
+            {"value": 93, "name": "ASTC 12x10 unorm srgb",  "jsrepr": "'astc-12x10-unorm-srgb'"},
+            {"value": 94, "name": "ASTC 12x12 unorm",       "jsrepr": "'astc-12x12-unorm'"},
+            {"value": 95, "name": "ASTC 12x12 unorm srgb",  "jsrepr": "'astc-12x12-unorm-srgb'"},
+
+            {"value": 96, "name": "R8 BG8 Biplanar 420 unorm", "tags": ["dawn"]}
+        ]
+    },
+    "texture usage": {
+        "category": "bitmask",
+        "values": [
+            {"value": 0, "name": "none"},
+            {"value": 1, "name": "copy src"},
+            {"value": 2, "name": "copy dst"},
+            {"value": 4, "name": "texture binding"},
+            {"value": 8, "name": "storage binding"},
+            {"value": 16, "name": "render attachment"},
+            {"value": 32, "name": "present", "tags": ["dawn"]}
+        ]
+    },
+    "texture view descriptor": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "format", "type": "texture format", "default": "undefined"},
+            {"name": "dimension", "type": "texture view dimension", "default": "undefined"},
+            {"name": "base mip level", "type": "uint32_t", "default": "0"},
+            {"name": "mip level count", "type": "uint32_t", "default": "WGPU_MIP_LEVEL_COUNT_UNDEFINED"},
+            {"name": "base array layer", "type": "uint32_t", "default": "0"},
+            {"name": "array layer count", "type": "uint32_t", "default": "WGPU_ARRAY_LAYER_COUNT_UNDEFINED"},
+            {"name": "aspect", "type": "texture aspect", "default": "all"}
+        ]
+    },
+    "texture view": {
+        "category": "object",
+        "methods": [
+            {
+                "name": "set label",
+                "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
+                "args": [
+                    {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+                ]
+            }
+        ]
+    },
+    "texture view dimension": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "undefined", "valid": false, "jsrepr": "undefined"},
+            {"value": 1, "name": "1D"},
+            {"value": 2, "name": "2D"},
+            {"value": 3, "name": "2D array"},
+            {"value": 4, "name": "cube"},
+            {"value": 5, "name": "cube array"},
+            {"value": 6, "name": "3D"}
+        ]
+    },
+    "vertex format": {
+        "category": "enum",
+        "values": [
+            {"value": 0,  "name": "undefined", "valid": false, "jsrepr": "undefined"},
+            {"value": 1,  "name": "uint8x2"},
+            {"value": 2,  "name": "uint8x4"},
+            {"value": 3,  "name": "sint8x2"},
+            {"value": 4,  "name": "sint8x4"},
+            {"value": 5,  "name": "unorm8x2"},
+            {"value": 6,  "name": "unorm8x4"},
+            {"value": 7,  "name": "snorm8x2"},
+            {"value": 8,  "name": "snorm8x4"},
+            {"value": 9,  "name": "uint16x2"},
+            {"value": 10, "name": "uint16x4"},
+            {"value": 11, "name": "sint16x2"},
+            {"value": 12, "name": "sint16x4"},
+            {"value": 13, "name": "unorm16x2"},
+            {"value": 14, "name": "unorm16x4"},
+            {"value": 15, "name": "snorm16x2"},
+            {"value": 16, "name": "snorm16x4"},
+            {"value": 17, "name": "float16x2"},
+            {"value": 18, "name": "float16x4"},
+            {"value": 19, "name": "float32"},
+            {"value": 20, "name": "float32x2"},
+            {"value": 21, "name": "float32x3"},
+            {"value": 22, "name": "float32x4"},
+            {"value": 23, "name": "uint32"},
+            {"value": 24, "name": "uint32x2"},
+            {"value": 25, "name": "uint32x3"},
+            {"value": 26, "name": "uint32x4"},
+            {"value": 27, "name": "sint32"},
+            {"value": 28, "name": "sint32x2"},
+            {"value": 29, "name": "sint32x3"},
+            {"value": 30, "name": "sint32x4"}
+        ]
+    },
+    "whole size" : {
+        "category": "constant",
+        "type": "uint64_t",
+        "value":  "(0xffffffffffffffffULL)"
+    },
+    "whole map size" : {
+        "category": "constant",
+        "type": "size_t",
+        "value":  "SIZE_MAX"
+    },
+    "stride undefined" : {
+        "category": "constant",
+        "tags": ["deprecated"],
+        "_TODO": "crbug.com/dawn/520: Remove WGPU_STRIDE_UNDEFINED in favor of WGPU_COPY_STRIDE_UNDEFINED.",
+        "type": "uint32_t",
+        "value":  "(0xffffffffUL)"
+    },
+    "copy stride undefined" : {
+        "category": "constant",
+        "type": "uint32_t",
+        "value":  "(0xffffffffUL)"
+    },
+    "limit u32 undefined" : {
+        "category": "constant",
+        "type": "uint32_t",
+        "value":  "(0xffffffffUL)"
+    },
+    "limit u64 undefined" : {
+        "category": "constant",
+        "type": "uint64_t",
+        "value":  "(0xffffffffffffffffULL)"
+    },
+    "array layer count undefined" : {
+        "category": "constant",
+        "type": "uint32_t",
+        "value":  "(0xffffffffUL)"
+    },
+    "mip level count undefined" : {
+        "category": "constant",
+        "type": "uint32_t",
+        "value":  "(0xffffffffUL)"
+    },
+    "ObjectType": {
+      "_comment": "Only used for the wire",
+      "category": "native"
+    },
+    "ObjectId": {
+      "_comment": "Only used for the wire",
+      "category": "native"
+    },
+    "ObjectHandle": {
+      "_comment": "Only used for the wire",
+      "category": "native"
+    },
+    "void": {
+        "category": "native"
+    },
+    "void *": {
+        "category": "native"
+    },
+    "void const *": {
+        "category": "native"
+    },
+    "int32_t": {
+        "category": "native"
+    },
+    "size_t": {
+        "category": "native"
+    },
+    "uint16_t": {
+        "category": "native"
+    },
+    "uint32_t": {
+        "category": "native"
+    },
+    "uint64_t": {
+        "category": "native"
+    },
+    "uint8_t": {
+        "category": "native"
+    },
+    "dawn texture internal usage descriptor": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn"],
+        "members": [
+            {"name": "internal usage", "type": "texture usage", "default": "none"}
+        ]
+    },
+    "dawn encoder internal usage descriptor": {
+        "category": "structure",
+        "chained": "in",
+        "tags": ["dawn"],
+        "members": [
+            {"name": "use internal usages", "type": "bool", "default": "false"}
+        ]
+    }
+}
diff --git a/dawn_wire.json b/dawn_wire.json
new file mode 100644
index 0000000..2e2318e
--- /dev/null
+++ b/dawn_wire.json
@@ -0,0 +1,233 @@
+{
+    "_comment": [
+        "Copyright 2019 The Dawn Authors",
+        "",
+        "Licensed under the Apache License, Version 2.0 (the \"License\");",
+        "you may not use this file except in compliance with the License.",
+        "You may obtain a copy of the License at",
+        "",
+        "    http://www.apache.org/licenses/LICENSE-2.0",
+        "",
+        "Unless required by applicable law or agreed to in writing, software",
+        "distributed under the License is distributed on an \"AS IS\" BASIS,",
+        "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
+        "See the License for the specific language governing permissions and",
+        "limitations under the License."
+    ],
+
+    "_doc": "See docs/dawn/codegen.md",
+
+    "commands": {
+        "buffer map async": [
+            { "name": "buffer id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "mode", "type": "map mode" },
+            { "name": "offset", "type": "uint64_t"},
+            { "name": "size", "type": "uint64_t"}
+        ],
+        "buffer update mapped data": [
+            { "name": "buffer id", "type": "ObjectId" },
+            { "name": "write data update info length", "type": "uint64_t" },
+            { "name": "write data update info", "type": "uint8_t", "annotation": "const*", "length": "write data update info length", "skip_serialize": true},
+            { "name": "offset", "type": "uint64_t"},
+            { "name": "size", "type": "uint64_t"}
+        ],
+        "device create buffer": [
+            { "name": "device id", "type": "ObjectId" },
+            { "name": "descriptor", "type": "buffer descriptor", "annotation": "const*" },
+            { "name": "result", "type": "ObjectHandle", "handle_type": "buffer" },
+            { "name": "read handle create info length", "type": "uint64_t" },
+            { "name": "read handle create info", "type": "uint8_t", "annotation": "const*", "length": "read handle create info length", "skip_serialize": true},
+            { "name": "write handle create info length", "type": "uint64_t" },
+            { "name": "write handle create info", "type": "uint8_t", "annotation": "const*", "length": "write handle create info length", "skip_serialize": true}
+        ],
+        "device create compute pipeline async": [
+            { "name": "device id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "pipeline object handle", "type": "ObjectHandle", "handle_type": "compute pipeline"},
+            { "name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"}
+        ],
+        "device create render pipeline async": [
+            { "name": "device id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "pipeline object handle", "type": "ObjectHandle", "handle_type": "render pipeline"},
+            { "name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"}
+        ],
+        "device pop error scope": [
+            { "name": "device id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" }
+        ],
+        "destroy object": [
+            { "name": "object type", "type": "ObjectType" },
+            { "name": "object id", "type": "ObjectId" }
+        ],
+        "queue on submitted work done": [
+            { "name": "queue id", "type": "ObjectId" },
+            { "name": "signal value", "type": "uint64_t" },
+            { "name": "request serial", "type": "uint64_t" }
+        ],
+        "queue write buffer": [
+            {"name": "queue id", "type": "ObjectId" },
+            {"name": "buffer id", "type": "ObjectId" },
+            {"name": "buffer offset", "type": "uint64_t"},
+            {"name": "data", "type": "uint8_t", "annotation": "const*", "length": "size", "wire_is_data_only": true},
+            {"name": "size", "type": "uint64_t"}
+        ],
+        "queue write texture": [
+            {"name": "queue id", "type": "ObjectId" },
+            {"name": "destination", "type": "image copy texture", "annotation": "const*"},
+            {"name": "data", "type": "uint8_t", "annotation": "const*", "length": "data size", "wire_is_data_only": true},
+            {"name": "data size", "type": "uint64_t"},
+            {"name": "data layout", "type": "texture data layout", "annotation": "const*"},
+            {"name": "writeSize", "type": "extent 3D", "annotation": "const*"}
+        ],
+        "shader module get compilation info": [
+            { "name": "shader module id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" }
+        ],
+        "instance request adapter": [
+            { "name": "instance id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "adapter object handle", "type": "ObjectHandle", "handle_type": "adapter"},
+            { "name": "options", "type": "request adapter options", "annotation": "const*" }
+        ],
+        "adapter request device": [
+            { "name": "adapter id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "device object handle", "type": "ObjectHandle", "handle_type": "device"},
+            { "name": "descriptor", "type": "device descriptor", "annotation": "const*" }
+        ]
+    },
+    "return commands": {
+        "buffer map async callback": [
+            { "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "uint32_t" },
+            { "name": "read data update info length", "type": "uint64_t" },
+            { "name": "read data update info", "type": "uint8_t", "annotation": "const*", "length": "read data update info length", "skip_serialize": true }
+        ],
+        "device create compute pipeline async callback": [
+            { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "create pipeline async status" },
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
+        ],
+        "device create render pipeline async callback": [
+            { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "create pipeline async status" },
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
+        ],
+        "device uncaptured error callback": [
+            { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+            { "name": "type", "type": "error type"},
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
+        ],
+        "device logging callback": [
+            { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+            { "name": "type", "type": "logging type"},
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
+        ],
+        "device lost callback" : [
+            { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+            { "name": "reason", "type": "device lost reason" },
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
+        ],
+        "device pop error scope callback": [
+            { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "type", "type": "error type" },
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
+        ],
+        "queue work done callback": [
+            { "name": "queue", "type": "ObjectHandle", "handle_type": "queue" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "queue work done status" }
+        ],
+        "shader module get compilation info callback": [
+            { "name": "shader module", "type": "ObjectHandle", "handle_type": "shader module" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "compilation info request status" },
+            { "name": "info", "type": "compilation info", "annotation": "const*", "optional": true }
+        ],
+        "instance request adapter callback": [
+            { "name": "instance", "type": "ObjectHandle", "handle_type": "instance" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "request adapter status" },
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true },
+            { "name": "properties", "type": "adapter properties", "annotation": "const*", "optional": "true" },
+            { "name": "limits", "type": "supported limits", "annotation": "const*", "optional": "true" },
+            { "name": "features count", "type": "uint32_t"},
+            { "name": "features", "type": "feature name", "annotation": "const*", "length": "features count"}
+        ],
+        "adapter request device callback": [
+            { "name": "adapter", "type": "ObjectHandle", "handle_type": "adapter" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "request device status" },
+            { "name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true },
+            { "name": "limits", "type": "supported limits", "annotation": "const*", "optional": "true" },
+            { "name": "features count", "type": "uint32_t"},
+            { "name": "features", "type": "feature name", "annotation": "const*", "length": "features count"}
+        ]
+    },
+    "special items": {
+        "client_side_structures": [
+            "SurfaceDescriptorFromMetalLayer",
+            "SurfaceDescriptorFromWindowsHWND",
+            "SurfaceDescriptorFromXlibWindow",
+            "SurfaceDescriptorFromWindowsCoreWindow",
+            "SurfaceDescriptorFromWindowsSwapChainPanel",
+            "SurfaceDescriptorFromAndroidNativeWindow"
+        ],
+        "client_side_commands": [
+            "AdapterCreateDevice",
+            "AdapterGetProperties",
+            "AdapterGetLimits",
+            "AdapterHasFeature",
+            "AdapterEnumerateFeatures",
+            "AdapterRequestDevice",
+            "BufferMapAsync",
+            "BufferGetConstMappedRange",
+            "BufferGetMappedRange",
+            "DeviceCreateBuffer",
+            "DeviceCreateComputePipelineAsync",
+            "DeviceCreateRenderPipelineAsync",
+            "DeviceGetLimits",
+            "DeviceHasFeature",
+            "DeviceEnumerateFeatures",
+            "DevicePopErrorScope",
+            "DeviceSetDeviceLostCallback",
+            "DeviceSetUncapturedErrorCallback",
+            "DeviceSetLoggingCallback",
+            "InstanceRequestAdapter",
+            "ShaderModuleGetCompilationInfo",
+            "QueueOnSubmittedWorkDone",
+            "QueueWriteBuffer",
+            "QueueWriteTexture"
+        ],
+        "client_handwritten_commands": [
+            "BufferDestroy",
+            "BufferUnmap",
+            "DeviceCreateErrorBuffer",
+            "DeviceGetQueue",
+            "DeviceInjectError"
+        ],
+        "client_special_objects": [
+            "Adapter",
+            "Buffer",
+            "Device",
+            "Instance",
+            "Queue",
+            "ShaderModule"
+        ],
+        "server_custom_pre_handler_commands": [
+            "BufferDestroy",
+            "BufferUnmap"
+        ],
+        "server_handwritten_commands": [
+            "QueueSignal"
+        ],
+        "server_reverse_lookup_objects": [
+        ]
+    }
+}
diff --git a/docs/dawn/OWNERS b/docs/dawn/OWNERS
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/docs/dawn/OWNERS
@@ -0,0 +1 @@
+*
diff --git a/docs/dawn/buffer_mapping.md b/docs/dawn/buffer_mapping.md
new file mode 100644
index 0000000..0663f68
--- /dev/null
+++ b/docs/dawn/buffer_mapping.md
@@ -0,0 +1,3 @@
+- Buffer mapping dawn wire memory transfer interface design
+    - https://docs.google.com/document/d/1JOhCpmJ_JyNZJtX6MVbSgxjtG1TdKORdeOGYtSfVYjk/edit?usp=sharing&resourcekey=0-1bFi47mR1jkBLdRFxcTVig
+- TODO: make a md doc targeted at code walkthrough for contributors
diff --git a/docs/dawn/building.md b/docs/dawn/building.md
new file mode 100644
index 0000000..230c222
--- /dev/null
+++ b/docs/dawn/building.md
@@ -0,0 +1,46 @@
+# Building Dawn
+
+## System requirements
+
+- Linux
+  - The `pkg-config` command:
+    ```sh
+    # Install pkg-config on Ubuntu
+    sudo apt-get install pkg-config
+    ```
+
+- Mac
+  - [Xcode](https://developer.apple.com/xcode/) 12.2+.
+  - The macOS 11.0 SDK. Run `xcode-select` to check whether you have it.
+    ```sh
+    ls `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKs
+    ```
+
+## Install `depot_tools`
+
+Dawn uses the Chromium build system and dependency management so you need to [install depot_tools] and add it to the PATH.
+
+[install depot_tools]: http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up
+
+## Get the code
+
+```sh
+# Clone the repo as "dawn"
+git clone https://dawn.googlesource.com/dawn dawn && cd dawn
+
+# Bootstrap the gclient configuration
+cp scripts/standalone.gclient .gclient
+
+# Fetch external dependencies and toolchains with gclient
+gclient sync
+```
+
+## Build Dawn
+
+Then generate build files using `gn args out/Debug` or `gn args out/Release`.
+A text editor will appear asking build options, the most common option is `is_debug=true/false`; otherwise `gn args out/Release --list` shows all the possible options.
+
+On macOS you'll want to add the `use_system_xcode=true` in most cases. (and if you're a googler please get XCode from go/xcode).
+
+Then use `ninja -C out/Release` to build dawn and for example `./out/Release/dawn_end2end_tests` to run the tests.
+
diff --git a/docs/dawn/codegen.md b/docs/dawn/codegen.md
new file mode 100644
index 0000000..b62c449
--- /dev/null
+++ b/docs/dawn/codegen.md
@@ -0,0 +1,112 @@
+# Dawn's code generators.
+
+Dawn relies on a lot of code generation to produce boilerplate code, especially webgpu.h-related code. They start by reading some JSON files (and sometimes XML too), process the data into an in-memory representation that's then used by some [Jinja2](https://jinja.palletsprojects.com/) templates to generate the code. This is similar to the model/view separation in Web development.
+
+Generators are based on [generator_lib.py](../generator/generator_lib.py) which provides facilities for integrating in build systems and using Jinja2. Templates can be found in [`generator/templates`](../generator/templates) and the generated files are in `out/<Debug/Release/foo>/gen/src` when building Dawn in standalone. Generated files can also be found in [Chromium's code search](https://source.chromium.org/chromium/chromium/src/+/master:out/Debug/gen/third_party/dawn/src/).
+
+## Dawn "JSON API" generators
+
+Most of the code generation is done from [`dawn.json`](../dawn.json) which is a JSON description of the WebGPU API with extra annotation used by some of the generators. The code for all the "Dawn JSON" generators is in [`dawn_json_generator.py`](../generator/dawn_json_generator.py) (with templates in the regular template dir).
+
+At this time it is used to generate:
+
+ - the Dawn, Emscripten, and upstream webgpu-native `webgpu.h` C header
+ - the Dawn and Emscripten `webgpu_cpp.cpp/h` C++ wrapper over the C header
+ - libraries that implements `webgpu.h` by calling in a static or `thread_local` proc table
+ - other parts of the [Emscripten](https://emscripten.org/) WebGPU implementation
+ - a GMock version of the API with its proc table for testing
+ - validation helper functions for dawn_native
+ - the definition of dawn_native's proc table
+ - dawn_native's internal version of the webgpu.h types
+ - utilities for working with dawn_native's chained structs
+ - a lot of dawn_wire parts, see below
+
+Internally `dawn.json` is a dictionary from the "canonical name" of things to their definition. The "canonical name" is a space-separated (mostly) lower-case version of the name that's parsed into a `Name` Python object. Then that name can be turned into various casings with `.CamelCase()` `.SNAKE_CASE()`, etc. When `dawn.json` things reference each other, it is always via these "canonical names".
+
+The `"_metadata"` key in the JSON file is used by flexible templates for generating various Web Standard API that contains following metadata:
+
+ - `"api"` a string, the name of the Web API
+ - `"namespace"` a string, the namespace of C++ wrapper
+ - `"c_prefix"` (optional) a string, the prefix of C function and data type, it will default to upper-case of `"namespace"` if it's not provided.
+ - `"proc_table_prefix"` a string, the prefix of proc table.
+ - `"impl_dir"` a string, the directory of API implementation
+ - `"native_namespace"` a string, the namespace of native implementation
+ - `"copyright_year"` (optional) a string, templates will use the year of copyright.
+
+The basic schema is that every entry is a thing with a `"category"` key what determines the sub-schema to apply to that thing. Categories and their sub-shema are defined below. Several parts of the schema use the concept of "record" which is a list of "record members" which are a combination of a type, a name and other metadata. For example the list of arguments of a function is a record. The list of structure members is a record. This combined concept is useful for the dawn_wire generator to generate code for structure and function calls in a very similar way.
+
+Most items and sub-items can include a list of `"tags"`, which, if specified, conditionally includes the item if any of its tags appears in the `enabled_tags` configuration passed to `parse_json`. This is used to include and exclude various items for Dawn, Emscripten, or upstream header variants. Tags are applied in the "parse_json" step ([rather than later](https://docs.google.com/document/d/1fBniVOxx3-hQbxHMugEPcQsaXaKBZYVO8yG9iXJp-fU/edit?usp=sharing)): this has the benefit of automatically catching when, for a particular tag configuration, an included item references an excluded item.
+
+A **record** is a list of **record members**, each of which is a dictionary with the following schema:
+ - `"name"` a string
+ - `"type"` a string, the name of the base type for this member
+ - `"annotation"` a string, default to "value". Define the C annotation to apply to the base type. Allowed annotations are `"value"` (the default), `"*"`, `"const*"`
+ - `"length"` (default to 1 if not set), a string. Defines length of the array pointed to for pointer arguments. If not set the length is implicitly 1 (so not an array), but otherwise it can be set to the name of another member in the same record that will contain the length of the array (this is heavily used in the `fooCount` `foos` pattern in the API). As a special case `"strlen"` can be used for `const char*` record members to denote that the length should be determined with `strlen`.
+ - `"optional"` (default to false) a boolean that says whether this member is optional. Member records can be optional if they are pointers (otherwise dawn_wire will always try to dereference them), objects (otherwise dawn_wire will always try to encode their ID and crash), or if they have a `"default"` key. Optional pointers and objects will always default to `nullptr`.
+ - `"default"` (optional) a number or string. If set the record member will use that value as default value. Depending on the member's category it can be a number, a string containing a number, or the name of an enum/bitmask value.
+ - `"wire_is_data_only"` (default to false) a boolean that says whether it is safe to directly return a pointer of this member that is pointing to a piece of memory in the transfer buffer into dawn_wire. To prevent TOCTOU attacks, by default in dawn_wire we must ensure every single value returned to dawn_native a copy of what's in the wire, so `"wire_is_data_only"` is set to true only when the member is data-only and don't impact control flow.
+
+**`"native"`**, doesn't have any other key. This is used to define native types that can be referenced by name in other things.
+
+**`"typedef"`** (usually only used for gradual deprecations):
+ - `"type"`: the name of the things this is a typedef for.
+
+**`"enum"`** an `uint32_t`-based enum value.
+ - `"values"` an array of enum values. Each value is a dictionary containing:
+   - `"name"` a string
+   - `"value"` a number that can be decimal or hexadecimal
+   - `"jsrepr"` (optional) a string to allow overriding how this value map to Javascript for the Emscripten bits
+   - `"valid"` (defaults to true) a boolean that controls whether the dawn_native validation utilities will consider this enum value valid.
+ - `"emscripten_no_enum_table"` (optional) if true, skips generating an enum table in `library_webgpu_enum_tables.js`
+
+**`"bitmask"`** an `uint32_t`-based bitmask. It is similar to **`"enum"`** but can be output differently.
+
+**`"function pointer"`** defines a function pointer type that can be used by other things.
+ - `"returns"` a string that's the name of the return type
+ - `"args"` a **record**, so an array of **record members**
+
+**`"structure"`**
+ - `"members"` a **record**, so an array of **record members**
+ - `"extensible"` (defaults to false) a boolean defining if this is an "extensible" WebGPU structure (i.e. has `nextInChain`). "descriptor" structures should usually have this set to true.
+ - `"chained"` (defaults to false) a boolean defining if this is a structure that can be "chained" in a WebGPU structure (i.e. has `nextInChain` and `sType`)
+
+**`"object"`**
+ - `**methods**` an array of methods for this object. Note that "release" and "reference" don't need to be specified. Each method is a dictionary containing:
+   - `"name"` a string
+   - `"return_type"` (default to no return type) a string that's the name of the return type.
+   - `"arguments"` a **record**, so an array of **record members**
+
+**`"constant"`**
+ - `"type"`: a string, the name of the base data type
+ - `"value"`: a string, the value is defined with preprocessor macro
+
+**`"function"`** declares a function that not belongs to any class.
+ - `"returns"` a string that's the name of the return type
+ - `"args"` a **record**, so an array of **record members**
+
+## Dawn "wire" generators
+
+The generator for the pieces of dawn_wire need additional data which is found in [`dawn_wire_json`](../dawn_wire.json). Examples of pieces that are generated are:
+
+ - `WireCmd.cpp/.h` the most important piece: the meat of the serialization / deserialization code for WebGPU structures and commands
+ - `ServerHandlers/Doers.cpp` that does the complete handling of all regular WebGPU methods in the server
+ - `ApiProcs.cpp` that implements the complete handling of all regular WebGPU methods in the client
+
+Most of the WebGPU methods can be handled automatically by the wire client/server but some of them need custom handling (for example because they handle callbacks or need client-side state tracking). `dawn_wire.json` defines which methods need special handling, and extra wire commands that can be used by that special handling (and will get `WireCmd` support).
+
+The schema of `dawn_wire.json` is a dictionary with the following keys:
+ - `"commands"` an array of **records** defining extra client->server commands that can be used in special-cased code path.
+   - Each **record member** can have an extra `"skip_serialize"` key that's a boolean that default to false and makes `WireCmd` skip it on its on-wire format.
+ - `"return commands"` like `"commands"` but in revers, an array of **records** defining extra server->client commands
+ - `"special items"` a dictionary containing various lists of methods or object that require special handling in places in the dawn_wire autogenerated files
+   - `"client_side_structures"`: a list of structure that we shouldn't generate serialization/deserialization code for because they are client-side only
+   - `"client_handwritten_commands"`: a list of methods that are written manually and won't be automatically generated in the client
+   - `"client_side_commands"`: a list of methods that won't be automatically generated in the server. Gets added to `"client_handwritten_commands"`
+   - `"client_special_objects"`: a list of objects that need special manual state-tracking in the client and won't be autogenerated
+   - `"server_custom_pre_handler_commands"`: a list of methods that will run custom "pre-handlers" before calling the autogenerated handlers in the server
+   - `"server_handwrittten_commands"`: a list of methods that are written manually and won't be automatically generated in the server.
+   - `server_reverse_object_lookup_objects`: a list of objects for which the server will maintain an object -> ID mapping.
+
+## OpenGL loader generator
+
+The code to load OpenGL entrypoints from a `GetProcAddress` function is generated from [`gl.xml`](../third_party/khronos/gl.xml) and the [list of extensions](../src/dawn/native/opengl/supported_extensions.json) it supports.
diff --git a/docs/dawn/contributing.md b/docs/dawn/contributing.md
new file mode 100644
index 0000000..6fabb37
--- /dev/null
+++ b/docs/dawn/contributing.md
@@ -0,0 +1,122 @@
+# How to contribute to Dawn
+
+First off, we'd love to get your contributions to Dawn!
+
+Everything helps other folks using Dawn and WebGPU: from small fixes and documentation
+improvements to larger features and optimizations.
+Please read on to learn about the contribution process.
+
+## One time setup
+
+### Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution.
+This simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different Google project), you probably don't need to do
+it again.
+
+### Gerrit setup
+
+Dawn's contributions are submitted and reviewed on [Dawn's Gerrit](https://dawn-review.googlesource.com).
+
+Gerrit works a bit differently than Github (if that's what you're used to):
+there are no forks. Instead everyone works on the same repository. Gerrit has
+magic branches for various purpose:
+
+ - `refs/for/<branch>` (most commonly `refs/for/main`) is a branch that anyone
+can push to that will create or update code reviews (called CLs for ChangeList)
+for the commits pushed.
+ - `refs/changes/00/<change number>/<patchset>` is a branch that corresponds to
+the commits that were pushed for codereview for "change number" at a certain
+"patchset" (a new patchset is created each time you push to a CL).
+
+#### Gerrit's .gitcookies
+
+To push commits to Gerrit your `git` command needs to be authenticated. This is
+done with `.gitcookies` that will make `git` send authentication information
+when connecting to the remote. To get the `.gitcookies`, log-in to [Dawn's Gerrit](https://dawn-review.googlesource.com)
+and browse to the [new-password](https://dawn.googlesource.com/new-password)
+page that will give you shell/cmd commands to run to update `.gitcookie`.
+
+#### Set up the commit-msg hook
+
+Gerrit associates commits to CLs based on a `Change-Id:` tag in the commit
+message. Each push with commits with a `Change-Id:` will update the
+corresponding CL.
+
+To add the `commit-msg` hook that will automatically add a `Change-Id:` to your
+commit messages, run the following command:
+
+```
+f=`git rev-parse --git-dir`/hooks/commit-msg ; mkdir -p $(dirname $f) ; curl -Lo $f https://gerrit-review.googlesource.com/tools/hooks/commit-msg ; chmod +x $f
+```
+
+Gerrit helpfully reminds you of that command if you forgot to set up the hook
+before pushing commits.
+
+## The code review process
+
+All submissions, including submissions by project members, require review.
+
+### Discuss the change if needed
+
+Some changes are inherently risky, because they have long-term or architectural
+consequences, contain a lot of unknowns or other reasons. When that's the case
+it is better to discuss it on the [Dawn Matrix Channel](https://matrix.to/#/#webgpu-dawn:matrix.org)
+or the [Dawn mailing-list](https://groups.google.com/g/dawn-graphics/members).
+
+### Pushing changes to code review
+
+Before pushing changes to code review, it is better to run `git cl presubmit`
+that will check the formatting of files and other small things.
+
+Pushing commits is done with `git push origin HEAD:refs/for/main`. Which means
+push to `origin` (i.e. Gerrit) the currently checkout out commit to the
+`refs/for/main` magic branch that creates or updates CLs.
+
+In the terminal you will see a URL where code review for this CL will happen.
+CLs start in the "Work In Progress" state. To start the code review proper,
+click on "Start Review", add reviewers and click "Send and start review". If
+you are unsure which reviewers to use, pick one of the reviewers in the
+[OWNERS file](../OWNERS) who will review or triage the CL.
+
+When code review asks for changes in the commits, you can amend them any way
+you want (small fixup commit and `git rebase -i` are crowd favorites) and run
+the same `git push origin HEAD:refs/for/main` command.
+
+### Tracking issues
+
+We usually like to have commits associated with issues in [Dawn's issue tracker](https://bugs.chromium.org/p/dawn/issues/list)
+so that commits for the issue can all be found on the same page. This is done
+by adding a `Bug: dawn:<issue number>` tag at the end of the commit message. It
+is also possible to reference Chromium or Tint issues with
+`Bug: tint:<issue number>` or `Bug: chromium:<issue number>`.
+
+Some small fixes (like typo fixes, or some one-off maintenance) don't need a
+tracking issue. When that's the case, it's good practice to call it out by
+adding a `Bug: None` tag.
+
+It is possible to make issues fixed automatically when the CL is merged by
+adding a `Fixed: <project>:<issue number>` tag in the commit message.
+
+### Iterating on code review
+
+Dawn follows the general [Google code review guidelines](https://google.github.io/eng-practices/review/).
+Most Dawn changes need reviews from two Dawn committers. Reviewers will set the
+"Code Review" CR+1 or CR+2 label once the change looks good to them (although
+it could still have comments that need to be addressed first). When addressing
+comments, please mark them as "Done" if you just address them, or start a
+discussion until they are resolved.
+
+Once you are granted rights (you can ask on your first contribution), you can
+add the "Commit Queue" CQ+1 label to run the automated tests for Dawn. Once the
+CL has CR+2 you can then add the CQ+2 label to run the automated tests and
+submit the commit if they pass.
+
+The "Auto Submit" AS+1 label can be used to make Gerrit automatically set the
+CQ+2 label once the CR+2 label is added.
diff --git a/docs/dawn/debug_markers.md b/docs/dawn/debug_markers.md
new file mode 100644
index 0000000..d7fd266
--- /dev/null
+++ b/docs/dawn/debug_markers.md
@@ -0,0 +1,50 @@
+# Debug Markers
+
+Dawn provides debug tooling integration for each backend.
+
+Debugging markers are exposed through this API:
+```
+partial GPUProgrammablePassEncoder {
+    void pushDebugGroup(const char * markerLabel);
+    void popDebugGroup();
+    void insertDebugMarker(const char * markerLabel);
+};
+```
+
+These APIs will result in silent no-ops if they are used without setting up
+the execution environment properly. Each backend has a specific process
+for setting up this environment.
+
+## D3D12
+
+Debug markers on D3D12 are implemented with the [PIX Event Runtime](https://blogs.msdn.microsoft.com/pix/winpixeventruntime/).
+
+To enable marker functionality, you must:
+1. Click the download link on https://www.nuget.org/packages/WinPixEventRuntime
+2. Rename the .nupkg file to a .zip extension, then extract its contents.
+3. Copy `bin\WinPixEventRuntime.dll` into the same directory as `libdawn_native.dll`.
+4. Launch your application.
+
+You may now call the debug marker APIs mentioned above and see them from your GPU debugging tool. When using your tool, it is supported to both launch your application with the debugger attached, or attach the debugger while your application is running.
+
+D3D12 debug markers have been tested with [Microsoft PIX](https://devblogs.microsoft.com/pix/) and [Intel Graphics Frame Analyzer](https://software.intel.com/en-us/gpa/graphics-frame-analyzer).
+
+Unfortunately, PIX's UI does does not lend itself to capturing single frame applications like tests. You must enable capture from within your application. To do this in Dawn tests, pass the --begin-capture-on-startup flag to dawn_end2end_tests.exe.
+
+## Vulkan
+
+Debug markers on Vulkan are implemented with [VK_EXT_debug_utils](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_debug_utils.html).
+
+To enable marker functionality, you must launch your application from your debugging tool. Attaching to an already running application is not supported.
+
+Vulkan markers have been tested with [RenderDoc](https://renderdoc.org/).
+
+## Metal
+
+Debug markers on Metal are used with the XCode debugger.
+
+To enable marker functionality, you must launch your application from XCode and use [GPU Frame Capture](https://developer.apple.com/documentation/metal/tools_profiling_and_debugging/metal_gpu_capture).
+
+## OpenGL
+
+Debug markers on OpenGL are not implemented and will result in a silent no-op. This is due to low adoption of the GL_EXT_debug_marker extension in Linux device drivers.
diff --git a/docs/dawn/debugging.md b/docs/dawn/debugging.md
new file mode 100644
index 0000000..740d0b2
--- /dev/null
+++ b/docs/dawn/debugging.md
@@ -0,0 +1,3 @@
+# Debugging Dawn
+
+(TODO)
diff --git a/docs/dawn/device_facilities.md b/docs/dawn/device_facilities.md
new file mode 100644
index 0000000..b625558
--- /dev/null
+++ b/docs/dawn/device_facilities.md
@@ -0,0 +1,106 @@
+# Devices
+
+In Dawn the `Device` is a "god object" that contains a lot of facilities useful for the whole object graph that descends from it.
+There a number of facilities common to all backends that live in the frontend and backend-specific facilities.
+Example of frontend facilities are the management of content-less object caches, or the toggle management.
+Example of backend facilities are GPU memory allocators or the backing API function pointer table.
+
+## Frontend facilities
+
+### Error Handling
+
+Dawn (dawn_native) uses the [Error.h](../src/dawn/native/Error.h) error handling to robustly handle errors.
+With `DAWN_TRY` errors bubble up all the way to, and are "consumed" by the entry-point that was called by the application.
+Error consumption uses `Device::ConsumeError` that expose them via the WebGPU "error scopes" and can also influence the device lifecycle by notifying of a device loss, or triggering a device loss..
+
+See [Error.h](../src/dawn/native/Error.h) for more information about using errors.
+
+### Device Lifecycle
+
+The device lifecycle is a bit more complicated than other objects in Dawn for multiple reasons:
+
+ - The device initialization creates facilities in both the backend and the frontend, which can fail.
+   When a device fails to initialize, it should still be possible to destroy it without crashing.
+ - Execution of commands on the GPU must be finished before the device can be destroyed (because there's noone to "DeleteWhenUnused" the device).
+ - On creation a device might want to run some GPU commands (like initializing zero-buffers), which must be completed before it is destroyed.
+ - A device can become "disconnected" when a TDR or hot-unplug happens.
+   In this case, destruction of the device doesn't need to wait on GPU commands to finish because they just disappeared.
+
+There is a state machine `State` defined in [Device.h](../src/dawn/native/Device.h) that controls all of the above.
+The most common state is `Alive` when there are potentially GPU commands executing.
+
+Initialization of a device looks like the following:
+
+ - `DeviceBase::DeviceBase` is called and does mostly nothing except setting `State` to `BeingCreated` (and initial toggles).
+ - `backend::Device::Initialize` creates things like the underlying device and other stuff that doesn't run GPU commands.
+ - It then calls `DeviceBase::Initialize` that enables the `DeviceBase` facilities and sets the `State` to `Alive`.
+ - Optionally, `backend::Device::Initialize` can now enqueue GPU commands for its initialization.
+ - The device is ready to be used by the application!
+
+While it is `Alive` the device can notify it has been disconnected by the backend, in which case it jumps directly to the `Disconnected` state.
+Internal errors, or a call to `LoseForTesting` can also disconnect the device, but in the underlying API commands are still running, so the frontend will finish all commands (with `WaitForIdleForDesctruction`) and prevent any new commands to be enqueued (by setting state to `BeingDisconnected`).
+After this the device is set in the `Disconnected` state.
+If an `Alive` device is destroyed, then a similar flow to `LoseForTesting happens`.
+
+All this ensures that during destruction or forceful disconnect of the device, it properly gets to the `Disconnected` state with no commands executing on the GPU.
+After disconnecting, frontend will call `backend::Device::DestroyImpl` so that it can properly free driver objects.
+
+### Toggles
+
+Toggles are booleans that control code paths inside of Dawn, like lazy-clearing resources or using D3D12 render passes.
+They aren't just booleans close to the code path they control, because embedders of Dawn like Chromium want to be able to surface what toggles are used by a device (like in about:gpu).
+
+Toogles are to be used for any optional code path in Dawn, including:
+
+ - Workarounds for driver bugs.
+ - Disabling select parts of the validation or robustness.
+ - Enabling limitations that help with testing.
+ - Using more advanced or optional backend API features.
+
+Toggles can be queried using `DeviceBase::IsToggleEnabled`:
+```
+bool useRenderPass = device->IsToggleEnabled(Toggle::UseD3D12RenderPass);
+```
+
+Toggles are defined in a table in [Toggles.cpp](../src/dawn/native/Toggles.cpp) that also includes their name and description.
+The name can be used to force enabling of a toggle or, at the contrary, force the disabling of a toogle.
+This is particularly useful in tests so that the two sides of a code path can be tested (for example using D3D12 render passes and not).
+
+Here's an example of a test that is run in the D3D12 backend both with the D3D12 render passes forcibly disabled, and in the default configuration.
+```
+DAWN_INSTANTIATE_TEST(RenderPassTest,
+                      D3D12Backend(),
+                      D3D12Backend({}, {"use_d3d12_render_pass"}));
+// The {} is the list of force enabled toggles, {"..."} the force disabled ones.
+```
+
+The initialization order of toggles looks as follows:
+
+ - The toggles overrides from the device descriptor are applied.
+ - The frontend device default toggles are applied (unless already overriden).
+ - The backend device default toggles are applied (unless already overriden) using `DeviceBase::SetToggle`
+ - The backend device can ignore overriden toggles if it can't support them by using `DeviceBase::ForceSetToggle`
+
+Forcing toggles should only be done when there is no "safe" option for the toggle.
+This is to avoid crashes during testing when the tests try to use both sides of a toggle.
+For toggles that are safe to enable, like workarounds, the tests can run against the base configuration and with the toggle enabled.
+For toggles that are safe to disable, like using more advanced backing API features, the tests can run against the base configuation and with the toggle disabled.
+
+### Immutable object caches
+
+A number of WebGPU objects are immutable once created, and can be expensive to create, like pipelines.
+`DeviceBase` contains caches for these objects so that they are free to create the second time.
+This is also useful to be able to compare objects by pointers like `BindGroupLayouts` since two BGLs would be equal iff they are the same object.
+
+### Format Tables
+
+The frontend has a `Format` structure that represent all the information that are known about a particular WebGPU format for this Device based on the enabled features.
+Formats are precomputed at device initialization and can be queried from a WebGPU format either assuming the format is a valid enum, or in a safe manner that doesn't do this assumption.
+A reference to these formats can be stored persistently as they have the same lifetime as the `Device`.
+
+Formats also have an "index" so that backends can create parallel tables for internal informations about formats, like what they translate to in the backing API.
+
+### Object factory
+
+Like WebGPU's device object, `DeviceBase` is an factory with methods to create all kinds of other WebGPU objects.
+WebGPU has some objects that aren't created from the device, like the texture view, but in Dawn these creations also go through `DeviceBase` so that there is a single factory for each backend.
diff --git a/docs/dawn/errors.md b/docs/dawn/errors.md
new file mode 100644
index 0000000..9f60ba7
--- /dev/null
+++ b/docs/dawn/errors.md
@@ -0,0 +1,118 @@
+# Dawn Errors
+
+Dawn produces errors for several reasons. The most common is validation errors, indicating that a
+given descriptor, configuration, state, or action is not valid according to the WebGPU spec. Errors
+can also be produced during exceptional circumstances such as the system running out of GPU memory
+or the device being lost.
+
+The messages attached to these errors will frequently be one of the primary tools developers use to
+debug problems their applications, so it is important that the messages Dawn returns are useful.
+
+Following the guidelines in document will help ensure that Dawn's errors are clear, informative, and
+consistent.
+
+## Returning Errors
+
+Since errors are expected to be an exceptional case, it's important that code that produces an error
+doesn't adversely impact the performance of the error-free path. The best way to ensure that is to
+make sure that all errors are returned from within an `if` statement that uses the `DAWN_UNLIKELY()`
+macro to indicate that the expression is not expected to evaluate to true. For example:
+
+```C++
+if (DAWN_UNLIKELY(offset > buffer.size)) {
+  return DAWN_VALIDATION_ERROR("Offset (%u) is larger than the size (%u) of %s."
+    offset, buffer.size, buffer);
+}
+```
+
+To simplify producing validation errors, it's strongly suggested that the `DAWN_INVALID_IF()` macro
+is used, which will wrap the expression in the `DAWN_UNLIKELY()` macro for you:
+
+```C++
+// This is equivalent to the previous example.
+DAWN_INVALID_IF(offset > buffer.size, "Offset (%u) is larger than the size (%u) of %s."
+    offset, buffer.size, buffer);
+```
+
+// TODO: Cover `MaybeError`, `ResultOrError<T>`, `DAWN_TRY(_ASSIGN)`, `DAWN_TRY_CONTEXT`, etc...
+
+## Error message formatting
+
+Errors returned from `DAWN_INVALID_IF()` or `DAWN_VALIDATION_ERROR()` should follow these guidelines:
+
+**Write error messages as complete sentences. (First word capitalized, ends with a period, etc.)**
+ * Example: `Command encoding has already finished.`
+ * Instead of: `encoder finished`
+
+**Error messages should be in the present tense.**
+ * Example: `Buffer is not large enough...`
+ * Instead of: `Buffer was not large enough...`
+
+**When possible any values mentioned should be immediately followed in parentheses by the given value.**
+ * Example: `("Array stride (%u) is not...", stride)`
+ * Output: `Array stride (16) is not...`
+
+**When possible any object or descriptors should be represented by the object formatted as a string.**
+ * Example: `("The %s size (%s) is...", buffer, buffer.size)`
+ * Output: `The [Buffer] size (512) is...` or `The [Buffer "Label"] size (512) is...`
+
+**Enum and bitmask values should be formatted as strings rather than integers or hex values.**
+ * Example: `("The %s format (%s) is...", texture, texture.format)`
+ * Output: `The [Texture "Label"] format (TextureFormat::RGBA8Unorm) is...`
+
+**When possible state both the given value and the expected value or limit.**
+ * Example: `("Offset (%u) is larger than the size (%u) of %s.", offset, buffer.size, buffer)`
+ * Output: `Offset (256) is larger than the size (144) of [Buffer "Label"].`
+
+**State errors in terms of what failed, rather than how to satisfy the rule.**
+ * Example: `Binding size (3) is less than the minimum binding size (32).`
+ * Instead of: `Binding size (3) must not be less than the minimum binding size (32).`
+
+**Don't repeat information given in context.**
+ * See next section for details
+
+## Error Context
+
+When calling functions that perform validation consider if calling `DAWN_TRY_CONTEXT()` rather than
+`DAWN_TRY()` is appropriate. Context messages, when provided, will be appended to any validation
+errors as a type of human readable "callstack". An error with context messages appears will be
+formatted as:
+
+```
+<Primary error message.>
+ - While <context message lvl 2>
+ - While <context message lvl 1>
+ - While <context message lvl 0>
+```
+
+For example, if a validation error occurs while validating the creation of a BindGroup, the message
+may be:
+
+```
+Binding size (256) is larger than the size (80) of [Buffer "View Matrix"].
+ - While validating entries[1] as a Buffer
+ - While validating [BindGroupDescriptor "Frame Bind Group"] against [BindGroupLayout]
+ - While calling CreateBindGroup
+```
+
+// TODO: Guidelines about when to include context
+
+## Context message formatting
+
+Context messages should follow these guidelines:
+
+**Begin with the action being taken, starting with a lower case. `- While ` will be appended by Dawn.**
+ * Example: `("validating primitive state")`
+ * Output: `- While validating primitive state`
+
+**When looping through arrays, indicate the array name and index.**
+ * Example: `("validating buffers[%u]", i)`
+ * Output: `- While validating buffers[2]`
+
+**Indicate which descriptors or objects are being examined in as high-level a context as possible.**
+ * Example: `("validating % against %", descriptor, descriptor->layout)`
+ * Output: `- While validating [BindGroupDescriptor "Label"] against [BindGroupLayout]`
+
+**When possible, indicate the function call being made as the top-level context, as well as the parameters passed.**
+ * Example: `("calling %s.CreatePipelineLayout(%s).", this, descriptor)`
+ * Output: `- While calling [Device].CreatePipelineLayout([PipelineLayoutDescriptor]).`
diff --git a/docs/dawn/external_resources.md b/docs/dawn/external_resources.md
new file mode 100644
index 0000000..91f7a60
--- /dev/null
+++ b/docs/dawn/external_resources.md
@@ -0,0 +1,6 @@
+# Dawn's external resources links
+
+## Design Docs
+
+- Buffer mapping dawn wire memory transfer interface design
+    - https://docs.google.com/document/d/1JOhCpmJ_JyNZJtX6MVbSgxjtG1TdKORdeOGYtSfVYjk/edit?usp=sharing&resourcekey=0-1bFi47mR1jkBLdRFxcTVig
\ No newline at end of file
diff --git a/docs/dawn/features/dawn_internal_usages.md b/docs/dawn/features/dawn_internal_usages.md
new file mode 100644
index 0000000..521a3ac
--- /dev/null
+++ b/docs/dawn/features/dawn_internal_usages.md
@@ -0,0 +1,38 @@
+# Dawn Internal Usages
+
+The `dawn-internal-usages` feature allows adding additional usage which affects how a texture is allocated, but does not affect normal frontend validation.
+
+Adds `WGPUDawnTextureInternalUsageDescriptor` for specifying additional internal usages to create a texture with.
+
+Example Usage:
+```
+wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
+internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
+
+wgpu::TextureDescriptor desc = {};
+// set properties of desc.
+desc.nextInChain = &internalDesc;
+
+device.CreateTexture(&desc);
+```
+
+Adds `WGPUDawnEncoderInternalUsageDescriptor` which may be chained on `WGPUCommandEncoderDescriptor`. Setting `WGPUDawnEncoderInternalUsageDescriptor::useInternalUsages` to `true` means that internal resource usages will be visible during validation. ex.) A texture that has `WGPUTextureUsage_CopySrc` in `WGPUDawnEncoderInternalUsageDescriptor::internalUsage`, but not in `WGPUTextureDescriptor::usage` may be used as the source of a copy command.
+
+
+Example Usage:
+```
+wgpu::DawnEncoderInternalUsageDescriptor internalEncoderDesc = { true };
+wgpu::CommandEncoderDescriptor encoderDesc = {};
+encoderDesc.nextInChain = &internalEncoderDesc;
+
+wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc);
+
+// This will be valid
+wgpu::ImageCopyTexture src = {};
+src.texture = texture;
+encoder.CopyTextureToBuffer(&src, ...);
+```
+
+One use case for this is so that Chromium can use an internal copyTextureToTexture command to implement copies from a WebGPU texture-backed canvas to other Web platform primitives when the swapchain texture was not explicitly created with CopySrc usage in Javascript.
+
+Note: copyTextureToTextureInternal will be removed in favor of `WGPUDawnEncoderInternalUsageDescriptor`.
diff --git a/docs/dawn/features/dawn_native.md b/docs/dawn/features/dawn_native.md
new file mode 100644
index 0000000..0b4664b
--- /dev/null
+++ b/docs/dawn/features/dawn_native.md
@@ -0,0 +1,15 @@
+# Dawn Native
+
+The `dawn-native` feature enables additional functionality that is supported only
+when the WebGPU implementation is `dawn_native`.
+
+Additional functionality:
+ - `wgpu::DawnTogglesDeviceDescriptor` may be chained on `wgpu::DeviceDescriptor` on device creation to enable Dawn-specific toggles on the device.
+
+ - `wgpu::DawnCacheDeviceDescriptor` may be chained on `wgpu::DeviceDescriptor` on device creation to enable cache options such as isolation keys.
+
+ - Synchronous `adapter.CreateDevice(const wgpu::DeviceDescriptor*)` may be called.
+
+Notes:
+ - Enabling this feature in the `wgpu::DeviceDescriptor` does nothing, but
+its presence in the Adapter's set of supported features means that the additional functionality is supported.
diff --git a/docs/dawn/fuzzing.md b/docs/dawn/fuzzing.md
new file mode 100644
index 0000000..8521901
--- /dev/null
+++ b/docs/dawn/fuzzing.md
@@ -0,0 +1,18 @@
+# Fuzzing Dawn
+
+## `dawn_wire_server_and_frontend_fuzzer`
+
+The `dawn_wire_server_and_frontend_fuzzer` sets up Dawn using the Null backend, and passes inputs to the wire server. This fuzzes the `dawn_wire` deserialization, as well as Dawn's frontend validation.
+
+## `dawn_wire_server_and_vulkan_backend_fuzzer`
+
+The `dawn_wire_server_and_vulkan_backend_fuzzer` is like `dawn_wire_server_and_frontend_fuzzer` but it runs using a Vulkan CPU backend such as Swiftshader. This fuzzer supports error injection by using the first bytes of the fuzzing input as a Vulkan call index for which to mock a failure.
+
+## Automatic Seed Corpus Generation
+
+Using a seed corpus significantly improves the efficiency of fuzzing. Dawn's fuzzers use interesting testcases discovered in previous fuzzing runs to seed future runs. Fuzzing can be further improved by using Dawn tests as a example of API usage which allows the fuzzer to quickly discover and use new API entrypoints and usage patterns.
+
+Dawn has a CI builder [cron-linux-clang-rel-x64](https://ci.chromium.org/p/dawn/builders/ci/cron-linux-clang-rel-x64) which runs on a periodic schedule. This bot runs the `dawn_end2end_tests` and `dawn_unittests` using the wire and writes out traces of the commands. This can manually be done by running: `<test_binary> --use-wire --wire-trace-dir=tmp_dir`. The output directory will contain one trace for each test, where the traces are prepended with `0xFFFFFFFFFFFFFFFF`. The header is the callsite index at which the error injector should inject an error. If the fuzzer doesn't support error injection it will skip the header. [cron-linux-clang-rel-x64] then hashes the output files to produce unique names and uploads them to the fuzzer corpus directories.
+Please see the `dawn.py`[https://source.chromium.org/chromium/chromium/tools/build/+/master:recipes/recipes/dawn.py] recipe for specific details.
+
+Regenerating the seed corpus keeps it up to date when Dawn's API or wire protocol changes.
\ No newline at end of file
diff --git a/docs/dawn/infra.md b/docs/dawn/infra.md
new file mode 100644
index 0000000..605d9ca
--- /dev/null
+++ b/docs/dawn/infra.md
@@ -0,0 +1,92 @@
+# Dawn's Continuous Testing Infrastructure
+
+Dawn uses Chromium's continuous integration (CI) infrastructure to continually run tests on changes to Dawn and provide a way for developers to run tests against their changes before submitting. CI bots continually build and run tests for every new change, and Try bots build and run developers' pending changes before submission. Dawn uses two different build recipes. There is a Dawn build recipe which checks out Dawn standalone, compiles, and runs the `dawn_unittests`. And, there is the Chromium build recipe which checks out Dawn inside a Chromium checkout. Inside a Chromium checkout, there is more infrastructure available for triggering `dawn_end2end_tests` that run on real GPU hardware, and we are able to run Chromium integration tests as well as tests for WebGPU.
+
+ - [Dawn CI Builders](https://ci.chromium.org/p/dawn/g/ci/builders)
+ - [Dawn Try Builders](https://ci.chromium.org/p/dawn/g/try/builders)
+ - [chromium.dawn Waterfall](https://ci.chromium.org/p/chromium/g/chromium.dawn/console)
+
+For additional information on GPU testing in Chromium, please see [[chromium/src]//docs/gpu/gpu_testing_bot_details.md](https://chromium.googlesource.com/chromium/src.git/+/master/docs/gpu/gpu_testing_bot_details.md).
+
+## Dawn CI/Try Builders
+Dawn builders are specified in [[dawn]//infra/config/global/cr-buildbucket.cfg](../infra/config/global/cr-buildbucket.cfg). This file contains a few mixins such as `clang`, `no_clang`, `x64`, `x86`, `debug`, `release` which are used to specify the bot dimensions and build properties (builder_mixins.recipe.properties). At the time of writing, we have the following builders:
+  - [dawn/try/presubmit](https://ci.chromium.org/p/dawn/builders/try/presubmit)
+  - [dawn/try/linux-clang-dbg-x64](https://ci.chromium.org/p/dawn/builders/try/linux-clang-dbg-x64)
+  - [dawn/try/linux-clang-dbg-x86](https://ci.chromium.org/p/dawn/builders/try/linux-clang-dbg-x86)
+  - [dawn/try/linux-clang-rel-x64](https://ci.chromium.org/p/dawn/builders/try/linux-clang-rel-x64)
+  - [dawn/try/mac-dbg](https://ci.chromium.org/p/dawn/builders/try/mac-dbg)
+  - [dawn/try/mac-rel](https://ci.chromium.org/p/dawn/builders/try/mac-rel)
+  - [dawn/try/win-clang-dbg-x86](https://ci.chromium.org/p/dawn/builders/try/win-clang-dbg-x86)
+  - [dawn/try/win-clang-rel-x64](https://ci.chromium.org/p/dawn/builders/try/win-clang-rel-x64)
+  - [dawn/try/win-msvc-dbg-x86](https://ci.chromium.org/p/dawn/builders/try/win-msvc-dbg-x86)
+  - [dawn/try/win-msvc-rel-x64](https://ci.chromium.org/p/dawn/builders/try/win-msvc-rel-x64)
+
+There are additional `chromium/try` builders, but those are described later in this document.
+
+These bots are defined in both buckets luci.dawn.ci and luci.dawn.try, though their ACL permissions differ. luci.dawn.ci bots will be scheduled regularly based on [[dawn]//infra/config/global/luci-scheduler.cfg](../infra/config/global/luci-scheduler.cfg). luci.dawn.try bots will be triggered on the CQ based on [[dawn]//infra/config/global/commit-queue.cfg](../infra/config/global/commit-queue.cfg).
+
+One particular note is `buckets.swarming.builder_defaults.recipe.name: "dawn"` which specifies these use the [`dawn.py`](https://source.chromium.org/search/?q=file:recipes/dawn.py) build recipe.
+
+Build status for both CI and Try builders can be seen at this [console](https://ci.chromium.org/p/dawn) which is generated from [[dawn]//infra/config/global/luci-milo.cfg](../infra/config/global/luci-milo.cfg).
+
+## Dawn Build Recipe
+The [`dawn.py`](https://cs.chromium.org/search/?q=file:recipes/dawn.py) build recipe is simple and intended only for testing compilation and unit tests. It does the following:
+  1. Checks out Dawn standalone and dependencies
+  2. Builds based on the `builder_mixins.recipe.properties` coming from the builder config in [[dawn]//infra/config/global/cr-buildbucket.cfg](../infra/config/global/cr-buildbucket.cfg).
+  3. Runs the `dawn_unittests` on that same bot.
+
+## Dawn Chromium-Based CI Waterfall Bots
+The [`chromium.dawn`](https://ci.chromium.org/p/chromium/g/chromium.dawn/console) waterfall consists of the bots specified in the `chromium.dawn` section of [[chromium/src]//testing/buildbot/waterfalls.pyl](https://source.chromium.org/search/?q=file:waterfalls.pyl%20chromium.dawn). Bots named "Builder" are responsible for building top-of-tree Dawn, whereas bots named "DEPS Builder" are responsible for building Chromium's DEPS version of Dawn.
+
+The other bots, such as "Dawn Linux x64 DEPS Release (Intel HD 630)" receive the build products from the Builders and are responsible for running tests. The Tester configuration may specify `mixins` from [[chromium/src]//testing/buildbot/mixins.pyl](https://source.chromium.org/search/?q=file:buildbot/mixins.pyl) which help specify bot test dimensions like OS version and GPU vendor. The Tester configuration also specifies `test_suites` from [[chromium/src]//testing/buildbot/test_suites.pyl](https://source.chromium.org/search/?q=file:buildbot/test_suites.pyl%20dawn_end2end_tests) which declare the tests are arguments passed to tests that should be run on the bot.
+
+The Builder and Tester bots are additionally configured at [[chromium/tools/build]//scripts/slave/recipe_modules/chromium_tests/chromium_dawn.py](https://source.chromium.org/search?q=file:chromium_dawn.py) which defines the bot specs for the builders and testers. Some things to note:
+ - The Tester bots set `parent_buildername` to be their respective Builder bot.
+ - The non DEPS bots use the `dawn_top_of_tree` config.
+ - The bots apply the `mb` config which references [[chromium]//tools/mb/mb_config.pyl](https://source.chromium.org/search?q=file:mb_config.pyl%20%22Dawn%20Linux%20x64%20Builder%22) and [[chromium]//tools/mb/mb_config_buckets.pyl](https://source.chromium.org/search?q=file:mb_config_buckets.pyl%20%22Dawn%20Linux%20x64%20Builder%22). Various mixins there specify build dimensions like debug, release, gn args, x86, x64, etc.
+
+Finally, builds on these waterfall bots are automatically scheduled based on the configuration in [[chromium/src]//infra/config/buckets/ci.star](https://source.chromium.org/search?q=file:ci.star%20%22Dawn%20Linux%20x64%20Builder%22). Note that the Tester bots are `triggered_by` the Builder bots.
+
+## Dawn Chromium-Based Tryjobs
+[[dawn]//infra/config/global/commit-queue.cfg](../infra/config/global/commit-queue.cfg) declares additional tryjob builders which are defined in the Chromium workspace. The reason for this separation is that jobs sent to these bots rely on the Chromium infrastructure for doing builds and triggering jobs on bots with GPU hardware in swarming.
+
+At the time of writing, the bots for Dawn CLs are:
+  - [chromium/try/linux-dawn-rel](https://ci.chromium.org/p/chromium/builders/try/linux-dawn-rel)
+  - [chromium/try/mac-dawn-rel](https://ci.chromium.org/p/chromium/builders/try/mac-dawn-rel)
+  - [chromium/try/win-dawn-rel](https://ci.chromium.org/p/chromium/builders/try/win-dawn-rel)
+
+And for Chromium CLs:
+  - [chromium/try/dawn-linux-x64-deps-rel](https://ci.chromium.org/p/chromium/builders/try/dawn-linux-x64-deps-rel)
+  - [chromium/try/dawn-mac-x64-deps-rel](https://ci.chromium.org/p/chromium/builders/try/dawn-mac-x64-deps-rel)
+  - [chromium/try/dawn-win10-x86-deps-rel](https://ci.chromium.org/p/chromium/builders/try/dawn-win10-x86-deps-rel)
+  - [chromium/try/dawn-win10-x64-deps-rel](https://ci.chromium.org/p/chromium/builders/try/dawn-win10-x64-deps-rel)
+
+ The configuration for these bots is generated from [[chromium]//infra/config/buckets/try.star](https://source.chromium.org/search/?q=file:try.star%20linux-dawn-rel) which uses the [`chromium_dawn_builder`](https://source.chromium.org/search/?q=%22def%20chromium_dawn_builder%22) function which sets the `mastername` to `tryserver.chromium.dawn`.
+
+[[chromium/tools/build]//scripts/slave/recipe_modules/chromium_tests/trybots.py](https://source.chromium.org/search/?q=file:trybots.py%20tryserver.chromium.dawn) specifies `tryserver.chromium.dawn` bots as mirroring bots from the `chromium.dawn` waterfall. Example:
+```
+'dawn-linux-x64-deps-rel': {
+    'bot_ids': [
+        {
+            'mastername': 'chromium.dawn',
+            'buildername': 'Dawn Linux x64 DEPS Builder',
+            'tester': 'Dawn Linux x64 DEPS Release (Intel HD 630)',
+        },
+        {
+            'mastername': 'chromium.dawn',
+            'buildername': 'Dawn Linux x64 DEPS Builder',
+            'tester': 'Dawn Linux x64 DEPS Release (NVIDIA)',
+        },
+    ],
+},
+```
+
+Using the [[chromium/tools/build]//scripts/slave/recipes/chromium_trybot.py](https://source.chromium.org/search/?q=file:chromium_trybot.py) recipe, these trybots will cherry-pick a CL and run the same tests as the CI waterfall bots. The trybots also pick up some build mixins from [[chromium]//tools/mb/mb_config.pyl](https://source.chromium.org/search?q=file:mb_config.pyl%20dawn-linux-x64-deps-rel).
+
+## Bot Allocation
+
+Bots are physically allocated based on the configuration in [[chromium/infradata/config]//configs/chromium-swarm/starlark/bots/dawn.star](https://chrome-internal.googlesource.com/infradata/config/+/refs/heads/master/configs/chromium-swarm/starlark/bots/dawn.star) (Google only).
+
+`dawn/try` bots are using builderless configurations which means they use builderless GCEs shared with Chromium bots and don't need explicit allocation.
+
+`chromium/try` bots are still explicitly allocated with a number of GCE instances and lifetime of the build cache. All of the GCE bots should eventually be migrated to builderless (crbug.com/dawn/328). Mac bots such as `dawn-mac-x64-deps-rel`, `mac-dawn-rel`, `Dawn Mac x64 Builder`, and `Dawn Mac x64 DEPS Builder` point to specific ranges of machines that have been reserved by the infrastructure team.
diff --git a/docs/dawn/overview.md b/docs/dawn/overview.md
new file mode 100644
index 0000000..acb3848
--- /dev/null
+++ b/docs/dawn/overview.md
@@ -0,0 +1,54 @@
+# Dawn repository overview
+
+This repository contains the implementation of Dawn, which is itself composed of two main libraries (dawn_native and dawn_wire), along with support libraries, tests, and samples. Dawn makes heavy use of code-generation based on the `dawn.json` file that describes the native WebGPU API. It is used to generate the API headers, C++ wrapper, parts of the client-server implementation, and more!
+
+## Directory structure
+
+- [`dawn.json`](../dawn.json): contains a description of the native WebGPU in JSON form. It is the data model that's used by the code generators.
+- [`dawn_wire.json`](../dawn_wire.json): contains additional information used to generate `dawn_wire` files, such as commands in addition to regular WebGPU commands.
+- [`examples`](../examples): a small collection of samples using the native WebGPU API. They were mostly used when bringing up Dawn for the first time, and to test the `WGPUSwapChain` object.
+- [`generator`](../generator): directory containg the code generators and their templates. Generators are based on Jinja2 and parse data-models from JSON files.
+    - [`dawn_json_generator.py`](../generator/dawn_json_generator.py): the main code generator that outputs the WebGPU headers, C++ wrapper, client-server implementation, etc.
+    - [`templates`](../generator/templates): Jinja2 templates for the generator, with subdirectories for groups of templates that are all used in the same library.
+- [`infra`](../infra): configuration file for the commit-queue infrastructure.
+- [`scripts`](../scripts): contains a grab-bag of files that are used for building Dawn, in testing, etc.
+- [`src`](../src):
+  - [`dawn`](../src/dawn): root directory for Dawn code
+      - [`common`](../src/dawn/common): helper code that is allowed to be used by Dawn's core libraries, `dawn_native` and `dawn_wire`. Also allowed for use in all other Dawn targets.
+      - [`fuzzers`](../src/dawn/fuzzers): various fuzzers for Dawn that are running in [Clusterfuzz](https://google.github.io/clusterfuzz/).
+      - [`native`](../src/dawn/native): code for the implementation of WebGPU on top of graphics APIs. Files in this folder are the "frontend" while subdirectories are "backends".
+         - `<backend>`: code for the implementation of the backend on a specific graphics API, for example `d3d12`, `metal` or `vulkan`.
+      - [`tests`](../src/dawn/tests):
+        - [`end2end`](../src/dawn/tests/end2end): tests for the execution of the WebGPU API and require a GPU to run.
+        - [`perf_tests`](../src/dawn/tests/perf_tests): benchmarks for various aspects of Dawn.
+        - [`unittests`](../src/dawn/tests/unittests): code unittests of internal classes, but also by extension WebGPU API tests that don't require a GPU to run.
+          - [`validation`](../src/dawn/tests/unittests/validation): WebGPU validation tests not using the GPU (frontend tests)
+        - [`white_box`](../src/dawn/tests/white_box): tests using the GPU that need to access the internals of `dawn_native` or `dawn_wire`.
+      - [`wire`](../src/dawn/wire): code for an implementation of WebGPU as a client-server architecture.
+      - [`utils`](../src/dawn/utils): helper code to use Dawn used by tests and samples but disallowed for `dawn_native` and `dawn_wire`.
+      - [`platform`](../src/dawn/platform): definition of interfaces for dependency injection in `dawn_native` or `dawn_wire`.
+  - [`include`](../src/include): public headers with subdirectories for each library. Note that some headers are auto-generated and not present directly in the directory.
+- [`third_party`](../third_party): directory where dependencies live as well as their buildfiles.
+
+## Dawn Native (`dawn_native`)
+
+The largest library in Dawn is `dawn_native` which implements the WebGPU API by translating to native graphics APIs such as D3D12, Metal or Vulkan. It is composed of a frontend that does all the state-tracking and validation, and backends that do the actual translation to the native graphics APIs.
+
+`dawn_native` hosts the [spirv-val](https://github.com/KhronosGroup/SPIRV-Tools) for validation of SPIR-V shaders and uses [Tint](https://dawn.googlesource.com/tint/) shader translator to convert WGSL shaders to an equivalent shader for use in the native graphics API (HLSL for D3D12, MSL for Metal or Vulkan SPIR-V for Vulkan).
+
+## Dawn Wire (`dawn_wire`)
+
+A second library that implements both a client that takes WebGPU commands and serializes them into a buffer, and a server that deserializes commands from a buffer, validates they are well-formed and calls the relevant WebGPU commands. Some server to client communication also happens so the API's callbacks work properly.
+
+Note that `dawn_wire` is meant to do as little state-tracking as possible so that the client can be lean and defer most of the heavy processing to the server side where the server calls into `dawn_native`.
+
+## Dawn Proc (`dawn_proc`)
+
+Normally libraries implementing `webgpu.h` should implement function like `wgpuDeviceCreateBuffer` but instead `dawn_native` and `dawn_wire` implement the `dawnProcTable` which is a structure containing all the WebGPU functions Dawn implements. Then a `dawn_proc` library contains a static version of this `dawnProcTable` and for example forwards `wgpuDeviceCreateBuffer` to the `procTable.deviceCreateBuffer` function pointer. This is useful in two ways:
+
+ - It allows deciding at runtime whether to use `dawn_native` and `dawn_wire`, which is useful to test boths paths with the same binary in our infrastructure.
+ - It avoids applications that know they will only use Dawn to query all entrypoints at once instead of using `wgpuGetProcAddress` repeatedly.
+
+## Code generation
+
+When the WebGPU API evolves, a lot of places in Dawn have to be updated, so to reduce efforts, Dawn relies heavily on code generation for things like headers, proc tables and de/serialization. For more information, see [codegen.md](codegen.md).
diff --git a/docs/dawn/testing.md b/docs/dawn/testing.md
new file mode 100644
index 0000000..749736b
--- /dev/null
+++ b/docs/dawn/testing.md
@@ -0,0 +1,69 @@
+# Testing Dawn
+
+(TODO)
+
+## Dawn Perf Tests
+
+For benchmarking with `dawn_perf_tests`, it's best to build inside a Chromium checkout using the following GN args:
+```
+is_official_build = true  # Enables highest optimization level, using LTO on some platforms
+use_dawn = true           # Required to build Dawn
+use_cfi_icall=false       # Required because Dawn dynamically loads function pointers, and we don't sanitize them yet.
+```
+
+A Chromium checkout is required for the highest optimization flags. It is possible to build and run `dawn_perf_tests` from a standalone Dawn checkout as well, only using GN arg `is_debug=false`. For more information on building, please see [building.md](./building.md).
+
+### Terminology
+
+ - Iteration: The unit of work being measured. It could be a frame, a draw call, a data upload, a computation, etc. `dawn_perf_tests` metrics are reported as time per iteration.
+ - Step: A group of Iterations run together. The number of `iterationsPerStep` is provided to the constructor of `DawnPerfTestBase`.
+ - Trial: A group of Steps run consecutively. `kNumTrials` are run for each test. A Step in a Trial is run repetitively for approximately `kCalibrationRunTimeSeconds`. Metrics are accumlated per-trial and reported as the total time divided by `numSteps * iterationsPerStep`. `maxStepsInFlight` is passed to the `DawnPerfTestsBase` constructor to limit the number of Steps pipelined.
+
+(See [`//src/dawn/tests/perf_tests/DawnPerfTest.h`](https://cs.chromium.org/chromium/src/third_party/dawn/src/dawn/tests/perf_tests/DawnPerfTest.h) for the values of the constants).
+
+### Metrics
+
+`dawn_perf_tests` measures the following metrics:
+ - `wall_time`: The time per iteration, including time waiting for the GPU between Steps in a Trial.
+ - `cpu_time`: The time per iteration, not including time waiting for the GPU between Steps in a Trial.
+ - `validation_time`: The time for CommandBuffer / RenderBundle validation.
+ - `recording_time`: The time to convert Dawn commands to native commands.
+
+Metrics are reported according to the format specified at
+[[chromium]//build/scripts/slave/performance_log_processor.py](https://cs.chromium.org/chromium/build/scripts/slave/performance_log_processor.py)
+
+### Dumping Trace Files
+
+The test harness supports a `--trace-file=path/to/trace.json` argument where Dawn trace events can be dumped. The traces can be viewed in Chrome's `about://tracing` viewer.
+
+### Test Runner
+
+[`//scripts/perf_test_runner.py`](https://cs.chromium.org/chromium/src/third_party/dawn/scripts/perf_test_runner.py) may be run to continuously run a test and report mean times and variances.
+
+Currently the script looks in the `out/Release` build directory and measures the `wall_time` metric (hardcoded into the script). These should eventually become arguments.
+
+Example usage:
+
+```
+scripts/perf_test_runner.py DrawCallPerf.Run/Vulkan__e_skip_validation
+```
+
+### Tests
+
+**BufferUploadPerf**
+
+Tests repetitively uploading data to the GPU using either `WriteBuffer` or `CreateBuffer` with `mappedAtCreation = true`.
+
+**DrawCallPerf**
+
+DrawCallPerf tests drawing a simple triangle with many ways of encoding commands,
+binding, and uploading data to the GPU. The rationale for this is the following:
+  - Static/Multiple/Dynamic vertex buffers: Tests switching buffer bindings. This has
+    a state tracking cost as well as a GPU driver cost.
+  - Static/Multiple/Dynamic bind groups: Same rationale as vertex buffers
+  - Static/Dynamic pipelines: In addition to a change to GPU state, changing the pipeline
+    layout incurs additional state tracking costs in Dawn.
+  - With/Without render bundles: All of the above can have lower validation costs if
+    precomputed in a render bundle.
+  - Static/Dynamic data: Updating data for each draw is a common use case. It also tests
+    the efficiency of resource transitions.
diff --git a/docs/imgs/README.md b/docs/imgs/README.md
new file mode 100644
index 0000000..60f42f4
--- /dev/null
+++ b/docs/imgs/README.md
@@ -0,0 +1 @@
+Dawn's logo and derivatives found in this folder are under the [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/) license.
diff --git a/docs/imgs/dawn_logo.png b/docs/imgs/dawn_logo.png
new file mode 100644
index 0000000..a7d40cb
--- /dev/null
+++ b/docs/imgs/dawn_logo.png
Binary files differ
diff --git a/docs/imgs/dawn_logo.svg b/docs/imgs/dawn_logo.svg
new file mode 100644
index 0000000..034aad2
--- /dev/null
+++ b/docs/imgs/dawn_logo.svg
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="768"
+   height="768"
+   viewBox="0 0 768 768"
+   fill="none"
+   version="1.1"
+   id="svg47"
+   sodipodi:docname="dawn_logo.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs51" />
+  <sodipodi:namedview
+     id="namedview49"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="true"
+     showgrid="false"
+     inkscape:zoom="1.6830615"
+     inkscape:cx="187.15894"
+     inkscape:cy="384.41852"
+     inkscape:window-width="3840"
+     inkscape:window-height="2066"
+     inkscape:window-x="-11"
+     inkscape:window-y="-11"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg47" />
+  <circle
+     cx="309"
+     cy="214"
+     r="121"
+     fill="#FDE293"
+     id="circle33" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M429.5 126L670.255 543L188.745 543L429.5 126Z"
+     fill="#005A9C"
+     id="path35" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M429.5 543L550 335L309 335L429.5 543Z"
+     fill="#0066B0"
+     id="path37" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M308.5 335L369 439L248 439L308.5 335Z"
+     fill="#0086E8"
+     id="path39" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M308.5 543L369 439L248 439L308.5 543Z"
+     fill="#0093FF"
+     id="path41" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M217.5 335L338 543L97 543L217.5 335Z"
+     fill="#0076CC"
+     id="path43" />
+  <path
+     d="M210.52 682V578.896H241.624C252.376 578.896 261.64 581.104 269.416 585.52C277.192 589.84 283.192 595.888 287.416 603.664C291.64 611.44 293.752 620.368 293.752 630.448C293.752 640.528 291.64 649.456 287.416 657.232C283.192 664.912 277.192 670.96 269.416 675.376C261.64 679.792 252.376 682 241.624 682H210.52ZM222.76 670.336H241.624C249.688 670.336 256.696 668.8 262.648 665.728C268.6 662.56 273.208 658 276.472 652.048C279.736 646.096 281.368 638.896 281.368 630.448C281.368 622 279.736 614.8 276.472 608.848C273.208 602.896 268.6 598.384 262.648 595.312C256.696 592.144 249.688 590.56 241.624 590.56H222.76V670.336ZM332.794 684.304C327.322 684.304 322.522 683.248 318.394 681.136C314.266 679.024 311.002 676.144 308.602 672.496C306.298 668.752 305.146 664.528 305.146 659.824C305.146 654.448 306.538 649.936 309.322 646.288C312.106 642.544 315.85 639.76 320.554 637.936C325.258 636.016 330.442 635.056 336.106 635.056C341.002 635.056 345.322 635.584 349.066 636.64C352.81 637.696 355.498 638.752 357.13 639.808V635.344C357.13 629.776 355.162 625.36 351.226 622.096C347.29 618.832 342.49 617.2 336.826 617.2C332.794 617.2 329.002 618.112 325.45 619.936C321.994 621.664 319.258 624.112 317.242 627.28L308.026 620.368C310.906 616.048 314.842 612.64 319.834 610.144C324.922 607.552 330.586 606.256 336.826 606.256C346.81 606.256 354.634 608.896 360.298 614.176C365.962 619.456 368.794 626.56 368.794 635.488V682H357.13V671.488H356.554C354.634 674.752 351.61 677.728 347.482 680.416C343.354 683.008 338.458 684.304 332.794 684.304ZM333.946 673.504C338.17 673.504 342.01 672.448 345.466 670.336C349.018 668.224 351.85 665.392 353.962 661.84C356.074 658.288 357.13 654.4 357.13 650.176C354.922 648.64 352.138 647.392 348.778 646.432C345.514 645.472 341.914 644.992 337.978 644.992C330.97 644.992 325.834 646.432 322.57 649.312C319.306 652.192 317.674 655.744 317.674 659.968C317.674 664 319.21 667.264 322.282 669.76C325.354 672.256 329.242 673.504 333.946 673.504ZM399.968 682L376.352 608.56H389.024L406.448 666.592H406.592L425.168 608.56H437.696L456.272 666.448H456.416L473.84 608.56H486.224L462.464 682H450.08L431.072 623.392L412.208 682H399.968ZM496.353 682V608.56H508.017V619.36H508.593C510.513 615.808 513.633 612.736 517.953 610.144C522.369 607.552 527.169 606.256 532.353 606.256C541.377 606.256 548.145 608.896 552.657 614.176C557.265 619.36 559.569 626.272 559.569 634.912V682H547.329V636.784C547.329 629.68 545.601 624.688 542.145 621.808C538.785 618.832 534.417 617.344 529.041 617.344C525.009 617.344 521.457 618.496 518.385 620.8C515.313 623.008 512.913 625.888 511.185 629.44C509.457 632.992 508.593 636.736 508.593 640.672V682H496.353Z"
+     fill="black"
+     id="path45" />
+</svg>
diff --git a/docs/imgs/dawn_logo_black.png b/docs/imgs/dawn_logo_black.png
new file mode 100644
index 0000000..3c74794
--- /dev/null
+++ b/docs/imgs/dawn_logo_black.png
Binary files differ
diff --git a/docs/imgs/dawn_logo_black.svg b/docs/imgs/dawn_logo_black.svg
new file mode 100644
index 0000000..627bf3b
--- /dev/null
+++ b/docs/imgs/dawn_logo_black.svg
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="768"
+   height="768"
+   viewBox="0 0 768 768"
+   fill="none"
+   version="1.1"
+   id="svg47"
+   sodipodi:docname="dawn_logo_black.svg"
+   inkscape:version="1.1 (c4e8f9e, 2021-05-24)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs51" />
+  <sodipodi:namedview
+     id="namedview49"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="true"
+     showgrid="false"
+     inkscape:zoom="0.96102398"
+     inkscape:cx="255.45668"
+     inkscape:cy="371.99904"
+     inkscape:window-width="1296"
+     inkscape:window-height="997"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg47"
+     showguides="false" />
+  <path
+     id="circle33"
+     style="fill:#808080"
+     d="m 306.7315,89 a 121,121 0 0 0 -121,121 121,121 0 0 0 120.8418,120.98438 L 411.40142,149.41797 A 121,121 0 0 0 306.7315,89 Z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M429.5 543L550 335L309 335L429.5 543Z"
+     fill="#0066B0"
+     id="path37"
+     style="fill:#000000" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 429.5,124 550.29135,332.50291 H 308.70865 Z"
+     fill="#0066b0"
+     id="path37-7"
+     style="fill:#000000;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     id="path37-7-5"
+     style="fill:#000000;fill-opacity:1;stroke-width:0.489674"
+     d="m 306.64855,336.55438 -44.67773,77.12109 14.32812,24.73242 h 89.35547 z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 552,337 672.79135,545.50291 H 431.20865 Z"
+     fill="#0066b0"
+     id="path37-7-9"
+     style="fill:#000000;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 321.32659,515.63497 43.72296,-75.16014 h -87.44593 z"
+     fill="#0093ff"
+     id="path41"
+     style="stroke-width:0.722694;fill:#000000" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 214.90584,337 120.5,208 H 94.405844 Z"
+     fill="#0076cc"
+     id="path43"
+     style="fill:#000000" />
+  <path
+     d="M 208.52,682 V 578.896 h 31.104 c 10.752,0 20.016,2.208 27.792,6.624 7.776,4.32 13.776,10.368 18,18.144 4.224,7.776 6.336,16.704 6.336,26.784 0,10.08 -2.112,19.008 -6.336,26.784 -4.224,7.68 -10.224,13.728 -18,18.144 -7.776,4.416 -17.04,6.624 -27.792,6.624 z m 12.24,-11.664 h 18.864 c 8.064,0 15.072,-1.536 21.024,-4.608 5.952,-3.168 10.56,-7.728 13.824,-13.68 3.264,-5.952 4.896,-13.152 4.896,-21.6 0,-8.448 -1.632,-15.648 -4.896,-21.6 -3.264,-5.952 -7.872,-10.464 -13.824,-13.536 -5.952,-3.168 -12.96,-4.752 -21.024,-4.752 H 220.76 Z m 110.034,13.968 c -5.472,0 -10.272,-1.056 -14.4,-3.168 -4.128,-2.112 -7.392,-4.992 -9.792,-8.64 -2.304,-3.744 -3.456,-7.968 -3.456,-12.672 0,-5.376 1.392,-9.888 4.176,-13.536 2.784,-3.744 6.528,-6.528 11.232,-8.352 4.704,-1.92 9.888,-2.88 15.552,-2.88 4.896,0 9.216,0.528 12.96,1.584 3.744,1.056 6.432,2.112 8.064,3.168 v -4.464 c 0,-5.568 -1.968,-9.984 -5.904,-13.248 -3.936,-3.264 -8.736,-4.896 -14.4,-4.896 -4.032,0 -7.824,0.912 -11.376,2.736 -3.456,1.728 -6.192,4.176 -8.208,7.344 l -9.216,-6.912 c 2.88,-4.32 6.816,-7.728 11.808,-10.224 5.088,-2.592 10.752,-3.888 16.992,-3.888 9.984,0 17.808,2.64 23.472,7.92 5.664,5.28 8.496,12.384 8.496,21.312 V 682 H 355.13 v -10.512 h -0.576 c -1.92,3.264 -4.944,6.24 -9.072,8.928 -4.128,2.592 -9.024,3.888 -14.688,3.888 z m 1.152,-10.8 c 4.224,0 8.064,-1.056 11.52,-3.168 3.552,-2.112 6.384,-4.944 8.496,-8.496 2.112,-3.552 3.168,-7.44 3.168,-11.664 -2.208,-1.536 -4.992,-2.784 -8.352,-3.744 -3.264,-0.96 -6.864,-1.44 -10.8,-1.44 -7.008,0 -12.144,1.44 -15.408,4.32 -3.264,2.88 -4.896,6.432 -4.896,10.656 0,4.032 1.536,7.296 4.608,9.792 3.072,2.496 6.96,3.744 11.664,3.744 z M 397.968,682 374.352,608.56 h 12.672 l 17.424,58.032 h 0.144 l 18.576,-58.032 h 12.528 l 18.576,57.888 h 0.144 L 471.84,608.56 h 12.384 L 460.464,682 H 448.08 L 429.072,623.392 410.208,682 Z m 96.385,0 v -73.44 h 11.664 v 10.8 h 0.576 c 1.92,-3.552 5.04,-6.624 9.36,-9.216 4.416,-2.592 9.216,-3.888 14.4,-3.888 9.024,0 15.792,2.64 20.304,7.92 4.608,5.184 6.912,12.096 6.912,20.736 V 682 h -12.24 v -45.216 c 0,-7.104 -1.728,-12.096 -5.184,-14.976 -3.36,-2.976 -7.728,-4.464 -13.104,-4.464 -4.032,0 -7.584,1.152 -10.656,3.456 -3.072,2.208 -5.472,5.088 -7.2,8.64 -1.728,3.552 -2.592,7.296 -2.592,11.232 V 682 Z"
+     fill="#000000"
+     id="path45" />
+  <path
+     id="path22856"
+     style="fill:#000000;fill-opacity:1"
+     d="M 367.29708,441 322.58028,517.86914 338.29708,545 h 89.5 z" />
+</svg>
diff --git a/docs/imgs/dawn_logo_black_notext.png b/docs/imgs/dawn_logo_black_notext.png
new file mode 100644
index 0000000..11d5416
--- /dev/null
+++ b/docs/imgs/dawn_logo_black_notext.png
Binary files differ
diff --git a/docs/imgs/dawn_logo_black_notext.svg b/docs/imgs/dawn_logo_black_notext.svg
new file mode 100644
index 0000000..d3804fd
--- /dev/null
+++ b/docs/imgs/dawn_logo_black_notext.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="768"
+   height="768"
+   viewBox="0 0 768 768"
+   fill="none"
+   version="1.1"
+   id="svg47"
+   sodipodi:docname="dawn_logo_black_notext.svg"
+   inkscape:version="1.1 (c4e8f9e, 2021-05-24)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs51" />
+  <sodipodi:namedview
+     id="namedview49"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="true"
+     showgrid="false"
+     inkscape:zoom="0.96102398"
+     inkscape:cx="255.45668"
+     inkscape:cy="371.99904"
+     inkscape:window-width="1296"
+     inkscape:window-height="997"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg47"
+     showguides="false" />
+  <path
+     id="circle33"
+     style="fill:#808080"
+     d="m 306.7315,89 a 121,121 0 0 0 -121,121 121,121 0 0 0 120.8418,120.98438 L 411.40142,149.41797 A 121,121 0 0 0 306.7315,89 Z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M429.5 543L550 335L309 335L429.5 543Z"
+     fill="#0066B0"
+     id="path37"
+     style="fill:#000000" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 429.5,124 550.29135,332.50291 H 308.70865 Z"
+     fill="#0066b0"
+     id="path37-7"
+     style="fill:#000000;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     id="path37-7-5"
+     style="fill:#000000;fill-opacity:1;stroke-width:0.489674"
+     d="m 306.64855,336.55438 -44.67773,77.12109 14.32812,24.73242 h 89.35547 z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 552,337 672.79135,545.50291 H 431.20865 Z"
+     fill="#0066b0"
+     id="path37-7-9"
+     style="fill:#000000;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 321.32659,515.63497 43.72296,-75.16014 h -87.44593 z"
+     fill="#0093ff"
+     id="path41"
+     style="stroke-width:0.722694;fill:#000000" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 214.90584,337 120.5,208 H 94.405844 Z"
+     fill="#0076cc"
+     id="path43"
+     style="fill:#000000" />
+  <path
+     id="path22856"
+     style="fill:#000000;fill-opacity:1"
+     d="M 367.29708,441 322.58028,517.86914 338.29708,545 h 89.5 z" />
+</svg>
diff --git a/docs/imgs/dawn_logo_notext.png b/docs/imgs/dawn_logo_notext.png
new file mode 100644
index 0000000..f9732e5
--- /dev/null
+++ b/docs/imgs/dawn_logo_notext.png
Binary files differ
diff --git a/docs/imgs/dawn_logo_notext.svg b/docs/imgs/dawn_logo_notext.svg
new file mode 100644
index 0000000..890619b
--- /dev/null
+++ b/docs/imgs/dawn_logo_notext.svg
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="768"
+   height="768"
+   viewBox="0 0 768 768"
+   fill="none"
+   version="1.1"
+   id="svg47"
+   sodipodi:docname="dawn_notext_logo.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs51" />
+  <sodipodi:namedview
+     id="namedview49"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="true"
+     showgrid="false"
+     inkscape:zoom="1.6830615"
+     inkscape:cx="187.15894"
+     inkscape:cy="384.41852"
+     inkscape:window-width="3840"
+     inkscape:window-height="2066"
+     inkscape:window-x="-11"
+     inkscape:window-y="-11"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg47" />
+  <circle
+     cx="304.81589"
+     cy="248.44208"
+     r="141.44208"
+     fill="#fde293"
+     id="circle33"
+     style="stroke-width:1.16894" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 445.67349,145.57511 727.10233,633.02428 H 164.24466 Z"
+     fill="#005a9c"
+     id="path35"
+     style="stroke-width:1.16894" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 445.67349,633.02428 586.5311,389.88417 H 304.81588 Z"
+     fill="#0066b0"
+     id="path37"
+     style="stroke-width:1.16894" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 304.23141,389.88417 70.72104,121.57005 H 233.51037 Z"
+     fill="#0086e8"
+     id="path39"
+     style="stroke-width:1.16894" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 304.23141,633.02428 374.95245,511.45422 H 233.51037 Z"
+     fill="#0093ff"
+     id="path41"
+     style="stroke-width:1.16894" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 197.85761,389.88417 338.71522,633.02428 H 57 Z"
+     fill="#0076cc"
+     id="path43"
+     style="stroke-width:1.16894" />
+</svg>
diff --git a/docs/imgs/dawn_logo_white.png b/docs/imgs/dawn_logo_white.png
new file mode 100644
index 0000000..8d835c4
--- /dev/null
+++ b/docs/imgs/dawn_logo_white.png
Binary files differ
diff --git a/docs/imgs/dawn_logo_white.svg b/docs/imgs/dawn_logo_white.svg
new file mode 100644
index 0000000..0f9d00c
--- /dev/null
+++ b/docs/imgs/dawn_logo_white.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="768"
+   height="768"
+   viewBox="0 0 768 768"
+   fill="none"
+   version="1.1"
+   id="svg47"
+   sodipodi:docname="dawn_white.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs51" />
+  <sodipodi:namedview
+     id="namedview49"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="true"
+     showgrid="false"
+     inkscape:zoom="2.3802083"
+     inkscape:cx="255.01969"
+     inkscape:cy="371.81619"
+     inkscape:window-width="3840"
+     inkscape:window-height="2066"
+     inkscape:window-x="-11"
+     inkscape:window-y="-11"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg47"
+     showguides="false" />
+  <path
+     id="circle33"
+     style="fill:#ececec"
+     d="m 306.7315,89 a 121,121 0 0 0 -121,121 121,121 0 0 0 120.8418,120.98438 L 411.40142,149.41797 A 121,121 0 0 0 306.7315,89 Z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M429.5 543L550 335L309 335L429.5 543Z"
+     fill="#0066B0"
+     id="path37"
+     style="fill:#ffffff" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 429.5,124 550.29135,332.50291 H 308.70865 Z"
+     fill="#0066b0"
+     id="path37-7"
+     style="fill:#ffffff;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     id="path37-7-5"
+     style="fill:#ffffff;fill-opacity:1;stroke-width:0.489674"
+     d="m 306.64855,336.55438 -44.67773,77.12109 14.32812,24.73242 h 89.35547 z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 552,337 672.79135,545.50291 H 431.20865 Z"
+     fill="#0066b0"
+     id="path37-7-9"
+     style="fill:#ffffff;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 321.32659,515.63497 43.72296,-75.16014 h -87.44593 z"
+     fill="#0093ff"
+     id="path41"
+     style="stroke-width:0.722694;fill:#ffffff" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 214.90584,337 120.5,208 H 94.405844 Z"
+     fill="#0076cc"
+     id="path43"
+     style="fill:#ffffff" />
+  <path
+     d="M 208.52,682 V 578.896 h 31.104 c 10.752,0 20.016,2.208 27.792,6.624 7.776,4.32 13.776,10.368 18,18.144 4.224,7.776 6.336,16.704 6.336,26.784 0,10.08 -2.112,19.008 -6.336,26.784 -4.224,7.68 -10.224,13.728 -18,18.144 -7.776,4.416 -17.04,6.624 -27.792,6.624 z m 12.24,-11.664 h 18.864 c 8.064,0 15.072,-1.536 21.024,-4.608 5.952,-3.168 10.56,-7.728 13.824,-13.68 3.264,-5.952 4.896,-13.152 4.896,-21.6 0,-8.448 -1.632,-15.648 -4.896,-21.6 -3.264,-5.952 -7.872,-10.464 -13.824,-13.536 -5.952,-3.168 -12.96,-4.752 -21.024,-4.752 H 220.76 Z m 110.034,13.968 c -5.472,0 -10.272,-1.056 -14.4,-3.168 -4.128,-2.112 -7.392,-4.992 -9.792,-8.64 -2.304,-3.744 -3.456,-7.968 -3.456,-12.672 0,-5.376 1.392,-9.888 4.176,-13.536 2.784,-3.744 6.528,-6.528 11.232,-8.352 4.704,-1.92 9.888,-2.88 15.552,-2.88 4.896,0 9.216,0.528 12.96,1.584 3.744,1.056 6.432,2.112 8.064,3.168 v -4.464 c 0,-5.568 -1.968,-9.984 -5.904,-13.248 -3.936,-3.264 -8.736,-4.896 -14.4,-4.896 -4.032,0 -7.824,0.912 -11.376,2.736 -3.456,1.728 -6.192,4.176 -8.208,7.344 l -9.216,-6.912 c 2.88,-4.32 6.816,-7.728 11.808,-10.224 5.088,-2.592 10.752,-3.888 16.992,-3.888 9.984,0 17.808,2.64 23.472,7.92 5.664,5.28 8.496,12.384 8.496,21.312 V 682 H 355.13 v -10.512 h -0.576 c -1.92,3.264 -4.944,6.24 -9.072,8.928 -4.128,2.592 -9.024,3.888 -14.688,3.888 z m 1.152,-10.8 c 4.224,0 8.064,-1.056 11.52,-3.168 3.552,-2.112 6.384,-4.944 8.496,-8.496 2.112,-3.552 3.168,-7.44 3.168,-11.664 -2.208,-1.536 -4.992,-2.784 -8.352,-3.744 -3.264,-0.96 -6.864,-1.44 -10.8,-1.44 -7.008,0 -12.144,1.44 -15.408,4.32 -3.264,2.88 -4.896,6.432 -4.896,10.656 0,4.032 1.536,7.296 4.608,9.792 3.072,2.496 6.96,3.744 11.664,3.744 z M 397.968,682 374.352,608.56 h 12.672 l 17.424,58.032 h 0.144 l 18.576,-58.032 h 12.528 l 18.576,57.888 h 0.144 L 471.84,608.56 h 12.384 L 460.464,682 H 448.08 L 429.072,623.392 410.208,682 Z m 96.385,0 v -73.44 h 11.664 v 10.8 h 0.576 c 1.92,-3.552 5.04,-6.624 9.36,-9.216 4.416,-2.592 9.216,-3.888 14.4,-3.888 9.024,0 15.792,2.64 20.304,7.92 4.608,5.184 6.912,12.096 6.912,20.736 V 682 h -12.24 v -45.216 c 0,-7.104 -1.728,-12.096 -5.184,-14.976 -3.36,-2.976 -7.728,-4.464 -13.104,-4.464 -4.032,0 -7.584,1.152 -10.656,3.456 -3.072,2.208 -5.472,5.088 -7.2,8.64 -1.728,3.552 -2.592,7.296 -2.592,11.232 V 682 Z"
+     fill="#000000"
+     id="path45"
+     style="fill:#ffffff" />
+  <path
+     id="path22856"
+     style="fill:#ffffff;fill-opacity:1"
+     d="M 367.29708,441 322.58028,517.86914 338.29708,545 h 89.5 z" />
+</svg>
diff --git a/docs/imgs/dawn_logo_white_notext.png b/docs/imgs/dawn_logo_white_notext.png
new file mode 100644
index 0000000..e6fe2b5
--- /dev/null
+++ b/docs/imgs/dawn_logo_white_notext.png
Binary files differ
diff --git a/docs/imgs/dawn_logo_white_notext.svg b/docs/imgs/dawn_logo_white_notext.svg
new file mode 100644
index 0000000..fba1f26
--- /dev/null
+++ b/docs/imgs/dawn_logo_white_notext.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="768"
+   height="768"
+   viewBox="0 0 768 768"
+   fill="none"
+   version="1.1"
+   id="svg47"
+   sodipodi:docname="dawn_logo_white_notext.svg"
+   inkscape:version="1.1 (c4e8f9e, 2021-05-24)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs51" />
+  <sodipodi:namedview
+     id="namedview49"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="true"
+     showgrid="false"
+     inkscape:zoom="1.1009789"
+     inkscape:cx="254.77327"
+     inkscape:cy="371.94172"
+     inkscape:window-width="1296"
+     inkscape:window-height="997"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg47"
+     showguides="false" />
+  <path
+     id="circle33"
+     style="fill:#ececec"
+     d="m 306.7315,89 a 121,121 0 0 0 -121,121 121,121 0 0 0 120.8418,120.98438 L 411.40142,149.41797 A 121,121 0 0 0 306.7315,89 Z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M429.5 543L550 335L309 335L429.5 543Z"
+     fill="#0066B0"
+     id="path37"
+     style="fill:#ffffff" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 429.5,124 550.29135,332.50291 H 308.70865 Z"
+     fill="#0066b0"
+     id="path37-7"
+     style="fill:#ffffff;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     id="path37-7-5"
+     style="fill:#ffffff;fill-opacity:1;stroke-width:0.489674"
+     d="m 306.64855,336.55438 -44.67773,77.12109 14.32812,24.73242 h 89.35547 z" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="M 552,337 672.79135,545.50291 H 431.20865 Z"
+     fill="#0066b0"
+     id="path37-7-9"
+     style="fill:#ffffff;fill-opacity:1;stroke-width:1.00242" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 321.32659,515.63497 43.72296,-75.16014 h -87.44593 z"
+     fill="#0093ff"
+     id="path41"
+     style="stroke-width:0.722694;fill:#ffffff" />
+  <path
+     fill-rule="evenodd"
+     clip-rule="evenodd"
+     d="m 214.90584,337 120.5,208 H 94.405844 Z"
+     fill="#0076cc"
+     id="path43"
+     style="fill:#ffffff" />
+  <path
+     id="path22856"
+     style="fill:#ffffff;fill-opacity:1"
+     d="M 367.29708,441 322.58028,517.86914 338.29708,545 h 89.5 z" />
+</svg>
diff --git a/generator/BUILD.gn b/generator/BUILD.gn
new file mode 100644
index 0000000..a1d954a
--- /dev/null
+++ b/generator/BUILD.gn
@@ -0,0 +1,63 @@
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../scripts/dawn_overrides_with_defaults.gni")
+import("dawn_generator.gni")
+
+# The list of directories in which to check for stale autogenerated files.
+# It should include the list of all directories in which we ever generated
+# files but we can't just put dawn_gen_root because there are more than
+# autogenerated sources there.
+_stale_dirs = [
+  "dawn",
+  "dawn/native",
+  "dawn/wire",
+  "mock",
+  "src",
+]
+
+_allowed_output_dirs_file =
+    "${dawn_gen_root}/removed_stale_autogen_files.allowed_output_dirs"
+write_file(_allowed_output_dirs_file, dawn_allowed_gen_output_dirs)
+
+_stale_dirs_file = "${dawn_gen_root}/removed_stale_autogen_files.stale_dirs"
+write_file(_stale_dirs_file, _stale_dirs)
+
+_stamp_file = "${dawn_gen_root}/removed_stale_autogen_files.stamp"
+
+# An action that removes autogenerated files that aren't in allowed directories
+# see dawn_generator.gni for more details.
+action("remove_stale_autogen_files") {
+  script = "remove_files.py"
+  args = [
+    "--root-dir",
+    rebase_path(dawn_gen_root, root_build_dir),
+    "--allowed-output-dirs-file",
+    rebase_path(_allowed_output_dirs_file, root_build_dir),
+    "--stale-dirs-file",
+    rebase_path(_stale_dirs_file, root_build_dir),
+    "--stamp",
+    rebase_path(_stamp_file, root_build_dir),
+  ]
+
+  # Have the "list of file" inputs as a dependency so that the action reruns
+  # as soon as they change.
+  inputs = [
+    _allowed_output_dirs_file,
+    _stale_dirs_file,
+  ]
+
+  # Output a stamp file so we don't re-run this action on every build.
+  outputs = [ _stamp_file ]
+}
diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt
new file mode 100644
index 0000000..a2d6784
--- /dev/null
+++ b/generator/CMakeLists.txt
@@ -0,0 +1,116 @@
+# Copyright 2020 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+find_package(PythonInterp REQUIRED)
+message(STATUS "Dawn: using python at ${PYTHON_EXECUTABLE}")
+
+# Check for Jinja2
+if (NOT DAWN_JINJA2_DIR)
+    message(STATUS "Dawn: Using system jinja2")
+    execute_process(
+        COMMAND ${PYTHON_EXECUTABLE} -c "import jinja2"
+        RESULT_VARIABLE RET
+    )
+    if (NOT RET EQUAL 0)
+        message(FATAL_ERROR "Dawn: Missing dependencies for code generation, please ensure you have python-jinja2 installed.")
+    endif()
+else()
+    message(STATUS "Dawn: Using jinja2 at ${DAWN_JINJA2_DIR}")
+endif()
+
+# Function to invoke a generator_lib.py generator.
+#  - SCRIPT is the name of the script to call
+#  - ARGS are the extra arguments to pass to the script in addition to the base generator_lib.py arguments
+#  - PRINT_NAME is the name to use when outputting status or errors
+#  - RESULT_VARIABLE will be modified to contain the list of files generated by this generator
+function(DawnGenerator)
+    set(oneValueArgs SCRIPT RESULT_VARIABLE PRINT_NAME)
+    set(multiValueArgs ARGS)
+    cmake_parse_arguments(G "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    # Build the set of args common to all invocation of that generator.
+    set(BASE_ARGS
+        ${PYTHON_EXECUTABLE}
+        ${G_SCRIPT}
+        --template-dir
+        "${DAWN_TEMPLATE_DIR}"
+        --root-dir
+        "${Dawn_SOURCE_DIR}"
+        --output-dir
+        "${DAWN_BUILD_GEN_DIR}"
+        ${G_ARGS}
+    )
+    if (DAWN_JINJA2_DIR)
+        list(APPEND BASE_ARGS --jinja2-path ${DAWN_JINJA2_DIR})
+    endif()
+
+    # Call the generator to get the list of its dependencies.
+    execute_process(
+        COMMAND ${BASE_ARGS} --print-cmake-dependencies
+        OUTPUT_VARIABLE DEPENDENCIES
+        RESULT_VARIABLE RET
+    )
+    if (NOT RET EQUAL 0)
+        message(FATAL_ERROR "Dawn: Failed to get the dependencies for ${G_PRINT_NAME}. Base args are '${BASE_ARGS}'.")
+    endif()
+
+    # Ask CMake to re-run if any of the dependencies changed as it might modify the build graph.
+    if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0")
+        set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${DEPENDENCIES})
+    endif()
+
+    # Call the generator to get the list of its outputs.
+    execute_process(
+        COMMAND ${BASE_ARGS} --print-cmake-outputs
+        OUTPUT_VARIABLE OUTPUTS
+        RESULT_VARIABLE RET
+    )
+    if (NOT RET EQUAL 0)
+        message(FATAL_ERROR "Dawn: Failed to get the outputs for ${G_PRINT_NAME}. Base args are '${BASE_ARGS}'.")
+    endif()
+
+    # Add the custom command that calls the generator.
+    add_custom_command(
+        COMMAND ${BASE_ARGS}
+        DEPENDS ${DEPENDENCIES}
+        OUTPUT ${OUTPUTS}
+        COMMENT "Dawn: Generating files for ${G_PRINT_NAME}."
+    )
+
+    # Return the list of outputs.
+    set(${G_RESULT_VARIABLE} ${OUTPUTS} PARENT_SCOPE)
+endfunction()
+
+# Helper function to call dawn_generator.py:
+#  - TARGET is the generator target to build
+#  - PRINT_NAME and RESULT_VARIABLE are like for DawnGenerator
+function(DawnJSONGenerator)
+    set(oneValueArgs TARGET RESULT_VARIABLE)
+    cmake_parse_arguments(G "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    DawnGenerator(
+        SCRIPT "${Dawn_SOURCE_DIR}/generator/dawn_json_generator.py"
+        ARGS --dawn-json
+             "${Dawn_SOURCE_DIR}/dawn.json"
+             --wire-json
+             "${Dawn_SOURCE_DIR}/dawn_wire.json"
+             --targets
+             ${G_TARGET}
+        RESULT_VARIABLE RET
+        ${G_UNPARSED_ARGUMENTS}
+    )
+
+    # Forward the result up one more scope
+    set(${G_RESULT_VARIABLE} ${RET} PARENT_SCOPE)
+endfunction()
diff --git a/generator/dawn_generator.gni b/generator/dawn_generator.gni
new file mode 100644
index 0000000..28c5301
--- /dev/null
+++ b/generator/dawn_generator.gni
@@ -0,0 +1,121 @@
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../scripts/dawn_overrides_with_defaults.gni")
+import("generator_lib.gni")
+
+# Dawn used to put autogenerated files in a lot of different places. When we
+# started to move them around, some compilation issues arised because some
+# stale include files stayed in the build directory and were picked up.
+# To counter this, now Dawn does the following:
+#
+#  1. The generated output file directory structure has to match the structure
+#    of the source tree, starting at dawn_gen_root (gen/ or
+#    gen/third_party/dawn depending on where we are).
+#  2. include and dawn_gen_root/include has to match the structure of
+#    the source tree too.
+#  3. Dawn files must use include relative to src/ or include such as
+#    "dawn/dawn.h" or "dawn/native/backend/BackendStuff.h".
+#
+# The allowed list below ensure 1). Include directory rules for Dawn ensure 3)
+# and 2) is something we need to enforce in code review.
+#
+# However GN's toolchains automatically add some include directories for us
+# which breaks 3) slightly. To avoid stale headers in for example
+# dawn_gen_root/src/dawn/dawn/ to be picked up (instead of
+# dawn_gen_root/src/dawn), we have a special action that removes files in
+# disallowed gen directories.
+
+dawn_allowed_gen_output_dirs = [
+  "src/dawn/",
+  "src/dawn/common/",
+  "src/dawn/native/",
+  "src/dawn/native/opengl/",
+  "src/dawn/wire/client/",
+  "src/dawn/wire/server/",
+  "src/dawn/wire/",
+  "include/dawn/",
+  "emscripten-bits/",
+  "webgpu-headers/",
+]
+
+# Template to help invoking Dawn code generators based on generator_lib
+#
+#   dawn_generator("my_target_gen") {
+#     # The script and generator specific arguments
+#     script = [ "my_awesome_generator.py" ]
+#     args = [
+#       "--be-awesome",
+#       "yes"
+#     ]
+#
+#     # The list of expected outputs, generation fails if there's a mismatch
+#     outputs = [
+#       "MyAwesomeTarget.cpp",
+#       "MyAwesomeTarget.h",
+#     ]
+#   }
+#
+# Using the generated files is done like so:
+#
+#   shared_library("my_target") {
+#     deps = [ ":my_target_gen "]
+#     sources = get_target_outputs(":my_target_gen")
+#   }
+#
+template("dawn_generator") {
+  generator_lib_action(target_name) {
+    forward_variables_from(invoker, "*")
+
+    # Set arguments required to find the python libraries for the generator
+    generator_lib_dir = "${dawn_root}/generator"
+    jinja2_path = dawn_jinja2_dir
+
+    # Force Dawn's autogenerated file structure to mirror exactly the source
+    # tree but start at ${dawn_gen_root} instead of ${dawn_root}
+    allowed_output_dirs = dawn_allowed_gen_output_dirs
+    custom_gen_dir = dawn_gen_root
+
+    # Make sure that we delete stale autogenerated file in directories that are
+    # no longer used by code generation to avoid include conflicts.
+    deps = [ "${dawn_root}/generator:remove_stale_autogen_files" ]
+  }
+}
+
+# Helper generator for calling the generator from dawn.json
+#
+#   dawn_json_generator("my_target_gen") {
+#     # Which generator target to output
+#     target = "my_target"
+#
+#     # Also supports `outputs` and `custom_gen_dir` like dawn_generator.
+#   }
+template("dawn_json_generator") {
+  dawn_generator(target_name) {
+    script = "${dawn_root}/generator/dawn_json_generator.py"
+
+    # The base arguments for the generator: from this dawn.json, generate this
+    # target using templates in this directory.
+    args = [
+      "--dawn-json",
+      rebase_path("${dawn_root}/dawn.json", root_build_dir),
+      "--wire-json",
+      rebase_path("${dawn_root}/dawn_wire.json", root_build_dir),
+      "--targets",
+      invoker.target,
+    ]
+
+    forward_variables_from(invoker, "*", [ "target" ])
+  }
+}
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
new file mode 100644
index 0000000..29c1be9
--- /dev/null
+++ b/generator/dawn_json_generator.py
@@ -0,0 +1,1031 @@
+#!/usr/bin/env python3
+# Copyright 2017 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json, os, sys
+from collections import namedtuple
+
+from generator_lib import Generator, run_generator, FileRender
+
+############################################################
+# OBJECT MODEL
+############################################################
+
+
+class Metadata:
+    def __init__(self, metadata):
+        self.api = metadata['api']
+        self.namespace = metadata['namespace']
+        self.c_prefix = metadata.get('c_prefix', self.namespace.upper())
+        self.proc_table_prefix = metadata['proc_table_prefix']
+        self.impl_dir = metadata.get('impl_dir', '')
+        self.native_namespace = metadata['native_namespace']
+        self.copyright_year = metadata.get('copyright_year', None)
+
+
+class Name:
+    def __init__(self, name, native=False):
+        self.native = native
+        self.name = name
+        if native:
+            self.chunks = [name]
+        else:
+            self.chunks = name.split(' ')
+
+    def get(self):
+        return self.name
+
+    def CamelChunk(self, chunk):
+        return chunk[0].upper() + chunk[1:]
+
+    def canonical_case(self):
+        return (' '.join(self.chunks)).lower()
+
+    def concatcase(self):
+        return ''.join(self.chunks)
+
+    def camelCase(self):
+        return self.chunks[0] + ''.join(
+            [self.CamelChunk(chunk) for chunk in self.chunks[1:]])
+
+    def CamelCase(self):
+        return ''.join([self.CamelChunk(chunk) for chunk in self.chunks])
+
+    def SNAKE_CASE(self):
+        return '_'.join([chunk.upper() for chunk in self.chunks])
+
+    def snake_case(self):
+        return '_'.join(self.chunks)
+
+    def namespace_case(self):
+        return '::'.join(self.chunks)
+
+    def Dirs(self):
+        return '/'.join(self.chunks)
+
+    def js_enum_case(self):
+        result = self.chunks[0].lower()
+        for chunk in self.chunks[1:]:
+            if not result[-1].isdigit():
+                result += '-'
+            result += chunk.lower()
+        return result
+
+
+def concat_names(*names):
+    return ' '.join([name.canonical_case() for name in names])
+
+
+class Type:
+    def __init__(self, name, json_data, native=False):
+        self.json_data = json_data
+        self.dict_name = name
+        self.name = Name(name, native=native)
+        self.category = json_data['category']
+        self.is_wire_transparent = False
+
+
+EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'json_data'])
+
+
+class EnumType(Type):
+    def __init__(self, is_enabled, name, json_data):
+        Type.__init__(self, name, json_data)
+
+        self.values = []
+        self.contiguousFromZero = True
+        lastValue = -1
+        for m in self.json_data['values']:
+            if not is_enabled(m):
+                continue
+            value = m['value']
+            if value != lastValue + 1:
+                self.contiguousFromZero = False
+            lastValue = value
+            self.values.append(
+                EnumValue(Name(m['name']), value, m.get('valid', True), m))
+
+        # Assert that all values are unique in enums
+        all_values = set()
+        for value in self.values:
+            if value.value in all_values:
+                raise Exception("Duplicate value {} in enum {}".format(
+                    value.value, name))
+            all_values.add(value.value)
+        self.is_wire_transparent = True
+
+
+BitmaskValue = namedtuple('BitmaskValue', ['name', 'value', 'json_data'])
+
+
+class BitmaskType(Type):
+    def __init__(self, is_enabled, name, json_data):
+        Type.__init__(self, name, json_data)
+        self.values = [
+            BitmaskValue(Name(m['name']), m['value'], m)
+            for m in self.json_data['values'] if is_enabled(m)
+        ]
+        self.full_mask = 0
+        for value in self.values:
+            self.full_mask = self.full_mask | value.value
+        self.is_wire_transparent = True
+
+
+class FunctionPointerType(Type):
+    def __init__(self, is_enabled, name, json_data):
+        Type.__init__(self, name, json_data)
+        self.return_type = None
+        self.arguments = []
+
+
+class TypedefType(Type):
+    def __init__(self, is_enabled, name, json_data):
+        Type.__init__(self, name, json_data)
+        self.type = None
+
+
+class NativeType(Type):
+    def __init__(self, is_enabled, name, json_data):
+        Type.__init__(self, name, json_data, native=True)
+        self.is_wire_transparent = True
+
+
+# Methods and structures are both "records", so record members correspond to
+# method arguments or structure members.
+class RecordMember:
+    def __init__(self,
+                 name,
+                 typ,
+                 annotation,
+                 json_data,
+                 optional=False,
+                 is_return_value=False,
+                 default_value=None,
+                 skip_serialize=False):
+        self.name = name
+        self.type = typ
+        self.annotation = annotation
+        self.json_data = json_data
+        self.length = None
+        self.optional = optional
+        self.is_return_value = is_return_value
+        self.handle_type = None
+        self.default_value = default_value
+        self.skip_serialize = skip_serialize
+
+    def set_handle_type(self, handle_type):
+        assert self.type.dict_name == "ObjectHandle"
+        self.handle_type = handle_type
+
+
+Method = namedtuple('Method',
+                    ['name', 'return_type', 'arguments', 'json_data'])
+
+
+class ObjectType(Type):
+    def __init__(self, is_enabled, name, json_data):
+        json_data_override = {'methods': []}
+        if 'methods' in json_data:
+            json_data_override['methods'] = [
+                m for m in json_data['methods'] if is_enabled(m)
+            ]
+        Type.__init__(self, name, dict(json_data, **json_data_override))
+
+
+class Record:
+    def __init__(self, name):
+        self.name = Name(name)
+        self.members = []
+        self.may_have_dawn_object = False
+
+    def update_metadata(self):
+        def may_have_dawn_object(member):
+            if isinstance(member.type, ObjectType):
+                return True
+            elif isinstance(member.type, StructureType):
+                return member.type.may_have_dawn_object
+            else:
+                return False
+
+        self.may_have_dawn_object = any(
+            may_have_dawn_object(member) for member in self.members)
+
+        # Set may_have_dawn_object to true if the type is chained or
+        # extensible. Chained structs may contain a Dawn object.
+        if isinstance(self, StructureType):
+            self.may_have_dawn_object = (self.may_have_dawn_object
+                                         or self.chained or self.extensible)
+
+
+class StructureType(Record, Type):
+    def __init__(self, is_enabled, name, json_data):
+        Record.__init__(self, name)
+        json_data_override = {}
+        if 'members' in json_data:
+            json_data_override['members'] = [
+                m for m in json_data['members'] if is_enabled(m)
+            ]
+        Type.__init__(self, name, dict(json_data, **json_data_override))
+        self.chained = json_data.get("chained", None)
+        self.extensible = json_data.get("extensible", None)
+        if self.chained:
+            assert (self.chained == "in" or self.chained == "out")
+        if self.extensible:
+            assert (self.extensible == "in" or self.extensible == "out")
+        # Chained structs inherit from wgpu::ChainedStruct, which has
+        # nextInChain, so setting both extensible and chained would result in
+        # two nextInChain members.
+        assert not (self.extensible and self.chained)
+
+    def update_metadata(self):
+        Record.update_metadata(self)
+
+        if self.may_have_dawn_object:
+            self.is_wire_transparent = False
+            return
+
+        assert not (self.chained or self.extensible)
+
+        def get_is_wire_transparent(member):
+            return member.type.is_wire_transparent and member.annotation == 'value'
+
+        self.is_wire_transparent = all(
+            get_is_wire_transparent(m) for m in self.members)
+
+    @property
+    def output(self):
+        return self.chained == "out" or self.extensible == "out"
+
+
+class ConstantDefinition():
+    def __init__(self, is_enabled, name, json_data):
+        self.type = None
+        self.value = json_data['value']
+        self.json_data = json_data
+        self.name = Name(name)
+
+
+class FunctionDeclaration():
+    def __init__(self, is_enabled, name, json_data):
+        self.return_type = None
+        self.arguments = []
+        self.json_data = json_data
+        self.name = Name(name)
+
+
+class Command(Record):
+    def __init__(self, name, members=None):
+        Record.__init__(self, name)
+        self.members = members or []
+        self.derived_object = None
+        self.derived_method = None
+
+
+def linked_record_members(json_data, types):
+    members = []
+    members_by_name = {}
+    for m in json_data:
+        member = RecordMember(Name(m['name']),
+                              types[m['type']],
+                              m.get('annotation', 'value'),
+                              m,
+                              optional=m.get('optional', False),
+                              is_return_value=m.get('is_return_value', False),
+                              default_value=m.get('default', None),
+                              skip_serialize=m.get('skip_serialize', False))
+        handle_type = m.get('handle_type')
+        if handle_type:
+            member.set_handle_type(types[handle_type])
+        members.append(member)
+        members_by_name[member.name.canonical_case()] = member
+
+    for (member, m) in zip(members, json_data):
+        if member.annotation != 'value':
+            if not 'length' in m:
+                if member.type.category != 'object':
+                    member.length = "constant"
+                    member.constant_length = 1
+                else:
+                    assert False
+            elif m['length'] == 'strlen':
+                member.length = 'strlen'
+            elif isinstance(m['length'], int):
+                assert m['length'] > 0
+                member.length = "constant"
+                member.constant_length = m['length']
+            else:
+                member.length = members_by_name[m['length']]
+
+    return members
+
+
+############################################################
+# PARSE
+############################################################
+
+
+def link_object(obj, types):
+    def make_method(json_data):
+        arguments = linked_record_members(json_data.get('args', []), types)
+        return Method(Name(json_data['name']),
+                      types[json_data.get('returns',
+                                          'void')], arguments, json_data)
+
+    obj.methods = [make_method(m) for m in obj.json_data.get('methods', [])]
+    obj.methods.sort(key=lambda method: method.name.canonical_case())
+
+
+def link_structure(struct, types):
+    struct.members = linked_record_members(struct.json_data['members'], types)
+
+
+def link_function_pointer(function_pointer, types):
+    link_function(function_pointer, types)
+
+
+def link_typedef(typedef, types):
+    typedef.type = types[typedef.json_data['type']]
+
+
+def link_constant(constant, types):
+    constant.type = types[constant.json_data['type']]
+    assert constant.type.name.native
+
+
+def link_function(function, types):
+    function.return_type = types[function.json_data.get('returns', 'void')]
+    function.arguments = linked_record_members(function.json_data['args'],
+                                               types)
+
+
+# Sort structures so that if struct A has struct B as a member, then B is
+# listed before A.
+#
+# This is a form of topological sort where we try to keep the order reasonably
+# similar to the original order (though the sort isn't technically stable).
+#
+# It works by computing for each struct type what is the depth of its DAG of
+# dependents, then re-sorting based on that depth using Python's stable sort.
+# This makes a toposort because if A depends on B then its depth will be bigger
+# than B's. It is also nice because all nodes with the same depth are kept in
+# the input order.
+def topo_sort_structure(structs):
+    for struct in structs:
+        struct.visited = False
+        struct.subdag_depth = 0
+
+    def compute_depth(struct):
+        if struct.visited:
+            return struct.subdag_depth
+
+        max_dependent_depth = 0
+        for member in struct.members:
+            if member.type.category == 'structure':
+                max_dependent_depth = max(max_dependent_depth,
+                                          compute_depth(member.type) + 1)
+
+        struct.subdag_depth = max_dependent_depth
+        struct.visited = True
+        return struct.subdag_depth
+
+    for struct in structs:
+        compute_depth(struct)
+
+    result = sorted(structs, key=lambda struct: struct.subdag_depth)
+
+    for struct in structs:
+        del struct.visited
+        del struct.subdag_depth
+
+    return result
+
+
+def parse_json(json, enabled_tags, disabled_tags=None):
+    is_enabled = lambda json_data: item_is_enabled(
+        enabled_tags, json_data) and not item_is_disabled(
+            disabled_tags, json_data)
+    category_to_parser = {
+        'bitmask': BitmaskType,
+        'enum': EnumType,
+        'native': NativeType,
+        'function pointer': FunctionPointerType,
+        'object': ObjectType,
+        'structure': StructureType,
+        'typedef': TypedefType,
+        'constant': ConstantDefinition,
+        'function': FunctionDeclaration
+    }
+
+    types = {}
+
+    by_category = {}
+    for name in category_to_parser.keys():
+        by_category[name] = []
+
+    for (name, json_data) in json.items():
+        if name[0] == '_' or not is_enabled(json_data):
+            continue
+        category = json_data['category']
+        parsed = category_to_parser[category](is_enabled, name, json_data)
+        by_category[category].append(parsed)
+        types[name] = parsed
+
+    for obj in by_category['object']:
+        link_object(obj, types)
+
+    for struct in by_category['structure']:
+        link_structure(struct, types)
+
+    for function_pointer in by_category['function pointer']:
+        link_function_pointer(function_pointer, types)
+
+    for typedef in by_category['typedef']:
+        link_typedef(typedef, types)
+
+    for constant in by_category['constant']:
+        link_constant(constant, types)
+
+    for function in by_category['function']:
+        link_function(function, types)
+
+    for category in by_category.keys():
+        by_category[category] = sorted(
+            by_category[category], key=lambda typ: typ.name.canonical_case())
+
+    by_category['structure'] = topo_sort_structure(by_category['structure'])
+
+    for struct in by_category['structure']:
+        struct.update_metadata()
+
+    api_params = {
+        'types': types,
+        'by_category': by_category,
+        'enabled_tags': enabled_tags,
+        'disabled_tags': disabled_tags,
+    }
+    return {
+        'metadata': Metadata(json['_metadata']),
+        'types': types,
+        'by_category': by_category,
+        'enabled_tags': enabled_tags,
+        'disabled_tags': disabled_tags,
+        'c_methods': lambda typ: c_methods(api_params, typ),
+        'c_methods_sorted_by_name': get_c_methods_sorted_by_name(api_params),
+    }
+
+
+############################################################
+# WIRE STUFF
+############################################################
+
+
+# Create wire commands from api methods
+def compute_wire_params(api_params, wire_json):
+    wire_params = api_params.copy()
+    types = wire_params['types']
+
+    commands = []
+    return_commands = []
+
+    wire_json['special items']['client_handwritten_commands'] += wire_json[
+        'special items']['client_side_commands']
+
+    # Generate commands from object methods
+    for api_object in wire_params['by_category']['object']:
+        for method in api_object.methods:
+            command_name = concat_names(api_object.name, method.name)
+            command_suffix = Name(command_name).CamelCase()
+
+            # Only object return values or void are supported.
+            # Other methods must be handwritten.
+            is_object = method.return_type.category == 'object'
+            is_void = method.return_type.name.canonical_case() == 'void'
+            if not (is_object or is_void):
+                assert command_suffix in (
+                    wire_json['special items']['client_handwritten_commands'])
+                continue
+
+            if command_suffix in (
+                    wire_json['special items']['client_side_commands']):
+                continue
+
+            # Create object method commands by prepending "self"
+            members = [
+                RecordMember(Name('self'), types[api_object.dict_name],
+                             'value', {})
+            ]
+            members += method.arguments
+
+            # Client->Server commands that return an object return the
+            # result object handle
+            if method.return_type.category == 'object':
+                result = RecordMember(Name('result'),
+                                      types['ObjectHandle'],
+                                      'value', {},
+                                      is_return_value=True)
+                result.set_handle_type(method.return_type)
+                members.append(result)
+
+            command = Command(command_name, members)
+            command.derived_object = api_object
+            command.derived_method = method
+            commands.append(command)
+
+    for (name, json_data) in wire_json['commands'].items():
+        commands.append(Command(name, linked_record_members(json_data, types)))
+
+    for (name, json_data) in wire_json['return commands'].items():
+        return_commands.append(
+            Command(name, linked_record_members(json_data, types)))
+
+    wire_params['cmd_records'] = {
+        'command': commands,
+        'return command': return_commands
+    }
+
+    for commands in wire_params['cmd_records'].values():
+        for command in commands:
+            command.update_metadata()
+        commands.sort(key=lambda c: c.name.canonical_case())
+
+    wire_params.update(wire_json.get('special items', {}))
+
+    return wire_params
+
+
+#############################################################
+# Generator
+#############################################################
+
+
+def as_varName(*names):
+    return names[0].camelCase() + ''.join(
+        [name.CamelCase() for name in names[1:]])
+
+
+def as_cType(c_prefix, name):
+    if name.native:
+        return name.concatcase()
+    else:
+        return c_prefix + name.CamelCase()
+
+
+def as_cppType(name):
+    if name.native:
+        return name.concatcase()
+    else:
+        return name.CamelCase()
+
+
+def as_jsEnumValue(value):
+    if 'jsrepr' in value.json_data: return value.json_data['jsrepr']
+    return "'" + value.name.js_enum_case() + "'"
+
+
+def convert_cType_to_cppType(typ, annotation, arg, indent=0):
+    if typ.category == 'native':
+        return arg
+    if annotation == 'value':
+        if typ.category == 'object':
+            return '{}::Acquire({})'.format(as_cppType(typ.name), arg)
+        elif typ.category == 'structure':
+            converted_members = [
+                convert_cType_to_cppType(
+                    member.type, member.annotation,
+                    '{}.{}'.format(arg, as_varName(member.name)), indent + 1)
+                for member in typ.members
+            ]
+
+            converted_members = [(' ' * 4) + m for m in converted_members]
+            converted_members = ',\n'.join(converted_members)
+
+            return as_cppType(typ.name) + ' {\n' + converted_members + '\n}'
+        elif typ.category == 'function pointer':
+            return 'reinterpret_cast<{}>({})'.format(as_cppType(typ.name), arg)
+        else:
+            return 'static_cast<{}>({})'.format(as_cppType(typ.name), arg)
+    else:
+        return 'reinterpret_cast<{} {}>({})'.format(as_cppType(typ.name),
+                                                    annotation, arg)
+
+
+def decorate(name, typ, arg):
+    if arg.annotation == 'value':
+        return typ + ' ' + name
+    elif arg.annotation == '*':
+        return typ + ' * ' + name
+    elif arg.annotation == 'const*':
+        return typ + ' const * ' + name
+    elif arg.annotation == 'const*const*':
+        return 'const ' + typ + '* const * ' + name
+    else:
+        assert False
+
+
+def annotated(typ, arg):
+    name = as_varName(arg.name)
+    return decorate(name, typ, arg)
+
+
+def item_is_enabled(enabled_tags, json_data):
+    tags = json_data.get('tags')
+    if tags is None: return True
+    return any(tag in enabled_tags for tag in tags)
+
+
+def item_is_disabled(disabled_tags, json_data):
+    if disabled_tags is None: return False
+    tags = json_data.get('tags')
+    if tags is None: return False
+
+    return any(tag in disabled_tags for tag in tags)
+
+
+def as_cppEnum(value_name):
+    assert not value_name.native
+    if value_name.concatcase()[0].isdigit():
+        return "e" + value_name.CamelCase()
+    return value_name.CamelCase()
+
+
+def as_MethodSuffix(type_name, method_name):
+    assert not type_name.native and not method_name.native
+    return type_name.CamelCase() + method_name.CamelCase()
+
+
+def as_frontendType(metadata, typ):
+    if typ.category == 'object':
+        return typ.name.CamelCase() + 'Base*'
+    elif typ.category in ['bitmask', 'enum']:
+        return metadata.namespace + '::' + typ.name.CamelCase()
+    elif typ.category == 'structure':
+        return as_cppType(typ.name)
+    else:
+        return as_cType(metadata.c_prefix, typ.name)
+
+
+def as_wireType(metadata, typ):
+    if typ.category == 'object':
+        return typ.name.CamelCase() + '*'
+    elif typ.category in ['bitmask', 'enum', 'structure']:
+        return metadata.c_prefix + typ.name.CamelCase()
+    else:
+        return as_cppType(typ.name)
+
+
+def as_formatType(typ):
+    # Unsigned integral types
+    if typ.json_data['type'] in ['bool', 'uint32_t', 'uint64_t']:
+        return 'u'
+
+    # Defaults everything else to strings.
+    return 's'
+
+
+def c_methods(params, typ):
+    return typ.methods + [
+        x for x in [
+            Method(Name('reference'), params['types']['void'], [],
+                   {'tags': ['dawn', 'emscripten']}),
+            Method(Name('release'), params['types']['void'], [],
+                   {'tags': ['dawn', 'emscripten']}),
+        ] if item_is_enabled(params['enabled_tags'], x.json_data)
+        and not item_is_disabled(params['disabled_tags'], x.json_data)
+    ]
+
+
+def get_c_methods_sorted_by_name(api_params):
+    unsorted = [(as_MethodSuffix(typ.name, method.name), typ, method) \
+            for typ in api_params['by_category']['object'] \
+            for method in c_methods(api_params, typ) ]
+    return [(typ, method) for (_, typ, method) in sorted(unsorted)]
+
+
+def has_callback_arguments(method):
+    return any(arg.type.category == 'function pointer' for arg in method.arguments)
+
+
+def make_base_render_params(metadata):
+    c_prefix = metadata.c_prefix
+
+    def as_cTypeEnumSpecialCase(typ):
+        if typ.category == 'bitmask':
+            return as_cType(c_prefix, typ.name) + 'Flags'
+        return as_cType(c_prefix, typ.name)
+
+    def as_cEnum(type_name, value_name):
+        assert not type_name.native and not value_name.native
+        return c_prefix + type_name.CamelCase() + '_' + value_name.CamelCase()
+
+    def as_cMethod(type_name, method_name):
+        c_method = c_prefix.lower()
+        if type_name != None:
+            assert not type_name.native
+            c_method += type_name.CamelCase()
+        assert not method_name.native
+        c_method += method_name.CamelCase()
+        return c_method
+
+    def as_cProc(type_name, method_name):
+        c_proc = c_prefix + 'Proc'
+        if type_name != None:
+            assert not type_name.native
+            c_proc += type_name.CamelCase()
+        assert not method_name.native
+        c_proc += method_name.CamelCase()
+        return c_proc
+
+    return {
+            'Name': lambda name: Name(name),
+            'as_annotated_cType': \
+                lambda arg: annotated(as_cTypeEnumSpecialCase(arg.type), arg),
+            'as_annotated_cppType': \
+                lambda arg: annotated(as_cppType(arg.type.name), arg),
+            'as_cEnum': as_cEnum,
+            'as_cppEnum': as_cppEnum,
+            'as_cMethod': as_cMethod,
+            'as_MethodSuffix': as_MethodSuffix,
+            'as_cProc': as_cProc,
+            'as_cType': lambda name: as_cType(c_prefix, name),
+            'as_cppType': as_cppType,
+            'as_jsEnumValue': as_jsEnumValue,
+            'convert_cType_to_cppType': convert_cType_to_cppType,
+            'as_varName': as_varName,
+            'decorate': decorate,
+            'as_formatType': as_formatType
+        }
+
+
+class MultiGeneratorFromDawnJSON(Generator):
+    def get_description(self):
+        return 'Generates code for various target from Dawn.json.'
+
+    def add_commandline_arguments(self, parser):
+        allowed_targets = [
+            'dawn_headers', 'cpp_headers', 'cpp', 'proc', 'mock_api', 'wire',
+            'native_utils'
+        ]
+
+        parser.add_argument('--dawn-json',
+                            required=True,
+                            type=str,
+                            help='The DAWN JSON definition to use.')
+        parser.add_argument('--wire-json',
+                            default=None,
+                            type=str,
+                            help='The DAWN WIRE JSON definition to use.')
+        parser.add_argument(
+            '--targets',
+            required=True,
+            type=str,
+            help=
+            'Comma-separated subset of targets to output. Available targets: '
+            + ', '.join(allowed_targets))
+    def get_file_renders(self, args):
+        with open(args.dawn_json) as f:
+            loaded_json = json.loads(f.read())
+
+        targets = args.targets.split(',')
+
+        wire_json = None
+        if args.wire_json:
+            with open(args.wire_json) as f:
+                wire_json = json.loads(f.read())
+
+        renders = []
+
+        params_dawn = parse_json(loaded_json,
+                                 enabled_tags=['dawn', 'native', 'deprecated'])
+        metadata = params_dawn['metadata']
+        RENDER_PARAMS_BASE = make_base_render_params(metadata)
+
+        api = metadata.api.lower()
+        prefix = metadata.proc_table_prefix.lower()
+        if 'headers' in targets:
+            renders.append(
+                FileRender('api.h', 'include/dawn/' + api + '.h',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+            renders.append(
+                FileRender('dawn_proc_table.h',
+                           'include/dawn/' + prefix + '_proc_table.h',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+        if 'cpp_headers' in targets:
+            renders.append(
+                FileRender('api_cpp.h', 'include/dawn/' + api + '_cpp.h',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+            renders.append(
+                FileRender('api_cpp_print.h',
+                           'include/dawn/' + api + '_cpp_print.h',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+        if 'proc' in targets:
+            renders.append(
+                FileRender('dawn_proc.c', 'src/dawn/' + prefix + '_proc.c',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+            renders.append(
+                FileRender('dawn_thread_dispatch_proc.cpp',
+                           'src/dawn/' + prefix + '_thread_dispatch_proc.cpp',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+        if 'webgpu_dawn_native_proc' in targets:
+            renders.append(
+                FileRender('dawn/native/api_dawn_native_proc.cpp',
+                           'src/dawn/native/webgpu_dawn_native_proc.cpp',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+        if 'cpp' in targets:
+            renders.append(
+                FileRender('api_cpp.cpp', 'src/dawn/' + api + '_cpp.cpp',
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+        if 'webgpu_headers' in targets:
+            params_upstream = parse_json(loaded_json,
+                                         enabled_tags=['upstream', 'native'],
+                                         disabled_tags=['dawn'])
+            renders.append(
+                FileRender('api.h', 'webgpu-headers/' + api + '.h',
+                           [RENDER_PARAMS_BASE, params_upstream]))
+
+        if 'emscripten_bits' in targets:
+            params_emscripten = parse_json(loaded_json,
+                                           enabled_tags=['emscripten'])
+            renders.append(
+                FileRender('api.h', 'emscripten-bits/' + api + '.h',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+            renders.append(
+                FileRender('api_cpp.h', 'emscripten-bits/' + api + '_cpp.h',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+            renders.append(
+                FileRender('api_cpp.cpp', 'emscripten-bits/' + api + '_cpp.cpp',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+            renders.append(
+                FileRender('api_struct_info.json',
+                           'emscripten-bits/' + api + '_struct_info.json',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+            renders.append(
+                FileRender('library_api_enum_tables.js',
+                           'emscripten-bits/library_' + api + '_enum_tables.js',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+
+        if 'mock_api' in targets:
+            mock_params = [
+                RENDER_PARAMS_BASE, params_dawn, {
+                    'has_callback_arguments': has_callback_arguments
+                }
+            ]
+            renders.append(
+                FileRender('mock_api.h', 'src/dawn/mock_' + api + '.h',
+                           mock_params))
+            renders.append(
+                FileRender('mock_api.cpp', 'src/dawn/mock_' + api + '.cpp',
+                           mock_params))
+
+        if 'native_utils' in targets:
+            frontend_params = [
+                RENDER_PARAMS_BASE,
+                params_dawn,
+                {
+                    # TODO: as_frontendType and co. take a Type, not a Name :(
+                    'as_frontendType': lambda typ: as_frontendType(metadata, typ),
+                    'as_annotated_frontendType': \
+                        lambda arg: annotated(as_frontendType(metadata, arg.type), arg),
+                }
+            ]
+
+            impl_dir = metadata.impl_dir + '/' if metadata.impl_dir else ''
+            native_dir = impl_dir + Name(metadata.native_namespace).Dirs()
+            namespace = metadata.namespace
+            renders.append(
+                FileRender('dawn/native/ValidationUtils.h',
+                           'src/' + native_dir + '/ValidationUtils_autogen.h',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/ValidationUtils.cpp',
+                           'src/' + native_dir + '/ValidationUtils_autogen.cpp',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/dawn_platform.h',
+                           'src/' + native_dir + '/' + prefix + '_platform_autogen.h',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/api_structs.h',
+                           'src/' + native_dir + '/' + namespace + '_structs_autogen.h',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/api_structs.cpp',
+                           'src/' + native_dir + '/' + namespace + '_structs_autogen.cpp',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/ProcTable.cpp',
+                           'src/' + native_dir + '/ProcTable.cpp', frontend_params))
+            renders.append(
+                FileRender('dawn/native/ChainUtils.h',
+                           'src/' + native_dir + '/ChainUtils_autogen.h',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/ChainUtils.cpp',
+                           'src/' + native_dir + '/ChainUtils_autogen.cpp',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/api_absl_format.h',
+                           'src/' + native_dir + '/' + api + '_absl_format_autogen.h',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/api_absl_format.cpp',
+                           'src/' + native_dir + '/' + api + '_absl_format_autogen.cpp',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/ObjectType.h',
+                           'src/' + native_dir + '/ObjectType_autogen.h',
+                           frontend_params))
+            renders.append(
+                FileRender('dawn/native/ObjectType.cpp',
+                           'src/' + native_dir + '/ObjectType_autogen.cpp',
+                           frontend_params))
+
+        if 'wire' in targets:
+            params_dawn_wire = parse_json(loaded_json,
+                                          enabled_tags=['dawn', 'deprecated'],
+                                          disabled_tags=['native'])
+            additional_params = compute_wire_params(params_dawn_wire,
+                                                    wire_json)
+
+            wire_params = [
+                RENDER_PARAMS_BASE, params_dawn_wire, {
+                    'as_wireType': lambda type : as_wireType(metadata, type),
+                    'as_annotated_wireType': \
+                        lambda arg: annotated(as_wireType(metadata, arg.type), arg),
+                }, additional_params
+            ]
+            renders.append(
+                FileRender('dawn/wire/ObjectType.h',
+                           'src/dawn/wire/ObjectType_autogen.h', wire_params))
+            renders.append(
+                FileRender('dawn/wire/WireCmd.h',
+                           'src/dawn/wire/WireCmd_autogen.h', wire_params))
+            renders.append(
+                FileRender('dawn/wire/WireCmd.cpp',
+                           'src/dawn/wire/WireCmd_autogen.cpp', wire_params))
+            renders.append(
+                FileRender('dawn/wire/client/ApiObjects.h',
+                           'src/dawn/wire/client/ApiObjects_autogen.h',
+                           wire_params))
+            renders.append(
+                FileRender('dawn/wire/client/ApiProcs.cpp',
+                           'src/dawn/wire/client/ApiProcs_autogen.cpp',
+                           wire_params))
+            renders.append(
+                FileRender('dawn/wire/client/ClientBase.h',
+                           'src/dawn/wire/client/ClientBase_autogen.h',
+                           wire_params))
+            renders.append(
+                FileRender('dawn/wire/client/ClientHandlers.cpp',
+                           'src/dawn/wire/client/ClientHandlers_autogen.cpp',
+                           wire_params))
+            renders.append(
+                FileRender(
+                    'dawn/wire/client/ClientPrototypes.inc',
+                    'src/dawn/wire/client/ClientPrototypes_autogen.inc',
+                    wire_params))
+            renders.append(
+                FileRender('dawn/wire/server/ServerBase.h',
+                           'src/dawn/wire/server/ServerBase_autogen.h',
+                           wire_params))
+            renders.append(
+                FileRender('dawn/wire/server/ServerDoers.cpp',
+                           'src/dawn/wire/server/ServerDoers_autogen.cpp',
+                           wire_params))
+            renders.append(
+                FileRender('dawn/wire/server/ServerHandlers.cpp',
+                           'src/dawn/wire/server/ServerHandlers_autogen.cpp',
+                           wire_params))
+            renders.append(
+                FileRender(
+                    'dawn/wire/server/ServerPrototypes.inc',
+                    'src/dawn/wire/server/ServerPrototypes_autogen.inc',
+                    wire_params))
+
+        return renders
+
+    def get_dependencies(self, args):
+        deps = [os.path.abspath(args.dawn_json)]
+        if args.wire_json != None:
+            deps += [os.path.abspath(args.wire_json)]
+        return deps
+
+
+if __name__ == '__main__':
+    sys.exit(run_generator(MultiGeneratorFromDawnJSON()))
diff --git a/generator/dawn_version_generator.py b/generator/dawn_version_generator.py
new file mode 100644
index 0000000..1907e88
--- /dev/null
+++ b/generator/dawn_version_generator.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+# Copyright 2022 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os, subprocess, sys
+
+from generator_lib import Generator, run_generator, FileRender
+
+
+def get_git():
+    return 'git.bat' if sys.platform == 'win32' else 'git'
+
+
+def get_gitHash(dawnDir):
+    result = subprocess.run([get_git(), 'rev-parse', 'HEAD'],
+                            stdout=subprocess.PIPE,
+                            cwd=dawnDir)
+    if result.returncode == 0:
+        return result.stdout.decode('utf-8').strip()
+    # No hash was available (possibly) because the directory was not a git checkout. Dawn should
+    # explicitly handle its absenece and disable features relying on the hash, i.e. caching.
+    return ''
+
+
+def get_gitHead(dawnDir):
+    return os.path.join(dawnDir, '.git', 'HEAD')
+
+
+def gitExists(dawnDir):
+    return os.path.exists(get_gitHead(dawnDir))
+
+
+def unpackGitRef(packed, resolved):
+    with open(packed) as fin:
+        refs = fin.read().strip().split('\n')
+
+    # Strip comments
+    refs = [ref.split(' ') for ref in refs if ref.strip()[0] != '#']
+
+    # Parse results which are in the format [<gitHash>, <refFile>] from previous step.
+    refs = [gitHash for (gitHash, refFile) in refs if refFile == resolved]
+    if len(refs) == 1:
+        with open(resolved, 'w') as fout:
+            fout.write(refs[0] + '\n')
+        return True
+    return False
+
+
+def get_gitResolvedHead(dawnDir):
+    result = subprocess.run(
+        [get_git(), 'rev-parse', '--symbolic-full-name', 'HEAD'],
+        stdout=subprocess.PIPE,
+        cwd=dawnDir)
+    if result.returncode != 0:
+        raise Exception('Failed to execute git rev-parse to resolve git head.')
+
+    resolved = os.path.join(dawnDir, '.git',
+                            result.stdout.decode('utf-8').strip())
+
+    # Check a packed-refs file exists. If so, we need to potentially unpack and include it as a dep.
+    packed = os.path.join(dawnDir, '.git', 'packed-refs')
+    if os.path.exists(packed) and unpackGitRef(packed, resolved):
+        return [packed, resolved]
+
+    if not os.path.exists(resolved):
+        raise Exception('Unable to resolve git HEAD hash file:', path)
+    return [resolved]
+
+
+def compute_params(args):
+    return {
+        'get_gitHash': lambda: get_gitHash(os.path.abspath(args.dawn_dir)),
+    }
+
+
+class DawnVersionGenerator(Generator):
+    def get_description(self):
+        return 'Generates version dependent Dawn code. Currently regenerated dependent on git hash.'
+
+    def add_commandline_arguments(self, parser):
+        parser.add_argument('--dawn-dir',
+                            required=True,
+                            type=str,
+                            help='The Dawn root directory path to use')
+
+    def get_dependencies(self, args):
+        dawnDir = os.path.abspath(args.dawn_dir)
+        if gitExists(dawnDir):
+            return [get_gitHead(dawnDir)] + get_gitResolvedHead(dawnDir)
+        return []
+
+    def get_file_renders(self, args):
+        params = compute_params(args)
+
+        return [
+            FileRender('dawn/common/Version.h',
+                       'src/dawn/common/Version_autogen.h', [params]),
+        ]
+
+
+if __name__ == '__main__':
+    sys.exit(run_generator(DawnVersionGenerator()))
diff --git a/generator/extract_json.py b/generator/extract_json.py
new file mode 100644
index 0000000..67114bf
--- /dev/null
+++ b/generator/extract_json.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+# Copyright 2018 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import os, sys, json
+
+if __name__ == "__main__":
+    if len(sys.argv) != 3:
+        print("Usage: extract_json.py JSON DIR")
+        sys.exit(1)
+
+    with open(sys.argv[1]) as f:
+        files = json.loads(f.read())
+
+    output_dir = sys.argv[2]
+
+    for (name, content) in files.items():
+        output_file = output_dir + os.path.sep + name
+
+        # Create the output directory if needed.
+        directory = os.path.dirname(output_file)
+        if not os.path.exists(directory):
+            os.makedirs(directory)
+
+        # Skip writing to the file if it already has the correct content.
+        try:
+            with open(output_file, 'r') as outfile:
+                if outfile.read() == content:
+                    continue
+        except (OSError, EnvironmentError):
+            pass
+
+        with open(output_file, 'w') as outfile:
+            outfile.write(content)
diff --git a/generator/generator_lib.gni b/generator/generator_lib.gni
new file mode 100644
index 0000000..8b9e04c
--- /dev/null
+++ b/generator/generator_lib.gni
@@ -0,0 +1,164 @@
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Template to help invoking code generators based on generator_lib.py
+# Internal use only, this should only be called from templates implementing
+# generator-specific actions.
+#
+# Variables:
+#   script: Path to generator script.
+#
+#   args: List of extra command-line arguments passed to the generator.
+#
+#   outputs: List of expected outputs, generation will fail if there is a
+#     mistmatch.
+#
+#   deps: additional deps for the code generation targets.
+#
+#   generator_lib_dir: directory where generator_lib.py is located.
+#
+#   custom_gen_dir: Optional custom target gen dir. Defaults to $target_gen_dir
+#     but allows output files to not depend on the location of the BUILD.gn
+#     that generates them.
+#
+#   template_dir: Optional template root directory. Defaults to
+#     "${generator_lib_dir}/templates".
+#
+#   jinja2_path: Optional Jinja2 installation path.
+#
+#   allowed_output_dirs: Optional list of directories that are the only
+#     directories in which files of `outputs` are allowed to be (and not
+#     in children directories). Generation will fail if an output isn't
+#     in a directory in the list.
+#
+#   root_dir: Optional root source dir for Python dependencies
+#     computation. Defaults to "${generator_lib_dir}/..". Any dependency
+#     outside of this directory is considered a system file and will be
+#     omitted.
+#
+template("generator_lib_action") {
+  _generator_args = []
+  if (defined(invoker.args)) {
+    _generator_args += invoker.args
+  }
+
+  assert(defined(invoker.generator_lib_dir),
+         "generator_lib_dir must be defined before calling this action!")
+
+  _template_dir = "${invoker.generator_lib_dir}/templates"
+  if (defined(invoker.template_dir)) {
+    _template_dir = invoker.template_dir
+  }
+  _generator_args += [
+    "--template-dir",
+    rebase_path(_template_dir),
+  ]
+
+  if (defined(invoker.root_dir)) {
+    _generator_args += [
+      "--root-dir",
+      rebase_path(_root_dir, root_build_dir),
+    ]
+  }
+
+  if (defined(invoker.jinja2_path)) {
+    _generator_args += [
+      "--jinja2-path",
+      rebase_path(invoker.jinja2_path),
+    ]
+  }
+
+  # Chooses either the default gen_dir or the custom one required by the
+  # invoker. This allows moving the definition of code generators in different
+  # BUILD.gn files without changing the location of generated file. Without
+  # this generated headers could cause issues when old headers aren't removed.
+  _gen_dir = target_gen_dir
+  if (defined(invoker.custom_gen_dir)) {
+    _gen_dir = invoker.custom_gen_dir
+  }
+
+  # For build parallelism GN wants to know the exact inputs and outputs of
+  # action targets like we use for our code generator. We avoid asking the
+  # generator about its inputs by using the "depfile" feature of GN/Ninja.
+  #
+  # A ninja limitation is that the depfile is a subset of Makefile that can
+  # contain a single target, so we output a single "JSON-tarball" instead.
+  _json_tarball = "${_gen_dir}/${target_name}.json_tarball"
+  _json_tarball_target = "${target_name}__json_tarball"
+  _json_tarball_depfile = "${_json_tarball}.d"
+
+  _generator_args += [
+    "--output-json-tarball",
+    rebase_path(_json_tarball, root_build_dir),
+    "--depfile",
+    rebase_path(_json_tarball_depfile, root_build_dir),
+  ]
+
+  # After the JSON tarball is created we need an action target to extract it
+  # with a list of its outputs. The invoker provided a list of expected
+  # outputs. To make sure the list is in sync between the generator and the
+  # build files, we write it to a file and ask the generator to assert it is
+  # correct.
+  _expected_outputs_file = "${_gen_dir}/${target_name}.expected_outputs"
+  write_file(_expected_outputs_file, invoker.outputs)
+
+  _generator_args += [
+    "--expected-outputs-file",
+    rebase_path(_expected_outputs_file, root_build_dir),
+  ]
+
+  # Check that all of the outputs are in a directory that's allowed. This is
+  # useful to keep the list of directories in sink with other parts of the
+  # build.
+  if (defined(invoker.allowed_output_dirs)) {
+    _allowed_output_dirs_file = "${_gen_dir}/${target_name}.allowed_output_dirs"
+    write_file(_allowed_output_dirs_file, invoker.allowed_output_dirs)
+
+    _generator_args += [
+      "--allowed-output-dirs-file",
+      rebase_path(_allowed_output_dirs_file, root_build_dir),
+    ]
+  }
+
+  # The code generator invocation that will write the JSON tarball, check the
+  # outputs are what's expected and write a depfile for Ninja.
+  action(_json_tarball_target) {
+    script = invoker.script
+    outputs = [ _json_tarball ]
+    depfile = _json_tarball_depfile
+    args = _generator_args
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+
+  # Extract the JSON tarball into the gen_dir
+  action(target_name) {
+    script = "${invoker.generator_lib_dir}/extract_json.py"
+    args = [
+      rebase_path(_json_tarball, root_build_dir),
+      rebase_path(_gen_dir, root_build_dir),
+    ]
+
+    deps = [ ":${_json_tarball_target}" ]
+    inputs = [ _json_tarball ]
+
+    # The expected output list is relative to the gen_dir but action
+    # target outputs are from the root dir so we need to rebase them.
+    outputs = []
+    foreach(source, invoker.outputs) {
+      outputs += [ "${_gen_dir}/${source}" ]
+    }
+  }
+}
diff --git a/generator/generator_lib.py b/generator/generator_lib.py
new file mode 100644
index 0000000..11b3ed2
--- /dev/null
+++ b/generator/generator_lib.py
@@ -0,0 +1,374 @@
+#!/usr/bin/env python3
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Module to create generators that render multiple Jinja2 templates for GN.
+
+A helper module that can be used to create generator scripts (clients)
+that expand one or more Jinja2 templates, without outputs usable from
+GN and Ninja build-based systems. See generator_lib.gni as well.
+
+Clients should create a Generator sub-class, then call run_generator()
+with a proper derived class instance.
+
+Clients specify a list of FileRender operations, each one of them will
+output a file into a temporary output directory through Jinja2 expansion.
+All temporary output files are then grouped and written to into a single JSON
+file, that acts as a convenient single GN output target. Use extract_json.py
+to extract the output files from the JSON tarball in another GN action.
+
+--depfile can be used to specify an output Ninja dependency file for the
+JSON tarball, to ensure it is regenerated any time one of its dependencies
+changes.
+
+Finally, --expected-output-files can be used to check the list of generated
+output files.
+"""
+
+import argparse, json, os, re, sys
+from collections import namedtuple
+
+# A FileRender represents a single Jinja2 template render operation:
+#
+#   template: Jinja2 template name, relative to --template-dir path.
+#
+#   output: Output file path, relative to temporary output directory.
+#
+#   params_dicts: iterable of (name:string -> value:string) dictionaries.
+#       All of them will be merged before being sent as Jinja2 template
+#       expansion parameters.
+#
+# Example:
+#   FileRender('api.c', 'src/project_api.c', [{'PROJECT_VERSION': '1.0.0'}])
+#
+FileRender = namedtuple('FileRender', ['template', 'output', 'params_dicts'])
+
+
+# The interface that must be implemented by generators.
+class Generator:
+    def get_description(self):
+        """Return generator description for --help."""
+        return ""
+
+    def add_commandline_arguments(self, parser):
+        """Add generator-specific argparse arguments."""
+        pass
+
+    def get_file_renders(self, args):
+        """Return the list of FileRender objects to process."""
+        return []
+
+    def get_dependencies(self, args):
+        """Return a list of extra input dependencies."""
+        return []
+
+
+# Allow custom Jinja2 installation path through an additional python
+# path from the arguments if present. This isn't done through the regular
+# argparse because PreprocessingLoader uses jinja2 in the global scope before
+# "main" gets to run.
+#
+# NOTE: If this argument appears several times, this only uses the first
+#       value, while argparse would typically keep the last one!
+kJinja2Path = '--jinja2-path'
+try:
+    jinja2_path_argv_index = sys.argv.index(kJinja2Path)
+    # Add parent path for the import to succeed.
+    path = os.path.join(sys.argv[jinja2_path_argv_index + 1], os.pardir)
+    sys.path.insert(1, path)
+except ValueError:
+    # --jinja2-path isn't passed, ignore the exception and just import Jinja2
+    # assuming it already is in the Python PATH.
+    pass
+
+import jinja2
+
+
+# A custom Jinja2 template loader that removes the extra indentation
+# of the template blocks so that the output is correctly indented
+class _PreprocessingLoader(jinja2.BaseLoader):
+    def __init__(self, path):
+        self.path = path
+
+    def get_source(self, environment, template):
+        path = os.path.join(self.path, template)
+        if not os.path.exists(path):
+            raise jinja2.TemplateNotFound(template)
+        mtime = os.path.getmtime(path)
+        with open(path) as f:
+            source = self.preprocess(f.read())
+        return source, path, lambda: mtime == os.path.getmtime(path)
+
+    blockstart = re.compile('{%-?\s*(if|elif|else|for|block|macro)[^}]*%}')
+    blockend = re.compile('{%-?\s*(end(if|for|block|macro)|elif|else)[^}]*%}')
+
+    def preprocess(self, source):
+        lines = source.split('\n')
+
+        # Compute the current indentation level of the template blocks and
+        # remove their indentation
+        result = []
+        indentation_level = 0
+
+        # Filter lines that are pure comments. line_comment_prefix is not
+        # enough because it removes the comment but doesn't completely remove
+        # the line, resulting in more verbose output.
+        lines = filter(lambda line: not line.strip().startswith('//*'), lines)
+
+        # Remove indentation templates have for the Jinja control flow.
+        for line in lines:
+            # The capture in the regex adds one element per block start or end,
+            # so we divide by two. There is also an extra line chunk
+            # corresponding to the line end, so we subtract it.
+            numends = (len(self.blockend.split(line)) - 1) // 2
+            indentation_level -= numends
+
+            result.append(self.remove_indentation(line, indentation_level))
+
+            numstarts = (len(self.blockstart.split(line)) - 1) // 2
+            indentation_level += numstarts
+
+        return '\n'.join(result) + '\n'
+
+    def remove_indentation(self, line, n):
+        for _ in range(n):
+            if line.startswith(' '):
+                line = line[4:]
+            elif line.startswith('\t'):
+                line = line[1:]
+            else:
+                assert line.strip() == ''
+        return line
+
+
+_FileOutput = namedtuple('FileOutput', ['name', 'content'])
+
+
+def _do_renders(renders, template_dir):
+    loader = _PreprocessingLoader(template_dir)
+    env = jinja2.Environment(extensions=['jinja2.ext.do'],
+                             loader=loader,
+                             lstrip_blocks=True,
+                             trim_blocks=True,
+                             line_comment_prefix='//*')
+
+    def do_assert(expr):
+        assert expr
+        return ''
+
+    def debug(text):
+        print(text)
+
+    base_params = {
+        'enumerate': enumerate,
+        'format': format,
+        'len': len,
+        'debug': debug,
+        'assert': do_assert,
+    }
+
+    outputs = []
+    for render in renders:
+        params = {}
+        params.update(base_params)
+        for param_dict in render.params_dicts:
+            params.update(param_dict)
+        content = env.get_template(render.template).render(**params)
+        outputs.append(_FileOutput(render.output, content))
+
+    return outputs
+
+
+# Compute the list of imported, non-system Python modules.
+# It assumes that any path outside of the root directory is system.
+def _compute_python_dependencies(root_dir=None):
+    if not root_dir:
+        # Assume this script is under generator/ by default.
+        root_dir = os.path.join(os.path.dirname(__file__), os.pardir)
+    root_dir = os.path.abspath(root_dir)
+
+    module_paths = (module.__file__ for module in sys.modules.values()
+                    if module and hasattr(module, '__file__'))
+
+    paths = set()
+    for path in module_paths:
+        # Builtin/namespaced modules may return None for the file path.
+        if not path:
+            continue
+
+        path = os.path.abspath(path)
+
+        if not path.startswith(root_dir):
+            continue
+
+        if (path.endswith('.pyc')
+                or (path.endswith('c') and not os.path.splitext(path)[1])):
+            path = path[:-1]
+
+        paths.add(path)
+
+    return paths
+
+
+def run_generator(generator):
+    parser = argparse.ArgumentParser(
+        description=generator.get_description(),
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+    )
+
+    generator.add_commandline_arguments(parser)
+    parser.add_argument('--template-dir',
+                        default='templates',
+                        type=str,
+                        help='Directory with template files.')
+    parser.add_argument(
+        kJinja2Path,
+        default=None,
+        type=str,
+        help='Additional python path to set before loading Jinja2')
+    parser.add_argument(
+        '--output-json-tarball',
+        default=None,
+        type=str,
+        help=('Name of the "JSON tarball" to create (tar is too annoying '
+              'to use in python).'))
+    parser.add_argument(
+        '--depfile',
+        default=None,
+        type=str,
+        help='Name of the Ninja depfile to create for the JSON tarball')
+    parser.add_argument(
+        '--expected-outputs-file',
+        default=None,
+        type=str,
+        help="File to compare outputs with and fail if it doesn't match")
+    parser.add_argument(
+        '--root-dir',
+        default=None,
+        type=str,
+        help=('Optional source root directory for Python dependency '
+              'computations'))
+    parser.add_argument(
+        '--allowed-output-dirs-file',
+        default=None,
+        type=str,
+        help=("File containing a list of allowed directories where files "
+              "can be output."))
+    parser.add_argument(
+        '--print-cmake-dependencies',
+        default=False,
+        action="store_true",
+        help=("Prints a semi-colon separated list of dependencies to "
+              "stdout and exits."))
+    parser.add_argument(
+        '--print-cmake-outputs',
+        default=False,
+        action="store_true",
+        help=("Prints a semi-colon separated list of outputs to "
+              "stdout and exits."))
+    parser.add_argument('--output-dir',
+                        default=None,
+                        type=str,
+                        help='Directory where to output generate files.')
+
+    args = parser.parse_args()
+
+    renders = generator.get_file_renders(args)
+
+    # Output a list of all dependencies for CMake or the tarball for GN/Ninja.
+    if args.depfile != None or args.print_cmake_dependencies:
+        dependencies = generator.get_dependencies(args)
+        dependencies += [
+            args.template_dir + os.path.sep + render.template
+            for render in renders
+        ]
+        dependencies += _compute_python_dependencies(args.root_dir)
+
+        if args.depfile != None:
+            with open(args.depfile, 'w') as f:
+                f.write(args.output_json_tarball + ": " +
+                        " ".join(dependencies))
+
+        if args.print_cmake_dependencies:
+            sys.stdout.write(";".join(dependencies))
+            return 0
+
+    # The caller wants to assert that the outputs are what it expects.
+    # Load the file and compare with our renders.
+    if args.expected_outputs_file != None:
+        with open(args.expected_outputs_file) as f:
+            expected = set([line.strip() for line in f.readlines()])
+
+        actual = {render.output for render in renders}
+
+        if actual != expected:
+            print("Wrong expected outputs, caller expected:\n    " +
+                  repr(sorted(expected)))
+            print("Actual output:\n    " + repr(sorted(actual)))
+            return 1
+
+    # Print the list of all the outputs for cmake.
+    if args.print_cmake_outputs:
+        sys.stdout.write(";".join([
+            os.path.join(args.output_dir, render.output) for render in renders
+        ]))
+        return 0
+
+    outputs = _do_renders(renders, args.template_dir)
+
+    # The caller wants to assert that the outputs are only in specific
+    # directories.
+    if args.allowed_output_dirs_file != None:
+        with open(args.allowed_output_dirs_file) as f:
+            allowed_dirs = set([line.strip() for line in f.readlines()])
+
+        for directory in allowed_dirs:
+            if not directory.endswith('/'):
+                print('Allowed directory entry "{}" doesn\'t '
+                      'end with /'.format(directory))
+                return 1
+
+        def check_in_subdirectory(path, directory):
+            return path.startswith(
+                directory) and not '/' in path[len(directory):]
+
+        for render in renders:
+            if not any(
+                    check_in_subdirectory(render.output, directory)
+                    for directory in allowed_dirs):
+                print('Output file "{}" is not in the allowed directory '
+                      'list below:'.format(render.output))
+                for directory in sorted(allowed_dirs):
+                    print('    "{}"'.format(directory))
+                return 1
+
+    # Output the JSON tarball
+    if args.output_json_tarball != None:
+        json_root = {}
+        for output in outputs:
+            json_root[output.name] = output.content
+
+        with open(args.output_json_tarball, 'w') as f:
+            f.write(json.dumps(json_root))
+
+    # Output the files directly.
+    if args.output_dir != None:
+        for output in outputs:
+            output_path = os.path.join(args.output_dir, output.name)
+
+            directory = os.path.dirname(output_path)
+            if not os.path.exists(directory):
+                os.makedirs(directory)
+
+            with open(output_path, 'w') as outfile:
+                outfile.write(output.content)
diff --git a/generator/opengl_loader_generator.py b/generator/opengl_loader_generator.py
new file mode 100644
index 0000000..db253e2
--- /dev/null
+++ b/generator/opengl_loader_generator.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python3
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os, json, sys
+from collections import namedtuple
+import xml.etree.ElementTree as etree
+
+from generator_lib import Generator, run_generator, FileRender
+
+
+class ProcName:
+    def __init__(self, gl_name, proc_name=None):
+        assert gl_name.startswith('gl')
+        if proc_name == None:
+            proc_name = gl_name[2:]
+
+        self.gl_name = gl_name
+        self.proc_name = proc_name
+
+    def glProcName(self):
+        return self.gl_name
+
+    def ProcName(self):
+        return self.proc_name
+
+    def PFNPROCNAME(self):
+        return 'PFN' + self.gl_name.upper() + 'PROC'
+
+    def __repr__(self):
+        return 'Proc("{}", "{}")'.format(self.gl_name, self.proc_name)
+
+
+ProcParam = namedtuple('ProcParam', ['name', 'type'])
+
+
+class Proc:
+    def __init__(self, element):
+        # Type declaration for return values and arguments all have the same
+        # (weird) format.
+        # <element>[A][<ptype>B</ptype>][C]<other stuff.../></element>
+        #
+        # Some examples are:
+        #   <proto>void <name>glFinish</name></proto>
+        #   <proto><ptype>GLenum</ptype><name>glFenceSync</name></proto>
+        #   <proto>const <ptype>GLubyte</ptype> *<name>glGetString</name></proto>
+        #
+        # This handles all the shapes found in gl.xml except for this one that
+        # has an array specifier after </name>:
+        #   <param><ptype>GLuint</ptype> <name>baseAndCount</name>[2]</param>
+        def parse_type_declaration(element):
+            result = ''
+            if element.text != None:
+                result += element.text
+            ptype = element.find('ptype')
+            if ptype != None:
+                result += ptype.text
+                if ptype.tail != None:
+                    result += ptype.tail
+            return result.strip()
+
+        proto = element.find('proto')
+
+        self.return_type = parse_type_declaration(proto)
+
+        self.params = []
+        for param in element.findall('./param'):
+            self.params.append(
+                ProcParam(
+                    param.find('name').text, parse_type_declaration(param)))
+
+        self.gl_name = proto.find('name').text
+        self.alias = None
+        if element.find('alias') != None:
+            self.alias = element.find('alias').attrib['name']
+
+    def glProcName(self):
+        return self.gl_name
+
+    def ProcName(self):
+        assert self.gl_name.startswith('gl')
+        return self.gl_name[2:]
+
+    def PFNGLPROCNAME(self):
+        return 'PFN' + self.gl_name.upper() + 'PROC'
+
+    def __repr__(self):
+        return 'Proc("{}")'.format(self.gl_name)
+
+
+EnumDefine = namedtuple('EnumDefine', ['name', 'value'])
+Version = namedtuple('Version', ['major', 'minor'])
+VersionBlock = namedtuple('VersionBlock', ['version', 'procs', 'enums'])
+HeaderBlock = namedtuple('HeaderBlock', ['description', 'procs', 'enums'])
+ExtensionBlock = namedtuple('ExtensionBlock',
+                            ['extension', 'procs', 'enums', 'supported_specs'])
+
+
+def parse_version(version):
+    return Version(*map(int, version.split('.')))
+
+
+def compute_params(root, supported_extensions):
+    # Parse all the commands and enums
+    all_procs = {}
+    for command in root.findall('''commands[@namespace='GL']/command'''):
+        proc = Proc(command)
+        assert proc.gl_name not in all_procs
+        all_procs[proc.gl_name] = proc
+
+    all_enums = {}
+    for enum in root.findall('''enums[@namespace='GL']/enum'''):
+        enum_name = enum.attrib['name']
+        # Special case an enum we'll never use that has different values in GL and GLES
+        if enum_name == 'GL_ACTIVE_PROGRAM_EXT':
+            continue
+
+        assert enum_name not in all_enums
+        all_enums[enum_name] = EnumDefine(enum_name, enum.attrib['value'])
+
+    # Get the list of all Desktop OpenGL function removed by the Core Profile.
+    core_removed_procs = set()
+    for proc in root.findall('''feature/remove[@profile='core']/command'''):
+        core_removed_procs.add(proc.attrib['name'])
+
+    # Get list of enums and procs per OpenGL ES/Desktop OpenGL version
+    def parse_version_blocks(api, removed_procs=set()):
+        blocks = []
+        for section in root.findall('''feature[@api='{}']'''.format(api)):
+            section_procs = []
+            for command in section.findall('./require/command'):
+                proc_name = command.attrib['name']
+                assert all_procs[proc_name].alias == None
+                if proc_name not in removed_procs:
+                    section_procs.append(all_procs[proc_name])
+
+            section_enums = []
+            for enum in section.findall('./require/enum'):
+                section_enums.append(all_enums[enum.attrib['name']])
+
+            blocks.append(
+                VersionBlock(parse_version(section.attrib['number']),
+                             section_procs, section_enums))
+
+        return blocks
+
+    gles_blocks = parse_version_blocks('gles2')
+    desktop_gl_blocks = parse_version_blocks('gl', core_removed_procs)
+
+    def parse_extension_block(extension):
+        section = root.find(
+            '''extensions/extension[@name='{}']'''.format(extension))
+        supported_specs = section.attrib['supported'].split('|')
+        section_procs = []
+        for command in section.findall('./require/command'):
+            proc_name = command.attrib['name']
+            assert all_procs[proc_name].alias == None
+            section_procs.append(all_procs[proc_name])
+
+        section_enums = []
+        for enum in section.findall('./require/enum'):
+            section_enums.append(all_enums[enum.attrib['name']])
+
+        return ExtensionBlock(extension, section_procs, section_enums,
+                              supported_specs)
+
+    extension_desktop_gl_blocks = []
+    extension_gles_blocks = []
+    for extension in supported_extensions:
+        extension_block = parse_extension_block(extension)
+        if 'gl' in extension_block.supported_specs:
+            extension_desktop_gl_blocks.append(extension_block)
+        if 'gles2' in extension_block.supported_specs:
+            extension_gles_blocks.append(extension_block)
+
+    # Compute the blocks for headers such that there is no duplicate definition
+    already_added_header_procs = set()
+    already_added_header_enums = set()
+    header_blocks = []
+
+    def add_header_block(description, block):
+        block_procs = []
+        for proc in block.procs:
+            if not proc.glProcName() in already_added_header_procs:
+                already_added_header_procs.add(proc.glProcName())
+                block_procs.append(proc)
+
+        block_enums = []
+        for enum in block.enums:
+            if not enum.name in already_added_header_enums:
+                already_added_header_enums.add(enum.name)
+                block_enums.append(enum)
+
+        if len(block_procs) > 0 or len(block_enums) > 0:
+            header_blocks.append(
+                HeaderBlock(description, block_procs, block_enums))
+
+    for block in gles_blocks:
+        add_header_block(
+            'OpenGL ES {}.{}'.format(block.version.major, block.version.minor),
+            block)
+
+    for block in desktop_gl_blocks:
+        add_header_block(
+            'Desktop OpenGL {}.{}'.format(block.version.major,
+                                          block.version.minor), block)
+
+    for block in extension_desktop_gl_blocks:
+        add_header_block(block.extension, block)
+
+    for block in extension_gles_blocks:
+        add_header_block(block.extension, block)
+
+    return {
+        'gles_blocks': gles_blocks,
+        'desktop_gl_blocks': desktop_gl_blocks,
+        'extension_desktop_gl_blocks': extension_desktop_gl_blocks,
+        'extension_gles_blocks': extension_gles_blocks,
+        'header_blocks': header_blocks,
+    }
+
+
+class OpenGLLoaderGenerator(Generator):
+    def get_description(self):
+        return 'Generates code to load OpenGL function pointers'
+
+    def add_commandline_arguments(self, parser):
+        parser.add_argument('--gl-xml',
+                            required=True,
+                            type=str,
+                            help='The Khronos gl.xml to use.')
+        parser.add_argument(
+            '--supported-extensions',
+            required=True,
+            type=str,
+            help=
+            'The JSON file that defines the OpenGL and GLES extensions to use.'
+        )
+
+    def get_file_renders(self, args):
+        supported_extensions = []
+        with open(args.supported_extensions) as f:
+            supported_extensions_json = json.loads(f.read())
+            supported_extensions = supported_extensions_json[
+                'supported_extensions']
+
+        params = compute_params(
+            etree.parse(args.gl_xml).getroot(), supported_extensions)
+
+        return [
+            FileRender(
+                'opengl/OpenGLFunctionsBase.cpp',
+                'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.cpp',
+                [params]),
+            FileRender('opengl/OpenGLFunctionsBase.h',
+                       'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.h',
+                       [params]),
+            FileRender('opengl/opengl_platform.h',
+                       'src/dawn/native/opengl/opengl_platform_autogen.h',
+                       [params]),
+        ]
+
+    def get_dependencies(self, args):
+        return [
+            os.path.abspath(args.gl_xml),
+            os.path.abspath(args.supported_extensions)
+        ]
+
+
+if __name__ == '__main__':
+    sys.exit(run_generator(OpenGLLoaderGenerator()))
diff --git a/generator/remove_files.py b/generator/remove_files.py
new file mode 100644
index 0000000..6ddf463
--- /dev/null
+++ b/generator/remove_files.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+# Copyright 2019 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse, glob, os, sys
+
+
+def check_in_subdirectory(path, directory):
+    return path.startswith(directory) and not '/' in path[len(directory):]
+
+
+def check_is_allowed(path, allowed_dirs):
+    return any(
+        check_in_subdirectory(path, directory) for directory in allowed_dirs)
+
+
+def get_all_files_in_dir(find_directory):
+    result = []
+    for (directory, _, files) in os.walk(find_directory):
+        result += [os.path.join(directory, filename) for filename in files]
+    return result
+
+
+def run():
+    # Parse command line arguments
+    parser = argparse.ArgumentParser(
+        description="Removes stale autogenerated files from gen/ directories.")
+    parser.add_argument(
+        '--root-dir',
+        type=str,
+        help='The root directory, all other paths in files are relative to it.'
+    )
+    parser.add_argument(
+        '--allowed-output-dirs-file',
+        type=str,
+        help='The file containing a list of allowed directories')
+    parser.add_argument(
+        '--stale-dirs-file',
+        type=str,
+        help=
+        'The file containing a list of directories to check for stale files')
+    parser.add_argument('--stamp',
+                        type=str,
+                        help='A stamp written once this script completes')
+    args = parser.parse_args()
+
+    root_dir = args.root_dir
+    stamp_file = args.stamp
+
+    # Load the list of allowed and stale directories
+    with open(args.allowed_output_dirs_file) as f:
+        allowed_dirs = set(
+            [os.path.join(root_dir, line.strip()) for line in f.readlines()])
+
+    for directory in allowed_dirs:
+        if not directory.endswith('/'):
+            print('Allowed directory entry "{}" doesn\'t end with /'.format(
+                directory))
+            return 1
+
+    with open(args.stale_dirs_file) as f:
+        stale_dirs = set([line.strip() for line in f.readlines()])
+
+    # Remove all files in stale dirs that aren't in the allowed dirs.
+    for stale_dir in stale_dirs:
+        stale_dir = os.path.join(root_dir, stale_dir)
+
+        for candidate in get_all_files_in_dir(stale_dir):
+            if not check_is_allowed(candidate, allowed_dirs):
+                os.remove(candidate)
+
+    # Finished! Write the stamp file so ninja knows to not run this again.
+    with open(stamp_file, "w") as f:
+        f.write("")
+
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(run())
diff --git a/generator/templates/.clang-format b/generator/templates/.clang-format
new file mode 100644
index 0000000..9d15924
--- /dev/null
+++ b/generator/templates/.clang-format
@@ -0,0 +1,2 @@
+DisableFormat: true
+SortIncludes: false
diff --git a/generator/templates/BSD_LICENSE b/generator/templates/BSD_LICENSE
new file mode 100644
index 0000000..eaef87a
--- /dev/null
+++ b/generator/templates/BSD_LICENSE
@@ -0,0 +1,29 @@
+// BSD 3-Clause License
+//
+// Copyright (c) {{metadata.copyright_year}}, "{{metadata.api}} native" developers
+// All rights reserved.
+//
+// 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.
diff --git a/generator/templates/api.h b/generator/templates/api.h
new file mode 100644
index 0000000..db9d94a
--- /dev/null
+++ b/generator/templates/api.h
@@ -0,0 +1,181 @@
+//* This template itself is part of the Dawn source and follows Dawn's license,
+//* which is Apache 2.0.
+//*
+//* The WebGPU native API is a joint project used by Google, Mozilla, and Apple.
+//* It was agreed to use a BSD 3-Clause license so that it is GPLv2-compatible.
+//*
+//* As a result, the template comments using //* at the top of the file are
+//* removed during generation such that the resulting file starts with the
+//* BSD 3-Clause comment, which is inside BSD_LICENSE as included below.
+//*
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+//*
+//*
+{% include 'BSD_LICENSE' %}
+{% if 'dawn' in enabled_tags %}
+    #ifdef __EMSCRIPTEN__
+    #error "Do not include this header. Emscripten already provides headers needed for {{metadata.api}}."
+    #endif
+{% endif %}
+#ifndef {{metadata.api.upper()}}_H_
+#define {{metadata.api.upper()}}_H_
+
+{% set c_prefix = metadata.c_prefix %}
+#if defined({{c_prefix}}_SHARED_LIBRARY)
+#    if defined(_WIN32)
+#        if defined({{c_prefix}}_IMPLEMENTATION)
+#            define {{c_prefix}}_EXPORT __declspec(dllexport)
+#        else
+#            define {{c_prefix}}_EXPORT __declspec(dllimport)
+#        endif
+#    else  // defined(_WIN32)
+#        if defined({{c_prefix}}_IMPLEMENTATION)
+#            define {{c_prefix}}_EXPORT __attribute__((visibility("default")))
+#        else
+#            define {{c_prefix}}_EXPORT
+#        endif
+#    endif  // defined(_WIN32)
+#else       // defined({{c_prefix}}_SHARED_LIBRARY)
+#    define {{c_prefix}}_EXPORT
+#endif  // defined({{c_prefix}}_SHARED_LIBRARY)
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+{% for constant in by_category["constant"] %}
+    #define {{c_prefix}}_{{constant.name.SNAKE_CASE()}} {{constant.value}}
+{% endfor %}
+
+typedef uint32_t {{c_prefix}}Flags;
+
+{% for type in by_category["object"] %}
+    typedef struct {{as_cType(type.name)}}Impl* {{as_cType(type.name)}};
+{% endfor %}
+
+{% for type in by_category["enum"] + by_category["bitmask"] %}
+    typedef enum {{as_cType(type.name)}} {
+        {% for value in type.values %}
+            {{as_cEnum(type.name, value.name)}} = 0x{{format(value.value, "08X")}},
+        {% endfor %}
+        {{as_cEnum(type.name, Name("force32"))}} = 0x7FFFFFFF
+    } {{as_cType(type.name)}};
+    {% if type.category == "bitmask" %}
+        typedef {{c_prefix}}Flags {{as_cType(type.name)}}Flags;
+    {% endif %}
+
+{% endfor -%}
+
+typedef struct {{c_prefix}}ChainedStruct {
+    struct {{c_prefix}}ChainedStruct const * next;
+    {{c_prefix}}SType sType;
+} {{c_prefix}}ChainedStruct;
+
+typedef struct {{c_prefix}}ChainedStructOut {
+    struct {{c_prefix}}ChainedStructOut * next;
+    {{c_prefix}}SType sType;
+} {{c_prefix}}ChainedStructOut;
+
+{% for type in by_category["structure"] %}
+    typedef struct {{as_cType(type.name)}} {
+        {% set Out = "Out" if type.output else "" %}
+        {% set const = "const " if not type.output else "" %}
+        {% if type.extensible %}
+            {{c_prefix}}ChainedStruct{{Out}} {{const}}* nextInChain;
+        {% endif %}
+        {% if type.chained %}
+            {{c_prefix}}ChainedStruct{{Out}} chain;
+        {% endif %}
+        {% for member in type.members %}
+            {{as_annotated_cType(member)}};
+        {% endfor %}
+    } {{as_cType(type.name)}};
+
+{% endfor %}
+{% for typeDef in by_category["typedef"] %}
+    // {{as_cType(typeDef.name)}} is deprecated.
+    // Use {{as_cType(typeDef.type.name)}} instead.
+    typedef {{as_cType(typeDef.type.name)}} {{as_cType(typeDef.name)}};
+
+{% endfor %}
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+{% for type in by_category["function pointer"] %}
+    typedef {{as_cType(type.return_type.name)}} (*{{as_cType(type.name)}})(
+        {%- if type.arguments == [] -%}
+            void
+        {%- else -%}
+            {%- for arg in type.arguments -%}
+                {% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        {%- endif -%}
+    );
+{% endfor %}
+
+#if !defined({{c_prefix}}_SKIP_PROCS)
+
+{% for function in by_category["function"] %}
+    typedef {{as_cType(function.return_type.name)}} (*{{as_cProc(None, function.name)}})(
+            {%- for arg in function.arguments -%}
+                {% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        );
+{% endfor %}
+
+{% for type in by_category["object"] if len(c_methods(type)) > 0 %}
+    // Procs of {{type.name.CamelCase()}}
+    {% for method in c_methods(type) %}
+        typedef {{as_cType(method.return_type.name)}} (*{{as_cProc(type.name, method.name)}})(
+            {{-as_cType(type.name)}} {{as_varName(type.name)}}
+            {%- for arg in method.arguments -%}
+                , {{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        );
+    {% endfor %}
+
+{% endfor %}
+#endif  // !defined({{c_prefix}}_SKIP_PROCS)
+
+#if !defined({{c_prefix}}_SKIP_DECLARATIONS)
+
+{% for function in by_category["function"] %}
+    {{c_prefix}}_EXPORT {{as_cType(function.return_type.name)}} {{as_cMethod(None, function.name)}}(
+            {%- for arg in function.arguments -%}
+                {% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        );
+{% endfor %}
+
+{% for type in by_category["object"] if len(c_methods(type)) > 0 %}
+    // Methods of {{type.name.CamelCase()}}
+    {% for method in c_methods(type) %}
+        {{c_prefix}}_EXPORT {{as_cType(method.return_type.name)}} {{as_cMethod(type.name, method.name)}}(
+            {{-as_cType(type.name)}} {{as_varName(type.name)}}
+            {%- for arg in method.arguments -%}
+                , {{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        );
+    {% endfor %}
+
+{% endfor %}
+#endif  // !defined({{c_prefix}}_SKIP_DECLARATIONS)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // {{metadata.api.upper()}}_H_
diff --git a/generator/templates/api_cpp.cpp b/generator/templates/api_cpp.cpp
new file mode 100644
index 0000000..d540e0b
--- /dev/null
+++ b/generator/templates/api_cpp.cpp
@@ -0,0 +1,175 @@
+//* Copyright 2017 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+{% set api = metadata.api.lower() %}
+{% if 'dawn' in enabled_tags %}
+    #include "dawn/{{api}}_cpp.h"
+{% else %}
+    #include "{{api}}/{{api}}_cpp.h"
+{% endif %}
+
+#ifdef __GNUC__
+// error: 'offsetof' within non-standard-layout type '{{metadata.namespace}}::XXX' is conditionally-supported
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+namespace {{metadata.namespace}} {
+    {% for type in by_category["enum"] %}
+        {% set CppType = as_cppType(type.name) %}
+        {% set CType = as_cType(type.name) %}
+
+        // {{CppType}}
+
+        static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
+        static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
+
+        {% for value in type.values %}
+            static_assert(static_cast<uint32_t>({{CppType}}::{{as_cppEnum(value.name)}}) == {{as_cEnum(type.name, value.name)}}, "value mismatch for {{CppType}}::{{as_cppEnum(value.name)}}");
+        {% endfor %}
+    {% endfor -%}
+
+    {% for type in by_category["bitmask"] %}
+        {% set CppType = as_cppType(type.name) %}
+        {% set CType = as_cType(type.name) + "Flags" %}
+
+        // {{CppType}}
+
+        static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
+        static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
+
+        {% for value in type.values %}
+            static_assert(static_cast<uint32_t>({{CppType}}::{{as_cppEnum(value.name)}}) == {{as_cEnum(type.name, value.name)}}, "value mismatch for {{CppType}}::{{as_cppEnum(value.name)}}");
+        {% endfor %}
+    {% endfor %}
+
+    // ChainedStruct
+
+    {% set c_prefix = metadata.c_prefix %}
+    static_assert(sizeof(ChainedStruct) == sizeof({{c_prefix}}ChainedStruct),
+            "sizeof mismatch for ChainedStruct");
+    static_assert(alignof(ChainedStruct) == alignof({{c_prefix}}ChainedStruct),
+            "alignof mismatch for ChainedStruct");
+    static_assert(offsetof(ChainedStruct, nextInChain) == offsetof({{c_prefix}}ChainedStruct, next),
+            "offsetof mismatch for ChainedStruct::nextInChain");
+    static_assert(offsetof(ChainedStruct, sType) == offsetof({{c_prefix}}ChainedStruct, sType),
+            "offsetof mismatch for ChainedStruct::sType");
+    {% for type in by_category["structure"] %}
+        {% set CppType = as_cppType(type.name) %}
+        {% set CType = as_cType(type.name) %}
+
+        // {{CppType}}
+
+        static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
+        static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
+
+        {% if type.extensible %}
+            static_assert(offsetof({{CppType}}, nextInChain) == offsetof({{CType}}, nextInChain),
+                    "offsetof mismatch for {{CppType}}::nextInChain");
+        {% endif %}
+        {% for member in type.members %}
+            {% set memberName = member.name.camelCase() %}
+            static_assert(offsetof({{CppType}}, {{memberName}}) == offsetof({{CType}}, {{memberName}}),
+                    "offsetof mismatch for {{CppType}}::{{memberName}}");
+        {% endfor %}
+    {% endfor -%}
+
+    {%- macro render_c_actual_arg(arg) -%}
+        {%- if arg.annotation == "value" -%}
+            {%- if arg.type.category == "object" -%}
+                {{as_varName(arg.name)}}.Get()
+            {%- elif arg.type.category == "enum" or arg.type.category == "bitmask" -%}
+                static_cast<{{as_cType(arg.type.name)}}>({{as_varName(arg.name)}})
+            {%- elif arg.type.category in ["function pointer", "native"] -%}
+                {{as_varName(arg.name)}}
+            {%- else -%}
+                UNHANDLED
+            {%- endif -%}
+        {%- else -%}
+            reinterpret_cast<{{decorate("", as_cType(arg.type.name), arg)}}>({{as_varName(arg.name)}})
+        {%- endif -%}
+    {%- endmacro -%}
+
+    {% for type in by_category["object"] %}
+        {% set CppType = as_cppType(type.name) %}
+        {% set CType = as_cType(type.name) %}
+
+        // {{CppType}}
+
+        static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
+        static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
+
+        {% macro render_cpp_method_declaration(type, method) -%}
+            {% set CppType = as_cppType(type.name) %}
+            {{as_cppType(method.return_type.name)}} {{CppType}}::{{method.name.CamelCase()}}(
+                {%- for arg in method.arguments -%}
+                    {%- if not loop.first %}, {% endif -%}
+                    {%- if arg.type.category == "object" and arg.annotation == "value" -%}
+                        {{as_cppType(arg.type.name)}} const& {{as_varName(arg.name)}}
+                    {%- else -%}
+                        {{as_annotated_cppType(arg)}}
+                    {%- endif -%}
+                {%- endfor -%}
+            ) const
+        {%- endmacro -%}
+
+        {%- macro render_cpp_to_c_method_call(type, method) -%}
+            {{as_cMethod(type.name, method.name)}}(Get()
+                {%- for arg in method.arguments -%},{{" "}}{{render_c_actual_arg(arg)}}
+                {%- endfor -%}
+            )
+        {%- endmacro -%}
+
+        {% for method in type.methods -%}
+            {{render_cpp_method_declaration(type, method)}} {
+                {% if method.return_type.name.concatcase() == "void" %}
+                    {{render_cpp_to_c_method_call(type, method)}};
+                {% else %}
+                    auto result = {{render_cpp_to_c_method_call(type, method)}};
+                    return {{convert_cType_to_cppType(method.return_type, 'value', 'result') | indent(8)}};
+                {% endif %}
+            }
+        {% endfor %}
+        void {{CppType}}::{{c_prefix}}Reference({{CType}} handle) {
+            if (handle != nullptr) {
+                {{as_cMethod(type.name, Name("reference"))}}(handle);
+            }
+        }
+        void {{CppType}}::{{c_prefix}}Release({{CType}} handle) {
+            if (handle != nullptr) {
+                {{as_cMethod(type.name, Name("release"))}}(handle);
+            }
+        }
+    {% endfor %}
+
+    // Function
+
+    {% for function in by_category["function"] %}
+        {%- macro render_function_call(function) -%}
+            {{as_cMethod(None, function.name)}}(
+                {%- for arg in function.arguments -%}
+                    {% if not loop.first %}, {% endif %}{{render_c_actual_arg(arg)}}
+                {%- endfor -%}
+            )
+        {%- endmacro -%}
+
+        {{as_cppType(function.return_type.name) | indent(4, true) }} {{as_cppType(function.name) }}(
+            {%- for arg in function.arguments -%}
+                {% if not loop.first %}, {% endif %}{{as_annotated_cppType(arg)}}
+            {%- endfor -%}
+        ) {
+            auto result = {{render_function_call(function)}};
+            return {{convert_cType_to_cppType(function.return_type, 'value', 'result')}};
+        }
+    {% endfor %}
+
+}
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
new file mode 100644
index 0000000..c3b21fb
--- /dev/null
+++ b/generator/templates/api_cpp.h
@@ -0,0 +1,260 @@
+//* Copyright 2017 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+{% set API = metadata.api.upper() %}
+{% set api = API.lower() %}
+{% if 'dawn' not in enabled_tags %}
+    #ifdef __EMSCRIPTEN__
+    #error "Do not include this header. Emscripten already provides headers needed for {{metadata.api}}."
+    #endif
+{% endif %}
+#ifndef {{API}}_CPP_H_
+#define {{API}}_CPP_H_
+
+#include "dawn/{{api}}.h"
+#include "dawn/EnumClassBitmasks.h"
+#include <cmath>
+
+namespace {{metadata.namespace}} {
+
+    {% set c_prefix = metadata.c_prefix %}
+    {% for constant in by_category["constant"] %}
+        {% set type = as_cppType(constant.type.name) %}
+        {% set value = c_prefix + "_" +  constant.name.SNAKE_CASE() %}
+        static constexpr {{type}} k{{as_cppType(constant.name)}} = {{ value }};
+    {% endfor %}
+
+    {% for type in by_category["enum"] %}
+        enum class {{as_cppType(type.name)}} : uint32_t {
+            {% for value in type.values %}
+                {{as_cppEnum(value.name)}} = 0x{{format(value.value, "08X")}},
+            {% endfor %}
+        };
+
+    {% endfor %}
+
+    {% for type in by_category["bitmask"] %}
+        enum class {{as_cppType(type.name)}} : uint32_t {
+            {% for value in type.values %}
+                {{as_cppEnum(value.name)}} = 0x{{format(value.value, "08X")}},
+            {% endfor %}
+        };
+
+    {% endfor %}
+
+    {% for type in by_category["function pointer"] %}
+        using {{as_cppType(type.name)}} = {{as_cType(type.name)}};
+    {% endfor %}
+
+    {% for type in by_category["object"] %}
+        class {{as_cppType(type.name)}};
+    {% endfor %}
+
+    {% for type in by_category["structure"] %}
+        struct {{as_cppType(type.name)}};
+    {% endfor %}
+
+    {% for typeDef in by_category["typedef"] %}
+        // {{as_cppType(typeDef.name)}} is deprecated.
+        // Use {{as_cppType(typeDef.type.name)}} instead.
+        using {{as_cppType(typeDef.name)}} = {{as_cppType(typeDef.type.name)}};
+
+    {% endfor %}
+    template<typename Derived, typename CType>
+    class ObjectBase {
+      public:
+        ObjectBase() = default;
+        ObjectBase(CType handle): mHandle(handle) {
+            if (mHandle) Derived::{{c_prefix}}Reference(mHandle);
+        }
+        ~ObjectBase() {
+            if (mHandle) Derived::{{c_prefix}}Release(mHandle);
+        }
+
+        ObjectBase(ObjectBase const& other)
+            : ObjectBase(other.Get()) {
+        }
+        Derived& operator=(ObjectBase const& other) {
+            if (&other != this) {
+                if (mHandle) Derived::{{c_prefix}}Release(mHandle);
+                mHandle = other.mHandle;
+                if (mHandle) Derived::{{c_prefix}}Reference(mHandle);
+            }
+
+            return static_cast<Derived&>(*this);
+        }
+
+        ObjectBase(ObjectBase&& other) {
+            mHandle = other.mHandle;
+            other.mHandle = 0;
+        }
+        Derived& operator=(ObjectBase&& other) {
+            if (&other != this) {
+                if (mHandle) Derived::{{c_prefix}}Release(mHandle);
+                mHandle = other.mHandle;
+                other.mHandle = 0;
+            }
+
+            return static_cast<Derived&>(*this);
+        }
+
+        ObjectBase(std::nullptr_t) {}
+        Derived& operator=(std::nullptr_t) {
+            if (mHandle != nullptr) {
+                Derived::{{c_prefix}}Release(mHandle);
+                mHandle = nullptr;
+            }
+            return static_cast<Derived&>(*this);
+        }
+
+        bool operator==(std::nullptr_t) const {
+            return mHandle == nullptr;
+        }
+        bool operator!=(std::nullptr_t) const {
+            return mHandle != nullptr;
+        }
+
+        explicit operator bool() const {
+            return mHandle != nullptr;
+        }
+        CType Get() const {
+            return mHandle;
+        }
+        CType Release() {
+            CType result = mHandle;
+            mHandle = 0;
+            return result;
+        }
+        static Derived Acquire(CType handle) {
+            Derived result;
+            result.mHandle = handle;
+            return result;
+        }
+
+      protected:
+        CType mHandle = nullptr;
+    };
+
+{% macro render_cpp_default_value(member, is_struct=True) -%}
+    {%- if member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%}
+        {{" "}}= nullptr
+    {%- elif member.type.category == "object" and member.optional and is_struct -%}
+        {{" "}}= nullptr
+    {%- elif member.type.category in ["enum", "bitmask"] and member.default_value != None -%}
+        {{" "}}= {{as_cppType(member.type.name)}}::{{as_cppEnum(Name(member.default_value))}}
+    {%- elif member.type.category == "native" and member.default_value != None -%}
+        {{" "}}= {{member.default_value}}
+    {%- elif member.default_value != None -%}
+        {{" "}}= {{member.default_value}}
+    {%- else -%}
+        {{assert(member.default_value == None)}}
+    {%- endif -%}
+{%- endmacro %}
+
+{% macro render_cpp_method_declaration(type, method) %}
+    {% set CppType = as_cppType(type.name) %}
+    {{as_cppType(method.return_type.name)}} {{method.name.CamelCase()}}(
+        {%- for arg in method.arguments -%}
+            {%- if not loop.first %}, {% endif -%}
+            {%- if arg.type.category == "object" and arg.annotation == "value" -%}
+                {{as_cppType(arg.type.name)}} const& {{as_varName(arg.name)}}
+            {%- else -%}
+                {{as_annotated_cppType(arg)}}
+            {%- endif -%}
+            {{render_cpp_default_value(arg, False)}}
+        {%- endfor -%}
+    ) const
+{%- endmacro %}
+
+    {% for type in by_category["object"] %}
+        {% set CppType = as_cppType(type.name) %}
+        {% set CType = as_cType(type.name) %}
+        class {{CppType}} : public ObjectBase<{{CppType}}, {{CType}}> {
+          public:
+            using ObjectBase::ObjectBase;
+            using ObjectBase::operator=;
+
+            {% for method in type.methods %}
+                {{render_cpp_method_declaration(type, method)}};
+            {% endfor %}
+
+          private:
+            friend ObjectBase<{{CppType}}, {{CType}}>;
+            static void {{c_prefix}}Reference({{CType}} handle);
+            static void {{c_prefix}}Release({{CType}} handle);
+        };
+
+    {% endfor %}
+
+    {% for function in by_category["function"] %}
+        {{as_cppType(function.return_type.name)}} {{as_cppType(function.name)}}(
+            {%- for arg in function.arguments -%}
+                {%- if not loop.first %}, {% endif -%}
+                {{as_annotated_cppType(arg)}}{{render_cpp_default_value(arg, False)}}
+            {%- endfor -%}
+        );
+    {% endfor %}
+
+    struct ChainedStruct {
+        ChainedStruct const * nextInChain = nullptr;
+        SType sType = SType::Invalid;
+    };
+
+    struct ChainedStructOut {
+        ChainedStruct * nextInChain = nullptr;
+        SType sType = SType::Invalid;
+    };
+
+    {% for type in by_category["structure"] %}
+        {% set Out = "Out" if type.output else "" %}
+        {% set const = "const" if not type.output else "" %}
+        {% if type.chained %}
+            struct {{as_cppType(type.name)}} : ChainedStruct{{Out}} {
+                {{as_cppType(type.name)}}() {
+                    sType = SType::{{type.name.CamelCase()}};
+                }
+        {% else %}
+            struct {{as_cppType(type.name)}} {
+        {% endif %}
+            {% if type.extensible %}
+                ChainedStruct{{Out}} {{const}} * nextInChain = nullptr;
+            {% endif %}
+            {% for member in type.members %}
+                {% set member_declaration = as_annotated_cppType(member) + render_cpp_default_value(member) %}
+                {% if type.chained and loop.first %}
+                    //* Align the first member to ChainedStruct to match the C struct layout.
+                    alignas(ChainedStruct{{Out}}) {{member_declaration}};
+                {% else %}
+                    {{member_declaration}};
+                {% endif %}
+            {% endfor %}
+        };
+
+    {% endfor %}
+
+    // The operators of EnumClassBitmmasks in the dawn:: namespace need to be imported
+    // in the {{metadata.namespace}} namespace for Argument Dependent Lookup.
+    DAWN_IMPORT_BITMASK_OPERATORS
+}  // namespace {{metadata.namespace}}
+
+namespace dawn {
+    {% for type in by_category["bitmask"] %}
+        template<>
+        struct IsDawnBitmask<{{metadata.namespace}}::{{as_cppType(type.name)}}> {
+            static constexpr bool enable = true;
+        };
+
+    {% endfor %}
+} // namespace dawn
+
+#endif // {{API}}_CPP_H_
diff --git a/generator/templates/api_cpp_print.h b/generator/templates/api_cpp_print.h
new file mode 100644
index 0000000..040f29c
--- /dev/null
+++ b/generator/templates/api_cpp_print.h
@@ -0,0 +1,92 @@
+//* Copyright 2021 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set API = metadata.api.upper() %}
+{% set api = API.lower() %}
+#ifndef {{API}}_CPP_PRINT_H_
+#define {{API}}_CPP_PRINT_H_
+
+#include "dawn/{{api}}_cpp.h"
+
+#include <iomanip>
+#include <ios>
+#include <ostream>
+#include <type_traits>
+
+namespace {{metadata.namespace}} {
+
+  {% for type in by_category["enum"] %}
+      template <typename CharT, typename Traits>
+      std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& o, {{as_cppType(type.name)}} value) {
+          switch (value) {
+            {% for value in type.values %}
+              case {{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}:
+                o << "{{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}";
+                break;
+            {% endfor %}
+              default:
+                o << "{{as_cppType(type.name)}}::" << std::showbase << std::hex << std::setfill('0') << std::setw(4) << static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value);
+          }
+          return o;
+      }
+  {% endfor %}
+
+  {% for type in by_category["bitmask"] %}
+      template <typename CharT, typename Traits>
+      std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& o, {{as_cppType(type.name)}} value) {
+        o << "{{as_cppType(type.name)}}::";
+        if (!static_cast<bool>(value)) {
+          {% for value in type.values if value.value == 0 %}
+            // 0 is often explicitly declared as None.
+            o << "{{as_cppEnum(value.name)}}";
+          {% else %}
+            o << std::showbase << std::hex << std::setfill('0') << std::setw(4) << 0;
+          {% endfor %}
+          return o;
+        }
+
+        bool moreThanOneBit = !HasZeroOrOneBits(value);
+        if (moreThanOneBit) {
+          o << "(";
+        }
+
+        bool first = true;
+        {% for value in type.values if value.value != 0 %}
+          if (value & {{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}) {
+            if (!first) {
+              o << "|";
+            }
+            first = false;
+            o << "{{as_cppEnum(value.name)}}";
+            value &= ~{{as_cppType(type.name)}}::{{as_cppEnum(value.name)}};
+          }
+        {% endfor %}
+
+        if (static_cast<bool>(value)) {
+          if (!first) {
+            o << "|";
+          }
+          o << std::showbase << std::hex << std::setfill('0') << std::setw(4) << static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value);
+        }
+
+        if (moreThanOneBit) {
+          o << ")";
+        }
+        return o;
+      }
+  {% endfor %}
+
+}  // namespace {{metadata.namespace}}
+
+#endif // {{API}}_CPP_PRINT_H_
diff --git a/generator/templates/api_struct_info.json b/generator/templates/api_struct_info.json
new file mode 100644
index 0000000..04e56cf
--- /dev/null
+++ b/generator/templates/api_struct_info.json
@@ -0,0 +1,51 @@
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+//*
+//*
+//* This generator is used to produce part of Emscripten's struct_info.json,
+//* which is a list of struct fields that it uses to generate field offset
+//* information for its own code generators.
+//* https://github.com/emscripten-core/emscripten/blob/master/src/struct_info.json
+//*
+    {
+        {% set api = metadata.api.lower() %}
+        "file": "{api}/{api}.h",
+        "defines": [],
+        "structs": {
+            "{{metadata.c_prefix}}ChainedStruct": [
+                "next",
+                "sType"
+            ],
+            {% for type in by_category["structure"] %}
+                "{{as_cType(type.name)}}": [
+                    {% if type.chained %}
+                        "chain"
+                    {%- elif type.extensible %}
+                        "nextInChain"
+                    {%- endif %}
+                    {% for member in type.members -%}
+                        {%- if (type.chained or type.extensible) or not loop.first -%}
+                            ,
+                        {% endif %}
+                        "{{as_varName(member.name)}}"
+                    {%- endfor %}
+
+                ]
+                {%- if not loop.last -%}
+                    ,
+                {% endif %}
+            {% endfor %}
+
+        }
+    }
diff --git a/generator/templates/dawn/common/Version.h b/generator/templates/dawn/common/Version.h
new file mode 100644
index 0000000..f9f67e7
--- /dev/null
+++ b/generator/templates/dawn/common/Version.h
@@ -0,0 +1,24 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMMON_VERISON_AUTOGEN_H_
+#define COMMON_VERISON_AUTOGEN_H_
+
+namespace dawn {
+
+static constexpr char kGitHash[] = "{{get_gitHash()}}";
+
+} // namespace dawn
+
+#endif  // COMMON_VERISON_AUTOGEN_H_
diff --git a/generator/templates/dawn/native/ChainUtils.cpp b/generator/templates/dawn/native/ChainUtils.cpp
new file mode 100644
index 0000000..2973788
--- /dev/null
+++ b/generator/templates/dawn/native/ChainUtils.cpp
@@ -0,0 +1,66 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/ChainUtils_autogen.h"
+
+#include <unordered_set>
+
+namespace {{native_namespace}} {
+
+{% set namespace = metadata.namespace %}
+{% for value in types["s type"].values %}
+    {% if value.valid %}
+        void FindInChain(const ChainedStruct* chain, const {{as_cppEnum(value.name)}}** out) {
+            for (; chain; chain = chain->nextInChain) {
+                if (chain->sType == {{namespace}}::SType::{{as_cppEnum(value.name)}}) {
+                    *out = static_cast<const {{as_cppEnum(value.name)}}*>(chain);
+                    break;
+                }
+            }
+        }
+    {% endif %}
+{% endfor %}
+
+MaybeError ValidateSTypes(const ChainedStruct* chain,
+                          std::vector<std::vector<{{namespace}}::SType>> oneOfConstraints) {
+    std::unordered_set<{{namespace}}::SType> allSTypes;
+    for (; chain; chain = chain->nextInChain) {
+        if (allSTypes.find(chain->sType) != allSTypes.end()) {
+            return DAWN_VALIDATION_ERROR("Chain cannot have duplicate sTypes");
+        }
+        allSTypes.insert(chain->sType);
+    }
+    for (const auto& oneOfConstraint : oneOfConstraints) {
+        bool satisfied = false;
+        for ({{namespace}}::SType oneOfSType : oneOfConstraint) {
+            if (allSTypes.find(oneOfSType) != allSTypes.end()) {
+                if (satisfied) {
+                    return DAWN_VALIDATION_ERROR("Unsupported sType combination");
+                }
+                satisfied = true;
+                allSTypes.erase(oneOfSType);
+            }
+        }
+    }
+    if (!allSTypes.empty()) {
+        return DAWN_VALIDATION_ERROR("Unsupported sType");
+    }
+    return {};
+}
+
+}  // namespace {{native_namespace}}
diff --git a/generator/templates/dawn/native/ChainUtils.h b/generator/templates/dawn/native/ChainUtils.h
new file mode 100644
index 0000000..3377220
--- /dev/null
+++ b/generator/templates/dawn/native/ChainUtils.h
@@ -0,0 +1,86 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set DIR = namespace_name.concatcase().upper() %}
+#ifndef {{DIR}}_CHAIN_UTILS_H_
+#define {{DIR}}_CHAIN_UTILS_H_
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+{% set prefix = metadata.proc_table_prefix.lower() %}
+#include "{{native_dir}}/{{prefix}}_platform.h"
+#include "{{native_dir}}/Error.h"
+
+namespace {{native_namespace}} {
+    {% for value in types["s type"].values %}
+        {% if value.valid %}
+            void FindInChain(const ChainedStruct* chain, const {{as_cppEnum(value.name)}}** out);
+        {% endif %}
+    {% endfor %}
+
+    // Verifies that |chain| only contains ChainedStructs of types enumerated in
+    // |oneOfConstraints| and contains no duplicate sTypes. Each vector in
+    // |oneOfConstraints| defines a set of sTypes that cannot coexist in the same chain.
+    // For example:
+    //   ValidateSTypes(chain, { { ShaderModuleSPIRVDescriptor, ShaderModuleWGSLDescriptor } }))
+    //   ValidateSTypes(chain, { { Extension1 }, { Extension2 } })
+    {% set namespace = metadata.namespace %}
+    MaybeError ValidateSTypes(const ChainedStruct* chain,
+                              std::vector<std::vector<{{namespace}}::SType>> oneOfConstraints);
+
+    template <typename T>
+    MaybeError ValidateSingleSTypeInner(const ChainedStruct* chain, T sType) {
+        DAWN_INVALID_IF(chain->sType != sType,
+            "Unsupported sType (%s). Expected (%s)", chain->sType, sType);
+        return {};
+    }
+
+    template <typename T, typename... Args>
+    MaybeError ValidateSingleSTypeInner(const ChainedStruct* chain, T sType, Args... sTypes) {
+        if (chain->sType == sType) {
+            return {};
+        }
+        return ValidateSingleSTypeInner(chain, sTypes...);
+    }
+
+    // Verifies that |chain| contains a single ChainedStruct of type |sType| or no ChainedStructs
+    // at all.
+    template <typename T>
+    MaybeError ValidateSingleSType(const ChainedStruct* chain, T sType) {
+        if (chain == nullptr) {
+            return {};
+        }
+        DAWN_INVALID_IF(chain->nextInChain != nullptr,
+            "Chain can only contain a single chained struct.");
+        return ValidateSingleSTypeInner(chain, sType);
+    }
+
+    // Verifies that |chain| contains a single ChainedStruct with a type enumerated in the
+    // parameter pack or no ChainedStructs at all.
+    template <typename T, typename... Args>
+    MaybeError ValidateSingleSType(const ChainedStruct* chain, T sType, Args... sTypes) {
+        if (chain == nullptr) {
+            return {};
+        }
+        DAWN_INVALID_IF(chain->nextInChain != nullptr,
+            "Chain can only contain a single chained struct.");
+        return ValidateSingleSTypeInner(chain, sType, sTypes...);
+    }
+
+}  // namespace {{native_namespace}}
+
+#endif  // {{DIR}}_CHAIN_UTILS_H_
diff --git a/generator/templates/dawn/native/ObjectType.cpp b/generator/templates/dawn/native/ObjectType.cpp
new file mode 100644
index 0000000..8fad3d4
--- /dev/null
+++ b/generator/templates/dawn/native/ObjectType.cpp
@@ -0,0 +1,34 @@
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/ObjectType_autogen.h"
+
+namespace {{native_namespace}} {
+
+    const char* ObjectTypeAsString(ObjectType type) {
+        switch (type) {
+            {% for type in by_category["object"] %}
+                case ObjectType::{{type.name.CamelCase()}}:
+                    return "{{type.name.CamelCase()}}";
+            {% endfor %}
+            default:
+                UNREACHABLE();
+        }
+    }
+
+} // namespace {{native_namespace}}
diff --git a/generator/templates/dawn/native/ObjectType.h b/generator/templates/dawn/native/ObjectType.h
new file mode 100644
index 0000000..1d59b50
--- /dev/null
+++ b/generator/templates/dawn/native/ObjectType.h
@@ -0,0 +1,41 @@
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set DIR = namespace_name.concatcase().upper() %}
+#ifndef {{DIR}}_OBJECTTPYE_AUTOGEN_H_
+#define {{DIR}}_OBJECTTPYE_AUTOGEN_H_
+
+#include "dawn/common/ityp_array.h"
+
+#include <cstdint>
+
+{% set native_namespace = namespace_name.namespace_case() %}
+namespace {{native_namespace}} {
+
+    enum class ObjectType : uint32_t {
+        {% for type in by_category["object"] %}
+            {{type.name.CamelCase()}},
+        {% endfor %}
+    };
+
+    template <typename T>
+    using PerObjectType = ityp::array<ObjectType, T, {{len(by_category["object"])}}>;
+
+    const char* ObjectTypeAsString(ObjectType type);
+
+} // namespace {{native_namespace}}
+
+
+#endif  // {{DIR}}_OBJECTTPYE_AUTOGEN_H_
diff --git a/generator/templates/dawn/native/ProcTable.cpp b/generator/templates/dawn/native/ProcTable.cpp
new file mode 100644
index 0000000..47ac2f5
--- /dev/null
+++ b/generator/templates/dawn/native/ProcTable.cpp
@@ -0,0 +1,159 @@
+//* Copyright 2017 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set Prefix = metadata.proc_table_prefix %}
+{% set prefix = Prefix.lower() %}
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/{{prefix}}_platform.h"
+#include "{{native_dir}}/{{Prefix}}Native.h"
+
+#include <algorithm>
+#include <vector>
+
+{% for type in by_category["object"] %}
+    {% if type.name.canonical_case() not in ["texture view"] %}
+        #include "{{native_dir}}/{{type.name.CamelCase()}}.h"
+    {% endif %}
+{% endfor %}
+
+namespace {{native_namespace}} {
+
+    {% for type in by_category["object"] %}
+        {% for method in c_methods(type) %}
+            {% set suffix = as_MethodSuffix(type.name, method.name) %}
+
+            {{as_cType(method.return_type.name)}} Native{{suffix}}(
+                {{-as_cType(type.name)}} cSelf
+                {%- for arg in method.arguments -%}
+                    , {{as_annotated_cType(arg)}}
+                {%- endfor -%}
+            ) {
+                //* Perform conversion between C types and frontend types
+                auto self = FromAPI(cSelf);
+
+                {% for arg in method.arguments %}
+                    {% set varName = as_varName(arg.name) %}
+                    {% if arg.type.category in ["enum", "bitmask"] and arg.annotation == "value" %}
+                        auto {{varName}}_ = static_cast<{{as_frontendType(arg.type)}}>({{varName}});
+                    {% elif arg.annotation != "value" or arg.type.category == "object" %}
+                        auto {{varName}}_ = reinterpret_cast<{{decorate("", as_frontendType(arg.type), arg)}}>({{varName}});
+                    {% else %}
+                        auto {{varName}}_ = {{as_varName(arg.name)}};
+                    {% endif %}
+                {%- endfor-%}
+
+                {% if method.return_type.name.canonical_case() != "void" %}
+                    auto result =
+                {%- endif %}
+                self->API{{method.name.CamelCase()}}(
+                    {%- for arg in method.arguments -%}
+                        {%- if not loop.first %}, {% endif -%}
+                        {{as_varName(arg.name)}}_
+                    {%- endfor -%}
+                );
+                {% if method.return_type.name.canonical_case() != "void" %}
+                    {% if method.return_type.category == "object" %}
+                        return ToAPI(result);
+                    {% else %}
+                        return result;
+                    {% endif %}
+                {% endif %}
+            }
+        {% endfor %}
+    {% endfor %}
+
+    namespace {
+
+        {% set c_prefix = metadata.c_prefix %}
+        struct ProcEntry {
+            {{c_prefix}}Proc proc;
+            const char* name;
+        };
+        static const ProcEntry sProcMap[] = {
+            {% for (type, method) in c_methods_sorted_by_name %}
+                { reinterpret_cast<{{c_prefix}}Proc>(Native{{as_MethodSuffix(type.name, method.name)}}), "{{as_cMethod(type.name, method.name)}}" },
+            {% endfor %}
+        };
+        static constexpr size_t sProcMapSize = sizeof(sProcMap) / sizeof(sProcMap[0]);
+
+    }  // anonymous namespace
+
+    {% for function in by_category["function"] %}
+        {{as_cType(function.return_type.name)}} Native{{as_cppType(function.name)}}(
+            {%- for arg in function.arguments -%}
+                {% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        ) {
+            {% if function.name.canonical_case() == "get proc address" %}
+                if (procName == nullptr) {
+                    return nullptr;
+                }
+
+                const ProcEntry* entry = std::lower_bound(&sProcMap[0], &sProcMap[sProcMapSize], procName,
+                    [](const ProcEntry &a, const char *b) -> bool {
+                        return strcmp(a.name, b) < 0;
+                    }
+                );
+
+                if (entry != &sProcMap[sProcMapSize] && strcmp(entry->name, procName) == 0) {
+                    return entry->proc;
+                }
+
+                // Special case the free-standing functions of the API.
+                // TODO(dawn:1238) Checking string one by one is slow, it needs to be optimized.
+                {% for function in by_category["function"] %}
+                    if (strcmp(procName, "{{as_cMethod(None, function.name)}}") == 0) {
+                        return reinterpret_cast<{{c_prefix}}Proc>(Native{{as_cppType(function.name)}});
+                    }
+
+                {% endfor %}
+                return nullptr;
+            {% else %}
+                return ToAPI({{as_cppType(function.return_type.name)}}Base::Create(
+                    {%- for arg in function.arguments -%}
+                        FromAPI({% if not loop.first %}, {% endif %}{{as_varName(arg.name)}})
+                    {%- endfor -%}
+                ));
+            {% endif %}
+        }
+
+    {% endfor %}
+
+    std::vector<const char*> GetProcMapNamesForTestingInternal() {
+        std::vector<const char*> result;
+        result.reserve(sProcMapSize);
+        for (const ProcEntry& entry : sProcMap) {
+            result.push_back(entry.name);
+        }
+        return result;
+    }
+
+    static {{Prefix}}ProcTable gProcTable = {
+        {% for function in by_category["function"] %}
+            Native{{as_cppType(function.name)}},
+        {% endfor %}
+        {% for type in by_category["object"] %}
+            {% for method in c_methods(type) %}
+                Native{{as_MethodSuffix(type.name, method.name)}},
+            {% endfor %}
+        {% endfor %}
+    };
+
+    const {{Prefix}}ProcTable& GetProcsAutogen() {
+        return gProcTable;
+    }
+}
diff --git a/generator/templates/dawn/native/ValidationUtils.cpp b/generator/templates/dawn/native/ValidationUtils.cpp
new file mode 100644
index 0000000..1cb78c6
--- /dev/null
+++ b/generator/templates/dawn/native/ValidationUtils.cpp
@@ -0,0 +1,48 @@
+//* Copyright 2018 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/ValidationUtils_autogen.h"
+
+namespace {{native_namespace}} {
+
+    {% set namespace = metadata.namespace %}
+    {% for type in by_category["enum"] %}
+        MaybeError Validate{{type.name.CamelCase()}}({{namespace}}::{{as_cppType(type.name)}} value) {
+            switch (value) {
+                {% for value in type.values if value.valid %}
+                    case {{namespace}}::{{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}:
+                        return {};
+                {% endfor %}
+                default:
+                    return DAWN_VALIDATION_ERROR("Invalid value for {{as_cType(type.name)}}");
+            }
+        }
+
+    {% endfor %}
+
+    {% for type in by_category["bitmask"] %}
+        MaybeError Validate{{type.name.CamelCase()}}({{namespace}}::{{as_cppType(type.name)}} value) {
+            if ((value & static_cast<{{namespace}}::{{as_cppType(type.name)}}>(~{{type.full_mask}})) == 0) {
+                return {};
+            }
+            return DAWN_VALIDATION_ERROR("Invalid value for {{as_cType(type.name)}}");
+        }
+
+    {% endfor %}
+
+} // namespace {{native_namespace}}
diff --git a/generator/templates/dawn/native/ValidationUtils.h b/generator/templates/dawn/native/ValidationUtils.h
new file mode 100644
index 0000000..06d3cc7
--- /dev/null
+++ b/generator/templates/dawn/native/ValidationUtils.h
@@ -0,0 +1,37 @@
+//* Copyright 2018 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#ifndef BACKEND_VALIDATIONUTILS_H_
+#define BACKEND_VALIDATIONUTILS_H_
+
+{% set api = metadata.api.lower() %}
+#include "dawn/{{api}}_cpp.h"
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/Error.h"
+
+namespace {{native_namespace}} {
+
+    // Helper functions to check the value of enums and bitmasks
+    {% for type in by_category["enum"] + by_category["bitmask"] %}
+        {% set namespace = metadata.namespace %}
+        MaybeError Validate{{type.name.CamelCase()}}({{namespace}}::{{as_cppType(type.name)}} value);
+    {% endfor %}
+
+} // namespace {{native_namespace}}
+
+#endif  // BACKEND_VALIDATIONUTILS_H_
diff --git a/generator/templates/dawn/native/api_absl_format.cpp b/generator/templates/dawn/native/api_absl_format.cpp
new file mode 100644
index 0000000..a3b7ea2
--- /dev/null
+++ b/generator/templates/dawn/native/api_absl_format.cpp
@@ -0,0 +1,173 @@
+//* Copyright 2021 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+{% set api = metadata.api.lower() %}
+#include "{{native_dir}}/{{api}}_absl_format_autogen.h"
+
+#include "{{native_dir}}/ObjectType_autogen.h"
+
+namespace {{native_namespace}} {
+
+    //
+    // Descriptors
+    //
+
+    {% for type in by_category["structure"] %}
+        {% for member in type.members %}
+            {% if member.name.canonical_case() == "label" %}
+                absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+                AbslFormatConvert(const {{as_cppType(type.name)}}* value,
+                                    const absl::FormatConversionSpec& spec,
+                                    absl::FormatSink* s) {
+                    if (value == nullptr) {
+                        s->Append("[null]");
+                        return {true};
+                    }
+                    s->Append("[{{as_cppType(type.name)}}");
+                    if (value->label != nullptr) {
+                        s->Append(absl::StrFormat(" \"%s\"", value->label));
+                    }
+                    s->Append("]");
+                    return {true};
+                }
+            {% endif %}
+        {% endfor %}
+    {% endfor %}
+
+    //
+    // Compatible with absl::StrFormat (Needs to be disjoint from having a 'label' for now.)
+    // Currently uses a hard-coded list to determine which structures are actually supported. If
+    // additional structures are added, be sure to update the header file's list as well.
+    //
+    using absl::ParsedFormat;
+
+    {% for type in by_category["structure"] %}
+        {% if type.name.get() in [
+             "buffer binding layout",
+             "sampler binding layout",
+             "texture binding layout",
+             "storage texture binding layout"
+           ]
+        %}
+        absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+            AbslFormatConvert(const {{as_cppType(type.name)}}& value,
+                              const absl::FormatConversionSpec& spec,
+                              absl::FormatSink* s) {
+            {% set members = [] %}
+            {% set format = [] %}
+            {% set template = [] %}
+            {% for member in type.members %}
+                {% set memberName = member.name.camelCase() %}
+                {% do members.append("value." + memberName) %}
+                {% do format.append(memberName + ": %" + as_formatType(member)) %}
+                {% do template.append("'" + as_formatType(member) + "'") %}
+            {% endfor %}
+            static const auto* const fmt =
+                new ParsedFormat<{{template|join(",")}}>("{ {{format|join(", ")}} }");
+            s->Append(absl::StrFormat(*fmt, {{members|join(", ")}}));
+            return {true};
+        }
+        {% endif %}
+    {% endfor %}
+
+}  // namespace {{native_namespace}}
+
+{% set namespace = metadata.namespace %}
+namespace {{namespace}} {
+
+    //
+    // Enums
+    //
+
+    {% for type in by_category["enum"] %}
+    absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
+    AbslFormatConvert({{as_cppType(type.name)}} value,
+                      const absl::FormatConversionSpec& spec,
+                      absl::FormatSink* s) {
+        if (spec.conversion_char() == absl::FormatConversionChar::s) {
+            s->Append("{{as_cppType(type.name)}}::");
+            switch (value) {
+            {% for value in type.values %}
+                case {{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}:
+                    s->Append("{{as_cppEnum(value.name)}}");
+                    break;
+            {% endfor %}
+            }
+        } else {
+            s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
+        }
+        return {true};
+    }
+    {% endfor %}
+
+    //
+    // Bitmasks
+    //
+
+    {% for type in by_category["bitmask"] %}
+    absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
+    AbslFormatConvert({{as_cppType(type.name)}} value,
+                      const absl::FormatConversionSpec& spec,
+                      absl::FormatSink* s) {
+        if (spec.conversion_char() == absl::FormatConversionChar::s) {
+            s->Append("{{as_cppType(type.name)}}::");
+            if (!static_cast<bool>(value)) {
+                {% for value in type.values if value.value == 0 %}
+                    // 0 is often explicitly declared as None.
+                    s->Append("{{as_cppEnum(value.name)}}");
+                {% else %}
+                    s->Append(absl::StrFormat("{{as_cppType(type.name)}}::%x", 0));
+                {% endfor %}
+                return {true};
+            }
+
+            bool moreThanOneBit = !HasZeroOrOneBits(value);
+            if (moreThanOneBit) {
+                s->Append("(");
+            }
+
+            bool first = true;
+            {% for value in type.values if value.value != 0 %}
+                if (value & {{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}) {
+                    if (!first) {
+                        s->Append("|");
+                    }
+                    first = false;
+                    s->Append("{{as_cppEnum(value.name)}}");
+                    value &= ~{{as_cppType(type.name)}}::{{as_cppEnum(value.name)}};
+                }
+            {% endfor %}
+
+            if (static_cast<bool>(value)) {
+                if (!first) {
+                    s->Append("|");
+                }
+                s->Append(absl::StrFormat("{{as_cppType(type.name)}}::%x", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
+            }
+
+            if (moreThanOneBit) {
+                s->Append(")");
+            }
+        } else {
+            s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
+        }
+        return {true};
+    }
+    {% endfor %}
+
+}  // namespace {{namespace}}
diff --git a/generator/templates/dawn/native/api_absl_format.h b/generator/templates/dawn/native/api_absl_format.h
new file mode 100644
index 0000000..ab06098
--- /dev/null
+++ b/generator/templates/dawn/native/api_absl_format.h
@@ -0,0 +1,95 @@
+//* Copyright 2021 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set API = metadata.api.upper() %}
+#ifndef {{API}}_ABSL_FORMAT_H_
+#define {{API}}_ABSL_FORMAT_H_
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+{% set prefix = metadata.proc_table_prefix.lower() %}
+#include "{{native_dir}}/{{prefix}}_platform.h"
+
+#include "absl/strings/str_format.h"
+
+namespace {{native_namespace}} {
+
+    //
+    // Descriptors
+    //
+
+    // Only includes structures that have a 'label' member.
+    {% for type in by_category["structure"] %}
+        {% for member in type.members %}
+            {% if member.name.canonical_case() == "label" %}
+                absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+                    AbslFormatConvert(const {{as_cppType(type.name)}}* value,
+                                      const absl::FormatConversionSpec& spec,
+                                      absl::FormatSink* s);
+            {% endif %}
+        {% endfor %}
+    {% endfor %}
+
+    //
+    // Compatible with absl::StrFormat (Needs to be disjoint from having a 'label' for now.)
+    // Currently uses a hard-coded list to determine which structures are actually supported. If
+    // additional structures are added, be sure to update the cpp file's list as well.
+    //
+    {% for type in by_category["structure"] %}
+        {% if type.name.get() in [
+             "buffer binding layout",
+             "sampler binding layout",
+             "texture binding layout",
+             "storage texture binding layout"
+           ]
+        %}
+        absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+            AbslFormatConvert(const {{as_cppType(type.name)}}& value,
+                              const absl::FormatConversionSpec& spec,
+                              absl::FormatSink* s);
+        {% endif %}
+    {% endfor %}
+
+} // namespace {{native_namespace}}
+
+{% set namespace = metadata.namespace %}
+namespace {{namespace}} {
+
+    //
+    // Enums
+    //
+
+    {% for type in by_category["enum"] %}
+        absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
+        AbslFormatConvert({{as_cppType(type.name)}} value,
+                          const absl::FormatConversionSpec& spec,
+                          absl::FormatSink* s);
+    {% endfor %}
+
+    //
+    // Bitmasks
+    //
+
+    {% for type in by_category["bitmask"] %}
+        absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
+        AbslFormatConvert({{as_cppType(type.name)}} value,
+                          const absl::FormatConversionSpec& spec,
+                          absl::FormatSink* s);
+    {% endfor %}
+
+}  // namespace {{namespace}}
+
+#endif // {{API}}_ABSL_FORMAT_H_
diff --git a/generator/templates/dawn/native/api_dawn_native_proc.cpp b/generator/templates/dawn/native/api_dawn_native_proc.cpp
new file mode 100644
index 0000000..f9147c6
--- /dev/null
+++ b/generator/templates/dawn/native/api_dawn_native_proc.cpp
@@ -0,0 +1,75 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <dawn/{{metadata.api.lower()}}.h>
+
+namespace dawn::native {
+
+// This file should be kept in sync with generator/templates/dawn/native/ProcTable.cpp
+
+{% for function in by_category["function"] %}
+    extern {{as_cType(function.return_type.name)}} Native{{as_cppType(function.name)}}(
+        {%- for arg in function.arguments -%}
+            {% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
+        {%- endfor -%}
+    );
+{% endfor %}
+{% for type in by_category["object"] %}
+    {% for method in c_methods(type) %}
+        extern {{as_cType(method.return_type.name)}} Native{{as_MethodSuffix(type.name, method.name)}}(
+            {{-as_cType(type.name)}} cSelf
+            {%- for arg in method.arguments -%}
+                , {{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        );
+    {% endfor %}
+{% endfor %}
+
+}
+
+extern "C" {
+    using namespace dawn::native;
+
+    {% for function in by_category["function"] %}
+        {{as_cType(function.return_type.name)}} {{metadata.namespace}}{{as_cppType(function.name)}} (
+            {%- for arg in function.arguments -%}
+                {% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
+            {%- endfor -%}
+        ) {
+            return Native{{as_cppType(function.name)}}(
+                {%- for arg in function.arguments -%}
+                    {% if not loop.first %}, {% endif %}{{as_varName(arg.name)}}
+                {%- endfor -%}
+            );
+        }
+    {% endfor %}
+
+    {% for type in by_category["object"] %}
+        {% for method in c_methods(type) %}
+            {{as_cType(method.return_type.name)}} {{metadata.namespace}}{{as_MethodSuffix(type.name, method.name)}}(
+                {{-as_cType(type.name)}} cSelf
+                {%- for arg in method.arguments -%}
+                    , {{as_annotated_cType(arg)}}
+                {%- endfor -%}
+            ) {
+                return Native{{as_MethodSuffix(type.name, method.name)}}(
+                    cSelf
+                    {%- for arg in method.arguments -%}
+                        , {{as_varName(arg.name)}}
+                    {%- endfor -%}
+                );
+            }
+        {% endfor %}
+    {% endfor %}
+}
diff --git a/generator/templates/dawn/native/api_structs.cpp b/generator/templates/dawn/native/api_structs.cpp
new file mode 100644
index 0000000..86f54f0
--- /dev/null
+++ b/generator/templates/dawn/native/api_structs.cpp
@@ -0,0 +1,75 @@
+//* Copyright 2018 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+{% set namespace = metadata.namespace %}
+#include "{{native_dir}}/{{namespace}}_structs_autogen.h"
+
+#include <tuple>
+
+#ifdef __GNUC__
+// error: 'offsetof' within non-standard-layout type '{{namespace}}::XXX' is conditionally-supported
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+namespace {{native_namespace}} {
+
+    {% set c_prefix = metadata.c_prefix %}
+    static_assert(sizeof(ChainedStruct) == sizeof({{c_prefix}}ChainedStruct),
+            "sizeof mismatch for ChainedStruct");
+    static_assert(alignof(ChainedStruct) == alignof({{c_prefix}}ChainedStruct),
+            "alignof mismatch for ChainedStruct");
+    static_assert(offsetof(ChainedStruct, nextInChain) == offsetof({{c_prefix}}ChainedStruct, next),
+            "offsetof mismatch for ChainedStruct::nextInChain");
+    static_assert(offsetof(ChainedStruct, sType) == offsetof({{c_prefix}}ChainedStruct, sType),
+            "offsetof mismatch for ChainedStruct::sType");
+
+    {% for type in by_category["structure"] %}
+        {% set CppType = as_cppType(type.name) %}
+        {% set CType = as_cType(type.name) %}
+
+        static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
+        static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
+
+        {% if type.extensible %}
+            static_assert(offsetof({{CppType}}, nextInChain) == offsetof({{CType}}, nextInChain),
+                    "offsetof mismatch for {{CppType}}::nextInChain");
+        {% endif %}
+        {% for member in type.members %}
+            {% set memberName = member.name.camelCase() %}
+            static_assert(offsetof({{CppType}}, {{memberName}}) == offsetof({{CType}}, {{memberName}}),
+                    "offsetof mismatch for {{CppType}}::{{memberName}}");
+        {% endfor %}
+
+        bool {{CppType}}::operator==(const {{as_cppType(type.name)}}& rhs) const {
+            return {% if type.extensible or type.chained -%}
+                (nextInChain == rhs.nextInChain) &&
+            {%- endif %} std::tie(
+                {% for member in type.members %}
+                    {{member.name.camelCase()-}}
+                    {{ "," if not loop.last else "" }}
+                {% endfor %}
+            ) == std::tie(
+                {% for member in type.members %}
+                    rhs.{{member.name.camelCase()-}}
+                    {{ "," if not loop.last else "" }}
+                {% endfor %}
+            );
+        }
+
+    {% endfor %}
+} // namespace {{native_namespace}}
diff --git a/generator/templates/dawn/native/api_structs.h b/generator/templates/dawn/native/api_structs.h
new file mode 100644
index 0000000..d655344
--- /dev/null
+++ b/generator/templates/dawn/native/api_structs.h
@@ -0,0 +1,87 @@
+//* Copyright 2017 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set DIR = namespace_name.concatcase().upper() %}
+{% set namespace = metadata.namespace %}
+#ifndef {{DIR}}_{{namespace.upper()}}_STRUCTS_H_
+#define {{DIR}}_{{namespace.upper()}}_STRUCTS_H_
+
+{% set api = metadata.api.lower() %}
+#include "dawn/{{api}}_cpp.h"
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/Forward.h"
+#include <cmath>
+
+namespace {{native_namespace}} {
+
+{% macro render_cpp_default_value(member) -%}
+    {%- if member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%}
+        {{" "}}= nullptr
+    {%- elif member.type.category == "object" and member.optional -%}
+        {{" "}}= nullptr
+    {%- elif member.type.category in ["enum", "bitmask"] and member.default_value != None -%}
+        {{" "}}= {{namespace}}::{{as_cppType(member.type.name)}}::{{as_cppEnum(Name(member.default_value))}}
+    {%- elif member.type.category == "native" and member.default_value != None -%}
+        {{" "}}= {{member.default_value}}
+    {%- elif member.default_value != None -%}
+        {{" "}}= {{member.default_value}}
+    {%- else -%}
+        {{assert(member.default_value == None)}}
+    {%- endif -%}
+{%- endmacro %}
+
+    struct ChainedStruct {
+        ChainedStruct const * nextInChain = nullptr;
+        {{namespace}}::SType sType = {{namespace}}::SType::Invalid;
+    };
+
+    {% for type in by_category["structure"] %}
+        {% if type.chained %}
+            struct {{as_cppType(type.name)}} : ChainedStruct {
+                {{as_cppType(type.name)}}() {
+                    sType = {{namespace}}::SType::{{type.name.CamelCase()}};
+                }
+        {% else %}
+            struct {{as_cppType(type.name)}} {
+        {% endif %}
+            {% if type.extensible %}
+                ChainedStruct const * nextInChain = nullptr;
+            {% endif %}
+            {% for member in type.members %}
+                {% set member_declaration = as_annotated_frontendType(member) + render_cpp_default_value(member) %}
+                {% if type.chained and loop.first %}
+                    //* Align the first member to ChainedStruct to match the C struct layout.
+                    alignas(ChainedStruct) {{member_declaration}};
+                {% else %}
+                    {{member_declaration}};
+                {% endif %}
+            {% endfor %}
+
+            // Equality operators, mostly for testing. Note that this tests
+            // strict pointer-pointer equality if the struct contains member pointers.
+            bool operator==(const {{as_cppType(type.name)}}& rhs) const;
+        };
+
+    {% endfor %}
+
+    {% for typeDef in by_category["typedef"] if typeDef.type.category == "structure" %}
+        using {{as_cppType(typeDef.name)}} = {{as_cppType(typeDef.type.name)}};
+    {% endfor %}
+
+} // namespace {{native_namespace}}
+
+#endif  // {{DIR}}_{{namespace.upper()}}_STRUCTS_H_
diff --git a/generator/templates/dawn/native/dawn_platform.h b/generator/templates/dawn/native/dawn_platform.h
new file mode 100644
index 0000000..e3f1c91
--- /dev/null
+++ b/generator/templates/dawn/native/dawn_platform.h
@@ -0,0 +1,82 @@
+//* Copyright 2021 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+{% set namespace_name = Name(metadata.native_namespace) %}
+{% set NATIVE_DIR = namespace_name.concatcase().upper() %}
+{% set PREFIX = metadata.proc_table_prefix.upper() %}
+#ifndef {{NATIVE_DIR}}_{{PREFIX}}_PLATFORM_AUTOGEN_H_
+#define {{NATIVE_DIR}}_{{PREFIX}}_PLATFORM_AUTOGEN_H_
+
+{% set api = metadata.api.lower() %}
+#include "dawn/{{api}}_cpp.h"
+{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
+{% set native_namespace = namespace_name.namespace_case() %}
+{% set native_dir = impl_dir + namespace_name.Dirs() %}
+#include "{{native_dir}}/Forward.h"
+
+{% set namespace = metadata.namespace %}
+// Use our autogenerated version of the {{namespace}} structures that point to {{native_namespace}} object types
+// (wgpu::Buffer is dawn::native::BufferBase*)
+#include <{{native_dir}}/{{namespace}}_structs_autogen.h>
+
+namespace {{native_namespace}} {
+
+    {% for type in by_category["structure"] %}
+        inline const {{as_cType(type.name)}}* ToAPI(const {{as_cppType(type.name)}}* rhs) {
+            return reinterpret_cast<const {{as_cType(type.name)}}*>(rhs);
+        }
+
+        inline {{as_cType(type.name)}}* ToAPI({{as_cppType(type.name)}}* rhs) {
+            return reinterpret_cast<{{as_cType(type.name)}}*>(rhs);
+        }
+
+        inline const {{as_cppType(type.name)}}* FromAPI(const {{as_cType(type.name)}}* rhs) {
+            return reinterpret_cast<const {{as_cppType(type.name)}}*>(rhs);
+        }
+
+        inline {{as_cppType(type.name)}}* FromAPI({{as_cType(type.name)}}* rhs) {
+            return reinterpret_cast<{{as_cppType(type.name)}}*>(rhs);
+        }
+    {% endfor %}
+
+    {% for type in by_category["object"] %}
+        inline const {{as_cType(type.name)}}Impl* ToAPI(const {{as_cppType(type.name)}}Base* rhs) {
+            return reinterpret_cast<const {{as_cType(type.name)}}Impl*>(rhs);
+        }
+
+        inline {{as_cType(type.name)}}Impl* ToAPI({{as_cppType(type.name)}}Base* rhs) {
+            return reinterpret_cast<{{as_cType(type.name)}}Impl*>(rhs);
+        }
+
+        inline const {{as_cppType(type.name)}}Base* FromAPI(const {{as_cType(type.name)}}Impl* rhs) {
+            return reinterpret_cast<const {{as_cppType(type.name)}}Base*>(rhs);
+        }
+
+        inline {{as_cppType(type.name)}}Base* FromAPI({{as_cType(type.name)}}Impl* rhs) {
+            return reinterpret_cast<{{as_cppType(type.name)}}Base*>(rhs);
+        }
+    {% endfor %}
+
+    template <typename T>
+    struct EnumCount;
+
+    {% for e in by_category["enum"] if e.contiguousFromZero %}
+        template<>
+        struct EnumCount<{{namespace}}::{{as_cppType(e.name)}}> {
+            static constexpr uint32_t value = {{len(e.values)}};
+        };
+    {% endfor %}
+}
+
+#endif  // {{NATIVE_DIR}}_{{PREFIX}}_PLATFORM_AUTOGEN_H_
diff --git a/generator/templates/dawn/wire/ObjectType.h b/generator/templates/dawn/wire/ObjectType.h
new file mode 100644
index 0000000..54ae08e
--- /dev/null
+++ b/generator/templates/dawn/wire/ObjectType.h
@@ -0,0 +1,34 @@
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#ifndef DAWNWIRE_OBJECTTPYE_AUTOGEN_H_
+#define DAWNWIRE_OBJECTTPYE_AUTOGEN_H_
+
+#include "dawn/common/ityp_array.h"
+
+namespace dawn::wire {
+
+    enum class ObjectType : uint32_t {
+        {% for type in by_category["object"] %}
+            {{type.name.CamelCase()}},
+        {% endfor %}
+    };
+
+    template <typename T>
+    using PerObjectType = ityp::array<ObjectType, T, {{len(by_category["object"])}}>;
+
+} // namespace dawn::wire
+
+
+#endif  // DAWNWIRE_OBJECTTPYE_AUTOGEN_H_
diff --git a/generator/templates/dawn/wire/WireCmd.cpp b/generator/templates/dawn/wire/WireCmd.cpp
new file mode 100644
index 0000000..c945bee
--- /dev/null
+++ b/generator/templates/dawn/wire/WireCmd.cpp
@@ -0,0 +1,855 @@
+//* Copyright 2017 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#include "dawn/wire/WireCmd_autogen.h"
+
+#include "dawn/common/Assert.h"
+#include "dawn/common/Log.h"
+#include "dawn/wire/BufferConsumer_impl.h"
+#include "dawn/wire/Wire.h"
+
+#include <algorithm>
+#include <cstring>
+#include <limits>
+
+#ifdef __GNUC__
+// error: 'offsetof' within non-standard-layout type 'wgpu::XXX' is conditionally-supported
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+//* Helper macros so that the main [de]serialization functions can be written in a generic manner.
+
+//* Outputs an rvalue that's the number of elements a pointer member points to.
+{% macro member_length(member, record_accessor) -%}
+    {%- if member.length == "constant" -%}
+        {{member.constant_length}}u
+    {%- else -%}
+        {{record_accessor}}{{as_varName(member.length.name)}}
+    {%- endif -%}
+{%- endmacro %}
+
+//* Outputs the type that will be used on the wire for the member
+{% macro member_transfer_type(member) -%}
+    {%- if member.type.category == "object" -%}
+        ObjectId
+    {%- elif member.type.category == "structure" -%}
+        {{as_cType(member.type.name)}}Transfer
+    {%- elif member.type.category == "bitmask" -%}
+        {{as_cType(member.type.name)}}Flags
+    {%- else -%}
+        {{ assert(as_cType(member.type.name) != "size_t") }}
+        {{as_cType(member.type.name)}}
+    {%- endif -%}
+{%- endmacro %}
+
+//* Outputs the size of one element of the type that will be used on the wire for the member
+{% macro member_transfer_sizeof(member) -%}
+    sizeof({{member_transfer_type(member)}})
+{%- endmacro %}
+
+//* Outputs the serialization code to put `in` in `out`
+{% macro serialize_member(member, in, out) %}
+    {%- if member.type.category == "object" -%}
+        {%- set Optional = "Optional" if member.optional else "" -%}
+        WIRE_TRY(provider.Get{{Optional}}Id({{in}}, &{{out}}));
+    {%- elif member.type.category == "structure" -%}
+        {%- if member.type.is_wire_transparent -%}
+            static_assert(sizeof({{out}}) == sizeof({{in}}), "Serialize memcpy size must match.");
+            memcpy(&{{out}}, &{{in}}, {{member_transfer_sizeof(member)}});
+        {%- else -%}
+            {%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%}
+            WIRE_TRY({{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer{{Provider}}));
+        {%- endif -%}
+    {%- else -%}
+        {{out}} = {{in}};
+    {%- endif -%}
+{% endmacro %}
+
+//* Outputs the deserialization code to put `in` in `out`
+{% macro deserialize_member(member, in, out) %}
+    {%- if member.type.category == "object" -%}
+        {%- set Optional = "Optional" if member.optional else "" -%}
+        WIRE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
+    {%- elif member.type.category == "structure" -%}
+        {%- if member.type.is_wire_transparent -%}
+            static_assert(sizeof({{out}}) == sizeof({{in}}), "Deserialize memcpy size must match.");
+            memcpy(&{{out}}, const_cast<const {{member_transfer_type(member)}}*>(&{{in}}), {{member_transfer_sizeof(member)}});
+        {%- else -%}
+            WIRE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, deserializeBuffer, allocator
+                {%- if member.type.may_have_dawn_object -%}
+                    , resolver
+                {%- endif -%}
+            ));
+        {%- endif -%}
+    {%- else -%}
+        static_assert(sizeof({{out}}) >= sizeof({{in}}), "Deserialize assignment may not narrow.");
+        {{out}} = {{in}};
+    {%- endif -%}
+{% endmacro %}
+
+//* The main [de]serialization macro
+//* Methods are very similar to structures that have one member corresponding to each arguments.
+//* This macro takes advantage of the similarity to output [de]serialization code for a record
+//* that is either a structure or a method, with some special cases for each.
+{% macro write_record_serialization_helpers(record, name, members, is_cmd=False, is_return_command=False) %}
+    {% set Return = "Return" if is_return_command else "" %}
+    {% set Cmd = "Cmd" if is_cmd else "" %}
+    {% set Inherits = " : CmdHeader" if is_cmd else "" %}
+
+    //* Structure for the wire format of each of the records. Members that are values
+    //* are embedded directly in the structure. Other members are assumed to be in the
+    //* memory directly following the structure in the buffer.
+    struct {{Return}}{{name}}Transfer{{Inherits}} {
+        static_assert({{[is_cmd, record.extensible, record.chained].count(True)}} <= 1,
+                      "Record must be at most one of is_cmd, extensible, and chained.");
+        {% if is_cmd %}
+            //* Start the transfer structure with the command ID, so that casting to WireCmd gives the ID.
+            {{Return}}WireCmd commandId;
+        {% elif record.extensible %}
+            bool hasNextInChain;
+        {% elif record.chained %}
+            WGPUChainedStructTransfer chain;
+        {% endif %}
+
+        //* Value types are directly in the command, objects being replaced with their IDs.
+        {% for member in members if member.annotation == "value" %}
+            {{member_transfer_type(member)}} {{as_varName(member.name)}};
+        {% endfor %}
+
+        //* const char* have their length embedded directly in the command.
+        {% for member in members if member.length == "strlen" %}
+            uint64_t {{as_varName(member.name)}}Strlen;
+        {% endfor %}
+
+        {% for member in members if member.optional and member.annotation != "value" and member.type.category != "object" %}
+            bool has_{{as_varName(member.name)}};
+        {% endfor %}
+    };
+
+    {% if is_cmd %}
+        static_assert(offsetof({{Return}}{{name}}Transfer, commandSize) == 0);
+        static_assert(offsetof({{Return}}{{name}}Transfer, commandId) == sizeof(CmdHeader));
+    {% endif %}
+
+    {% if record.chained %}
+        static_assert(offsetof({{Return}}{{name}}Transfer, chain) == 0);
+    {% endif %}
+
+    //* Returns the required transfer size for `record` in addition to the transfer structure.
+    DAWN_DECLARE_UNUSED size_t {{Return}}{{name}}GetExtraRequiredSize(const {{Return}}{{name}}{{Cmd}}& record) {
+        DAWN_UNUSED(record);
+
+        size_t result = 0;
+
+        //* Gather how much space will be needed for the extension chain.
+        {% if record.extensible %}
+            if (record.nextInChain != nullptr) {
+                result += GetChainedStructExtraRequiredSize(record.nextInChain);
+            }
+        {% endif %}
+
+        //* Special handling of const char* that have their length embedded directly in the command
+        {% for member in members if member.length == "strlen" %}
+            {% set memberName = as_varName(member.name) %}
+
+            {% if member.optional %}
+                bool has_{{memberName}} = record.{{memberName}} != nullptr;
+                if (has_{{memberName}})
+            {% endif %}
+            {
+            result += std::strlen(record.{{memberName}});
+            }
+        {% endfor %}
+
+        //* Gather how much space will be needed for pointer members.
+        {% for member in members if member.length != "strlen" and not member.skip_serialize %}
+            {% if member.type.category != "object" and member.optional %}
+                if (record.{{as_varName(member.name)}} != nullptr)
+            {% endif %}
+            {
+                {% if member.annotation != "value" %}
+                    {{ assert(member.annotation != "const*const*") }}
+                    auto memberLength = {{member_length(member, "record.")}};
+                    result += memberLength * {{member_transfer_sizeof(member)}};
+                    //* Structures might contain more pointers so we need to add their extra size as well.
+                    {% if member.type.category == "structure" %}
+                        for (decltype(memberLength) i = 0; i < memberLength; ++i) {
+                            {{assert(member.annotation == "const*")}}
+                            result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}}[i]);
+                        }
+                    {% endif %}
+                {% elif member.type.category == "structure" %}
+                    result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}});
+                {% endif %}
+            }
+        {% endfor %}
+
+        return result;
+    }
+    // GetExtraRequiredSize isn't used for structures that are value members of other structures
+    // because we assume they cannot contain pointers themselves.
+    DAWN_UNUSED_FUNC({{Return}}{{name}}GetExtraRequiredSize);
+
+    //* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data
+    //* and `provider` to serialize objects.
+    DAWN_DECLARE_UNUSED WireResult {{Return}}{{name}}Serialize(
+        const {{Return}}{{name}}{{Cmd}}& record,
+        {{Return}}{{name}}Transfer* transfer,
+        SerializeBuffer* buffer
+        {%- if record.may_have_dawn_object -%}
+            , const ObjectIdProvider& provider
+        {%- endif -%}
+    ) {
+        DAWN_UNUSED(buffer);
+
+        //* Handle special transfer members of methods.
+        {% if is_cmd %}
+            transfer->commandId = {{Return}}WireCmd::{{name}};
+        {% endif %}
+
+        //* Value types are directly in the transfer record, objects being replaced with their IDs.
+        {% for member in members if member.annotation == "value" %}
+            {% set memberName = as_varName(member.name) %}
+            {{serialize_member(member, "record." + memberName, "transfer->" + memberName)}}
+        {% endfor %}
+
+        {% if record.extensible %}
+            if (record.nextInChain != nullptr) {
+                transfer->hasNextInChain = true;
+                WIRE_TRY(SerializeChainedStruct(record.nextInChain, buffer, provider));
+            } else {
+                transfer->hasNextInChain = false;
+            }
+        {% endif %}
+
+        {% if record.chained %}
+            //* Should be set by the root descriptor's call to SerializeChainedStruct.
+            ASSERT(transfer->chain.sType == {{as_cEnum(types["s type"].name, record.name)}});
+            ASSERT(transfer->chain.hasNext == (record.chain.next != nullptr));
+        {% endif %}
+
+        //* Special handling of const char* that have their length embedded directly in the command
+        {% for member in members if member.length == "strlen" %}
+            {% set memberName = as_varName(member.name) %}
+
+            {% if member.optional %}
+                bool has_{{memberName}} = record.{{memberName}} != nullptr;
+                transfer->has_{{memberName}} = has_{{memberName}};
+                if (has_{{memberName}})
+            {% endif %}
+            {
+                transfer->{{memberName}}Strlen = std::strlen(record.{{memberName}});
+
+                char* stringInBuffer;
+                WIRE_TRY(buffer->NextN(transfer->{{memberName}}Strlen, &stringInBuffer));
+                memcpy(stringInBuffer, record.{{memberName}}, transfer->{{memberName}}Strlen);
+            }
+        {% endfor %}
+
+        //* Allocate space and write the non-value arguments in it.
+        {% for member in members if member.annotation != "value" and member.length != "strlen" and not member.skip_serialize %}
+            {{ assert(member.annotation != "const*const*") }}
+            {% set memberName = as_varName(member.name) %}
+
+            {% if member.type.category != "object" and member.optional %}
+                bool has_{{memberName}} = record.{{memberName}} != nullptr;
+                transfer->has_{{memberName}} = has_{{memberName}};
+                if (has_{{memberName}})
+            {% endif %}
+            {
+                auto memberLength = {{member_length(member, "record.")}};
+
+                {{member_transfer_type(member)}}* memberBuffer;
+                WIRE_TRY(buffer->NextN(memberLength, &memberBuffer));
+
+                {% if member.type.is_wire_transparent %}
+                    memcpy(
+                        memberBuffer, record.{{memberName}},
+                        {{member_transfer_sizeof(member)}} * memberLength);
+                {% else %}
+                    //* This loop cannot overflow because it iterates up to |memberLength|. Even if
+                    //* memberLength were the maximum integer value, |i| would become equal to it
+                    //* just before exiting the loop, but not increment past or wrap around.
+                    for (decltype(memberLength) i = 0; i < memberLength; ++i) {
+                        {{serialize_member(member, "record." + memberName + "[i]", "memberBuffer[i]" )}}
+                    }
+                {% endif %}
+            }
+        {% endfor %}
+        return WireResult::Success;
+    }
+    DAWN_UNUSED_FUNC({{Return}}{{name}}Serialize);
+
+    //* Deserializes `transfer` into `record` getting more serialized data from `buffer` and `size`
+    //* if needed, using `allocator` to store pointed-to values and `resolver` to translate object
+    //* Ids to actual objects.
+    DAWN_DECLARE_UNUSED WireResult {{Return}}{{name}}Deserialize(
+        {{Return}}{{name}}{{Cmd}}* record,
+        const volatile {{Return}}{{name}}Transfer* transfer,
+        DeserializeBuffer* deserializeBuffer,
+        DeserializeAllocator* allocator
+        {%- if record.may_have_dawn_object -%}
+            , const ObjectIdResolver& resolver
+        {%- endif -%}
+    ) {
+        DAWN_UNUSED(allocator);
+
+        {% if is_cmd %}
+            ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
+        {% endif %}
+
+        {% if record.derived_method %}
+            record->selfId = transfer->self;
+        {% endif %}
+
+        //* Value types are directly in the transfer record, objects being replaced with their IDs.
+        {% for member in members if member.annotation == "value" %}
+            {% set memberName = as_varName(member.name) %}
+            {{deserialize_member(member, "transfer->" + memberName, "record->" + memberName)}}
+        {% endfor %}
+
+        {% if record.extensible %}
+            record->nextInChain = nullptr;
+            if (transfer->hasNextInChain) {
+                WIRE_TRY(DeserializeChainedStruct(&record->nextInChain, deserializeBuffer, allocator, resolver));
+            }
+        {% endif %}
+
+        {% if record.chained %}
+            //* Should be set by the root descriptor's call to DeserializeChainedStruct.
+            //* Don't check |record->chain.next| matches because it is not set until the
+            //* next iteration inside DeserializeChainedStruct.
+            ASSERT(record->chain.sType == {{as_cEnum(types["s type"].name, record.name)}});
+            ASSERT(record->chain.next == nullptr);
+        {% endif %}
+
+        //* Special handling of const char* that have their length embedded directly in the command
+        {% for member in members if member.length == "strlen" %}
+            {% set memberName = as_varName(member.name) %}
+
+            {% if member.optional %}
+                bool has_{{memberName}} = transfer->has_{{memberName}};
+                record->{{memberName}} = nullptr;
+                if (has_{{memberName}})
+            {% endif %}
+            {
+                uint64_t stringLength64 = transfer->{{memberName}}Strlen;
+                if (stringLength64 >= std::numeric_limits<size_t>::max()) {
+                    //* Cannot allocate space for the string. It can be at most
+                    //* size_t::max() - 1. We need 1 byte for the null-terminator.
+                    return WireResult::FatalError;
+                }
+                size_t stringLength = static_cast<size_t>(stringLength64);
+
+                const volatile char* stringInBuffer;
+                WIRE_TRY(deserializeBuffer->ReadN(stringLength, &stringInBuffer));
+
+                char* copiedString;
+                WIRE_TRY(GetSpace(allocator, stringLength + 1, &copiedString));
+                //* We can cast away the volatile qualifier because DeserializeBuffer::ReadN already
+                //* validated that the range [stringInBuffer, stringInBuffer + stringLength) is valid.
+                //* memcpy may have an unknown access pattern, but this is fine since the string is only
+                //* data and won't affect control flow of this function.
+                memcpy(copiedString, const_cast<const char*>(stringInBuffer), stringLength);
+                copiedString[stringLength] = '\0';
+                record->{{memberName}} = copiedString;
+            }
+        {% endfor %}
+
+        //* Get extra buffer data, and copy pointed to values in extra allocated space.
+        {% for member in members if member.annotation != "value" and member.length != "strlen" %}
+            {{ assert(member.annotation != "const*const*") }}
+            {% set memberName = as_varName(member.name) %}
+
+            {% if member.type.category != "object" and member.optional %}
+                //* Non-constant length optional members use length=0 to denote they aren't present.
+                //* Otherwise we could have length=N and has_member=false, causing reads from an
+                //* uninitialized pointer.
+                {{ assert(member.length == "constant") }}
+                bool has_{{memberName}} = transfer->has_{{memberName}};
+                record->{{memberName}} = nullptr;
+                if (has_{{memberName}})
+            {% endif %}
+            {
+                auto memberLength = {{member_length(member, "record->")}};
+                const volatile {{member_transfer_type(member)}}* memberBuffer;
+                WIRE_TRY(deserializeBuffer->ReadN(memberLength, &memberBuffer));
+
+                //* For data-only members (e.g. "data" in WriteBuffer and WriteTexture), they are
+                //* not security sensitive so we can directly refer the data inside the transfer
+                //* buffer in dawn_native. For other members, as prevention of TOCTOU attacks is an
+                //* important feature of the wire, we must make sure every single value returned to
+                //* dawn_native must be a copy of what's in the wire.
+                {% if member.json_data["wire_is_data_only"] %}
+                    record->{{memberName}} =
+                        const_cast<const {{member_transfer_type(member)}}*>(memberBuffer);
+
+                {% else %}
+                    {{as_cType(member.type.name)}}* copiedMembers;
+                    WIRE_TRY(GetSpace(allocator, memberLength, &copiedMembers));
+                    record->{{memberName}} = copiedMembers;
+
+                    {% if member.type.is_wire_transparent %}
+                        //* memcpy is not allowed to copy from volatile objects. However, these
+                        //* arrays are just used as plain data, and don't impact control flow. So if
+                        //* the underlying data were changed while the copy was still executing, we
+                        //* would get different data - but it wouldn't cause unexpected downstream
+                        //* effects.
+                        memcpy(
+                            copiedMembers,
+                            const_cast<const {{member_transfer_type(member)}}*>(memberBuffer),
+                           {{member_transfer_sizeof(member)}} * memberLength);
+                    {% else %}
+                        //* This loop cannot overflow because it iterates up to |memberLength|. Even
+                        //* if memberLength were the maximum integer value, |i| would become equal
+                        //* to it just before exiting the loop, but not increment past or wrap
+                        //* around.
+                        for (decltype(memberLength) i = 0; i < memberLength; ++i) {
+                            {{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}}
+                        }
+                    {% endif %}
+                {% endif %}
+            }
+        {% endfor %}
+
+        return WireResult::Success;
+    }
+    DAWN_UNUSED_FUNC({{Return}}{{name}}Deserialize);
+{% endmacro %}
+
+{% macro write_command_serialization_methods(command, is_return) %}
+    {% set Return = "Return" if is_return else "" %}
+    {% set Name = Return + command.name.CamelCase() %}
+    {% set Cmd = Name + "Cmd" %}
+
+    size_t {{Cmd}}::GetRequiredSize() const {
+        size_t size = sizeof({{Name}}Transfer) + {{Name}}GetExtraRequiredSize(*this);
+        return size;
+    }
+
+    {% if command.may_have_dawn_object %}
+        WireResult {{Cmd}}::Serialize(
+            size_t commandSize,
+            SerializeBuffer* buffer,
+            const ObjectIdProvider& provider
+        ) const {
+            {{Name}}Transfer* transfer;
+            WIRE_TRY(buffer->Next(&transfer));
+            transfer->commandSize = commandSize;
+            return ({{Name}}Serialize(*this, transfer, buffer, provider));
+        }
+        WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer) const {
+            ErrorObjectIdProvider provider;
+            return Serialize(commandSize, buffer, provider);
+        }
+
+        WireResult {{Cmd}}::Deserialize(
+            DeserializeBuffer* deserializeBuffer,
+            DeserializeAllocator* allocator,
+            const ObjectIdResolver& resolver
+        ) {
+            const volatile {{Name}}Transfer* transfer;
+            WIRE_TRY(deserializeBuffer->Read(&transfer));
+            return {{Name}}Deserialize(this, transfer, deserializeBuffer, allocator, resolver);
+        }
+        WireResult {{Cmd}}::Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator) {
+            ErrorObjectIdResolver resolver;
+            return Deserialize(deserializeBuffer, allocator, resolver);
+        }
+    {% else %}
+        WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer) const {
+            {{Name}}Transfer* transfer;
+            WIRE_TRY(buffer->Next(&transfer));
+            transfer->commandSize = commandSize;
+            return ({{Name}}Serialize(*this, transfer, buffer));
+        }
+        WireResult {{Cmd}}::Serialize(
+            size_t commandSize,
+            SerializeBuffer* buffer,
+            const ObjectIdProvider&
+        ) const {
+            return Serialize(commandSize, buffer);
+        }
+
+        WireResult {{Cmd}}::Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator) {
+            const volatile {{Name}}Transfer* transfer;
+            WIRE_TRY(deserializeBuffer->Read(&transfer));
+            return {{Name}}Deserialize(this, transfer, deserializeBuffer, allocator);
+        }
+        WireResult {{Cmd}}::Deserialize(
+            DeserializeBuffer* deserializeBuffer,
+            DeserializeAllocator* allocator,
+            const ObjectIdResolver&
+        ) {
+            return Deserialize(deserializeBuffer, allocator);
+        }
+    {% endif %}
+{% endmacro %}
+
+{% macro make_chained_struct_serialization_helpers(out=None) %}
+        {% set ChainedStructPtr = "WGPUChainedStructOut*" if out else "const WGPUChainedStruct*" %}
+        {% set ChainedStruct = "WGPUChainedStructOut" if out else "WGPUChainedStruct" %}
+        size_t GetChainedStructExtraRequiredSize({{ChainedStructPtr}} chainedStruct) {
+            ASSERT(chainedStruct != nullptr);
+            size_t result = 0;
+            while (chainedStruct != nullptr) {
+                switch (chainedStruct->sType) {
+                    {% for sType in types["s type"].values if (
+                            sType.valid and
+                            (sType.name.CamelCase() not in client_side_structures) and
+                            (types[sType.name.get()].output == out)
+                    ) %}
+                        case {{as_cEnum(types["s type"].name, sType.name)}}: {
+                            const auto& typedStruct = *reinterpret_cast<{{as_cType(sType.name)}} const *>(chainedStruct);
+                            result += sizeof({{as_cType(sType.name)}}Transfer);
+                            result += {{as_cType(sType.name)}}GetExtraRequiredSize(typedStruct);
+                            chainedStruct = typedStruct.chain.next;
+                            break;
+                        }
+                    {% endfor %}
+                    // Explicitly list the Invalid enum. MSVC complains about no case labels.
+                    case WGPUSType_Invalid:
+                    default:
+                        // Invalid enum. Reserve space just for the transfer header (sType and hasNext).
+                        result += sizeof(WGPUChainedStructTransfer);
+                        chainedStruct = chainedStruct->next;
+                        break;
+                }
+            }
+            return result;
+        }
+
+        [[nodiscard]] WireResult SerializeChainedStruct({{ChainedStructPtr}} chainedStruct,
+                                                          SerializeBuffer* buffer,
+                                                          const ObjectIdProvider& provider) {
+            ASSERT(chainedStruct != nullptr);
+            ASSERT(buffer != nullptr);
+            do {
+                switch (chainedStruct->sType) {
+                    {% for sType in types["s type"].values if (
+                            sType.valid and
+                            (sType.name.CamelCase() not in client_side_structures) and
+                            (types[sType.name.get()].output == out)
+                    ) %}
+                        {% set CType = as_cType(sType.name) %}
+                        case {{as_cEnum(types["s type"].name, sType.name)}}: {
+
+                            {{CType}}Transfer* transfer;
+                            WIRE_TRY(buffer->Next(&transfer));
+                            transfer->chain.sType = chainedStruct->sType;
+                            transfer->chain.hasNext = chainedStruct->next != nullptr;
+
+                            WIRE_TRY({{CType}}Serialize(*reinterpret_cast<{{CType}} const*>(chainedStruct), transfer, buffer
+                                {%- if types[sType.name.get()].may_have_dawn_object -%}
+                                , provider
+                                {%- endif -%}
+                            ));
+
+                            chainedStruct = chainedStruct->next;
+                        } break;
+                    {% endfor %}
+                    // Explicitly list the Invalid enum. MSVC complains about no case labels.
+                    case WGPUSType_Invalid:
+                    default: {
+                        // Invalid enum. Serialize just the transfer header with Invalid as the sType.
+                        // TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
+                        if (chainedStruct->sType != WGPUSType_Invalid) {
+                            dawn::WarningLog() << "Unknown sType " << chainedStruct->sType << " discarded.";
+                        }
+
+                        WGPUChainedStructTransfer* transfer;
+                        WIRE_TRY(buffer->Next(&transfer));
+                        transfer->sType = WGPUSType_Invalid;
+                        transfer->hasNext = chainedStruct->next != nullptr;
+
+                        // Still move on in case there are valid structs after this.
+                        chainedStruct = chainedStruct->next;
+                        break;
+                    }
+                }
+            } while (chainedStruct != nullptr);
+            return WireResult::Success;
+        }
+
+        WireResult DeserializeChainedStruct({{ChainedStructPtr}}* outChainNext,
+                                            DeserializeBuffer* deserializeBuffer,
+                                            DeserializeAllocator* allocator,
+                                            const ObjectIdResolver& resolver) {
+            bool hasNext;
+            do {
+                const volatile WGPUChainedStructTransfer* header;
+                WIRE_TRY(deserializeBuffer->Peek(&header));
+                WGPUSType sType = header->sType;
+                switch (sType) {
+                    {% for sType in types["s type"].values if (
+                            sType.valid and
+                            (sType.name.CamelCase() not in client_side_structures) and
+                            (types[sType.name.get()].output == out)
+                    ) %}
+                        {% set CType = as_cType(sType.name) %}
+                        case {{as_cEnum(types["s type"].name, sType.name)}}: {
+                            const volatile {{CType}}Transfer* transfer;
+                            WIRE_TRY(deserializeBuffer->Read(&transfer));
+
+                            {{CType}}* outStruct;
+                            WIRE_TRY(GetSpace(allocator, sizeof({{CType}}), &outStruct));
+                            outStruct->chain.sType = sType;
+                            outStruct->chain.next = nullptr;
+
+                            *outChainNext = &outStruct->chain;
+                            outChainNext = &outStruct->chain.next;
+
+                            WIRE_TRY({{CType}}Deserialize(outStruct, transfer, deserializeBuffer, allocator
+                                {%- if types[sType.name.get()].may_have_dawn_object -%}
+                                    , resolver
+                                {%- endif -%}
+                            ));
+
+                            hasNext = transfer->chain.hasNext;
+                        } break;
+                    {% endfor %}
+                    // Explicitly list the Invalid enum. MSVC complains about no case labels.
+                    case WGPUSType_Invalid:
+                    default: {
+                        // Invalid enum. Deserialize just the transfer header with Invalid as the sType.
+                        // TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
+                        if (sType != WGPUSType_Invalid) {
+                            dawn::WarningLog() << "Unknown sType " << sType << " discarded.";
+                        }
+
+                        const volatile WGPUChainedStructTransfer* transfer;
+                        WIRE_TRY(deserializeBuffer->Read(&transfer));
+
+                        {{ChainedStruct}}* outStruct;
+                        WIRE_TRY(GetSpace(allocator, sizeof({{ChainedStruct}}), &outStruct));
+                        outStruct->sType = WGPUSType_Invalid;
+                        outStruct->next = nullptr;
+
+                        // Still move on in case there are valid structs after this.
+                        *outChainNext = outStruct;
+                        outChainNext = &outStruct->next;
+                        hasNext = transfer->hasNext;
+                        break;
+                    }
+                }
+            } while (hasNext);
+
+            return WireResult::Success;
+        }
+{% endmacro %}
+
+namespace dawn::wire {
+
+    ObjectHandle::ObjectHandle() = default;
+    ObjectHandle::ObjectHandle(ObjectId id, ObjectGeneration generation)
+        : id(id), generation(generation) {
+    }
+
+    ObjectHandle::ObjectHandle(const volatile ObjectHandle& rhs)
+        : id(rhs.id), generation(rhs.generation) {
+    }
+    ObjectHandle& ObjectHandle::operator=(const volatile ObjectHandle& rhs) {
+        id = rhs.id;
+        generation = rhs.generation;
+        return *this;
+    }
+
+    ObjectHandle& ObjectHandle::AssignFrom(const ObjectHandle& rhs) {
+        id = rhs.id;
+        generation = rhs.generation;
+        return *this;
+    }
+    ObjectHandle& ObjectHandle::AssignFrom(const volatile ObjectHandle& rhs) {
+        id = rhs.id;
+        generation = rhs.generation;
+        return *this;
+    }
+
+    namespace {
+        // Allocates enough space from allocator to countain T[count] and return it in out.
+        // Return FatalError if the allocator couldn't allocate the memory.
+        // Always writes to |out| on success.
+        template <typename T, typename N>
+        WireResult GetSpace(DeserializeAllocator* allocator, N count, T** out) {
+            constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
+            if (count > kMaxCountWithoutOverflows) {
+                return WireResult::FatalError;
+            }
+
+            size_t totalSize = sizeof(T) * count;
+            *out = static_cast<T*>(allocator->GetSpace(totalSize));
+            if (*out == nullptr) {
+                return WireResult::FatalError;
+            }
+
+            return WireResult::Success;
+        }
+
+        struct WGPUChainedStructTransfer {
+            WGPUSType sType;
+            bool hasNext;
+        };
+
+        size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct);
+        [[nodiscard]] WireResult SerializeChainedStruct(const WGPUChainedStruct* chainedStruct,
+                                                          SerializeBuffer* buffer,
+                                                          const ObjectIdProvider& provider);
+        WireResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
+                                            DeserializeBuffer* deserializeBuffer,
+                                            DeserializeAllocator* allocator,
+                                            const ObjectIdResolver& resolver);
+
+        size_t GetChainedStructExtraRequiredSize(WGPUChainedStructOut* chainedStruct);
+        [[nodiscard]] WireResult SerializeChainedStruct(WGPUChainedStructOut* chainedStruct,
+                                                          SerializeBuffer* buffer,
+                                                          const ObjectIdProvider& provider);
+        WireResult DeserializeChainedStruct(WGPUChainedStructOut** outChainNext,
+                                            DeserializeBuffer* deserializeBuffer,
+                                            DeserializeAllocator* allocator,
+                                            const ObjectIdResolver& resolver);
+
+        //* Output structure [de]serialization first because it is used by commands.
+        {% for type in by_category["structure"] %}
+            {% set name = as_cType(type.name) %}
+            {% if type.name.CamelCase() not in client_side_structures %}
+                {{write_record_serialization_helpers(type, name, type.members, is_cmd=False)}}
+            {% endif %}
+        {% endfor %}
+
+
+        {{ make_chained_struct_serialization_helpers(out=False) }}
+        {{ make_chained_struct_serialization_helpers(out=True) }}
+
+        //* Output [de]serialization helpers for commands
+        {% for command in cmd_records["command"] %}
+            {% set name = command.name.CamelCase() %}
+            {{write_record_serialization_helpers(command, name, command.members, is_cmd=True)}}
+        {% endfor %}
+
+        //* Output [de]serialization helpers for return commands
+        {% for command in cmd_records["return command"] %}
+            {% set name = command.name.CamelCase() %}
+            {{write_record_serialization_helpers(command, name, command.members,
+                                                 is_cmd=True, is_return_command=True)}}
+        {% endfor %}
+
+        // Implementation of ObjectIdResolver that always errors.
+        // Used when the generator adds a provider argument because of a chained
+        // struct, but in practice, a chained struct in that location is invalid.
+        class ErrorObjectIdResolver final : public ObjectIdResolver {
+            public:
+                {% for type in by_category["object"] %}
+                    WireResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const override {
+                        return WireResult::FatalError;
+                    }
+                    WireResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const override {
+                        return WireResult::FatalError;
+                    }
+                {% endfor %}
+        };
+
+        // Implementation of ObjectIdProvider that always errors.
+        // Used when the generator adds a provider argument because of a chained
+        // struct, but in practice, a chained struct in that location is invalid.
+        class ErrorObjectIdProvider final : public ObjectIdProvider {
+            public:
+                {% for type in by_category["object"] %}
+                    WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const override {
+                        return WireResult::FatalError;
+                    }
+                    WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const override {
+                        return WireResult::FatalError;
+                    }
+                {% endfor %}
+        };
+
+    }  // anonymous namespace
+
+    {% for command in cmd_records["command"] %}
+        {{ write_command_serialization_methods(command, False) }}
+    {% endfor %}
+
+    {% for command in cmd_records["return command"] %}
+        {{ write_command_serialization_methods(command, True) }}
+    {% endfor %}
+
+    // Implementations of serialization/deserialization of WPGUDeviceProperties.
+    size_t SerializedWGPUDevicePropertiesSize(const WGPUDeviceProperties* deviceProperties) {
+        return sizeof(WGPUDeviceProperties) +
+               WGPUDevicePropertiesGetExtraRequiredSize(*deviceProperties);
+    }
+
+    void SerializeWGPUDeviceProperties(const WGPUDeviceProperties* deviceProperties,
+                                       char* buffer) {
+        SerializeBuffer serializeBuffer(buffer, SerializedWGPUDevicePropertiesSize(deviceProperties));
+
+        WGPUDevicePropertiesTransfer* transfer;
+
+        WireResult result = serializeBuffer.Next(&transfer);
+        ASSERT(result == WireResult::Success);
+
+        ErrorObjectIdProvider provider;
+        result = WGPUDevicePropertiesSerialize(*deviceProperties, transfer, &serializeBuffer, provider);
+        ASSERT(result == WireResult::Success);
+    }
+
+    bool DeserializeWGPUDeviceProperties(WGPUDeviceProperties* deviceProperties,
+                                         const volatile char* buffer,
+                                         size_t size) {
+        const volatile WGPUDevicePropertiesTransfer* transfer;
+        DeserializeBuffer deserializeBuffer(buffer, size);
+        if (deserializeBuffer.Read(&transfer) != WireResult::Success) {
+            return false;
+        }
+
+        ErrorObjectIdResolver resolver;
+        return WGPUDevicePropertiesDeserialize(deviceProperties, transfer, &deserializeBuffer,
+                                               nullptr, resolver) == WireResult::Success;
+    }
+
+    size_t SerializedWGPUSupportedLimitsSize(const WGPUSupportedLimits* supportedLimits) {
+        return sizeof(WGPUSupportedLimits) +
+               WGPUSupportedLimitsGetExtraRequiredSize(*supportedLimits);
+    }
+
+    void SerializeWGPUSupportedLimits(
+        const WGPUSupportedLimits* supportedLimits,
+        char* buffer) {
+        SerializeBuffer serializeBuffer(buffer, SerializedWGPUSupportedLimitsSize(supportedLimits));
+
+        WGPUSupportedLimitsTransfer* transfer;
+
+        WireResult result = serializeBuffer.Next(&transfer);
+        ASSERT(result == WireResult::Success);
+
+        ErrorObjectIdProvider provider;
+        result = WGPUSupportedLimitsSerialize(*supportedLimits, transfer, &serializeBuffer, provider);
+        ASSERT(result == WireResult::Success);
+    }
+
+    bool DeserializeWGPUSupportedLimits(WGPUSupportedLimits* supportedLimits,
+                                        const volatile char* buffer,
+                                        size_t size) {
+        const volatile WGPUSupportedLimitsTransfer* transfer;
+        DeserializeBuffer deserializeBuffer(buffer, size);
+        if (deserializeBuffer.Read(&transfer) != WireResult::Success) {
+            return false;
+        }
+
+        ErrorObjectIdResolver resolver;
+        return WGPUSupportedLimitsDeserialize(supportedLimits, transfer, &deserializeBuffer,
+                                              nullptr, resolver) == WireResult::Success;
+    }
+
+}  // namespace dawn::wire
diff --git a/generator/templates/dawn/wire/WireCmd.h b/generator/templates/dawn/wire/WireCmd.h
new file mode 100644
index 0000000..f8c2762
--- /dev/null
+++ b/generator/templates/dawn/wire/WireCmd.h
@@ -0,0 +1,138 @@
+//* Copyright 2017 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#ifndef DAWNWIRE_WIRECMD_AUTOGEN_H_
+#define DAWNWIRE_WIRECMD_AUTOGEN_H_
+
+#include <dawn/webgpu.h>
+
+#include "dawn/wire/BufferConsumer.h"
+#include "dawn/wire/ObjectType_autogen.h"
+#include "dawn/wire/WireResult.h"
+
+namespace dawn::wire {
+
+    using ObjectId = uint32_t;
+    using ObjectGeneration = uint32_t;
+    struct ObjectHandle {
+      ObjectId id;
+      ObjectGeneration generation;
+
+      ObjectHandle();
+      ObjectHandle(ObjectId id, ObjectGeneration generation);
+
+      ObjectHandle(const volatile ObjectHandle& rhs);
+      ObjectHandle& operator=(const volatile ObjectHandle& rhs);
+
+      // MSVC has a bug where it thinks the volatile copy assignment is a duplicate.
+      // Workaround this by forwarding to a different function AssignFrom.
+      template <typename T>
+      ObjectHandle& operator=(const T& rhs) {
+          return AssignFrom(rhs);
+      }
+      ObjectHandle& AssignFrom(const ObjectHandle& rhs);
+      ObjectHandle& AssignFrom(const volatile ObjectHandle& rhs);
+    };
+
+    // Interface to allocate more space to deserialize pointed-to data.
+    // nullptr is treated as an error.
+    class DeserializeAllocator {
+        public:
+            virtual void* GetSpace(size_t size) = 0;
+    };
+
+    // Interface to convert an ID to a server object, if possible.
+    // Methods return FatalError if the ID is for a non-existent object and Success otherwise.
+    class ObjectIdResolver {
+        public:
+            {% for type in by_category["object"] %}
+                virtual WireResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const = 0;
+                virtual WireResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const = 0;
+            {% endfor %}
+    };
+
+    // Interface to convert a client object to its ID for the wiring.
+    class ObjectIdProvider {
+        public:
+            {% for type in by_category["object"] %}
+                virtual WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const = 0;
+                virtual WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const = 0;
+            {% endfor %}
+    };
+
+    //* Enum used as a prefix to each command on the wire format.
+    enum class WireCmd : uint32_t {
+        {% for command in cmd_records["command"] %}
+            {{command.name.CamelCase()}},
+        {% endfor %}
+    };
+
+    //* Enum used as a prefix to each command on the return wire format.
+    enum class ReturnWireCmd : uint32_t {
+        {% for command in cmd_records["return command"] %}
+            {{command.name.CamelCase()}},
+        {% endfor %}
+    };
+
+    struct CmdHeader {
+        uint64_t commandSize;
+    };
+
+{% macro write_command_struct(command, is_return_command) %}
+    {% set Return = "Return" if is_return_command else "" %}
+    {% set Cmd = command.name.CamelCase() + "Cmd" %}
+    struct {{Return}}{{Cmd}} {
+        //* From a filled structure, compute how much size will be used in the serialization buffer.
+        size_t GetRequiredSize() const;
+
+        //* Serialize the structure and everything it points to into serializeBuffer which must be
+        //* big enough to contain all the data (as queried from GetRequiredSize).
+        WireResult Serialize(size_t commandSize, SerializeBuffer* serializeBuffer, const ObjectIdProvider& objectIdProvider) const;
+        // Override which produces a FatalError if any object is used.
+        WireResult Serialize(size_t commandSize, SerializeBuffer* serializeBuffer) const;
+
+        //* Deserializes the structure from a buffer, consuming a maximum of *size bytes. When this
+        //* function returns, buffer and size will be updated by the number of bytes consumed to
+        //* deserialize the structure. Structures containing pointers will use allocator to get
+        //* scratch space to deserialize the pointed-to data.
+        //* Deserialize returns:
+        //*  - Success if everything went well (yay!)
+        //*  - FatalError is something bad happened (buffer too small for example)
+        WireResult Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator, const ObjectIdResolver& resolver);
+        // Override which produces a FatalError if any object is used.
+        WireResult Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator);
+
+        {% if command.derived_method %}
+            //* Command handlers want to know the object ID in addition to the backing object.
+            //* Doesn't need to be filled before Serialize, or GetRequiredSize.
+            ObjectId selfId;
+        {% endif %}
+
+        {% for member in command.members %}
+            {{as_annotated_cType(member)}};
+        {% endfor %}
+    };
+{% endmacro %}
+
+    {% for command in cmd_records["command"] %}
+        {{write_command_struct(command, False)}}
+    {% endfor %}
+
+    {% for command in cmd_records["return command"] %}
+        {{write_command_struct(command, True)}}
+    {% endfor %}
+
+}  // namespace dawn::wire
+
+#endif // DAWNWIRE_WIRECMD_AUTOGEN_H_
diff --git a/generator/templates/dawn/wire/client/ApiObjects.h b/generator/templates/dawn/wire/client/ApiObjects.h
new file mode 100644
index 0000000..8c1729d
--- /dev/null
+++ b/generator/templates/dawn/wire/client/ApiObjects.h
@@ -0,0 +1,53 @@
+//* Copyright 2019 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#ifndef DAWNWIRE_CLIENT_APIOBJECTS_AUTOGEN_H_
+#define DAWNWIRE_CLIENT_APIOBJECTS_AUTOGEN_H_
+
+#include "dawn/wire/ObjectType_autogen.h"
+#include "dawn/wire/client/ObjectBase.h"
+
+namespace dawn::wire::client {
+
+    template <typename T>
+    struct ObjectTypeToTypeEnum {
+        static constexpr ObjectType value = static_cast<ObjectType>(-1);
+    };
+
+    {% for type in by_category["object"] %}
+        {% set Type = type.name.CamelCase() %}
+        {% if type.name.CamelCase() in client_special_objects %}
+            class {{Type}};
+        {% else %}
+            struct {{type.name.CamelCase()}} final : ObjectBase {
+                using ObjectBase::ObjectBase;
+            };
+        {% endif %}
+
+        inline {{Type}}* FromAPI(WGPU{{Type}} obj) {
+            return reinterpret_cast<{{Type}}*>(obj);
+        }
+        inline WGPU{{Type}} ToAPI({{Type}}* obj) {
+            return reinterpret_cast<WGPU{{Type}}>(obj);
+        }
+
+        template <>
+        struct ObjectTypeToTypeEnum<{{Type}}> {
+            static constexpr ObjectType value = ObjectType::{{Type}};
+        };
+
+    {% endfor %}
+}  // namespace dawn::wire::client
+
+#endif  // DAWNWIRE_CLIENT_APIOBJECTS_AUTOGEN_H_
diff --git a/generator/templates/dawn/wire/client/ApiProcs.cpp b/generator/templates/dawn/wire/client/ApiProcs.cpp
new file mode 100644
index 0000000..d6e5279
--- /dev/null
+++ b/generator/templates/dawn/wire/client/ApiProcs.cpp
@@ -0,0 +1,178 @@
+//* Copyright 2019 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#include "dawn/common/Log.h"
+#include "dawn/wire/client/ApiObjects.h"
+#include "dawn/wire/client/Client.h"
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace dawn::wire::client {
+
+    //* Outputs an rvalue that's the number of elements a pointer member points to.
+    {% macro member_length(member, accessor) -%}
+        {%- if member.length == "constant" -%}
+            {{member.constant_length}}
+        {%- else -%}
+            {{accessor}}{{as_varName(member.length.name)}}
+        {%- endif -%}
+    {%- endmacro %}
+
+    //* Implementation of the client API functions.
+    {% for type in by_category["object"] %}
+        {% set Type = type.name.CamelCase() %}
+        {% set cType = as_cType(type.name) %}
+
+        {% for method in type.methods %}
+            {% set Suffix = as_MethodSuffix(type.name, method.name) %}
+
+            {% if Suffix in client_handwritten_commands %}
+                static
+            {% endif %}
+            {{as_cType(method.return_type.name)}} Client{{Suffix}}(
+                {{-cType}} cSelf
+                {%- for arg in method.arguments -%}
+                    , {{as_annotated_cType(arg)}}
+                {%- endfor -%}
+            ) {
+                auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
+                {% if Suffix not in client_handwritten_commands %}
+                    {{Suffix}}Cmd cmd;
+
+                    //* Create the structure going on the wire on the stack and fill it with the value
+                    //* arguments so it can compute its size.
+                    cmd.self = cSelf;
+
+                    //* For object creation, store the object ID the client will use for the result.
+                    {% if method.return_type.category == "object" %}
+                        auto* allocation = self->client->{{method.return_type.name.CamelCase()}}Allocator().New(self->client);
+                        cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
+                    {% endif %}
+
+                    {% for arg in method.arguments %}
+                        //* Commands with mutable pointers should not be autogenerated.
+                        {{assert(arg.annotation != "*")}}
+                        cmd.{{as_varName(arg.name)}} = {{as_varName(arg.name)}};
+                    {% endfor %}
+
+                    //* Allocate space to send the command and copy the value args over.
+                    self->client->SerializeCommand(cmd);
+
+                    {% if method.return_type.category == "object" %}
+                        return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
+                    {% endif %}
+                {% else %}
+                    return self->{{method.name.CamelCase()}}(
+                        {%- for arg in method.arguments -%}
+                            {%if not loop.first %}, {% endif %} {{as_varName(arg.name)}}
+                        {%- endfor -%});
+                {% endif %}
+            }
+        {% endfor %}
+
+        //* When an object's refcount reaches 0, notify the server side of it and delete it.
+        void Client{{as_MethodSuffix(type.name, Name("release"))}}({{cType}} cObj) {
+            {{Type}}* obj = reinterpret_cast<{{Type}}*>(cObj);
+            obj->refcount --;
+
+            if (obj->refcount > 0) {
+                return;
+            }
+
+            DestroyObjectCmd cmd;
+            cmd.objectType = ObjectType::{{type.name.CamelCase()}};
+            cmd.objectId = obj->id;
+
+            obj->client->SerializeCommand(cmd);
+            obj->client->{{type.name.CamelCase()}}Allocator().Free(obj);
+        }
+
+        void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) {
+            {{Type}}* obj = reinterpret_cast<{{Type}}*>(cObj);
+            obj->refcount ++;
+        }
+    {% endfor %}
+
+    namespace {
+        WGPUInstance ClientCreateInstance(WGPUInstanceDescriptor const* descriptor) {
+            UNREACHABLE();
+            return nullptr;
+        }
+
+        struct ProcEntry {
+            WGPUProc proc;
+            const char* name;
+        };
+        static const ProcEntry sProcMap[] = {
+            {% for (type, method) in c_methods_sorted_by_name %}
+                { reinterpret_cast<WGPUProc>(Client{{as_MethodSuffix(type.name, method.name)}}), "{{as_cMethod(type.name, method.name)}}" },
+            {% endfor %}
+        };
+        static constexpr size_t sProcMapSize = sizeof(sProcMap) / sizeof(sProcMap[0]);
+    }  // anonymous namespace
+
+    WGPUProc ClientGetProcAddress(WGPUDevice, const char* procName) {
+        if (procName == nullptr) {
+            return nullptr;
+        }
+
+        const ProcEntry* entry = std::lower_bound(&sProcMap[0], &sProcMap[sProcMapSize], procName,
+            [](const ProcEntry &a, const char *b) -> bool {
+                return strcmp(a.name, b) < 0;
+            }
+        );
+
+        if (entry != &sProcMap[sProcMapSize] && strcmp(entry->name, procName) == 0) {
+            return entry->proc;
+        }
+
+        // Special case the two free-standing functions of the API.
+        if (strcmp(procName, "wgpuGetProcAddress") == 0) {
+            return reinterpret_cast<WGPUProc>(ClientGetProcAddress);
+        }
+
+        if (strcmp(procName, "wgpuCreateInstance") == 0) {
+            return reinterpret_cast<WGPUProc>(ClientCreateInstance);
+        }
+
+        return nullptr;
+    }
+
+    std::vector<const char*> GetProcMapNamesForTesting() {
+        std::vector<const char*> result;
+        result.reserve(sProcMapSize);
+        for (const ProcEntry& entry : sProcMap) {
+            result.push_back(entry.name);
+        }
+        return result;
+    }
+
+    {% set Prefix = metadata.proc_table_prefix %}
+    static {{Prefix}}ProcTable gProcTable = {
+        {% for function in by_category["function"] %}
+            Client{{as_cppType(function.name)}},
+        {% endfor %}
+        {% for type in by_category["object"] %}
+            {% for method in c_methods(type) %}
+                Client{{as_MethodSuffix(type.name, method.name)}},
+            {% endfor %}
+        {% endfor %}
+    };
+    const {{Prefix}}ProcTable& GetProcs() {
+        return gProcTable;
+    }
+}  // namespace dawn::wire::client
diff --git a/generator/templates/dawn/wire/client/ClientBase.h b/generator/templates/dawn/wire/client/ClientBase.h
new file mode 100644
index 0000000..0f9cbfe
--- /dev/null
+++ b/generator/templates/dawn/wire/client/ClientBase.h
@@ -0,0 +1,74 @@
+//* Copyright 2019 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+
+#ifndef DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_
+#define DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_
+
+#include "dawn/wire/ChunkedCommandHandler.h"
+#include "dawn/wire/WireCmd_autogen.h"
+#include "dawn/wire/client/ApiObjects.h"
+#include "dawn/wire/client/ObjectAllocator.h"
+
+namespace dawn::wire::client {
+
+    class ClientBase : public ChunkedCommandHandler, public ObjectIdProvider {
+      public:
+        ClientBase() = default;
+        virtual ~ClientBase() = default;
+
+        {% for type in by_category["object"] %}
+            const