blob: c8b49ba06c84bee88a27bd32b7e71f64de99d600 [file] [log] [blame]
// 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_METHOD2(Call, void(dawnFenceCompletionStatus status, dawnCallbackUserdata userdata));
};
struct FenceOnCompletionExpectation {
dawn::Fence fence;
uint64_t value;
dawnFenceCompletionStatus status;
};
static std::unique_ptr<MockFenceOnCompletionCallback> 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<dawnCallbackUserdata>(reinterpret_cast<uintptr_t>(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<MockFenceOnCompletionCallback>();
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;
queue.CreateFence(&descriptor);
}
}
TEST_F(FenceValidationTest, GetCompletedValue) {
// Starts at initial value
{
dawn::FenceDescriptor descriptor;
descriptor.initialValue = 1;
dawn::Fence 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) {
dawn::FenceDescriptor descriptor;
descriptor.initialValue = 1;
dawn::Fence fence = queue.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 = queue.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 = queue.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 = queue.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 = 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) {
dawn::FenceDescriptor descriptor;
descriptor.initialValue = 1;
dawn::Fence fence = queue.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);
}
// Test it is invalid to signal a fence on a different queue than it was created on
TEST_F(FenceValidationTest, SignalWrongQueue) {
dawn::Queue queue2 = device.CreateQueue();
dawn::FenceDescriptor descriptor;
descriptor.initialValue = 1;
dawn::Fence 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
TEST_F(FenceValidationTest, SignalWrongQueueDoesNotUpdateValue) {
dawn::Queue queue2 = device.CreateQueue();
dawn::FenceDescriptor descriptor;
descriptor.initialValue = 1;
dawn::Fence fence = queue.CreateFence(&descriptor);
ASSERT_DEVICE_ERROR(queue2.Signal(fence, 2));
// Fence value should be unchanged.
Flush();
EXPECT_EQ(fence.GetCompletedValue(), 1u);
// Signaling with 2 on the correct queue should succeed
queue.Signal(fence, 2);
Flush();
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}