mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-24 04:32:08 +00:00
Previously, deleting the device in the wire implicitly released all child objects. This is no longer the case, so a leak of the client default queue caused the service-side queue to leak. Fixed: chromium:1332926 Change-Id: I1efa02e79246f985e99e1bc814d87f292ddc22bd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/92743 Reviewed-by: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Austin Eng <enga@chromium.org>
187 lines
7.3 KiB
C++
187 lines
7.3 KiB
C++
// Copyright 2020 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 "dawn/tests/unittests/wire/WireTest.h"
|
|
|
|
#include "dawn/common/Assert.h"
|
|
#include "dawn/tests/MockCallback.h"
|
|
#include "dawn/wire/WireClient.h"
|
|
|
|
namespace dawn::wire {
|
|
|
|
using testing::_;
|
|
using testing::Exactly;
|
|
using testing::InvokeWithoutArgs;
|
|
using testing::MockCallback;
|
|
using testing::Return;
|
|
using testing::Sequence;
|
|
using testing::StrEq;
|
|
|
|
namespace {
|
|
|
|
class WireDisconnectTests : public WireTest {};
|
|
|
|
} // anonymous namespace
|
|
|
|
// Test that commands are not received if the client disconnects.
|
|
TEST_F(WireDisconnectTests, CommandsAfterDisconnect) {
|
|
// Check that commands work at all.
|
|
wgpuDeviceCreateCommandEncoder(device, nullptr);
|
|
|
|
WGPUCommandEncoder apiCmdBufEncoder = api.GetNewCommandEncoder();
|
|
EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr))
|
|
.WillOnce(Return(apiCmdBufEncoder));
|
|
FlushClient();
|
|
|
|
// Disconnect.
|
|
GetWireClient()->Disconnect();
|
|
|
|
// Command is not received because client disconnected.
|
|
wgpuDeviceCreateCommandEncoder(device, nullptr);
|
|
EXPECT_CALL(api, DeviceCreateCommandEncoder(_, _)).Times(Exactly(0));
|
|
FlushClient();
|
|
}
|
|
|
|
// Test that commands that are serialized before a disconnect but flushed
|
|
// after are received.
|
|
TEST_F(WireDisconnectTests, FlushAfterDisconnect) {
|
|
// Check that commands work at all.
|
|
wgpuDeviceCreateCommandEncoder(device, nullptr);
|
|
|
|
// Disconnect.
|
|
GetWireClient()->Disconnect();
|
|
|
|
// Already-serialized commmands are still received.
|
|
WGPUCommandEncoder apiCmdBufEncoder = api.GetNewCommandEncoder();
|
|
EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr))
|
|
.WillOnce(Return(apiCmdBufEncoder));
|
|
FlushClient();
|
|
}
|
|
|
|
// Check that disconnecting the wire client calls the device lost callback exacty once.
|
|
TEST_F(WireDisconnectTests, CallsDeviceLostCallback) {
|
|
MockCallback<WGPUDeviceLostCallback> mockDeviceLostCallback;
|
|
wgpuDeviceSetDeviceLostCallback(device, mockDeviceLostCallback.Callback(),
|
|
mockDeviceLostCallback.MakeUserdata(this));
|
|
|
|
// Disconnect the wire client. We should receive device lost only once.
|
|
EXPECT_CALL(mockDeviceLostCallback, Call(WGPUDeviceLostReason_Undefined, _, this))
|
|
.Times(Exactly(1));
|
|
GetWireClient()->Disconnect();
|
|
GetWireClient()->Disconnect();
|
|
}
|
|
|
|
// Check that disconnecting the wire client after a device loss does not trigger the callback
|
|
// again.
|
|
TEST_F(WireDisconnectTests, ServerLostThenDisconnect) {
|
|
MockCallback<WGPUDeviceLostCallback> mockDeviceLostCallback;
|
|
wgpuDeviceSetDeviceLostCallback(device, mockDeviceLostCallback.Callback(),
|
|
mockDeviceLostCallback.MakeUserdata(this));
|
|
|
|
api.CallDeviceSetDeviceLostCallbackCallback(apiDevice, WGPUDeviceLostReason_Undefined,
|
|
"some reason");
|
|
|
|
// Flush the device lost return command.
|
|
EXPECT_CALL(mockDeviceLostCallback,
|
|
Call(WGPUDeviceLostReason_Undefined, StrEq("some reason"), this))
|
|
.Times(Exactly(1));
|
|
FlushServer();
|
|
|
|
// Disconnect the client. We shouldn't see the lost callback again.
|
|
EXPECT_CALL(mockDeviceLostCallback, Call(_, _, _)).Times(Exactly(0));
|
|
GetWireClient()->Disconnect();
|
|
}
|
|
|
|
// Check that disconnecting the wire client inside the device loss callback does not trigger the
|
|
// callback again.
|
|
TEST_F(WireDisconnectTests, ServerLostThenDisconnectInCallback) {
|
|
MockCallback<WGPUDeviceLostCallback> mockDeviceLostCallback;
|
|
wgpuDeviceSetDeviceLostCallback(device, mockDeviceLostCallback.Callback(),
|
|
mockDeviceLostCallback.MakeUserdata(this));
|
|
|
|
api.CallDeviceSetDeviceLostCallbackCallback(apiDevice, WGPUDeviceLostReason_Undefined,
|
|
"lost reason");
|
|
|
|
// Disconnect the client inside the lost callback. We should see the callback
|
|
// only once.
|
|
EXPECT_CALL(mockDeviceLostCallback,
|
|
Call(WGPUDeviceLostReason_Undefined, StrEq("lost reason"), this))
|
|
.WillOnce(InvokeWithoutArgs([&]() {
|
|
EXPECT_CALL(mockDeviceLostCallback, Call(_, _, _)).Times(Exactly(0));
|
|
GetWireClient()->Disconnect();
|
|
}));
|
|
FlushServer();
|
|
}
|
|
|
|
// Check that a device loss after a disconnect does not trigger the callback again.
|
|
TEST_F(WireDisconnectTests, DisconnectThenServerLost) {
|
|
MockCallback<WGPUDeviceLostCallback> mockDeviceLostCallback;
|
|
wgpuDeviceSetDeviceLostCallback(device, mockDeviceLostCallback.Callback(),
|
|
mockDeviceLostCallback.MakeUserdata(this));
|
|
|
|
// Disconnect the client. We should see the callback once.
|
|
EXPECT_CALL(mockDeviceLostCallback, Call(WGPUDeviceLostReason_Undefined, _, this))
|
|
.Times(Exactly(1));
|
|
GetWireClient()->Disconnect();
|
|
|
|
// Lose the device on the server. The client callback shouldn't be
|
|
// called again.
|
|
api.CallDeviceSetDeviceLostCallbackCallback(apiDevice, WGPUDeviceLostReason_Undefined,
|
|
"lost reason");
|
|
EXPECT_CALL(mockDeviceLostCallback, Call(_, _, _)).Times(Exactly(0));
|
|
FlushServer();
|
|
}
|
|
|
|
// Test that client objects are all destroyed if the WireClient is destroyed.
|
|
TEST_F(WireDisconnectTests, DeleteClientDestroysObjects) {
|
|
WGPUSamplerDescriptor desc = {};
|
|
wgpuDeviceCreateCommandEncoder(device, nullptr);
|
|
wgpuDeviceCreateSampler(device, &desc);
|
|
|
|
WGPUCommandEncoder apiCommandEncoder = api.GetNewCommandEncoder();
|
|
EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr))
|
|
.WillOnce(Return(apiCommandEncoder));
|
|
|
|
WGPUSampler apiSampler = api.GetNewSampler();
|
|
EXPECT_CALL(api, DeviceCreateSampler(apiDevice, _)).WillOnce(Return(apiSampler));
|
|
|
|
FlushClient();
|
|
|
|
DeleteClient();
|
|
|
|
// 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;
|
|
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
|
|
.Times(1)
|
|
.InSequence(s1, s2);
|
|
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr))
|
|
.Times(1)
|
|
.InSequence(s1, s2);
|
|
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr))
|
|
.Times(1)
|
|
.InSequence(s1, s2);
|
|
EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(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);
|
|
FlushClient();
|
|
|
|
// Signal that we already released and cleared callbacks for |apiDevice|
|
|
DefaultApiDeviceWasReleased();
|
|
}
|
|
|
|
} // namespace dawn::wire
|