blob: 22705e4e97db56f6d5dff5b03384ca7dce4785ea [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 <atomic>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
#include <gtest/gtest.h>
#include <vulkan/vulkan.h>
#include "src/lib/fxl/test/test_settings.h"
#include "vkreadback.h"
inline constexpr int64_t ms_to_ns(int64_t ms) { return ms * 1000000ull; }
int main(int argc, char** argv) {
if (!fxl::SetTestSettings(argc, argv)) {
return EXIT_FAILURE;
}
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(Vulkan, Readback) {
VkReadbackTest test;
ASSERT_TRUE(test.Initialize(VK_API_VERSION_1_1));
ASSERT_TRUE(test.Exec());
ASSERT_TRUE(test.Readback());
}
TEST(Vulkan, ManyReadback) {
std::vector<std::unique_ptr<VkReadbackTest>> tests;
constexpr uint32_t kReps = 75;
for (uint32_t i = 0; i < kReps; i++) {
tests.emplace_back(std::make_unique<VkReadbackTest>());
ASSERT_TRUE(tests.back()->Initialize(VK_API_VERSION_1_1));
ASSERT_TRUE(tests.back()->Exec());
}
for (auto& test : tests) {
ASSERT_TRUE(test->Readback());
}
}
TEST(Vulkan, ReadbackLoopWithFenceWaitThread) {
VkReadbackTest test;
ASSERT_TRUE(test.Initialize(VK_API_VERSION_1_1));
std::mutex mutex;
std::condition_variable cond_var;
std::queue<vk::Fence> fences;
constexpr uint32_t kCounter = 500;
const vk::Device device = test.vulkan_device();
std::thread thread([&] {
for (uint32_t i = 0; i < kCounter; i++) {
vk::Fence fence = {};
while (!fence) {
std::unique_lock<std::mutex> lock(mutex);
if (fences.empty()) {
cond_var.wait(lock);
continue;
}
fence = fences.front();
fences.pop();
}
EXPECT_EQ(vk::Result::eSuccess,
device.waitForFences(1, &fence, true /* waitAll */, ms_to_ns(1000)));
device.destroyFence(fence, nullptr /* allocator */);
}
});
const vk::FenceCreateInfo fence_info{};
for (uint32_t i = 0; i < kCounter; i++) {
vk::Fence fence{};
auto rv_fence = device.createFence(&fence_info, nullptr /* allocator */, &fence);
ASSERT_EQ(rv_fence, vk::Result::eSuccess);
{
std::unique_lock<std::mutex> lock(mutex);
fences.push(fence);
const bool transition_image = (i == 0);
EXPECT_TRUE(test.Submit(fence, transition_image));
cond_var.notify_one();
}
EXPECT_TRUE(test.Wait());
}
thread.join();
EXPECT_TRUE(test.Readback());
}
TEST(Vulkan, ReadbackLoopWithFenceWait) {
VkReadbackTest test;
ASSERT_TRUE(test.Initialize(VK_API_VERSION_1_1));
const vk::Device device = test.vulkan_device();
vk::Fence fence{};
{
vk::FenceCreateInfo fence_info{};
auto rv_fence = device.createFence(&fence_info, nullptr /* allocator */, &fence);
ASSERT_EQ(rv_fence, vk::Result::eSuccess);
}
constexpr uint32_t kCounter = 500;
for (uint32_t i = 0; i < kCounter; i++) {
{
const bool transition_image = (i == 0);
EXPECT_TRUE(test.Submit(fence, transition_image));
}
EXPECT_EQ(vk::Result::eSuccess,
device.waitForFences(1, &fence, true /* waitAll */, ms_to_ns(1000)));
device.resetFences(1, &fence);
EXPECT_TRUE(test.Readback());
}
device.destroyFence(fence, nullptr /* allocator */);
}
TEST(Vulkan, ReadbackLoopWithTimelineWait) {
VkReadbackTest test;
ASSERT_TRUE(test.Initialize(VK_API_VERSION_1_2));
{
vk::PhysicalDeviceTimelineSemaphoreProperties timeline_properties{};
auto properties = vk::PhysicalDeviceProperties2{};
properties.pNext = &timeline_properties;
test.physical_device().getProperties2(&properties);
// TODO(fxbug.dev/69054) - remove
if (timeline_properties.maxTimelineSemaphoreValueDifference == 0)
GTEST_SKIP();
}
const vk::Device device = test.vulkan_device();
vk::Semaphore semaphore{};
{
auto type_create_info =
vk::SemaphoreTypeCreateInfo().setSemaphoreType(vk::SemaphoreType::eTimeline);
auto create_info = vk::SemaphoreCreateInfo().setPNext(&type_create_info);
ASSERT_EQ(vk::Result::eSuccess,
device.createSemaphore(&create_info, nullptr /* allocator */, &semaphore));
}
constexpr uint32_t kCounter = 500;
for (uint32_t i = 0; i < kCounter; i++) {
uint64_t timeline_value = 1 + i;
{
const bool transition_image = (i == 0);
EXPECT_TRUE(test.Submit(semaphore, timeline_value, transition_image));
}
{
auto wait_info = vk::SemaphoreWaitInfo()
.setSemaphoreCount(1)
.setPSemaphores(&semaphore)
.setPValues(&timeline_value);
EXPECT_EQ(vk::Result::eSuccess, device.waitSemaphores(&wait_info, ms_to_ns(1000)));
}
{
auto rv_result = device.getSemaphoreCounterValue(semaphore);
EXPECT_EQ(rv_result.result, vk::Result::eSuccess);
EXPECT_EQ(rv_result.value, timeline_value);
}
EXPECT_TRUE(test.Readback());
}
device.destroySemaphore(semaphore, nullptr /* allocator */);
}