Use single DestroyObject command in the wire

Bug: dawn:83
Change-Id: Ic875d5111f59e7166d2decb3dc6a84973d9babdf
Reviewed-on: https://dawn-review.googlesource.com/c/3680
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/generator/templates/dawn_wire/WireClient.cpp b/generator/templates/dawn_wire/WireClient.cpp
index ba74c66..ce708e4 100644
--- a/generator/templates/dawn_wire/WireClient.cpp
+++ b/generator/templates/dawn_wire/WireClient.cpp
@@ -349,7 +349,8 @@
 
                     obj->builderCallback.Call(DAWN_BUILDER_ERROR_STATUS_UNKNOWN, "Unknown");
 
-                    {{as_MethodSuffix(type.name, Name("destroy"))}}Cmd cmd;
+                    DestroyObjectCmd cmd;
+                    cmd.objectType = ObjectType::{{type.name.CamelCase()}};
                     cmd.objectId = obj->id;
 
                     auto allocCmd = static_cast<decltype(cmd)*>(obj->device->GetCmdSpace(sizeof(cmd)));
diff --git a/generator/templates/dawn_wire/WireCmd.h b/generator/templates/dawn_wire/WireCmd.h
index a0052b7..28bc1ae 100644
--- a/generator/templates/dawn_wire/WireCmd.h
+++ b/generator/templates/dawn_wire/WireCmd.h
@@ -53,16 +53,22 @@
             {% endfor %}
     };
 
+    enum class ObjectType : uint32_t {
+        {% for type in by_category["object"] %}
+            {{type.name.CamelCase()}},
+        {% endfor %}
+    };
+
     //* Enum used as a prefix to each command on the wire format.
     enum class WireCmd : uint32_t {
         {% for type in by_category["object"] %}
             {% for method in type.methods %}
                 {{as_MethodSuffix(type.name, method.name)}},
             {% endfor %}
-            {{as_MethodSuffix(type.name, Name("destroy"))}},
         {% endfor %}
         BufferMapAsync,
         BufferUpdateMappedDataCmd,
+        DestroyObject,
     };
 
     {% for type in by_category["object"] %}
@@ -110,14 +116,6 @@
                 {% endfor %}
             };
         {% endfor %}
-
-        //* The command structure used when sending that an ID is destroyed.
-        {% set Suffix = as_MethodSuffix(type.name, Name("destroy")) %}
-        struct {{Suffix}}Cmd {
-            WireCmd commandId = WireCmd::{{Suffix}};
-            ObjectId objectId;
-        };
-
     {% endfor %}
 
     //* Enum used as a prefix to each command on the return wire format.
diff --git a/generator/templates/dawn_wire/WireServer.cpp b/generator/templates/dawn_wire/WireServer.cpp
index 99d91d6..9ea671a 100644
--- a/generator/templates/dawn_wire/WireServer.cpp
+++ b/generator/templates/dawn_wire/WireServer.cpp
@@ -406,10 +406,6 @@
                                             break;
                                     {% endif %}
                                 {% endfor %}
-                                {% set Suffix = as_MethodSuffix(type.name, Name("destroy")) %}
-                                case WireCmd::{{Suffix}}:
-                                    success = Handle{{Suffix}}(&commands, &size);
-                                    break;
                             {% endfor %}
                             case WireCmd::BufferMapAsync:
                                 success = HandleBufferMapAsync(&commands, &size);
@@ -417,7 +413,9 @@
                             case WireCmd::BufferUpdateMappedDataCmd:
                                 success = HandleBufferUpdateMappedData(&commands, &size);
                                 break;
-
+                            case WireCmd::DestroyObject:
+                                success = HandleDestroyObject(&commands, &size);
+                                break;
                             default:
                                 success = false;
                         }
@@ -632,45 +630,6 @@
                             }
                         {% endif %}
                     {% endfor %}
-
-                    //* Handlers for the destruction of objects: clients do the tracking of the
-                    //* reference / release and only send destroy on refcount = 0.
-                    {% set Suffix = as_MethodSuffix(type.name, Name("destroy")) %}
-                    bool Handle{{Suffix}}(const char** commands, size_t* size) {
-
-                        //* Freeing the device has to be done out of band.
-                        {% if type.name.canonical_case() == "device" %}
-                            return false;
-                        {% endif %}
-
-                        const auto* cmd = GetCommand<{{Suffix}}Cmd>(commands, size);
-                        if (cmd == nullptr) {
-                            return false;
-                        }
-
-                        ObjectId objectId = cmd->objectId;
-
-                        //* ID 0 are reserved for nullptr and cannot be destroyed.
-                        if (objectId == 0) {
-                            return false;
-                        }
-
-                        auto* data = mKnown{{type.name.CamelCase()}}.Get(objectId);
-                        if (data == nullptr) {
-                            return false;
-                        }
-
-                        {% if type.name.CamelCase() in reverse_lookup_object_types %}
-                            m{{type.name.CamelCase()}}IdTable.Remove(data->handle);
-                        {% endif %}
-
-                        if (data->handle != nullptr) {
-                            mProcs.{{as_varName(type.name, Name("release"))}}(data->handle);
-                        }
-
-                        mKnown{{type.name.CamelCase()}}.Free(objectId);
-                        return true;
-                    }
                 {% endfor %}
 
                 bool HandleBufferMapAsync(const char** commands, size_t* size) {
@@ -755,6 +714,48 @@
 
                     return true;
                 }
+
+                bool HandleDestroyObject(const char** commands, size_t* size) {
+                    const auto* cmd = GetCommand<DestroyObjectCmd>(commands, size);
+                    if (cmd == nullptr) {
+                        return false;
+                    }
+
+                    ObjectId objectId = cmd->objectId;
+                    //* ID 0 are reserved for nullptr and cannot be destroyed.
+                    if (objectId == 0) {
+                        return false;
+                    }
+
+                    switch (cmd->objectType) {
+                        {% for type in by_category["object"] %}
+                            {% set ObjectType = type.name.CamelCase() %}
+                            case ObjectType::{{ObjectType}}: {
+                                {% if ObjectType == "Device" %}
+                                    //* Freeing the device has to be done out of band.
+                                    return false;
+                                {% else %}
+                                    auto* data = mKnown{{type.name.CamelCase()}}.Get(objectId);
+                                    if (data == nullptr) {
+                                        return false;
+                                    }
+                                    {% if type.name.CamelCase() in reverse_lookup_object_types %}
+                                        m{{type.name.CamelCase()}}IdTable.Remove(data->handle);
+                                    {% endif %}
+
+                                    if (data->handle != nullptr) {
+                                        mProcs.{{as_varName(type.name, Name("release"))}}(data->handle);
+                                    }
+
+                                    mKnown{{type.name.CamelCase()}}.Free(objectId);
+                                    return true;
+                                {% endif %}
+                            }
+                        {% endfor %}
+                        default:
+                            UNREACHABLE();
+                    }
+                }
         };
 
         void ForwardDeviceErrorToServer(const char* message, dawnCallbackUserdata userdata) {
diff --git a/src/dawn_wire/WireCmd.h b/src/dawn_wire/WireCmd.h
index 5d6c371..3dfe6b9 100644
--- a/src/dawn_wire/WireCmd.h
+++ b/src/dawn_wire/WireCmd.h
@@ -71,6 +71,13 @@
         uint32_t dataLength;
     };
 
+    struct DestroyObjectCmd {
+        WireCmd commandId = WireCmd::DestroyObject;
+
+        ObjectType objectType;
+        ObjectId objectId;
+    };
+
 }  // namespace dawn_wire
 
 #endif  // DAWNWIRE_WIRECMD_H_