[dawn][wire] Removes InjectDevice.

- Updated SampleUtils to use WireHelper.
- Added swap chain utility function in WireHelper.

Change-Id: Ic830d4251f48cc3ae57d129040965aa8f3fb8b5b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/175784
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/mock_api.cpp b/generator/templates/mock_api.cpp
index d01b443..b66b27e 100644
--- a/generator/templates/mock_api.cpp
+++ b/generator/templates/mock_api.cpp
@@ -65,7 +65,11 @@
 
     {% for type in by_category["structure"] if type.has_free_members_function %}
         table->{{as_varName(type.name, Name("free members"))}} = []({{as_cType(type.name)}} {{as_varName(type.name)}}) {
-            dawn::WarningLog() << "No mock available for {{as_varName(type.name, Name('free members'))}}";
+            static bool calledOnce = false;
+            if (!calledOnce) {
+                calledOnce = true;
+                dawn::WarningLog() << "No mock available for {{as_varName(type.name, Name('free members'))}}";
+            }
         };
     {% endfor %}
 }
diff --git a/include/dawn/wire/WireClient.h b/include/dawn/wire/WireClient.h
index fea95b6..a1e268a 100644
--- a/include/dawn/wire/WireClient.h
+++ b/include/dawn/wire/WireClient.h
@@ -80,7 +80,6 @@
     ReservedTexture ReserveTexture(WGPUDevice device, const WGPUTextureDescriptor* descriptor);
     ReservedSwapChain ReserveSwapChain(WGPUDevice device,
                                        const WGPUSwapChainDescriptor* descriptor);
-    ReservedDevice ReserveDevice(WGPUInstance instance);
     ReservedInstance ReserveInstance(const WGPUInstanceDescriptor* descriptor = nullptr);
 
     void ReclaimTextureReservation(const ReservedTexture& reservation);
diff --git a/include/dawn/wire/WireServer.h b/include/dawn/wire/WireServer.h
index 3738cab..1c67262 100644
--- a/include/dawn/wire/WireServer.h
+++ b/include/dawn/wire/WireServer.h
@@ -56,7 +56,6 @@
 
     bool InjectTexture(WGPUTexture texture, const Handle& handle, const Handle& deviceHandle);
     bool InjectSwapChain(WGPUSwapChain swapchain, const Handle& handle, const Handle& deviceHandle);
-    bool InjectDevice(WGPUDevice device, const Handle& handle);
     bool InjectInstance(WGPUInstance instance, const Handle& handle);
 
     // Look up a device by (id, generation) pair. Returns nullptr if the generation
diff --git a/src/dawn/samples/SampleUtils.cpp b/src/dawn/samples/SampleUtils.cpp
index 844459f..6acb553 100644
--- a/src/dawn/samples/SampleUtils.cpp
+++ b/src/dawn/samples/SampleUtils.cpp
@@ -42,6 +42,7 @@
 #include "dawn/dawn_proc.h"
 #include "dawn/native/DawnNative.h"
 #include "dawn/utils/TerribleCommandBuffer.h"
+#include "dawn/utils/WireHelper.h"
 #include "dawn/wire/WireClient.h"
 #include "dawn/wire/WireServer.h"
 #include "webgpu/webgpu_glfw.h"
@@ -110,16 +111,14 @@
 static std::vector<std::string> disableToggles;
 
 static CmdBufType cmdBufType = CmdBufType::Terrible;
-static std::unique_ptr<dawn::native::Instance> instance;
+static std::unique_ptr<dawn::native::Instance> backendInstance;
+static std::unique_ptr<dawn::utils::WireHelper> wireHelper;
+static dawn::native::Adapter backendAdapter;
+static WGPUDevice backendDevice;
 static wgpu::SwapChain swapChain;
 
 static GLFWwindow* window = nullptr;
 
-static dawn::wire::WireServer* wireServer = nullptr;
-static dawn::wire::WireClient* wireClient = nullptr;
-static dawn::utils::TerribleCommandBuffer* c2sBuf = nullptr;
-static dawn::utils::TerribleCommandBuffer* s2cBuf = nullptr;
-
 static constexpr uint32_t kWidth = 640;
 static constexpr uint32_t kHeight = 480;
 
@@ -144,59 +143,107 @@
 
     WGPUInstanceDescriptor instanceDescriptor{};
     instanceDescriptor.features.timedWaitAnyEnable = true;
-    instance = std::make_unique<dawn::native::Instance>(&instanceDescriptor);
+    backendInstance = std::make_unique<dawn::native::Instance>(&instanceDescriptor);
 
-    wgpu::RequestAdapterOptions options = {};
-    options.backendType = backendType;
-
-    // Get an adapter for the backend to use, and create the device.
-    auto adapters = instance->EnumerateAdapters(&options);
-    wgpu::DawnAdapterPropertiesPowerPreference power_props{};
-    wgpu::AdapterProperties adapterProperties{};
-    adapterProperties.nextInChain = &power_props;
-    // Find the first adapter which satisfies the adapterType requirement.
-    auto isAdapterType = [&adapterProperties](const auto& adapter) -> bool {
-        // picks the first adapter when adapterType is unknown.
-        if (adapterType == wgpu::AdapterType::Unknown) {
-            return true;
-        }
-        adapter.GetProperties(&adapterProperties);
-        return adapterProperties.adapterType == adapterType;
-    };
-    auto preferredAdapter = std::find_if(adapters.begin(), adapters.end(), isAdapterType);
-    if (preferredAdapter == adapters.end()) {
-        fprintf(stderr, "Failed to find an adapter! Please try another adapter type.\n");
-        return wgpu::Device();
-    }
-
-    std::vector<const char*> enableToggleNames;
-    std::vector<const char*> disabledToggleNames;
-    for (const std::string& toggle : enableToggles) {
-        enableToggleNames.push_back(toggle.c_str());
-    }
-
-    for (const std::string& toggle : disableToggles) {
-        disabledToggleNames.push_back(toggle.c_str());
-    }
-    WGPUDawnTogglesDescriptor toggles;
-    toggles.chain.sType = WGPUSType_DawnTogglesDescriptor;
-    toggles.chain.next = nullptr;
-    toggles.enabledToggles = enableToggleNames.data();
-    toggles.enabledToggleCount = enableToggleNames.size();
-    toggles.disabledToggles = disabledToggleNames.data();
-    toggles.disabledToggleCount = disabledToggleNames.size();
-
-    WGPUDeviceDescriptor deviceDesc = {};
-    deviceDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&toggles);
-
-    WGPUDevice backendDevice = preferredAdapter->CreateDevice(&deviceDesc);
+    // Set up native proc tables to override the behavior given command-line flags.
     DawnProcTable backendProcs = dawn::native::GetProcs();
+    backendProcs.instanceRequestAdapter = [](WGPUInstance, const WGPURequestAdapterOptions*,
+                                             WGPURequestAdapterCallback callback, void* userdata) {
+        wgpu::RequestAdapterOptions options = {};
+        auto adapters = backendInstance->EnumerateAdapters(&options);
+        wgpu::DawnAdapterPropertiesPowerPreference power_props{};
+        wgpu::AdapterProperties adapterProperties{};
+        adapterProperties.nextInChain = &power_props;
+        // Find the first adapter which satisfies the adapterType requirement.
+        auto isAdapterType = [&adapterProperties](const auto& adapter) -> bool {
+            // picks the first adapter when adapterType is unknown.
+            if (adapterType == wgpu::AdapterType::Unknown) {
+                return true;
+            }
+            adapter.GetProperties(&adapterProperties);
+            return adapterProperties.adapterType == adapterType;
+        };
+        auto preferredAdapter = std::find_if(adapters.begin(), adapters.end(), isAdapterType);
+
+        if (preferredAdapter != adapters.end()) {
+            backendAdapter = *preferredAdapter;
+            WGPUAdapter cAdapter = preferredAdapter->Get();
+            dawn::native::GetProcs().adapterReference(cAdapter);
+            callback(WGPURequestAdapterStatus_Success, cAdapter, nullptr, userdata);
+        } else {
+            callback(WGPURequestAdapterStatus_Error, nullptr,
+                     "Failed to find an adapter! Please try another adapter type.\n", userdata);
+        }
+    };
+    backendProcs.adapterRequestDevice = [](WGPUAdapter, const WGPUDeviceDescriptor*,
+                                           WGPURequestDeviceCallback callback, void* userdata) {
+        std::vector<const char*> enableToggleNames;
+        std::vector<const char*> disabledToggleNames;
+        for (const std::string& toggle : enableToggles) {
+            enableToggleNames.push_back(toggle.c_str());
+        }
+
+        for (const std::string& toggle : disableToggles) {
+            disabledToggleNames.push_back(toggle.c_str());
+        }
+        WGPUDawnTogglesDescriptor toggles;
+        toggles.chain.sType = WGPUSType_DawnTogglesDescriptor;
+        toggles.chain.next = nullptr;
+        toggles.enabledToggles = enableToggleNames.data();
+        toggles.enabledToggleCount = enableToggleNames.size();
+        toggles.disabledToggles = disabledToggleNames.data();
+        toggles.disabledToggleCount = disabledToggleNames.size();
+
+        WGPUDeviceDescriptor deviceDesc = {};
+        deviceDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&toggles);
+        backendDevice = backendAdapter.CreateDevice(&deviceDesc);
+        if (backendDevice != nullptr) {
+            callback(WGPURequestDeviceStatus_Success, backendDevice, nullptr, userdata);
+        } else {
+            callback(WGPURequestDeviceStatus_Error, nullptr, "Failed to create a device!\n",
+                     userdata);
+        }
+    };
+
+    wireHelper = dawn::utils::CreateWireHelper(backendProcs, cmdBufType == CmdBufType::Terrible);
+    wgpu::Instance instance = wireHelper->RegisterInstance(backendInstance->Get());
+
+    wgpu::Adapter adapter = nullptr;
+    instance.RequestAdapter(
+        nullptr,
+        [](WGPURequestAdapterStatus, WGPUAdapter cAdapter, const char* message, void* userdata) {
+            if (message != nullptr) {
+                fprintf(stderr, "%s", message);
+                return;
+            }
+            *static_cast<wgpu::Adapter*>(userdata) = wgpu::Adapter::Acquire(cAdapter);
+        },
+        &adapter);
+    DoFlush();
+    DAWN_ASSERT(adapter != nullptr);
+
+    wgpu::Device device = nullptr;
+    adapter.RequestDevice(
+        nullptr,
+        [](WGPURequestDeviceStatus, WGPUDevice cDevice, const char* message, void* userdata) {
+            if (message != nullptr) {
+                fprintf(stderr, "%s", message);
+                return;
+            }
+            *static_cast<wgpu::Device*>(userdata) = wgpu::Device::Acquire(cDevice);
+        },
+        &device);
+    DoFlush();
+    DAWN_ASSERT(device != nullptr);
+    device.SetUncapturedErrorCallback(PrintDeviceError, nullptr);
+    device.SetDeviceLostCallback(DeviceLostCallback, nullptr);
+    device.SetLoggingCallback(DeviceLogCallback, nullptr);
 
     // Create the swapchain
     auto surfaceChainedDesc = wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
     WGPUSurfaceDescriptor surfaceDesc;
     surfaceDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(surfaceChainedDesc.get());
-    WGPUSurface surface = backendProcs.instanceCreateSurface(instance->Get(), &surfaceDesc);
+    WGPUSurface surface = backendProcs.instanceCreateSurface(backendInstance->Get(), &surfaceDesc);
 
     WGPUSwapChainDescriptor swapChainDesc = {};
     swapChainDesc.usage = WGPUTextureUsage_RenderAttachment;
@@ -204,57 +251,9 @@
     swapChainDesc.width = kWidth;
     swapChainDesc.height = kHeight;
     swapChainDesc.presentMode = WGPUPresentMode_Mailbox;
-    WGPUSwapChain backendSwapChain =
-        backendProcs.deviceCreateSwapChain(backendDevice, surface, &swapChainDesc);
+    swapChain = wireHelper->CreateSwapChain(surface, backendDevice, device.Get(), &swapChainDesc);
 
-    // Choose whether to use the backend procs and devices/swapchains directly, or set up the wire.
-    WGPUDevice cDevice = nullptr;
-    DawnProcTable procs;
-
-    switch (cmdBufType) {
-        case CmdBufType::None:
-            procs = backendProcs;
-            cDevice = backendDevice;
-            swapChain = wgpu::SwapChain::Acquire(backendSwapChain);
-            break;
-
-        case CmdBufType::Terrible: {
-            c2sBuf = new dawn::utils::TerribleCommandBuffer();
-            s2cBuf = new dawn::utils::TerribleCommandBuffer();
-
-            dawn::wire::WireServerDescriptor serverDesc = {};
-            serverDesc.procs = &backendProcs;
-            serverDesc.serializer = s2cBuf;
-
-            wireServer = new dawn::wire::WireServer(serverDesc);
-            c2sBuf->SetHandler(wireServer);
-
-            dawn::wire::WireClientDescriptor clientDesc = {};
-            clientDesc.serializer = c2sBuf;
-
-            wireClient = new dawn::wire::WireClient(clientDesc);
-            procs = dawn::wire::client::GetProcs();
-            s2cBuf->SetHandler(wireClient);
-
-            auto reservedInstance = wireClient->ReserveInstance();
-            wireServer->InjectInstance(instance->Get(), reservedInstance.handle);
-
-            auto reservedDevice = wireClient->ReserveDevice(reservedInstance.instance);
-            wireServer->InjectDevice(backendDevice, reservedDevice.handle);
-            cDevice = reservedDevice.device;
-
-            auto reservedSwapChain = wireClient->ReserveSwapChain(cDevice, &swapChainDesc);
-            wireServer->InjectSwapChain(backendSwapChain, reservedSwapChain.handle,
-                                        reservedSwapChain.deviceHandle);
-            swapChain = wgpu::SwapChain::Acquire(reservedSwapChain.swapchain);
-        } break;
-    }
-
-    dawnProcSetProcs(&procs);
-    procs.deviceSetUncapturedErrorCallback(cDevice, PrintDeviceError, nullptr);
-    procs.deviceSetDeviceLostCallback(cDevice, DeviceLostCallback, nullptr);
-    procs.deviceSetLoggingCallback(cDevice, DeviceLogCallback, nullptr);
-    return wgpu::Device::Acquire(cDevice);
+    return device;
 }
 
 wgpu::TextureFormat GetPreferredSwapChainTextureFormat() {
@@ -423,8 +422,8 @@
 
 void DoFlush() {
     if (cmdBufType == CmdBufType::Terrible) {
-        bool c2sSuccess = c2sBuf->Flush();
-        bool s2cSuccess = s2cBuf->Flush();
+        bool c2sSuccess = wireHelper->FlushClient();
+        bool s2cSuccess = wireHelper->FlushServer();
 
         DAWN_ASSERT(c2sSuccess && s2cSuccess);
     }
@@ -440,5 +439,5 @@
 }
 
 void ProcessEvents() {
-    dawn::native::InstanceProcessEvents(instance->Get());
+    dawn::native::InstanceProcessEvents(backendInstance->Get());
 }
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index 05fe619..35cc1c5 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -435,7 +435,6 @@
     "unittests/wire/WireExtensionTests.cpp",
     "unittests/wire/WireFutureTest.cpp",
     "unittests/wire/WireFutureTest.h",
-    "unittests/wire/WireInjectDeviceTests.cpp",
     "unittests/wire/WireInjectInstanceTests.cpp",
     "unittests/wire/WireInjectSwapChainTests.cpp",
     "unittests/wire/WireInjectTextureTests.cpp",
diff --git a/src/dawn/tests/unittests/GetProcAddressTests.cpp b/src/dawn/tests/unittests/GetProcAddressTests.cpp
index 1f8dabc..b6c3b85 100644
--- a/src/dawn/tests/unittests/GetProcAddressTests.cpp
+++ b/src/dawn/tests/unittests/GetProcAddressTests.cpp
@@ -91,8 +91,11 @@
                 clientDesc.serializer = mC2sBuf.get();
                 mWireClient = std::make_unique<wire::WireClient>(clientDesc);
 
-                mDevice = wgpu::Device::Acquire(
-                    mWireClient->ReserveDevice(ToAPI(mNativeInstance.Get())).device);
+                // Note that currently we are passing a null device since we do not actually use the
+                // device in determining the resulting proc addresses. If/when we actually care
+                // about features on the device to determine a proc address, this should be updated
+                // accordingly.
+                mDevice = nullptr;
                 mProcs = wire::client::GetProcs();
                 break;
             }
diff --git a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
index f216372..20ce02c 100644
--- a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
@@ -64,61 +64,6 @@
                               void* userdata = nullptr) {
         CallImpl(userdata, a.Get(), reinterpret_cast<WGPUDeviceDescriptor const*>(descriptor));
     }
-
-    // Bootstrap the tests and create a fake adapter.
-    void SetUp() override {
-        WireAdapterTestBase::SetUp();
-
-        WGPURequestAdapterOptions options = {};
-        MockCallback<WGPURequestAdapterCallback> cb;
-        wgpuInstanceRequestAdapter(instance, &options, cb.Callback(), cb.MakeUserdata(this));
-
-        // Expect the server to receive the message. Then, mock a fake reply.
-        apiAdapter = api.GetNewAdapter();
-        EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
-            .WillOnce(InvokeWithoutArgs([&] {
-                EXPECT_CALL(api, AdapterHasFeature(apiAdapter, _)).WillRepeatedly(Return(false));
-
-                EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
-                    .WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
-                        *properties = {};
-                        properties->vendorName = "";
-                        properties->architecture = "";
-                        properties->name = "";
-                        properties->driverDescription = "";
-                    })));
-
-                EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
-                    .WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
-                        *limits = {};
-                        return true;
-                    })));
-
-                EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, nullptr))
-                    .WillOnce(Return(0))
-                    .WillOnce(Return(0));
-                api.CallInstanceRequestAdapterCallback(
-                    apiInstance, WGPURequestAdapterStatus_Success, apiAdapter, nullptr);
-            }));
-        FlushClient();
-
-        // Expect the callback in the client.
-        WGPUAdapter cAdapter;
-        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
-            .WillOnce(SaveArg<1>(&cAdapter));
-        FlushServer();
-
-        EXPECT_NE(cAdapter, nullptr);
-        adapter = wgpu::Adapter::Acquire(cAdapter);
-    }
-
-    void TearDown() override {
-        adapter = nullptr;
-        WireAdapterTestBase::TearDown();
-    }
-
-    WGPUAdapter apiAdapter;
-    wgpu::Adapter adapter;
 };
 DAWN_INSTANTIATE_WIRE_FUTURE_TEST_P(WireAdapterTests);
 
diff --git a/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp b/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
index 889b52f..8220400 100644
--- a/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
@@ -173,7 +173,7 @@
     // Expect release on all objects created by the client. Note: the device
     // should be deleted first because it may free its reference to the default queue
     // on deletion.
-    Sequence s1, s2, s3, s4;
+    Sequence s1, s2, s3, s4, s5;
     EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
         .Times(1)
         .InSequence(s1, s2);
@@ -183,15 +183,17 @@
     EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr))
         .Times(1)
         .InSequence(s1, s2);
-    EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3, s4);
+    EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3, s4, s5);
     EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1).InSequence(s1);
     EXPECT_CALL(api, CommandEncoderRelease(apiCommandEncoder)).Times(1).InSequence(s2);
     EXPECT_CALL(api, SamplerRelease(apiSampler)).Times(1).InSequence(s3);
-    EXPECT_CALL(api, InstanceRelease(apiInstance)).Times(1).InSequence(s4);
+    EXPECT_CALL(api, AdapterRelease(apiAdapter)).Times(1).InSequence(s4);
+    EXPECT_CALL(api, InstanceRelease(apiInstance)).Times(1).InSequence(s5);
     FlushClient();
 
     // Signal that we already released and cleared callbacks for |apiDevice|
     DefaultApiDeviceWasReleased();
+    DefaultApiAdapterWasReleased();
 }
 
 }  // anonymous namespace
diff --git a/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp b/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp
deleted file mode 100644
index b49348d..0000000
--- a/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2021 The Dawn & Tint Authors
-//
-// 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.
-
-#include "dawn/tests/unittests/wire/WireTest.h"
-
-#include "dawn/wire/WireClient.h"
-#include "dawn/wire/WireServer.h"
-
-namespace dawn::wire {
-namespace {
-
-using testing::_;
-using testing::Exactly;
-using testing::Mock;
-using testing::Return;
-
-class WireInjectDeviceTests : public WireTest {
-  public:
-    WireInjectDeviceTests() {}
-    ~WireInjectDeviceTests() override = default;
-};
-
-// Test that reserving and injecting a device makes calls on the client object forward to the
-// server object correctly.
-TEST_F(WireInjectDeviceTests, CallAfterReserveInject) {
-    auto reserved = GetWireClient()->ReserveDevice(instance);
-
-    WGPUDevice serverDevice = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice, reserved.handle));
-
-    WGPUBufferDescriptor bufferDesc = {};
-    wgpuDeviceCreateBuffer(reserved.device, &bufferDesc);
-    WGPUBuffer serverBuffer = api.GetNewBuffer();
-    EXPECT_CALL(api, DeviceCreateBuffer(serverDevice, _)).WillOnce(Return(serverBuffer));
-    FlushClient();
-
-    // Called on shutdown.
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, nullptr, nullptr))
-        .Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, nullptr, nullptr)).Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, nullptr, nullptr))
-        .Times(Exactly(1));
-}
-
-// Test that reserve correctly returns different IDs each time.
-TEST_F(WireInjectDeviceTests, ReserveDifferentIDs) {
-    auto reserved1 = GetWireClient()->ReserveDevice(instance);
-    auto reserved2 = GetWireClient()->ReserveDevice(instance);
-
-    ASSERT_NE(reserved1.handle.id, reserved2.handle.id);
-    ASSERT_NE(reserved1.device, reserved2.device);
-}
-
-// Test that injecting the same id without a destroy first fails.
-TEST_F(WireInjectDeviceTests, InjectExistingID) {
-    auto reserved = GetWireClient()->ReserveDevice(instance);
-
-    WGPUDevice serverDevice = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice, reserved.handle));
-
-    // ID already in use, call fails.
-    ASSERT_FALSE(GetWireServer()->InjectDevice(serverDevice, reserved.handle));
-
-    // Called on shutdown.
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, nullptr, nullptr))
-        .Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, nullptr, nullptr)).Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, nullptr, nullptr))
-        .Times(Exactly(1));
-}
-
-// Test that the server only borrows the device and does a single reference-release
-TEST_F(WireInjectDeviceTests, InjectedDeviceLifetime) {
-    auto reserved = GetWireClient()->ReserveDevice(instance);
-
-    // Injecting the device adds a reference
-    WGPUDevice serverDevice = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice, reserved.handle));
-
-    // Releasing the device removes a single reference and clears its error callbacks.
-    wgpuDeviceRelease(reserved.device);
-    EXPECT_CALL(api, DeviceRelease(serverDevice));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, nullptr, nullptr)).Times(1);
-    FlushClient();
-
-    // Deleting the server doesn't release a second reference.
-    DeleteServer();
-    Mock::VerifyAndClearExpectations(&api);
-}
-
-// Test that it is an error to get the primary queue of a device before it has been
-// injected on the server.
-TEST_F(WireInjectDeviceTests, GetQueueBeforeInject) {
-    auto reserved = GetWireClient()->ReserveDevice(instance);
-
-    wgpuDeviceGetQueue(reserved.device);
-    FlushClient(false);
-}
-
-// Test that it is valid to get the primary queue of a device after it has been
-// injected on the server.
-TEST_F(WireInjectDeviceTests, GetQueueAfterInject) {
-    auto reserved = GetWireClient()->ReserveDevice(instance);
-
-    WGPUDevice serverDevice = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice, reserved.handle));
-
-    wgpuDeviceGetQueue(reserved.device);
-
-    WGPUQueue apiQueue = api.GetNewQueue();
-    EXPECT_CALL(api, DeviceGetQueue(serverDevice)).WillOnce(Return(apiQueue));
-    FlushClient();
-
-    // Called on shutdown.
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, nullptr, nullptr))
-        .Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice, nullptr, nullptr)).Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, nullptr, nullptr))
-        .Times(Exactly(1));
-}
-
-// Test that the list of live devices can be reflected using GetDevice.
-TEST_F(WireInjectDeviceTests, ReflectLiveDevices) {
-    // Reserve two devices.
-    auto reserved1 = GetWireClient()->ReserveDevice(instance);
-    auto reserved2 = GetWireClient()->ReserveDevice(instance);
-
-    // Inject both devices.
-
-    WGPUDevice serverDevice1 = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice1));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice1, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice1, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice1, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice1, reserved1.handle));
-
-    WGPUDevice serverDevice2 = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice2));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice2, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice2, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice2, reserved2.handle));
-
-    // Test that both devices can be reflected.
-    ASSERT_EQ(serverDevice1,
-              GetWireServer()->GetDevice(reserved1.handle.id, reserved1.handle.generation));
-    ASSERT_EQ(serverDevice2,
-              GetWireServer()->GetDevice(reserved2.handle.id, reserved2.handle.generation));
-
-    // Release the first device
-    wgpuDeviceRelease(reserved1.device);
-    EXPECT_CALL(api, DeviceRelease(serverDevice1));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice1, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice1, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice1, nullptr, nullptr)).Times(1);
-    FlushClient();
-
-    // The first device should no longer reflect, but the second should
-    ASSERT_EQ(nullptr,
-              GetWireServer()->GetDevice(reserved1.handle.id, reserved1.handle.generation));
-    ASSERT_EQ(serverDevice2,
-              GetWireServer()->GetDevice(reserved2.handle.id, reserved2.handle.generation));
-
-    // Called on shutdown.
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice2, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice2, nullptr, nullptr)).Times(1);
-}
-
-// This is a regression test where a second device reservation invalidated pointers into the
-// KnownObjects std::vector of devices. The fix was to store pointers to heap allocated
-// objects instead.
-TEST_F(WireInjectDeviceTests, TrackChildObjectsWithTwoReservedDevices) {
-    // Reserve one device, inject it, and get the primary queue.
-    auto reserved1 = GetWireClient()->ReserveDevice(instance);
-
-    WGPUDevice serverDevice1 = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice1));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice1, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice1, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice1, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice1, reserved1.handle));
-
-    WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(reserved1.device, nullptr);
-
-    WGPUCommandEncoder serverCommandEncoder = api.GetNewCommandEncoder();
-    EXPECT_CALL(api, DeviceCreateCommandEncoder(serverDevice1, _))
-        .WillOnce(Return(serverCommandEncoder));
-    FlushClient();
-
-    // Reserve a second device, and inject it.
-    auto reserved2 = GetWireClient()->ReserveDevice(instance);
-
-    WGPUDevice serverDevice2 = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(serverDevice2));
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, _, _));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice2, _, _));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice2, _, _));
-    ASSERT_TRUE(GetWireServer()->InjectDevice(serverDevice2, reserved2.handle));
-
-    // Release the encoder. This should work without error because it stores a stable
-    // pointer to its device's list of child objects. On destruction, it removes itself from the
-    // list.
-    wgpuCommandEncoderRelease(commandEncoder);
-    EXPECT_CALL(api, CommandEncoderRelease(serverCommandEncoder));
-    FlushClient();
-
-    // Called on shutdown.
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice1, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice1, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice1, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(serverDevice2, nullptr, nullptr)).Times(1);
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice2, nullptr, nullptr)).Times(1);
-}
-
-// Test that a device reservation can be reclaimed. This is necessary to
-// avoid leaking ObjectIDs for reservations that are never injected.
-TEST_F(WireInjectDeviceTests, ReclaimDeviceReservation) {
-    // Test that doing a reservation and full release is an error.
-    {
-        auto reserved = GetWireClient()->ReserveDevice(instance);
-        wgpuDeviceRelease(reserved.device);
-        FlushClient(false);
-    }
-
-    // Test that doing a reservation and then reclaiming it recycles the ID.
-    {
-        auto reserved1 = GetWireClient()->ReserveDevice(instance);
-        GetWireClient()->ReclaimDeviceReservation(reserved1);
-
-        auto reserved2 = GetWireClient()->ReserveDevice(instance);
-
-        // The ID is the same, but the generation is still different.
-        ASSERT_EQ(reserved1.handle.id, reserved2.handle.id);
-        ASSERT_NE(reserved1.handle.generation, reserved2.handle.generation);
-
-        // No errors should occur.
-        FlushClient();
-    }
-}
-
-}  // anonymous namespace
-}  // namespace dawn::wire
diff --git a/src/dawn/tests/unittests/wire/WireTest.cpp b/src/dawn/tests/unittests/wire/WireTest.cpp
index 42638c0..9ce777b 100644
--- a/src/dawn/tests/unittests/wire/WireTest.cpp
+++ b/src/dawn/tests/unittests/wire/WireTest.cpp
@@ -28,6 +28,7 @@
 #include "dawn/tests/unittests/wire/WireTest.h"
 
 #include "dawn/dawn_proc.h"
+#include "dawn/tests/MockCallback.h"
 #include "dawn/utils/TerribleCommandBuffer.h"
 #include "dawn/wire/WireClient.h"
 #include "dawn/wire/WireServer.h"
@@ -35,8 +36,13 @@
 using testing::_;
 using testing::AnyNumber;
 using testing::Exactly;
+using testing::Invoke;
 using testing::Mock;
+using testing::MockCallback;
+using testing::NotNull;
 using testing::Return;
+using testing::SaveArg;
+using testing::WithArg;
 
 WireTest::WireTest() {}
 
@@ -53,11 +59,6 @@
 void WireTest::SetUp() {
     DawnProcTable mockProcs;
     api.GetProcTable(&mockProcs);
-
-    // This SetCallback call cannot be ignored because it is done as soon as we start the server
-    EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(_, _, _)).Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetLoggingCallback(_, _, _)).Times(Exactly(1));
-    EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(_, _, _)).Times(Exactly(1));
     SetupIgnoredCallExpectations();
 
     mS2cBuf = std::make_unique<dawn::utils::TerribleCommandBuffer>();
@@ -86,11 +87,79 @@
     EXPECT_CALL(api, InstanceReference(apiInstance));
     EXPECT_TRUE(GetWireServer()->InjectInstance(apiInstance, reservedInstance.handle));
 
-    auto reservedDevice = mWireClient->ReserveDevice(instance);
-    device = reservedDevice.device;
+    // Create the adapter for testing.
+    apiAdapter = api.GetNewAdapter();
+    WGPURequestAdapterOptions adapterOpts = {};
+    MockCallback<WGPURequestAdapterCallback> adapterCb;
+    wgpuInstanceRequestAdapter(instance, &adapterOpts, adapterCb.Callback(),
+                               adapterCb.MakeUserdata(this));
+    EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
+        .WillOnce([&]() {
+            EXPECT_CALL(api, AdapterHasFeature(apiAdapter, _)).WillRepeatedly(Return(false));
+
+            EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
+                .WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
+                    *properties = {};
+                    properties->vendorName = "";
+                    properties->architecture = "";
+                    properties->name = "";
+                    properties->driverDescription = "";
+                })));
+
+            EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
+                .WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
+                    *limits = {};
+                    return true;
+                })));
+
+            EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, nullptr))
+                .WillOnce(Return(0))
+                .WillOnce(Return(0));
+
+            api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
+                                                   apiAdapter, nullptr);
+        });
+    FlushClient();
+    WGPUAdapter cAdapter = nullptr;
+    EXPECT_CALL(adapterCb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
+        .WillOnce(SaveArg<1>(&cAdapter));
+    FlushServer();
+    EXPECT_NE(cAdapter, nullptr);
+    adapter = wgpu::Adapter::Acquire(cAdapter);
+
+    // Create the device for testing.
     apiDevice = api.GetNewDevice();
-    EXPECT_CALL(api, DeviceReference(apiDevice));
-    mWireServer->InjectDevice(apiDevice, reservedDevice.handle);
+    WGPUDeviceDescriptor deviceDesc = {};
+    MockCallback<WGPURequestDeviceCallback> deviceCb;
+    wgpuAdapterRequestDevice(adapter.Get(), &deviceDesc, deviceCb.Callback(),
+                             deviceCb.MakeUserdata(this));
+    EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), NotNull(), NotNull()))
+        .WillOnce([&]() {
+            // Set on device creation to forward callbacks to the client.
+            EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, NotNull(), NotNull()))
+                .Times(1);
+            EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, NotNull(), NotNull())).Times(1);
+            EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, NotNull(), NotNull()))
+                .Times(1);
+
+            EXPECT_CALL(api, DeviceGetLimits(apiDevice, NotNull()))
+                .WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
+                    *limits = {};
+                    return true;
+                })));
+
+            EXPECT_CALL(api, DeviceEnumerateFeatures(apiDevice, nullptr))
+                .WillOnce(Return(0))
+                .WillOnce(Return(0));
+
+            api.CallAdapterRequestDeviceCallback(apiAdapter, WGPURequestDeviceStatus_Success,
+                                                 apiDevice, nullptr);
+        });
+    FlushClient();
+    EXPECT_CALL(deviceCb, Call(WGPURequestDeviceStatus_Success, NotNull(), nullptr, this))
+        .WillOnce(SaveArg<1>(&device));
+    FlushServer();
+    EXPECT_NE(device, nullptr);
 
     // The GetQueue is done on WireClient startup so we expect it now.
     queue = wgpuDeviceGetQueue(device);
@@ -100,6 +169,14 @@
 }
 
 void WireTest::TearDown() {
+    // Drop last refs on objects.
+    if (apiAdapter) {
+        adapter = nullptr;
+    } else {
+        // Don't call release on the C++ wrapper if the C objects are already destroyed.
+        adapter.MoveToCHandle();
+    }
+
     dawnProcSetProcs(nullptr);
 
     // Derived classes should call the base TearDown() first. The client must
@@ -121,12 +198,18 @@
     mWireServer = nullptr;
 }
 
-// This should be called if |apiDevice| is no longer exists on the wire.
-// This signals that expectations in |TearDowb| shouldn't be added.
+// This should be called if |apiDevice| no longer exists on the wire.
+// This signals that expectations in |TearDown| shouldn't be added.
 void WireTest::DefaultApiDeviceWasReleased() {
     apiDevice = nullptr;
 }
 
+// This should be called if |apiAdapter| no longer exists on the wire.
+// This signals that expectations in |TearDown| shouldn't be added.
+void WireTest::DefaultApiAdapterWasReleased() {
+    apiAdapter = nullptr;
+}
+
 void WireTest::FlushClient(bool success) {
     ASSERT_EQ(mC2sBuf->Flush(), success);
 
@@ -149,6 +232,7 @@
 void WireTest::DeleteServer() {
     EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1);
     EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1);
+    EXPECT_CALL(api, AdapterRelease(apiAdapter)).Times(1);
     EXPECT_CALL(api, InstanceRelease(apiInstance)).Times(1);
 
     if (mWireServer) {
diff --git a/src/dawn/tests/unittests/wire/WireTest.h b/src/dawn/tests/unittests/wire/WireTest.h
index a45c651..7b4074b 100644
--- a/src/dawn/tests/unittests/wire/WireTest.h
+++ b/src/dawn/tests/unittests/wire/WireTest.h
@@ -34,6 +34,8 @@
 #include "dawn/mock_webgpu.h"
 #include "gtest/gtest.h"
 
+#include "webgpu/webgpu_cpp.h"
+
 // Definition of a "Lambda predicate matcher" for GMock to allow checking deep structures
 // are passed correctly by the wire.
 
@@ -143,14 +145,17 @@
     void FlushServer(bool success = true);
 
     void DefaultApiDeviceWasReleased();
+    void DefaultApiAdapterWasReleased();
 
     testing::StrictMock<MockProcTable> api;
     WGPUInstance instance;
     WGPUInstance apiInstance;
-    WGPUDevice apiDevice;
-    WGPUQueue apiQueue;
+    wgpu::Adapter adapter;
+    WGPUAdapter apiAdapter;
     WGPUDevice device;
+    WGPUDevice apiDevice;
     WGPUQueue queue;
+    WGPUQueue apiQueue;
 
     dawn::wire::WireServer* GetWireServer();
     dawn::wire::WireClient* GetWireClient();
diff --git a/src/dawn/utils/WireHelper.cpp b/src/dawn/utils/WireHelper.cpp
index 13a0667..de72764 100644
--- a/src/dawn/utils/WireHelper.cpp
+++ b/src/dawn/utils/WireHelper.cpp
@@ -95,7 +95,9 @@
 
 class WireHelperDirect : public WireHelper {
   public:
-    explicit WireHelperDirect(const DawnProcTable& procs) { dawnProcSetProcs(&procs); }
+    explicit WireHelperDirect(const DawnProcTable& procs) : mProcs(procs) {
+        dawnProcSetProcs(&procs);
+    }
 
     wgpu::Instance RegisterInstance(WGPUInstance backendInstance,
                                     const WGPUInstanceDescriptor* wireDesc) override {
@@ -103,16 +105,30 @@
         return wgpu::Instance(backendInstance);
     }
 
+    wgpu::SwapChain CreateSwapChain(WGPUSurface backendSurface,
+                                    WGPUDevice backendDevice,
+                                    WGPUDevice apiDevice,
+                                    const WGPUSwapChainDescriptor* descriptor) override {
+        DAWN_ASSERT(backendDevice == apiDevice);
+        WGPUSwapChain cSwapChain =
+            mProcs.deviceCreateSwapChain(backendDevice, backendSurface, descriptor);
+        return wgpu::SwapChain::Acquire(cSwapChain);
+    }
+
     void BeginWireTrace(const char* name) override {}
 
     bool FlushClient() override { return true; }
 
     bool FlushServer() override { return true; }
+
+  private:
+    const DawnProcTable& mProcs;
 };
 
 class WireHelperProxy : public WireHelper {
   public:
-    explicit WireHelperProxy(const char* wireTraceDir, const DawnProcTable& procs) {
+    explicit WireHelperProxy(const char* wireTraceDir, const DawnProcTable& procs)
+        : mBackendProcs(procs) {
         mC2sBuf = std::make_unique<dawn::utils::TerribleCommandBuffer>();
         mS2cBuf = std::make_unique<dawn::utils::TerribleCommandBuffer>();
 
@@ -146,6 +162,19 @@
         return wgpu::Instance::Acquire(reserved.instance);
     }
 
+    wgpu::SwapChain CreateSwapChain(WGPUSurface backendSurface,
+                                    WGPUDevice backendDevice,
+                                    WGPUDevice apiDevice,
+                                    const WGPUSwapChainDescriptor* descriptor) override {
+        WGPUSwapChain cSwapChain =
+            mBackendProcs.deviceCreateSwapChain(backendDevice, backendSurface, descriptor);
+
+        auto reservation = mWireClient->ReserveSwapChain(apiDevice, descriptor);
+        mWireServer->InjectSwapChain(cSwapChain, reservation.handle, reservation.deviceHandle);
+
+        return wgpu::SwapChain::Acquire(reservation.swapchain);
+    }
+
     void BeginWireTrace(const char* name) override {
         if (mWireServerTraceLayer) {
             return mWireServerTraceLayer->BeginWireTrace(name);
@@ -157,6 +186,7 @@
     bool FlushServer() override { return mS2cBuf->Flush(); }
 
   private:
+    const DawnProcTable& mBackendProcs;
     std::unique_ptr<dawn::utils::TerribleCommandBuffer> mC2sBuf;
     std::unique_ptr<dawn::utils::TerribleCommandBuffer> mS2cBuf;
     std::unique_ptr<WireServerTraceLayer> mWireServerTraceLayer;
diff --git a/src/dawn/utils/WireHelper.h b/src/dawn/utils/WireHelper.h
index f39c63f..7c02388 100644
--- a/src/dawn/utils/WireHelper.h
+++ b/src/dawn/utils/WireHelper.h
@@ -59,6 +59,12 @@
         const wgpu::InstanceDescriptor* nativeDesc = nullptr,
         const wgpu::InstanceDescriptor* wireDesc = nullptr);
 
+    // Creates a swap chain given a native device and surface.
+    virtual wgpu::SwapChain CreateSwapChain(WGPUSurface backendSurface,
+                                            WGPUDevice backendDevice,
+                                            WGPUDevice apiDevice,
+                                            const WGPUSwapChainDescriptor* descriptor) = 0;
+
     virtual void BeginWireTrace(const char* name) = 0;
 
     virtual bool FlushClient() = 0;
diff --git a/src/dawn/wire/WireClient.cpp b/src/dawn/wire/WireClient.cpp
index 313073f..aa15aa2 100644
--- a/src/dawn/wire/WireClient.cpp
+++ b/src/dawn/wire/WireClient.cpp
@@ -51,10 +51,6 @@
     return mImpl->ReserveSwapChain(device, descriptor);
 }
 
-ReservedDevice WireClient::ReserveDevice(WGPUInstance instance) {
-    return mImpl->ReserveDevice(instance);
-}
-
 ReservedInstance WireClient::ReserveInstance(const WGPUInstanceDescriptor* descriptor) {
     return mImpl->ReserveInstance(descriptor);
 }
diff --git a/src/dawn/wire/WireServer.cpp b/src/dawn/wire/WireServer.cpp
index 6f299d8..02067d6 100644
--- a/src/dawn/wire/WireServer.cpp
+++ b/src/dawn/wire/WireServer.cpp
@@ -55,10 +55,6 @@
     return mImpl->InjectSwapChain(swapchain, handle, deviceHandle) == WireResult::Success;
 }
 
-bool WireServer::InjectDevice(WGPUDevice device, const Handle& handle) {
-    return mImpl->InjectDevice(device, handle) == WireResult::Success;
-}
-
 bool WireServer::InjectInstance(WGPUInstance instance, const Handle& handle) {
     return mImpl->InjectInstance(instance, handle) == WireResult::Success;
 }
diff --git a/src/dawn/wire/client/Client.cpp b/src/dawn/wire/client/Client.cpp
index 435246c..2bc76dc 100644
--- a/src/dawn/wire/client/Client.cpp
+++ b/src/dawn/wire/client/Client.cpp
@@ -115,15 +115,6 @@
     return result;
 }
 
-ReservedDevice Client::ReserveDevice(WGPUInstance instance) {
-    Device* device = Make<Device>(FromAPI(instance)->GetEventManagerHandle(), nullptr);
-
-    ReservedDevice result;
-    result.device = ToAPI(device);
-    result.handle = device->GetWireHandle();
-    return result;
-}
-
 ReservedInstance Client::ReserveInstance(const WGPUInstanceDescriptor* descriptor) {
     Instance* instance = Make<Instance>();
 
diff --git a/src/dawn/wire/client/Client.h b/src/dawn/wire/client/Client.h
index 3c15b81..0d57c02 100644
--- a/src/dawn/wire/client/Client.h
+++ b/src/dawn/wire/client/Client.h
@@ -90,7 +90,6 @@
     ReservedTexture ReserveTexture(WGPUDevice device, const WGPUTextureDescriptor* descriptor);
     ReservedSwapChain ReserveSwapChain(WGPUDevice device,
                                        const WGPUSwapChainDescriptor* descriptor);
-    ReservedDevice ReserveDevice(WGPUInstance instance);
     ReservedInstance ReserveInstance(const WGPUInstanceDescriptor* descriptor);
 
     void ReclaimTextureReservation(const ReservedTexture& reservation);
diff --git a/src/dawn/wire/server/Server.cpp b/src/dawn/wire/server/Server.cpp
index 3ca111e..34cddbf 100644
--- a/src/dawn/wire/server/Server.cpp
+++ b/src/dawn/wire/server/Server.cpp
@@ -104,26 +104,6 @@
     return WireResult::Success;
 }
 
-WireResult Server::InjectDevice(WGPUDevice device, const Handle& handle) {
-    DAWN_ASSERT(device != nullptr);
-    Known<WGPUDevice> data;
-    WIRE_TRY(DeviceObjects().Allocate(&data, handle));
-
-    data->handle = device;
-    data->generation = handle.generation;
-    data->state = AllocationState::Allocated;
-    data->info->server = this;
-    data->info->self = data.AsHandle();
-
-    // The device is externally owned so it shouldn't be destroyed when we receive a destroy
-    // message from the client. Add a reference to counterbalance the eventual release.
-    mProcs.deviceReference(device);
-
-    // Set callbacks to forward errors to the client.
-    SetForwardingDeviceCallbacks(data);
-    return WireResult::Success;
-}
-
 WireResult Server::InjectInstance(WGPUInstance instance, const Handle& handle) {
     DAWN_ASSERT(instance != nullptr);
     Known<WGPUInstance> data;
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index 5930e0a..ccd0a72 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -176,7 +176,6 @@
     WireResult InjectSwapChain(WGPUSwapChain swapchain,
                                const Handle& handle,
                                const Handle& deviceHandle);
-    WireResult InjectDevice(WGPUDevice device, const Handle& handle);
     WireResult InjectInstance(WGPUInstance instance, const Handle& handle);
 
     WGPUDevice GetDevice(uint32_t id, uint32_t generation);