Remove Fences

Fences are no longer part of the WebGPU spec, and have been removed from
Blink.

Bug: dawn:22
Change-Id: I240c4c4107acfaf9facec88a43a38b5ff327c7a6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/50702
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Brandon Jones
2021-05-21 00:01:08 +00:00
committed by Dawn LUCI CQ
parent 36cb5a86de
commit a548578f67
28 changed files with 16 additions and 1707 deletions

View File

@@ -197,7 +197,6 @@ test("dawn_unittests") {
"unittests/validation/DynamicStateCommandValidationTests.cpp",
"unittests/validation/ErrorScopeValidationTests.cpp",
"unittests/validation/ExternalTextureTests.cpp",
"unittests/validation/FenceValidationTests.cpp",
"unittests/validation/GetBindGroupLayoutValidationTests.cpp",
"unittests/validation/IndexBufferValidationTests.cpp",
"unittests/validation/MinimumBufferSizeValidationTests.cpp",
@@ -232,7 +231,6 @@ test("dawn_unittests") {
"unittests/wire/WireDisconnectTests.cpp",
"unittests/wire/WireErrorCallbackTests.cpp",
"unittests/wire/WireExtensionTests.cpp",
"unittests/wire/WireFenceTests.cpp",
"unittests/wire/WireInjectDeviceTests.cpp",
"unittests/wire/WireInjectSwapChainTests.cpp",
"unittests/wire/WireInjectTextureTests.cpp",
@@ -318,7 +316,6 @@ source_set("dawn_end2end_tests_sources") {
"end2end/DynamicBufferOffsetTests.cpp",
"end2end/EntryPointTests.cpp",
"end2end/ExternalTextureTests.cpp",
"end2end/FenceTests.cpp",
"end2end/FirstIndexOffsetTests.cpp",
"end2end/GpuMemorySynchronizationTests.cpp",
"end2end/IndexFormatTests.cpp",

View File

@@ -188,11 +188,6 @@ TEST_P(DeprecationTests, BindGroupLayoutEntryViewDimensionDefaulting) {
}
}
// Test that fences are deprecated.
TEST_P(DeprecationTests, CreateFence) {
EXPECT_DEPRECATION_WARNING(queue.CreateFence());
}
DAWN_INSTANTIATE_TEST(DeprecationTests,
D3D12Backend(),
MetalBackend(),

View File

@@ -35,23 +35,6 @@ static void ToMockDeviceLostCallback(const char* message, void* userdata) {
self->StartExpectDeviceError();
}
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletionFails(WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(WGPUFenceCompletionStatus_DeviceLost, status);
mockFenceOnCompletionCallback->Call(status, userdata);
mockFenceOnCompletionCallback = nullptr;
}
static void ToMockFenceOnCompletionSucceeds(WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(WGPUFenceCompletionStatus_Success, status);
mockFenceOnCompletionCallback->Call(status, userdata);
mockFenceOnCompletionCallback = nullptr;
}
class MockQueueWorkDoneCallback {
public:
MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
@@ -70,13 +53,11 @@ class DeviceLostTest : public DawnTest {
DawnTest::SetUp();
DAWN_SKIP_TEST_IF(UsesWire());
mockDeviceLostCallback = std::make_unique<MockDeviceLostCallback>();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
}
void TearDown() override {
mockDeviceLostCallback = nullptr;
mockFenceOnCompletionCallback = nullptr;
mockQueueWorkDoneCallback = nullptr;
DawnTest::TearDown();
}
@@ -416,67 +397,6 @@ TEST_P(DeviceLostTest, CommandEncoderFinishFails) {
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test that CreateFenceFails when device is lost
TEST_P(DeviceLostTest, CreateFenceFails) {
SetCallbackAndLoseForTesting();
EXPECT_DEPRECATION_WARNING(ASSERT_DEVICE_ERROR(queue.CreateFence()));
}
// Test that queue signal fails when device is lost
TEST_P(DeviceLostTest, QueueSignalFenceFails) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
SetCallbackAndLoseForTesting();
ASSERT_DEVICE_ERROR(queue.Signal(fence, 3));
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, nullptr))
.Times(1);
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr));
// completed value should not have changed from initial value
EXPECT_EQ(fence.GetCompletedValue(), 0u);
}
// Test that Fence On Completion fails after device is lost
TEST_P(DeviceLostTest, FenceOnCompletionFails) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
SetCallbackAndLoseForTesting();
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, nullptr))
.Times(1);
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr));
ASSERT_DEVICE_ERROR(device.Tick());
// completed value is the last value signaled (all previous GPU operations are as if completed)
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test that Fence::OnCompletion callbacks with device lost status when device is lost after calling
// OnCompletion
TEST_P(DeviceLostTest, FenceOnCompletionBeforeLossFails) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, nullptr))
.Times(1);
fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr);
SetCallbackAndLoseForTesting();
ASSERT_DEVICE_ERROR(device.Tick());
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test that QueueOnSubmittedWorkDone fails after device is lost.
TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneFails) {
SetCallbackAndLoseForTesting();
@@ -499,36 +419,6 @@ TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneBeforeLossFails) {
ASSERT_DEVICE_ERROR(device.Tick());
}
// Regression test for the Null backend not properly setting the completedSerial when
// WaitForIdleForDestruction is called, causing the fence signaling to not be retired and an
// ASSERT to fire.
TEST_P(DeviceLostTest, AfterSubmitAndSerial) {
queue.Submit(0, nullptr);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
SetCallbackAndLoseForTesting();
}
// Test that when you Signal, then Tick, then device lost, the fence completed value would be 2
TEST_P(DeviceLostTest, FenceSignalTickOnCompletion) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
WaitForAllOperations();
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
fence.OnCompletion(2u, ToMockFenceOnCompletionSucceeds, nullptr);
SetCallbackAndLoseForTesting();
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test that LostForTesting can only be called on one time
TEST_P(DeviceLostTest, LoseForTestingOnce) {
// First LoseForTesting call should occur normally

View File

@@ -1,277 +0,0 @@
// Copyright 2018 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 <gmock/gmock.h>
#include "tests/DawnTest.h"
#include <array>
#include <cstring>
using namespace testing;
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
mockFenceOnCompletionCallback->Call(status, userdata);
}
class MockPopErrorScopeCallback {
public:
MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
};
static std::unique_ptr<MockPopErrorScopeCallback> mockPopErrorScopeCallback;
static void ToMockPopErrorScopeCallback(WGPUErrorType type, const char* message, void* userdata) {
mockPopErrorScopeCallback->Call(type, message, userdata);
}
class FenceTests : public DawnTest {
private:
struct CallbackInfo {
FenceTests* test;
uint64_t value;
WGPUFenceCompletionStatus status;
int32_t callIndex = -1; // If this is -1, the callback was not called
void Update(WGPUFenceCompletionStatus status) {
this->callIndex = test->mCallIndex++;
this->status = status;
}
};
int32_t mCallIndex;
protected:
FenceTests() : mCallIndex(0) {
}
void SetUp() override {
DawnTest::SetUp();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
mockPopErrorScopeCallback = std::make_unique<MockPopErrorScopeCallback>();
}
void TearDown() override {
mockFenceOnCompletionCallback = nullptr;
mockPopErrorScopeCallback = nullptr;
DawnTest::TearDown();
}
void WaitForCompletedValue(wgpu::Fence fence, uint64_t completedValue) {
while (fence.GetCompletedValue() < completedValue) {
WaitABit();
}
}
};
// Test that signaling a fence updates the completed value
TEST_P(FenceTests, SimpleSignal) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1u;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// Completed value starts at initial value
EXPECT_EQ(fence.GetCompletedValue(), 1u);
queue.Signal(fence, 2);
WaitForCompletedValue(fence, 2);
// Completed value updates to signaled value
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test callbacks are called in increasing order of fence completion value
TEST_P(FenceTests, OnCompletionOrdering) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 4);
{
testing::InSequence s;
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 1))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 3))
.Times(1);
}
fence.OnCompletion(2u, ToMockFenceOnCompletion, this + 2);
fence.OnCompletion(0u, ToMockFenceOnCompletion, this + 0);
fence.OnCompletion(3u, ToMockFenceOnCompletion, this + 3);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 1);
WaitForCompletedValue(fence, 4);
}
// Test callbacks still occur if Queue::Signal happens multiple times
TEST_P(FenceTests, MultipleSignalOnCompletion) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
queue.Signal(fence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
fence.OnCompletion(3u, ToMockFenceOnCompletion, nullptr);
WaitForCompletedValue(fence, 4);
}
// Test callbacks still occur if Queue::Signal and fence::OnCompletion happens multiple times
TEST_P(FenceTests, SignalOnCompletionWait) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
queue.Signal(fence, 6);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 6))
.Times(1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 2);
fence.OnCompletion(5u, ToMockFenceOnCompletion, this + 6);
WaitForCompletedValue(fence, 6);
}
// Test callbacks still occur if Queue::Signal and fence::OnCompletion happens multiple times
TEST_P(FenceTests, SignalOnCompletionWaitStaggered) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 2);
queue.Signal(fence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 4))
.Times(1);
fence.OnCompletion(3u, ToMockFenceOnCompletion, this + 4);
WaitForCompletedValue(fence, 4);
}
// Test all callbacks are called if they are added for the same fence value
TEST_P(FenceTests, OnCompletionMultipleCallbacks) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 1))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 3))
.Times(1);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 0);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 1);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 2);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 3);
WaitForCompletedValue(fence, 4u);
}
// TODO(enga): Enable when fence is removed from fence signal tracker
// Currently it holds a reference and is not destructed
TEST_P(FenceTests, DISABLED_DestroyBeforeOnCompletionEnd) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
// The fence in this block will be deleted when it goes out of scope
{
wgpu::Fence testFence;
EXPECT_DEPRECATION_WARNING(testFence = queue.CreateFence());
queue.Signal(testFence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 1))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 3))
.Times(1);
testFence.OnCompletion(1u, ToMockFenceOnCompletion, this + 0);
testFence.OnCompletion(2u, ToMockFenceOnCompletion, this + 1);
testFence.OnCompletion(2u, ToMockFenceOnCompletion, this + 2);
testFence.OnCompletion(3u, ToMockFenceOnCompletion, this + 3);
}
// Wait for another fence to be sure all callbacks have cleared
queue.Signal(fence, 1);
WaitForCompletedValue(fence, 1);
}
// Regression test that validation errors that are tracked client-side are captured
// in error scopes.
TEST_P(FenceTests, ClientValidationErrorInErrorScope) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 4);
device.PushErrorScope(wgpu::ErrorFilter::Validation);
queue.Signal(fence, 2);
EXPECT_CALL(*mockPopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1);
device.PopErrorScope(ToMockPopErrorScopeCallback, this);
WaitForCompletedValue(fence, 4);
}
DAWN_INSTANTIATE_TEST(FenceTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
VulkanBackend());

View File

@@ -28,17 +28,6 @@ static void ToMockMapCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
mockMapCallback->Call(status, userdata);
}
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(status, WGPUFenceCompletionStatus_Success);
mockFenceOnCompletionCallback->Call(status, userdata);
}
class MockQueueWorkDoneCallback {
public:
MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
@@ -55,7 +44,6 @@ class QueueTimelineTests : public DawnTest {
DawnTest::SetUp();
mockMapCallback = std::make_unique<MockMapCallback>();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
wgpu::BufferDescriptor descriptor;
@@ -66,7 +54,6 @@ class QueueTimelineTests : public DawnTest {
void TearDown() override {
mockMapCallback = nullptr;
mockFenceOnCompletionCallback = nullptr;
mockQueueWorkDoneCallback = nullptr;
DawnTest::TearDown();
}
@@ -74,27 +61,6 @@ class QueueTimelineTests : public DawnTest {
wgpu::Buffer mMapReadBuffer;
};
// Test that mMapReadBuffer.MapAsync callback happens before fence.OnCompletion callback
// when queue.Signal is called after mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
TEST_P(QueueTimelineTests, MapReadSignalOnComplete) {
testing::InSequence sequence;
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.Times(1);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
// Test that mMapReadBuffer.MapAsync callback happens before queue.OnWorkDone callback
// when queue.OnSubmittedWorkDone is called after mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
@@ -111,26 +77,6 @@ TEST_P(QueueTimelineTests, MapRead_OnWorkDone) {
mMapReadBuffer.Unmap();
}
// Test that fence.OnCompletion callback happens before mMapReadBuffer.MapAsync callback when
// queue.OnSubmittedWorkDone is called before mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
TEST_P(QueueTimelineTests, SignalMapReadOnComplete) {
testing::InSequence sequence;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.Times(1);
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
fence.OnCompletion(2u, ToMockFenceOnCompletion, this);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
// Test that queue.OnWorkDone callback happens before mMapReadBuffer.MapAsync callback when
// queue.Signal is called before mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
@@ -147,65 +93,6 @@ TEST_P(QueueTimelineTests, OnWorkDone_MapRead) {
mMapReadBuffer.Unmap();
}
// Test that fence.OnCompletion callback happens before mMapReadBuffer.MapAsync callback when
// queue.Signal is called before mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called
TEST_P(QueueTimelineTests, SignalOnCompleteMapRead) {
testing::InSequence sequence;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.Times(1);
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
fence.OnCompletion(2u, ToMockFenceOnCompletion, this);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
// Test a complicated case with many signals surrounding a buffer mapping.
TEST_P(QueueTimelineTests, SurroundWithFenceSignals) {
testing::InSequence sequence;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 3))
.Times(1);
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 5))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 6))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 8))
.Times(1);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
queue.Signal(fence, 4);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 0);
fence.OnCompletion(2u, ToMockFenceOnCompletion, this + 2);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
queue.Signal(fence, 6);
fence.OnCompletion(3u, ToMockFenceOnCompletion, this + 3);
fence.OnCompletion(5u, ToMockFenceOnCompletion, this + 5);
fence.OnCompletion(6u, ToMockFenceOnCompletion, this + 6);
queue.Signal(fence, 8);
fence.OnCompletion(8u, ToMockFenceOnCompletion, this + 8);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
DAWN_INSTANTIATE_TEST(QueueTimelineTests,
D3D12Backend(),
MetalBackend(),

View File

@@ -31,11 +31,22 @@ static void ToMockDevicePopErrorScopeCallback(WGPUErrorType type,
mockDevicePopErrorScopeCallback->Call(type, message, userdata);
}
class MockQueueWorkDoneCallback {
public:
MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
};
static std::unique_ptr<MockQueueWorkDoneCallback> mockQueueWorkDoneCallback;
static void ToMockQueueWorkDone(WGPUQueueWorkDoneStatus status, void* userdata) {
mockQueueWorkDoneCallback->Call(status, userdata);
}
class ErrorScopeValidationTest : public ValidationTest {
private:
void SetUp() override {
ValidationTest::SetUp();
mockDevicePopErrorScopeCallback = std::make_unique<MockDevicePopErrorScopeCallback>();
mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
}
void TearDown() override {
@@ -43,6 +54,7 @@ class ErrorScopeValidationTest : public ValidationTest {
// Delete mocks so that expectations are checked
mockDevicePopErrorScopeCallback = nullptr;
mockQueueWorkDoneCallback = nullptr;
}
};
@@ -141,31 +153,6 @@ TEST_F(ErrorScopeValidationTest, PushPopBalanced) {
}
}
// Test that error scopes call their callbacks before an enclosed Queue::Submit
// completes
TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmit) {
wgpu::Queue queue = device.GetQueue();
device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
queue.Submit(0, nullptr);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
testing::Sequence seq;
MockCallback<WGPUFenceOnCompletionCallback> fenceCallback;
fence.OnCompletion(1, fenceCallback.Callback(), fenceCallback.MakeUserdata(this));
MockCallback<WGPUErrorCallback> errorScopeCallback;
EXPECT_CALL(errorScopeCallback, Call(WGPUErrorType_NoError, _, this + 1)).InSequence(seq);
device.PopErrorScope(errorScopeCallback.Callback(), errorScopeCallback.MakeUserdata(this + 1));
EXPECT_CALL(fenceCallback, Call(WGPUFenceCompletionStatus_Success, this)).InSequence(seq);
WaitForAllOperations(device);
}
// Test that parent error scopes also call their callbacks before an enclosed Queue::Submit
// completes
TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
@@ -175,15 +162,10 @@ TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
queue.Submit(0, nullptr);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
queue.OnSubmittedWorkDone(0u, ToMockQueueWorkDone, this);
testing::Sequence seq;
MockCallback<WGPUFenceOnCompletionCallback> fenceCallback;
fence.OnCompletion(1, fenceCallback.Callback(), fenceCallback.MakeUserdata(this));
MockCallback<WGPUErrorCallback> errorScopeCallback2;
EXPECT_CALL(errorScopeCallback2, Call(WGPUErrorType_NoError, _, this + 1)).InSequence(seq);
device.PopErrorScope(errorScopeCallback2.Callback(),
@@ -194,7 +176,8 @@ TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
device.PopErrorScope(errorScopeCallback1.Callback(),
errorScopeCallback1.MakeUserdata(this + 2));
EXPECT_CALL(fenceCallback, Call(WGPUFenceCompletionStatus_Success, this)).InSequence(seq);
EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_Success, this))
.InSequence(seq);
WaitForAllOperations(device);
}

View File

@@ -1,235 +0,0 @@
// Copyright 2018 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/validation/ValidationTest.h"
#include <gmock/gmock.h>
using namespace testing;
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
struct FenceOnCompletionExpectation {
wgpu::Fence fence;
uint64_t value;
WGPUFenceCompletionStatus status;
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
mockFenceOnCompletionCallback->Call(status, userdata);
}
class FenceValidationTest : public ValidationTest {
protected:
void TestOnCompletion(wgpu::Fence fence, uint64_t value, WGPUFenceCompletionStatus status) {
FenceOnCompletionExpectation* expectation = new FenceOnCompletionExpectation;
expectation->fence = fence;
expectation->value = value;
expectation->status = status;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(status, expectation)).Times(1);
fence.OnCompletion(value, ToMockFenceOnCompletion, expectation);
}
wgpu::Queue queue;
private:
void SetUp() override {
ValidationTest::SetUp();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
queue = device.GetQueue();
}
void TearDown() override {
// Delete mocks so that expectations are checked
mockFenceOnCompletionCallback = nullptr;
ValidationTest::TearDown();
}
};
// Test cases where creation should succeed
TEST_F(FenceValidationTest, CreationSuccess) {
// Success
{
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 0;
EXPECT_DEPRECATION_WARNING(queue.CreateFence(&descriptor));
}
}
// Creation succeeds if no descriptor is provided
TEST_F(FenceValidationTest, DefaultDescriptor) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
EXPECT_EQ(fence.GetCompletedValue(), 0u);
}
TEST_F(FenceValidationTest, GetCompletedValue) {
// Starts at initial value
{
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
EXPECT_EQ(fence.GetCompletedValue(), 1u);
}
}
// Test that OnCompletion handlers are called immediately for
// already completed fence values
TEST_F(FenceValidationTest, OnCompletionImmediate) {
// TODO(crbug.com/dawn/653): This has wrong different behavior on the wire, but fences will be
// removed soon.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
fence.OnCompletion(0u, ToMockFenceOnCompletion, this + 0);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 1))
.Times(1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 1);
}
// Test setting OnCompletion handlers for values > signaled value
TEST_F(FenceValidationTest, OnCompletionLargerThanSignaled) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// Cannot signal for values > signaled value
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Error, nullptr))
.Times(1);
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr));
// Can set handler after signaling
queue.Signal(fence, 2);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr);
WaitForAllOperations(device);
}
TEST_F(FenceValidationTest, GetCompletedValueInsideCallback) {
// TODO(crbug.com/dawn/653): This has wrong different behavior on the wire, but fences will be
// removed soon.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
queue.Signal(fence, 3);
fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.WillOnce(Invoke([&](WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(fence.GetCompletedValue(), 3u);
}));
WaitForAllOperations(device);
}
TEST_F(FenceValidationTest, GetCompletedValueAfterCallback) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
queue.Signal(fence, 2);
fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
TEST_F(FenceValidationTest, SignalError) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// value < fence signaled value
ASSERT_DEVICE_ERROR(queue.Signal(fence, 0));
// value == fence signaled value
ASSERT_DEVICE_ERROR(queue.Signal(fence, 1));
}
TEST_F(FenceValidationTest, SignalSuccess) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// Success
queue.Signal(fence, 2);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 2u);
// Success increasing fence value by more than 1
queue.Signal(fence, 6);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 6u);
}
// Test it is invalid to signal a fence on a different queue than it was created on
// DISABLED until we have support for multiple queues
TEST_F(FenceValidationTest, DISABLED_SignalWrongQueue) {
wgpu::Queue queue2 = device.GetQueue();
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
ASSERT_DEVICE_ERROR(queue2.Signal(fence, 2));
}
// Test that signaling a fence on a wrong queue does not update fence signaled value
// DISABLED until we have support for multiple queues
TEST_F(FenceValidationTest, DISABLED_SignalWrongQueueDoesNotUpdateValue) {
wgpu::Queue queue2 = device.GetQueue();
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
ASSERT_DEVICE_ERROR(queue2.Signal(fence, 2));
// Fence value should be unchanged.
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 1u);
// Signaling with 2 on the correct queue should succeed
queue.Signal(fence, 2);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}

View File

@@ -1,268 +0,0 @@
// Copyright 2019 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"
using namespace testing;
using namespace dawn_wire;
namespace {
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
std::unique_ptr<StrictMock<MockFenceOnCompletionCallback>> mockFenceOnCompletionCallback;
void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
mockFenceOnCompletionCallback->Call(status, userdata);
}
} // anonymous namespace
class WireFenceTests : public WireTest {
public:
WireFenceTests() {
}
~WireFenceTests() override = default;
void SetUp() override {
WireTest::SetUp();
mockFenceOnCompletionCallback =
std::make_unique<StrictMock<MockFenceOnCompletionCallback>>();
{
WGPUFenceDescriptor descriptor = {};
descriptor.initialValue = 1;
apiFence = api.GetNewFence();
fence = wgpuQueueCreateFence(queue, &descriptor);
EXPECT_CALL(api, QueueCreateFence(apiQueue, _)).WillOnce(Return(apiFence));
FlushClient();
}
}
void TearDown() override {
WireTest::TearDown();
mockFenceOnCompletionCallback = nullptr;
}
void FlushServer() {
WireTest::FlushServer();
Mock::VerifyAndClearExpectations(&mockFenceOnCompletionCallback);
}
protected:
void DoQueueSignal(uint64_t signalValue,
WGPUFenceCompletionStatus status = WGPUFenceCompletionStatus_Success) {
wgpuQueueSignal(queue, fence, signalValue);
EXPECT_CALL(api, QueueSignal(apiQueue, apiFence, signalValue)).Times(1);
// This callback is generated to update the completedValue of the fence
// on the client
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, signalValue, _, _))
.WillOnce(
InvokeWithoutArgs([=]() { api.CallFenceOnCompletionCallback(apiFence, status); }))
.RetiresOnSaturation();
}
// A successfully created fence
WGPUFence fence;
WGPUFence apiFence;
};
// Check that signaling a fence succeeds
TEST_F(WireFenceTests, QueueSignalSuccess) {
DoQueueSignal(2u);
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
}
// Check that signaling a fence twice succeeds
TEST_F(WireFenceTests, QueueSignalIncreasing) {
DoQueueSignal(2u);
DoQueueSignal(3u);
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u);
}
// Check that an error in queue signal does not update the completed value.
TEST_F(WireFenceTests, QueueSignalValidationError) {
DoQueueSignal(2u);
DoQueueSignal(1u, WGPUFenceCompletionStatus_Error);
FlushClient();
FlushServer();
// Value should stay at 2 and not be updated to 1.
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
}
// Check that a success in the on completion callback is forwarded to the client.
TEST_F(WireFenceTests, OnCompletionSuccess) {
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 0u, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
}));
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, _))
.Times(1);
FlushServer();
}
// Check that an error in the on completion callback is forwarded to the client.
TEST_F(WireFenceTests, OnCompletionError) {
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 0u, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Error);
}));
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Error, _)).Times(1);
FlushServer();
}
// Test that registering a callback then wire disconnect calls the callback with
// DeviceLost.
TEST_F(WireFenceTests, OnCompletionThenDisconnect) {
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, this);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 0u, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
}));
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, this))
.Times(1);
GetWireClient()->Disconnect();
}
// Test that registering a callback after wire disconnect calls the callback with
// DeviceLost.
TEST_F(WireFenceTests, OnCompletionAfterDisconnect) {
GetWireClient()->Disconnect();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, this))
.Times(1);
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, this);
}
// Without any flushes, it is valid to wait on a value less than or equal to
// the last signaled value
TEST_F(WireFenceTests, OnCompletionSynchronousValidationSuccess) {
wgpuQueueSignal(queue, fence, 4u);
wgpuFenceOnCompletion(fence, 2u, ToMockFenceOnCompletion, 0);
wgpuFenceOnCompletion(fence, 3u, ToMockFenceOnCompletion, 0);
wgpuFenceOnCompletion(fence, 4u, ToMockFenceOnCompletion, 0);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Unknown, _))
.Times(3);
}
// Check that the fence completed value is initialized
TEST_F(WireFenceTests, GetCompletedValueInitialization) {
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
}
// Check that the fence completed value updates after signaling the fence
TEST_F(WireFenceTests, GetCompletedValueUpdate) {
DoQueueSignal(3u);
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u);
}
// Check that the fence completed value updates after signaling the fence
TEST_F(WireFenceTests, GetCompletedValueUpdateInCallback) {
// Signal the fence
DoQueueSignal(3u);
// Register the callback
wgpuFenceOnCompletion(fence, 3u, ToMockFenceOnCompletion, this);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 3u, _, _))
.WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
}))
.RetiresOnSaturation();
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.WillOnce(InvokeWithoutArgs([&]() { EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u); }));
FlushServer();
}
// Check that the fence completed value does not update without a flush
TEST_F(WireFenceTests, GetCompletedValueNoUpdate) {
wgpuQueueSignal(queue, fence, 3u);
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
}
// Check that the callback is called with UNKNOWN when the fence is destroyed
// before the completed value is updated
TEST_F(WireFenceTests, DestroyBeforeOnCompletionEnd) {
wgpuQueueSignal(queue, fence, 3u);
wgpuFenceOnCompletion(fence, 2u, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Unknown, _))
.Times(1);
}
// Test that signaling a fence on a wrong queue is invalid
// DISABLED until we have support for multiple queues.
TEST_F(WireFenceTests, DISABLED_SignalWrongQueue) {
WGPUQueue queue2 = wgpuDeviceGetQueue(device);
WGPUQueue apiQueue2 = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetQueue(apiDevice)).WillOnce(Return(apiQueue2));
FlushClient();
wgpuQueueSignal(queue2, fence, 2u); // error
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
.Times(1);
FlushClient();
}
// Test that signaling a fence on a wrong queue does not update fence signaled value
// DISABLED until we have support for multiple queues.
TEST_F(WireFenceTests, DISABLED_SignalWrongQueueDoesNotUpdateValue) {
WGPUQueue queue2 = wgpuDeviceGetQueue(device);
WGPUQueue apiQueue2 = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetQueue(apiDevice)).WillOnce(Return(apiQueue2));
FlushClient();
wgpuQueueSignal(queue2, fence, 2u); // error
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
.Times(1);
FlushClient();
// Fence value should be unchanged.
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
// Signaling with 2 on the correct queue should succeed
DoQueueSignal(2u); // success
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
}