WebGPU: Implement the destructor of Blink::GPUDevice
This patch implements the destructor of Blink::GPUDevice so that when it
is destroyed in Blink, all the related data structures in both the
client and service side of WebGPU command buffer can also be destroyed.
BUG=chromium:996713
Change-Id: Ibe11aabf395d2dfa33ae3ccfa404d250ffd4c10d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2088690
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Cr-Commit-Position: refs/heads/master@{#748102}
diff --git a/gpu/command_buffer/build_webgpu_cmd_buffer.py b/gpu/command_buffer/build_webgpu_cmd_buffer.py
index 7e421cc..8d611c5 100755
--- a/gpu/command_buffer/build_webgpu_cmd_buffer.py
+++ b/gpu/command_buffer/build_webgpu_cmd_buffer.py
@@ -80,6 +80,11 @@
         'request_device_properties_size * sizeof(char)',
     },
   },
+  'RemoveDevice': {
+    'impl_func': False,
+    'internal': True,
+    'cmd_args': 'uint64_t device_client_id'
+  },
 }
 
 def main(argv):
diff --git a/gpu/command_buffer/client/webgpu_cmd_helper_autogen.h b/gpu/command_buffer/client/webgpu_cmd_helper_autogen.h
index 1c3c089..ce8d364 100644
--- a/gpu/command_buffer/client/webgpu_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/webgpu_cmd_helper_autogen.h
@@ -66,4 +66,11 @@
   }
 }
 
+void RemoveDevice(uint64_t device_client_id) {
+  webgpu::cmds::RemoveDevice* c = GetCmdSpace<webgpu::cmds::RemoveDevice>();
+  if (c) {
+    c->Init(device_client_id);
+  }
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_WEBGPU_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index 9a68053..cc8c468 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -603,5 +603,14 @@
 #endif
 }
 
+void WebGPUImplementation::RemoveDevice(DawnDeviceClientID device_client_id) {
+#if BUILDFLAG(USE_DAWN)
+  auto it = command_serializers_.find(device_client_id);
+  DCHECK(it != command_serializers_.end());
+  helper_->RemoveDevice(device_client_id);
+  command_serializers_.erase(it);
+#endif
+}
+
 }  // namespace webgpu
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/webgpu_implementation.h b/gpu/command_buffer/client/webgpu_implementation.h
index 25624f4..9a97ed4 100644
--- a/gpu/command_buffer/client/webgpu_implementation.h
+++ b/gpu/command_buffer/client/webgpu_implementation.h
@@ -159,6 +159,7 @@
       const WGPUDeviceProperties& requested_device_properties,
       base::OnceCallback<void(bool, DawnDeviceClientID)>
           request_device_callback) override;
+  void RemoveDevice(DawnDeviceClientID device_client_id) override;
 
  private:
   const char* GetLogPrefix() const { return "webgpu"; }
diff --git a/gpu/command_buffer/client/webgpu_interface.h b/gpu/command_buffer/client/webgpu_interface.h
index c065fd3a..f68cbe2 100644
--- a/gpu/command_buffer/client/webgpu_interface.h
+++ b/gpu/command_buffer/client/webgpu_interface.h
@@ -41,6 +41,7 @@
       const WGPUDeviceProperties& requested_device_properties,
       base::OnceCallback<void(bool, DawnDeviceClientID)>
           request_device_callback) = 0;
+  virtual void RemoveDevice(DawnDeviceClientID device_client_id) = 0;
 
 // Include the auto-generated part of this class. We split this because
 // it means we can easily edit the non-auto generated parts right here in
diff --git a/gpu/command_buffer/client/webgpu_interface_stub.cc b/gpu/command_buffer/client/webgpu_interface_stub.cc
index fba9e0d..e38d431 100644
--- a/gpu/command_buffer/client/webgpu_interface_stub.cc
+++ b/gpu/command_buffer/client/webgpu_interface_stub.cc
@@ -43,6 +43,7 @@
         request_device_callback) {
   return false;
 }
+void WebGPUInterfaceStub::RemoveDevice(DawnDeviceClientID device_client_id) {}
 
 // Include the auto-generated part of this class. We split this because
 // it means we can easily edit the non-auto generated parts right here in
diff --git a/gpu/command_buffer/client/webgpu_interface_stub.h b/gpu/command_buffer/client/webgpu_interface_stub.h
index d7d68413..c03b353 100644
--- a/gpu/command_buffer/client/webgpu_interface_stub.h
+++ b/gpu/command_buffer/client/webgpu_interface_stub.h
@@ -36,6 +36,7 @@
       const WGPUDeviceProperties& requested_device_properties,
       base::OnceCallback<void(bool, DawnDeviceClientID)>
           request_device_callback) override;
+  void RemoveDevice(DawnDeviceClientID device_client_id) override;
 
 // Include the auto-generated part of this class. We split this because
 // it means we can easily edit the non-auto generated parts right here in
diff --git a/gpu/command_buffer/common/webgpu_cmd_format_autogen.h b/gpu/command_buffer/common/webgpu_cmd_format_autogen.h
index 5464659..de415eb7 100644
--- a/gpu/command_buffer/common/webgpu_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/webgpu_cmd_format_autogen.h
@@ -288,4 +288,36 @@
     offsetof(RequestDevice, request_device_properties_size) == 20,
     "offset of RequestDevice request_device_properties_size should be 20");
 
+struct RemoveDevice {
+  typedef RemoveDevice ValueType;
+  static const CommandId kCmdId = kRemoveDevice;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(uint64_t _device_client_id) {
+    SetHeader();
+    device_client_id = _device_client_id;
+  }
+
+  void* Set(void* cmd, uint64_t _device_client_id) {
+    static_cast<ValueType*>(cmd)->Init(_device_client_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t device_client_id;
+};
+
+static_assert(sizeof(RemoveDevice) == 8, "size of RemoveDevice should be 8");
+static_assert(offsetof(RemoveDevice, header) == 0,
+              "offset of RemoveDevice header should be 0");
+static_assert(offsetof(RemoveDevice, device_client_id) == 4,
+              "offset of RemoveDevice device_client_id should be 4");
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_WEBGPU_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/webgpu_cmd_format_test_autogen.h b/gpu/command_buffer/common/webgpu_cmd_format_test_autogen.h
index 1c7faf8..50960d2 100644
--- a/gpu/command_buffer/common/webgpu_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/webgpu_cmd_format_test_autogen.h
@@ -110,4 +110,14 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(WebGPUFormatTest, RemoveDevice) {
+  cmds::RemoveDevice& cmd = *GetBufferAs<cmds::RemoveDevice>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<uint64_t>(11));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::RemoveDevice::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<uint64_t>(11), cmd.device_client_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_WEBGPU_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/webgpu_cmd_ids_autogen.h b/gpu/command_buffer/common/webgpu_cmd_ids_autogen.h
index 3e70690..6ebfffd 100644
--- a/gpu/command_buffer/common/webgpu_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/webgpu_cmd_ids_autogen.h
@@ -16,7 +16,8 @@
   OP(AssociateMailboxImmediate) /* 257 */ \
   OP(DissociateMailbox)         /* 258 */ \
   OP(RequestAdapter)            /* 259 */ \
-  OP(RequestDevice)             /* 260 */
+  OP(RequestDevice)             /* 260 */ \
+  OP(RemoveDevice)              /* 261 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index 923e49d..8e895d7 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -766,7 +766,6 @@
     const volatile void* cmd_data) {
   const volatile webgpu::cmds::RequestAdapter& c =
       *static_cast<const volatile webgpu::cmds::RequestAdapter*>(cmd_data);
-
   PowerPreference power_preference =
       static_cast<PowerPreference>(c.power_preference);
   DawnRequestAdapterSerial request_adapter_serial =
@@ -794,7 +793,6 @@
     const volatile void* cmd_data) {
   const volatile webgpu::cmds::RequestDevice& c =
       *static_cast<const volatile webgpu::cmds::RequestDevice*>(cmd_data);
-
   DawnDeviceClientID device_client_id =
       static_cast<DawnDeviceClientID>(c.device_client_id);
   uint32_t adapter_service_id = static_cast<uint32_t>(c.adapter_service_id);
@@ -832,7 +830,6 @@
     const volatile void* cmd_data) {
   const volatile webgpu::cmds::DawnCommands& c =
       *static_cast<const volatile webgpu::cmds::DawnCommands*>(cmd_data);
-
   uint32_t size = static_cast<uint32_t>(c.size);
   uint32_t commands_shm_id = static_cast<uint32_t>(c.commands_shm_id);
   uint32_t commands_shm_offset = static_cast<uint32_t>(c.commands_shm_offset);
@@ -866,7 +863,6 @@
   const volatile webgpu::cmds::AssociateMailboxImmediate& c =
       *static_cast<const volatile webgpu::cmds::AssociateMailboxImmediate*>(
           cmd_data);
-
   DawnDeviceClientID device_client_id =
       static_cast<DawnDeviceClientID>(c.device_client_id());
   uint32_t device_generation = static_cast<uint32_t>(c.device_generation);
@@ -956,7 +952,6 @@
     const volatile void* cmd_data) {
   const volatile webgpu::cmds::DissociateMailbox& c =
       *static_cast<const volatile webgpu::cmds::DissociateMailbox*>(cmd_data);
-
   uint32_t texture_id = static_cast<uint32_t>(c.texture_id);
   uint32_t texture_generation = static_cast<uint32_t>(c.texture_generation);
 
@@ -972,5 +967,22 @@
   return error::kNoError;
 }
 
+error::Error WebGPUDecoderImpl::HandleRemoveDevice(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile webgpu::cmds::RemoveDevice& c =
+      *static_cast<const volatile webgpu::cmds::RemoveDevice*>(cmd_data);
+  DawnDeviceClientID device_client_id =
+      static_cast<DawnDeviceClientID>(c.device_client_id);
+
+  auto it = dawn_device_and_wire_servers_.find(device_client_id);
+  if (it == dawn_device_and_wire_servers_.end()) {
+    return error::kInvalidArguments;
+  }
+
+  dawn_device_and_wire_servers_.erase(it);
+  return error::kNoError;
+}
+
 }  // namespace webgpu
 }  // namespace gpu
diff --git a/gpu/command_buffer/webgpu_cmd_buffer_functions.txt b/gpu/command_buffer/webgpu_cmd_buffer_functions.txt
index ee35ecfe..0203b01 100644
--- a/gpu/command_buffer/webgpu_cmd_buffer_functions.txt
+++ b/gpu/command_buffer/webgpu_cmd_buffer_functions.txt
@@ -10,4 +10,5 @@
 GL_APICALL void GL_APIENTRY wgAssociateMailbox (GLuint64 device_client_id, GLuint device_generation, GLuint id, GLuint generation, GLuint usage, const GLbyte* mailbox);
 GL_APICALL void GL_APIENTRY wgDissociateMailbox (GLuint texture_id, GLuint texture_generation);
 GL_APICALL void GL_APIENTRY wgRequestAdapter (GLuint64 request_adapter_serial, EnumClassPowerPreference power_preference = PowerPreference::kDefault);
-GL_APICALL void GL_APIENTRY wgRequestDevice (GLuint64 device_client_id, GLuint adapter_service_id, const char* dawn_request_device_properties, size_t request_device_properties_size);
\ No newline at end of file
+GL_APICALL void GL_APIENTRY wgRequestDevice (GLuint64 device_client_id, GLuint adapter_service_id, const char* dawn_request_device_properties, size_t request_device_properties_size);
+GL_APICALL void GL_APIENTRY wgRemoveDevice (GLuint64 device_client_id);
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 84e77d5..eb67079 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -61,7 +61,9 @@
   if (IsDawnControlClientDestroyed()) {
     return;
   }
+  queue_ = nullptr;
   GetProcs().deviceRelease(GetHandle());
+  GetInterface()->RemoveDevice(client_id_);
 }
 
 uint64_t GPUDevice::GetClientID() const {