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>
This commit is contained in:
Austin Eng
2021-01-13 20:58:18 +00:00
committed by Commit Bot service account
parent 0562802757
commit 8ba0a01d1e
19 changed files with 240 additions and 28 deletions

View File

@@ -218,6 +218,7 @@ test("dawn_unittests") {
"unittests/wire/WireBasicTests.cpp",
"unittests/wire/WireBufferMappingTests.cpp",
"unittests/wire/WireCreateReadyPipelineTests.cpp",
"unittests/wire/WireDestroyObjectTests.cpp",
"unittests/wire/WireDisconnectTests.cpp",
"unittests/wire/WireErrorCallbackTests.cpp",
"unittests/wire/WireExtensionTests.cpp",

View File

@@ -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);
}

View File

@@ -145,9 +145,10 @@ TEST_F(WireDisconnectTests, DeleteClientDestroysObjects) {
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();
}

View File

@@ -34,7 +34,8 @@ TEST_F(WireInjectTextureTests, CallAfterReserveInject) {
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 @@ TEST_F(WireInjectTextureTests, InjectExistingID) {
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 @@ TEST_F(WireInjectTextureTests, InjectedTextureLifetime) {
// 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);