// 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 using namespace testing; class MockFenceOnCompletionCallback { public: MOCK_METHOD2(Call, void(dawnFenceCompletionStatus status, dawnCallbackUserdata userdata)); }; struct FenceOnCompletionExpectation { dawn::Fence fence; uint64_t value; dawnFenceCompletionStatus status; }; static std::unique_ptr mockFenceOnCompletionCallback; static void ToMockFenceOnCompletionCallback(dawnFenceCompletionStatus status, dawnCallbackUserdata userdata) { mockFenceOnCompletionCallback->Call(status, userdata); } class FenceValidationTest : public ValidationTest { protected: void TestOnCompletion(dawn::Fence fence, uint64_t value, dawnFenceCompletionStatus status) { FenceOnCompletionExpectation* expectation = new FenceOnCompletionExpectation; expectation->fence = fence; expectation->value = value; expectation->status = status; dawnCallbackUserdata userdata = static_cast(reinterpret_cast(expectation)); EXPECT_CALL(*mockFenceOnCompletionCallback, Call(status, userdata)).Times(1); fence.OnCompletion(value, ToMockFenceOnCompletionCallback, userdata); } void Flush() { device.Tick(); } dawn::Queue queue; private: void SetUp() override { ValidationTest::SetUp(); mockFenceOnCompletionCallback = std::make_unique(); queue = device.CreateQueue(); } 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 { dawn::FenceDescriptor descriptor; descriptor.initialValue = 0; device.CreateFence(&descriptor); } } TEST_F(FenceValidationTest, GetCompletedValue) { // Starts at initial value { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.CreateFence(&descriptor); EXPECT_EQ(fence.GetCompletedValue(), 1u); } } // Test that OnCompletion handlers are called immediately for // already completed fence values TEST_F(FenceValidationTest, OnCompletionImmediate) { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.CreateFence(&descriptor); EXPECT_CALL(*mockFenceOnCompletionCallback, Call(DAWN_FENCE_COMPLETION_STATUS_SUCCESS, 0)) .Times(1); fence.OnCompletion(0u, ToMockFenceOnCompletionCallback, 0); EXPECT_CALL(*mockFenceOnCompletionCallback, Call(DAWN_FENCE_COMPLETION_STATUS_SUCCESS, 1)) .Times(1); fence.OnCompletion(1u, ToMockFenceOnCompletionCallback, 1); } // Test setting OnCompletion handlers for values > signaled value TEST_F(FenceValidationTest, OnCompletionLargerThanSignaled) { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.CreateFence(&descriptor); // Cannot signal for values > signaled value EXPECT_CALL(*mockFenceOnCompletionCallback, Call(DAWN_FENCE_COMPLETION_STATUS_ERROR, 0)) .Times(1); ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionCallback, 0)); // Can set handler after signaling queue.Signal(fence, 2); EXPECT_CALL(*mockFenceOnCompletionCallback, Call(DAWN_FENCE_COMPLETION_STATUS_SUCCESS, 0)) .Times(1); fence.OnCompletion(2u, ToMockFenceOnCompletionCallback, 0); Flush(); } TEST_F(FenceValidationTest, GetCompletedValueInsideCallback) { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.CreateFence(&descriptor); queue.Signal(fence, 3); fence.OnCompletion(2u, ToMockFenceOnCompletionCallback, 0); EXPECT_CALL(*mockFenceOnCompletionCallback, Call(DAWN_FENCE_COMPLETION_STATUS_SUCCESS, 0)) .WillOnce(Invoke([&](dawnFenceCompletionStatus status, dawnCallbackUserdata userdata) { EXPECT_EQ(fence.GetCompletedValue(), 3u); })); Flush(); } TEST_F(FenceValidationTest, GetCompletedValueAfterCallback) { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.CreateFence(&descriptor); queue.Signal(fence, 2); fence.OnCompletion(2u, ToMockFenceOnCompletionCallback, 0); EXPECT_CALL(*mockFenceOnCompletionCallback, Call(DAWN_FENCE_COMPLETION_STATUS_SUCCESS, 0)) .Times(1); Flush(); EXPECT_EQ(fence.GetCompletedValue(), 2u); } TEST_F(FenceValidationTest, SignalError) { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.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) { dawn::FenceDescriptor descriptor; descriptor.initialValue = 1; dawn::Fence fence = device.CreateFence(&descriptor); // Success queue.Signal(fence, 2); Flush(); EXPECT_EQ(fence.GetCompletedValue(), 2u); // Success increasing fence value by more than 1 queue.Signal(fence, 6); Flush(); EXPECT_EQ(fence.GetCompletedValue(), 6u); }