| // 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 "tests/unittests/wire/WireTest.h" |
| |
| #include "dawn_wire/WireClient.h" |
| #include "dawn_wire/WireServer.h" |
| |
| using namespace testing; |
| using namespace dawn_wire; |
| |
| 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) { |
| ReservedDevice reservation = GetWireClient()->ReserveDevice(); |
| |
| WGPUDevice serverDevice = api.GetNewDevice(); |
| EXPECT_CALL(api, DeviceReference(serverDevice)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _)); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _)); |
| ASSERT_TRUE( |
| GetWireServer()->InjectDevice(serverDevice, reservation.id, reservation.generation)); |
| |
| WGPUBufferDescriptor bufferDesc = {}; |
| wgpuDeviceCreateBuffer(reservation.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, OnDeviceSetDeviceLostCallback(serverDevice, nullptr, nullptr)) |
| .Times(Exactly(1)); |
| } |
| |
| // Test that reserve correctly returns different IDs each time. |
| TEST_F(WireInjectDeviceTests, ReserveDifferentIDs) { |
| ReservedDevice reservation1 = GetWireClient()->ReserveDevice(); |
| ReservedDevice reservation2 = GetWireClient()->ReserveDevice(); |
| |
| ASSERT_NE(reservation1.id, reservation2.id); |
| ASSERT_NE(reservation1.device, reservation2.device); |
| } |
| |
| // Test that injecting the same id without a destroy first fails. |
| TEST_F(WireInjectDeviceTests, InjectExistingID) { |
| ReservedDevice reservation = GetWireClient()->ReserveDevice(); |
| |
| WGPUDevice serverDevice = api.GetNewDevice(); |
| EXPECT_CALL(api, DeviceReference(serverDevice)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _)); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _)); |
| ASSERT_TRUE( |
| GetWireServer()->InjectDevice(serverDevice, reservation.id, reservation.generation)); |
| |
| // ID already in use, call fails. |
| ASSERT_FALSE( |
| GetWireServer()->InjectDevice(serverDevice, reservation.id, reservation.generation)); |
| |
| // Called on shutdown. |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(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) { |
| ReservedDevice reservation = GetWireClient()->ReserveDevice(); |
| |
| // Injecting the device adds a reference |
| WGPUDevice serverDevice = api.GetNewDevice(); |
| EXPECT_CALL(api, DeviceReference(serverDevice)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _)); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _)); |
| ASSERT_TRUE( |
| GetWireServer()->InjectDevice(serverDevice, reservation.id, reservation.generation)); |
| |
| // Releasing the device removes a single reference and clears its error callbacks. |
| wgpuDeviceRelease(reservation.device); |
| EXPECT_CALL(api, DeviceRelease(serverDevice)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(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 default queue of a device before it has been |
| // injected on the server. |
| TEST_F(WireInjectDeviceTests, GetQueueBeforeInject) { |
| ReservedDevice reservation = GetWireClient()->ReserveDevice(); |
| |
| wgpuDeviceGetDefaultQueue(reservation.device); |
| FlushClient(false); |
| } |
| |
| // Test that it is valid to get the default queue of a device after it has been |
| // injected on the server. |
| TEST_F(WireInjectDeviceTests, GetQueueAfterInject) { |
| ReservedDevice reservation = GetWireClient()->ReserveDevice(); |
| |
| WGPUDevice serverDevice = api.GetNewDevice(); |
| EXPECT_CALL(api, DeviceReference(serverDevice)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice, _, _)); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice, _, _)); |
| ASSERT_TRUE( |
| GetWireServer()->InjectDevice(serverDevice, reservation.id, reservation.generation)); |
| |
| wgpuDeviceGetDefaultQueue(reservation.device); |
| |
| WGPUQueue apiQueue = api.GetNewQueue(); |
| EXPECT_CALL(api, DeviceGetDefaultQueue(serverDevice)).WillOnce(Return(apiQueue)); |
| FlushClient(); |
| |
| // Called on shutdown. |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(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. |
| ReservedDevice reservation1 = GetWireClient()->ReserveDevice(); |
| ReservedDevice reservation2 = GetWireClient()->ReserveDevice(); |
| |
| // Inject both devices. |
| |
| WGPUDevice serverDevice1 = api.GetNewDevice(); |
| EXPECT_CALL(api, DeviceReference(serverDevice1)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice1, _, _)); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice1, _, _)); |
| ASSERT_TRUE( |
| GetWireServer()->InjectDevice(serverDevice1, reservation1.id, reservation1.generation)); |
| |
| WGPUDevice serverDevice2 = api.GetNewDevice(); |
| EXPECT_CALL(api, DeviceReference(serverDevice2)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, _, _)); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice2, _, _)); |
| ASSERT_TRUE( |
| GetWireServer()->InjectDevice(serverDevice2, reservation2.id, reservation2.generation)); |
| |
| // Test that both devices can be reflected. |
| ASSERT_EQ(serverDevice1, GetWireServer()->GetDevice(reservation1.id, reservation1.generation)); |
| ASSERT_EQ(serverDevice2, GetWireServer()->GetDevice(reservation2.id, reservation2.generation)); |
| |
| // Release the first device |
| wgpuDeviceRelease(reservation1.device); |
| EXPECT_CALL(api, DeviceRelease(serverDevice1)); |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(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(reservation1.id, reservation1.generation)); |
| ASSERT_EQ(serverDevice2, GetWireServer()->GetDevice(reservation2.id, reservation2.generation)); |
| |
| // Called on shutdown. |
| EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, nullptr, nullptr)).Times(1); |
| EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(serverDevice2, nullptr, nullptr)).Times(1); |
| } |