Ensure all wire child objects are destroyed before their device
Destroying a device will implicit destroy all its child objects.
Attempting to use a child object after results in a fatal error.
Bug: dawn:384
Change-Id: I43c27c92cacde759be83cca79ac890f41bac3927
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/37002
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/tests/unittests/wire/WireDestroyObjectTests.cpp b/src/tests/unittests/wire/WireDestroyObjectTests.cpp
new file mode 100644
index 0000000..f5e16b7
--- /dev/null
+++ b/src/tests/unittests/wire/WireDestroyObjectTests.cpp
@@ -0,0 +1,45 @@
+// 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"
+
+using namespace testing;
+using namespace dawn_wire;
+
+class WireDestroyObjectTests : public WireTest {};
+
+// Test that destroying the device also destroys child objects.
+TEST_F(WireDestroyObjectTests, DestroyDeviceDestroysChildren) {
+ WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
+
+ WGPUCommandEncoder apiEncoder = api.GetNewCommandEncoder();
+ EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr)).WillOnce(Return(apiEncoder));
+
+ FlushClient();
+
+ // Release the device. It should cause the command encoder to be destroyed.
+ wgpuDeviceRelease(device);
+
+ Sequence s1, s2;
+ // The device and child objects should be released.
+ EXPECT_CALL(api, CommandEncoderRelease(apiEncoder)).InSequence(s1);
+ EXPECT_CALL(api, QueueRelease(apiQueue)).InSequence(s2);
+ EXPECT_CALL(api, DeviceRelease(apiDevice)).InSequence(s1, s2);
+
+ FlushClient();
+
+ // Using the command encoder should be an error.
+ wgpuCommandEncoderFinish(encoder, nullptr);
+ FlushClient(false);
+}
diff --git a/src/tests/unittests/wire/WireDisconnectTests.cpp b/src/tests/unittests/wire/WireDisconnectTests.cpp
index 4c99ced..f44df13 100644
--- a/src/tests/unittests/wire/WireDisconnectTests.cpp
+++ b/src/tests/unittests/wire/WireDisconnectTests.cpp
@@ -145,9 +145,10 @@
DeleteClient();
// Expect release on all objects created by the client.
- EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1);
- EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1);
- EXPECT_CALL(api, CommandEncoderRelease(apiCommandEncoder)).Times(1);
- EXPECT_CALL(api, SamplerRelease(apiSampler)).Times(1);
+ Sequence s1, s2, s3;
+ 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, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3);
FlushClient();
}
diff --git a/src/tests/unittests/wire/WireInjectTextureTests.cpp b/src/tests/unittests/wire/WireInjectTextureTests.cpp
index 9e327cf..c6a1f2c 100644
--- a/src/tests/unittests/wire/WireInjectTextureTests.cpp
+++ b/src/tests/unittests/wire/WireInjectTextureTests.cpp
@@ -34,7 +34,8 @@
WGPUTexture apiTexture = api.GetNewTexture();
EXPECT_CALL(api, TextureReference(apiTexture));
- ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation));
+ ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation,
+ reservation.deviceId, reservation.deviceGeneration));
wgpuTextureCreateView(reservation.texture, nullptr);
WGPUTextureView apiDummyView = api.GetNewTextureView();
@@ -57,11 +58,13 @@
WGPUTexture apiTexture = api.GetNewTexture();
EXPECT_CALL(api, TextureReference(apiTexture));
- ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation));
+ ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation,
+ reservation.deviceId, reservation.deviceGeneration));
// ID already in use, call fails.
- ASSERT_FALSE(
- GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation));
+ ASSERT_FALSE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation,
+ reservation.deviceId,
+ reservation.deviceGeneration));
}
// Test that the server only borrows the texture and does a single reference-release
@@ -71,7 +74,8 @@
// Injecting the texture adds a reference
WGPUTexture apiTexture = api.GetNewTexture();
EXPECT_CALL(api, TextureReference(apiTexture));
- ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation));
+ ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id, reservation.generation,
+ reservation.deviceId, reservation.deviceGeneration));
// Releasing the texture removes a single reference.
wgpuTextureRelease(reservation.texture);