Add a build target for a webgpu_dawn library

This library binds directly to dawn_native and implements
webgpu.h. It may be built as a single library so it can
be easily used in other projects.

Bug: dawn:1220
Change-Id: I73be8c6455922fa526efd1600446cc46b07e82ed
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/53887
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index dbc98e9..5f3ec15 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -17,6 +17,7 @@
 group("all") {
   testonly = true
   deps = [
+    "src/dawn_native:webgpu_dawn",
     "src/fuzzers:dawn_fuzzers",
     "src/tests:dawn_tests",
   ]
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 9fb39fa..6d21eb8 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -786,6 +786,12 @@
                            'src/dawn/dawn_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 'dawncpp' in targets:
             renders.append(
                 FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp',
diff --git a/generator/templates/dawn_native/ProcTable.cpp b/generator/templates/dawn_native/ProcTable.cpp
index 3b6d9ff..73a9d8d 100644
--- a/generator/templates/dawn_native/ProcTable.cpp
+++ b/generator/templates/dawn_native/ProcTable.cpp
@@ -28,51 +28,51 @@
 
 namespace dawn_native {
 
-    namespace {
+    {% for type in by_category["object"] %}
+        {% for method in c_methods(type) %}
+            {% set suffix = as_MethodSuffix(type.name, method.name) %}
 
-        {% 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);
 
-                {{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"] %}
-                            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 %}
+                {% for arg in method.arguments %}
+                    {% set varName = as_varName(arg.name) %}
+                    {% if arg.type.category in ["enum", "bitmask"] %}
+                        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 %}
+                {%- 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 {
 
         struct ProcEntry {
             WGPUProc proc;
@@ -84,7 +84,8 @@
             {% endfor %}
         };
         static constexpr size_t sProcMapSize = sizeof(sProcMap) / sizeof(sProcMap[0]);
-    }
+
+    }  // anonymous namespace
 
     WGPUInstance NativeCreateInstance(WGPUInstanceDescriptor const* descriptor) {
         return ToAPI(InstanceBase::Create(FromAPI(descriptor)));
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..846a409
--- /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/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn
index cd977fa..82913a8 100644
--- a/src/dawn_native/BUILD.gn
+++ b/src/dawn_native/BUILD.gn
@@ -746,3 +746,32 @@
     }
   }
 }
+
+dawn_json_generator("webgpu_dawn_native_proc_gen") {
+  target = "webgpu_dawn_native_proc"
+  outputs = [ "src/dawn_native/webgpu_dawn_native_proc.cpp" ]
+}
+
+dawn_component("webgpu_dawn") {
+  # For a single library - build `webgpu_dawn_shared` with GN args:
+  #   dawn_complete_static_libs = true - to package a single lib
+  #
+  #   is_debug = false
+  #    - setting this to true makes library over 50Mb
+  #
+  #   use_custom_libcxx = false
+  #    - Otherwise, libc++ symbols may conflict if the
+  #      library is used outside of Chromium.
+  #
+  #   dawn_use_swiftshader = false
+  #   angle_enable_swiftshader = false
+  #    - SwiftShader can't be built without use_custom_libcxx.
+  #      It should be built separately.
+  DEFINE_PREFIX = "WGPU"
+
+  sources = get_target_outputs(":webgpu_dawn_native_proc_gen")
+  deps = [
+    ":dawn_native_static",
+    ":webgpu_dawn_native_proc_gen",
+  ]
+}
diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt
index bfeea4d..b6b4f47 100644
--- a/src/dawn_native/CMakeLists.txt
+++ b/src/dawn_native/CMakeLists.txt
@@ -545,3 +545,17 @@
 if (DAWN_ENABLE_VULKAN)
     target_sources(dawn_native PRIVATE "vulkan/VulkanBackend.cpp")
 endif()
+
+DawnJSONGenerator(
+    TARGET "webgpu_dawn_native_proc"
+    PRINT_NAME "Dawn native WebGPU procs"
+    RESULT_VARIABLE "WEBGPU_DAWN_NATIVE_PROC_GEN"
+)
+
+add_library(webgpu_dawn ${DAWN_DUMMY_FILE})
+target_link_libraries(webgpu_dawn PRIVATE dawn_native)
+target_compile_definitions(webgpu_dawn PRIVATE "WGPU_IMPLEMENTATION")
+if(BUILD_SHARED_LIBS)
+    target_compile_definitions(webgpu_dawn PRIVATE "WGPU_SHARED_LIBRARY")
+endif()
+target_sources(webgpu_dawn PRIVATE ${WEBGPU_DAWN_NATIVE_PROC_GEN})