blob: a92156084f4afda6070296cd8df6fabdfd665829 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "testing/gtest/include/gtest/gtest.h"
#include "base/bind.h"
#include "gpu/vulkan/tests/basic_vulkan_test.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_fence_helper.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_util.h"
namespace gpu {
using VulkanFenceHelperTest = BasicVulkanTest;
TEST_F(VulkanFenceHelperTest, BasicFenceUsage) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
VkFence fence = VK_NULL_HANDLE;
ASSERT_TRUE(VK_SUCCESS == fence_helper->GetFence(&fence));
ASSERT_TRUE(fence != VK_NULL_HANDLE);
ASSERT_TRUE(VK_SUCCESS == vkQueueSubmit(GetDeviceQueue()->GetVulkanQueue(), 0,
nullptr, fence));
VulkanFenceHelper::FenceHandle fence_handle =
fence_helper->EnqueueFence(fence);
EXPECT_TRUE(fence_helper->Wait(fence_handle, UINT64_MAX));
EXPECT_TRUE(fence_helper->HasPassed(fence_handle));
}
TEST_F(VulkanFenceHelperTest, TestBasicCallback) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
bool cleanup_run = false;
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce([](bool* cleanup_run, VulkanDeviceQueue* device_queue,
bool is_lost) { *cleanup_run = true; },
&cleanup_run));
VulkanFenceHelper::FenceHandle fence_handle =
fence_helper->GenerateCleanupFence();
EXPECT_TRUE(fence_handle.is_valid());
fence_helper->Wait(fence_handle, UINT64_MAX);
EXPECT_TRUE(cleanup_run);
}
TEST_F(VulkanFenceHelperTest, TestBasicCallbackExternalSubmission) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
bool cleanup_run = false;
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce([](bool* cleanup_run, VulkanDeviceQueue* device_queue,
bool is_lost) { *cleanup_run = true; },
&cleanup_run));
VkFence fence = VK_NULL_HANDLE;
ASSERT_TRUE(VK_SUCCESS == fence_helper->GetFence(&fence));
ASSERT_TRUE(fence != VK_NULL_HANDLE);
ASSERT_TRUE(VK_SUCCESS == vkQueueSubmit(GetDeviceQueue()->GetVulkanQueue(), 0,
nullptr, fence));
VulkanFenceHelper::FenceHandle fence_handle =
fence_helper->EnqueueFence(fence);
EXPECT_TRUE(fence_handle.is_valid());
fence_helper->Wait(fence_handle, UINT64_MAX);
EXPECT_TRUE(cleanup_run);
}
TEST_F(VulkanFenceHelperTest, TestMultipleCallbacks) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
uint32_t cleanups_run = 0;
auto increment_cleanups_callback =
[](uint32_t expected_index, uint32_t* cleanups_run,
VulkanDeviceQueue* device_queue, bool is_lost) {
EXPECT_EQ(expected_index, *cleanups_run);
*cleanups_run = *cleanups_run + 1;
};
// Enqueue 5 callbacks.
for (int i = 0; i < 5; i++) {
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
}
// Generate a cleanup fence for the first 5 callbacks.
VulkanFenceHelper::FenceHandle fence_handle =
fence_helper->GenerateCleanupFence();
// Enqueue 5 more callbacks.
for (int i = 5; i < 10; i++) {
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
}
// Generate a cleanup fence for the next 5 callbacks.
fence_handle = fence_helper->GenerateCleanupFence();
EXPECT_TRUE(fence_handle.is_valid());
fence_helper->Wait(fence_handle, UINT64_MAX);
EXPECT_EQ(10u, cleanups_run);
}
TEST_F(VulkanFenceHelperTest, TestSkiaCallback) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
bool cleanup_run = false;
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce([](bool* cleanup_run, VulkanDeviceQueue* device_queue,
bool is_lost) { *cleanup_run = true; },
&cleanup_run));
auto cleanup_closure = fence_helper->CreateExternalCallback();
EXPECT_FALSE(cleanup_run);
std::move(cleanup_closure).Run();
EXPECT_TRUE(cleanup_run);
}
TEST_F(VulkanFenceHelperTest, SkiaCallbackBeforeFences) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
uint32_t cleanups_run = 0;
auto increment_cleanups_callback =
[](uint32_t expected_index, uint32_t* cleanups_run,
VulkanDeviceQueue* device_queue, bool is_lost) {
EXPECT_EQ(expected_index, *cleanups_run);
*cleanups_run = *cleanups_run + 1;
};
// Enqueue 5 callbacks.
for (int i = 0; i < 5; i++) {
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
}
// The first 5 callbacks use a callback to trigger.
auto cleanup_closure = fence_helper->CreateExternalCallback();
// Enqueue 5 more callbacks.
for (int i = 5; i < 10; i++) {
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
}
// Generate a cleanup fence for the next 5 callbacks.
VulkanFenceHelper::FenceHandle fence_handle =
fence_helper->GenerateCleanupFence();
EXPECT_TRUE(fence_handle.is_valid());
// After waiting for the second fence, all callbacks should have run, Skia
// callbacks can be delayed, so we check future fences as well.
EXPECT_TRUE(fence_helper->Wait(fence_handle, UINT64_MAX));
EXPECT_EQ(10u, cleanups_run);
// Running the callback now should be a no-op.
std::move(cleanup_closure).Run();
EXPECT_EQ(10u, cleanups_run);
}
TEST_F(VulkanFenceHelperTest, SkiaCallbackAfterFences) {
VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
uint32_t cleanups_run = 0;
auto increment_cleanups_callback =
[](uint32_t expected_index, uint32_t* cleanups_run,
VulkanDeviceQueue* device_queue, bool is_lost) {
EXPECT_EQ(expected_index, *cleanups_run);
*cleanups_run = *cleanups_run + 1;
};
// Enqueue 5 callbacks.
for (int i = 0; i < 5; i++) {
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
}
// The first 5 callbacks use a fence to trigger.
VulkanFenceHelper::FenceHandle fence_handle =
fence_helper->GenerateCleanupFence();
EXPECT_TRUE(fence_handle.is_valid());
// Call vkQueueWaitIdle() to make sure the |fence_handle| is passed.
vkQueueWaitIdle(queue());
// Enqueue 5 more callbacks.
for (int i = 5; i < 10; i++) {
fence_helper->EnqueueCleanupTaskForSubmittedWork(
base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
}
// The next 5 callbacks use a callback to trigger.
auto cleanup_closure = fence_helper->CreateExternalCallback();
// Call the cleanup closure, all callbacks should run.
// Generate a cleanup fence for the next 5 callbacks.
std::move(cleanup_closure).Run();
EXPECT_EQ(10u, cleanups_run);
}
} // namespace gpu