dawn_wire: Add an API to reclaim reserved devices and textures

Dawn Wire has a way to reserve an ID and generation on the client side,
but if these reservations are never injected on the server, then
it will be impossible to reclaim the in-use ObjectIDs.

Bug: dawn:565
Change-Id: I751fce237c881e8cbdeaba18ad0ec1e124bd7ac2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38281
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Austin Eng 2021-01-22 00:25:05 +00:00 committed by Commit Bot service account
parent cef68bc8b7
commit 45ce1fda88
6 changed files with 74 additions and 0 deletions

View File

@ -41,6 +41,14 @@ namespace dawn_wire {
return mImpl->ReserveDevice(); return mImpl->ReserveDevice();
} }
void WireClient::ReclaimTextureReservation(const ReservedTexture& reservation) {
mImpl->ReclaimTextureReservation(reservation);
}
void WireClient::ReclaimDeviceReservation(const ReservedDevice& reservation) {
mImpl->ReclaimDeviceReservation(reservation);
}
void WireClient::Disconnect() { void WireClient::Disconnect() {
mImpl->Disconnect(); mImpl->Disconnect();
} }

View File

@ -118,6 +118,14 @@ namespace dawn_wire { namespace client {
return result; return result;
} }
void Client::ReclaimTextureReservation(const ReservedTexture& reservation) {
TextureAllocator().Free(FromAPI(reservation.texture));
}
void Client::ReclaimDeviceReservation(const ReservedDevice& reservation) {
DeviceAllocator().Free(FromAPI(reservation.device));
}
void Client::Disconnect() { void Client::Disconnect() {
mDisconnected = true; mDisconnected = true;
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance()); mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());

View File

@ -48,6 +48,9 @@ namespace dawn_wire { namespace client {
ReservedTexture ReserveTexture(WGPUDevice device); ReservedTexture ReserveTexture(WGPUDevice device);
ReservedDevice ReserveDevice(); ReservedDevice ReserveDevice();
void ReclaimTextureReservation(const ReservedTexture& reservation);
void ReclaimDeviceReservation(const ReservedDevice& reservation);
template <typename Cmd> template <typename Cmd>
void SerializeCommand(const Cmd& cmd) { void SerializeCommand(const Cmd& cmd) {
mSerializer.SerializeCommand(cmd, *this); mSerializer.SerializeCommand(cmd, *this);

View File

@ -61,6 +61,9 @@ namespace dawn_wire {
ReservedTexture ReserveTexture(WGPUDevice device); ReservedTexture ReserveTexture(WGPUDevice device);
ReservedDevice ReserveDevice(); ReservedDevice ReserveDevice();
void ReclaimTextureReservation(const ReservedTexture& reservation);
void ReclaimDeviceReservation(const ReservedDevice& reservation);
// Disconnects the client. // Disconnects the client.
// Commands allocated after this point will not be sent. // Commands allocated after this point will not be sent.
void Disconnect(); void Disconnect();

View File

@ -228,3 +228,29 @@ TEST_F(WireInjectDeviceTests, TrackChildObjectsWithTwoReservedDevices) {
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, nullptr, nullptr)).Times(1); EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(serverDevice2, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(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.
{
ReservedDevice reservation = GetWireClient()->ReserveDevice();
wgpuDeviceRelease(reservation.device);
FlushClient(false);
}
// Test that doing a reservation and then reclaiming it recycles the ID.
{
ReservedDevice reservation1 = GetWireClient()->ReserveDevice();
GetWireClient()->ReclaimDeviceReservation(reservation1);
ReservedDevice reservation2 = GetWireClient()->ReserveDevice();
// The ID is the same, but the generation is still different.
ASSERT_EQ(reservation1.id, reservation2.id);
ASSERT_NE(reservation1.generation, reservation2.generation);
// No errors should occur.
FlushClient();
}
}

View File

@ -86,3 +86,29 @@ TEST_F(WireInjectTextureTests, InjectedTextureLifetime) {
DeleteServer(); DeleteServer();
Mock::VerifyAndClearExpectations(&api); Mock::VerifyAndClearExpectations(&api);
} }
// Test that a texture reservation can be reclaimed. This is necessary to
// avoid leaking ObjectIDs for reservations that are never injected.
TEST_F(WireInjectTextureTests, ReclaimTextureReservation) {
// Test that doing a reservation and full release is an error.
{
ReservedTexture reservation = GetWireClient()->ReserveTexture(device);
wgpuTextureRelease(reservation.texture);
FlushClient(false);
}
// Test that doing a reservation and then reclaiming it recycles the ID.
{
ReservedTexture reservation1 = GetWireClient()->ReserveTexture(device);
GetWireClient()->ReclaimTextureReservation(reservation1);
ReservedTexture reservation2 = GetWireClient()->ReserveTexture(device);
// The ID is the same, but the generation is still different.
ASSERT_EQ(reservation1.id, reservation2.id);
ASSERT_NE(reservation1.generation, reservation2.generation);
// No errors should occur.
FlushClient();
}
}