blob: 610993ed2d96794337da307fcf02c87e1fbe5a85 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
*
* 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
*/
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
bool QueryTest::HasZeroTimestampValidBits() {
uint32_t queue_count;
vk::GetPhysicalDeviceQueueFamilyProperties(Gpu(), &queue_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_props(queue_count);
vk::GetPhysicalDeviceQueueFamilyProperties(Gpu(), &queue_count, queue_props.data());
return (queue_props[m_device->graphics_queue_node_index_].timestampValidBits == 0);
}
class PositiveQuery : public QueryTest {};
TEST_F(PositiveQuery, OutsideRenderPass) {
AddRequiredFeature(vkt::Feature::pipelineStatisticsQuery);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkQueryPoolCreateInfo qpci = vkt::QueryPool::CreateInfo(VK_QUERY_TYPE_PIPELINE_STATISTICS, 1);
qpci.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT;
vkt::QueryPool query_pool(*m_device, qpci);
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 1);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
m_command_buffer.EndRenderPass();
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
m_command_buffer.End();
}
TEST_F(PositiveQuery, InsideRenderPass) {
AddRequiredFeature(vkt::Feature::pipelineStatisticsQuery);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkQueryPoolCreateInfo qpci = vkt::QueryPool::CreateInfo(VK_QUERY_TYPE_PIPELINE_STATISTICS, 1);
qpci.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT;
vkt::QueryPool query_pool(*m_device, qpci);
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 1);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveQuery, ResetQueryPoolFromDifferentCB) {
#if defined(VVL_ENABLE_TSAN)
// NOTE: This test in particular has failed sporadically on CI when TSAN is enabled.
GTEST_SKIP() << "https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5965";
#endif
TEST_DESCRIPTION("Reset a query on one CB and use it in another.");
RETURN_IF_SKIP(Init());
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
VkCommandBuffer command_buffer[2];
VkCommandBufferAllocateInfo command_buffer_allocate_info = vku::InitStructHelper();
command_buffer_allocate_info.commandPool = m_command_pool;
command_buffer_allocate_info.commandBufferCount = 2;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, command_buffer);
{
VkCommandBufferBeginInfo begin_info = vku::InitStructHelper();
vk::BeginCommandBuffer(command_buffer[0], &begin_info);
vk::CmdResetQueryPool(command_buffer[0], query_pool, 0, 1);
vk::EndCommandBuffer(command_buffer[0]);
vk::BeginCommandBuffer(command_buffer[1], &begin_info);
vk::CmdBeginQuery(command_buffer[1], query_pool, 0, 0);
vk::CmdEndQuery(command_buffer[1], query_pool, 0);
vk::EndCommandBuffer(command_buffer[1]);
}
{
VkSubmitInfo submit_info[2]{};
submit_info[0] = vku::InitStructHelper();
submit_info[0].commandBufferCount = 1;
submit_info[0].pCommandBuffers = &command_buffer[0];
submit_info[0].signalSemaphoreCount = 0;
submit_info[0].pSignalSemaphores = nullptr;
submit_info[1] = vku::InitStructHelper();
submit_info[1].commandBufferCount = 1;
submit_info[1].pCommandBuffers = &command_buffer[1];
submit_info[1].signalSemaphoreCount = 0;
submit_info[1].pSignalSemaphores = nullptr;
vk::QueueSubmit(m_default_queue->handle(), 2, &submit_info[0], VK_NULL_HANDLE);
}
m_default_queue->Wait();
vk::FreeCommandBuffers(device(), m_command_pool, 2, command_buffer);
}
TEST_F(PositiveQuery, BasicQuery) {
TEST_DESCRIPTION("Use a couple occlusion queries");
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::Buffer buffer(*m_device, 4 * sizeof(uint64_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 2);
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 2);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBeginQuery(m_command_buffer, query_pool, 1, 0);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 1);
m_command_buffer.EndRenderPass();
vk::CmdCopyQueryPoolResults(m_command_buffer, query_pool, 0, 2, buffer, 0, sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
// alignas() for 32-bit machines
alignas(8) uint64_t samples_passed[4];
vk::GetQueryPoolResults(*m_device, query_pool, 0, 2, sizeof(samples_passed), samples_passed, sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
// Now reset query pool in a different command buffer than the BeginQuery
vk::ResetCommandBuffer(m_command_buffer, 0);
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 1);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
vk::ResetCommandBuffer(m_command_buffer, 0);
m_command_buffer.Begin();
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}
TEST_F(PositiveQuery, DestroyQueryPoolBasedOnQueryPoolResults) {
TEST_DESCRIPTION("Destroy a QueryPool based on vkGetQueryPoolResults");
RETURN_IF_SKIP(Init());
InitRenderTarget();
// alignas() for 32-bit machines
alignas(8) uint64_t samples_passed[4];
constexpr uint64_t sizeof_samples_passed = 4 * sizeof(uint64_t);
constexpr VkDeviceSize sample_stride = sizeof(uint64_t);
vkt::Buffer buffer(*m_device, sizeof_samples_passed, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
constexpr uint32_t query_count = 2;
VkQueryPoolCreateInfo query_pool_info = vkt::QueryPool::CreateInfo(VK_QUERY_TYPE_OCCLUSION, query_count);
VkQueryPool query_pool;
vk::CreateQueryPool(*m_device, &query_pool_info, nullptr, &query_pool);
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
// If VK_QUERY_RESULT_WAIT_BIT is not set, vkGetQueryPoolResults may return VK_NOT_READY
constexpr VkQueryResultFlags query_flags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, query_count);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBeginQuery(m_command_buffer, query_pool, 1, 0);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 1);
m_command_buffer.EndRenderPass();
vk::CmdCopyQueryPoolResults(m_command_buffer, query_pool, 0, query_count, buffer, 0, sample_stride, query_flags);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
VkResult res = vk::GetQueryPoolResults(*m_device, query_pool, 0, query_count, sizeof_samples_passed, samples_passed,
sample_stride, query_flags);
if (res == VK_SUCCESS) {
// "Applications can verify that queryPool can be destroyed by checking that vkGetQueryPoolResults() without the
// VK_QUERY_RESULT_PARTIAL_BIT flag returns VK_SUCCESS for all queries that are used in command buffers submitted for
// execution."
//
// i.e. You don't have to wait for an idle queue to destroy the query pool.
vk::DestroyQueryPool(*m_device, query_pool, nullptr);
m_default_queue->Wait();
} else {
// some devices (pixel 7) will return VK_NOT_READY
m_default_queue->Wait();
vk::DestroyQueryPool(*m_device, query_pool, nullptr);
}
}
TEST_F(PositiveQuery, QueryAndCopySecondaryCommandBuffers) {
TEST_DESCRIPTION("Issue a query on a secondary command buffer and copy it on a primary.");
all_queue_count_ = true;
RETURN_IF_SKIP(Init());
if ((m_device->Physical().queue_properties_.empty()) || (m_device->Physical().queue_properties_[0].queueCount < 2)) {
GTEST_SKIP() << "Queue family needs to have multiple queues to run this test";
}
if (HasZeroTimestampValidBits()) {
GTEST_SKIP() << "Device graphic queue has timestampValidBits of 0, skipping.\n";
}
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_TIMESTAMP, 1);
vkt::CommandPool command_pool(*m_device, m_device->graphics_queue_node_index_, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
vkt::CommandBuffer primary_buffer(*m_device, command_pool);
vkt::CommandBuffer secondary_buffer(*m_device, command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkQueue queue = VK_NULL_HANDLE;
vk::GetDeviceQueue(device(), m_device->graphics_queue_node_index_, 1, &queue);
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
VkCommandBufferInheritanceInfo hinfo = vku::InitStructHelper();
hinfo.renderPass = VK_NULL_HANDLE;
hinfo.subpass = 0;
hinfo.framebuffer = VK_NULL_HANDLE;
hinfo.occlusionQueryEnable = VK_FALSE;
hinfo.queryFlags = 0;
hinfo.pipelineStatistics = 0;
{
VkCommandBufferBeginInfo begin_info = vku::InitStructHelper();
begin_info.pInheritanceInfo = &hinfo;
secondary_buffer.Begin(&begin_info);
vk::CmdResetQueryPool(secondary_buffer, query_pool, 0, 1);
vk::CmdWriteTimestamp(secondary_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
secondary_buffer.End();
primary_buffer.Begin();
vk::CmdExecuteCommands(primary_buffer, 1, &secondary_buffer.handle());
vk::CmdCopyQueryPoolResults(primary_buffer, query_pool, 0, 1, buffer, 0, 0, VK_QUERY_RESULT_WAIT_BIT);
primary_buffer.End();
}
m_default_queue->SubmitAndWait(primary_buffer);
vk::QueueWaitIdle(queue);
}
TEST_F(PositiveQuery, QueryAndCopyMultipleCommandBuffers) {
TEST_DESCRIPTION("Issue a query and copy from it on a second command buffer.");
all_queue_count_ = true;
RETURN_IF_SKIP(Init());
if ((m_device->Physical().queue_properties_.empty()) || (m_device->Physical().queue_properties_[0].queueCount < 2)) {
GTEST_SKIP() << "Queue family needs to have multiple queues to run this test";
}
if (HasZeroTimestampValidBits()) {
GTEST_SKIP() << "Device graphic queue has timestampValidBits of 0, skipping.\n";
}
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_TIMESTAMP, 1);
VkCommandPoolCreateInfo pool_create_info = vku::InitStructHelper();
pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vkt::CommandPool command_pool(*m_device, pool_create_info);
VkCommandBuffer command_buffer[2];
VkCommandBufferAllocateInfo command_buffer_allocate_info = vku::InitStructHelper();
command_buffer_allocate_info.commandPool = command_pool;
command_buffer_allocate_info.commandBufferCount = 2;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, command_buffer);
VkQueue queue = VK_NULL_HANDLE;
vk::GetDeviceQueue(device(), m_device->graphics_queue_node_index_, 1, &queue);
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
{
VkCommandBufferBeginInfo begin_info = vku::InitStructHelper();
vk::BeginCommandBuffer(command_buffer[0], &begin_info);
vk::CmdResetQueryPool(command_buffer[0], query_pool, 0, 1);
vk::CmdWriteTimestamp(command_buffer[0], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
vk::EndCommandBuffer(command_buffer[0]);
vk::BeginCommandBuffer(command_buffer[1], &begin_info);
vk::CmdCopyQueryPoolResults(command_buffer[1], query_pool, 0, 1, buffer, 0, 0, VK_QUERY_RESULT_WAIT_BIT);
vk::EndCommandBuffer(command_buffer[1]);
}
{
VkSubmitInfo submit_info = vku::InitStructHelper();
submit_info.commandBufferCount = 2;
submit_info.pCommandBuffers = command_buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
vk::QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
}
vk::QueueWaitIdle(queue);
}
TEST_F(PositiveQuery, DestroyQueryPoolAfterGetQueryPoolResults) {
TEST_DESCRIPTION("Destroy query pool after GetQueryPoolResults() without VK_QUERY_RESULT_PARTIAL_BIT returns VK_SUCCESS");
RETURN_IF_SKIP(Init());
if (HasZeroTimestampValidBits()) {
GTEST_SKIP() << "Device graphic queue has timestampValidBits of 0, skipping.\n";
}
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_TIMESTAMP, 1);
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 1);
vk::CmdWriteTimestamp(m_command_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
const size_t out_data_size = 16;
uint8_t data[out_data_size];
VkResult res;
do {
res = vk::GetQueryPoolResults(device(), query_pool, 0, 1, out_data_size, &data, 4, 0);
} while (res != VK_SUCCESS);
m_default_queue->Wait();
}
TEST_F(PositiveQuery, WriteTimestampNoneAndAll) {
TEST_DESCRIPTION("Test using vkCmdWriteTimestamp2 with NONE and ALL_COMMANDS.");
AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (HasZeroTimestampValidBits()) {
GTEST_SKIP() << "Device graphic queue has timestampValidBits of 0, skipping.\n";
}
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_TIMESTAMP, 2);
m_command_buffer.Begin();
vk::CmdWriteTimestamp2KHR(m_command_buffer, VK_PIPELINE_STAGE_2_NONE, query_pool, 0);
vk::CmdWriteTimestamp2KHR(m_command_buffer, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, query_pool, 1);
m_command_buffer.End();
}
TEST_F(PositiveQuery, CommandBufferInheritanceFlags) {
TEST_DESCRIPTION("Test executing secondary command buffer with VkCommandBufferInheritanceInfo::queryFlags.");
AddRequiredFeature(vkt::Feature::inheritedQueries);
AddRequiredFeature(vkt::Feature::occlusionQueryPrecise);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferInheritanceInfo cbii = vku::InitStructHelper();
cbii.renderPass = m_renderPass;
cbii.framebuffer = Framebuffer();
cbii.occlusionQueryEnable = VK_TRUE;
cbii.queryFlags = VK_QUERY_CONTROL_PRECISE_BIT;
VkCommandBufferBeginInfo cbbi = vku::InitStructHelper();
cbbi.pInheritanceInfo = &cbii;
cbbi.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
VkCommandBuffer secondary_handle = secondary;
vk::BeginCommandBuffer(secondary_handle, &cbbi);
vk::EndCommandBuffer(secondary_handle);
m_command_buffer.Begin();
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_handle);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 1);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, VK_QUERY_CONTROL_PRECISE_BIT);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_handle);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
m_command_buffer.End();
}
TEST_F(PositiveQuery, PerformanceQueries) {
#if defined(VVL_ENABLE_TSAN)
// NOTE: This test in particular has failed sporadically on CI when TSAN is enabled.
GTEST_SKIP() << "https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5965";
#endif
TEST_DESCRIPTION("Test performance queries.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::performanceCounterQueryPools);
RETURN_IF_SKIP(Init());
uint32_t counterCount = 0u;
vk::EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(m_device->Physical(), m_device->graphics_queue_node_index_,
&counterCount, nullptr, nullptr);
std::vector<VkPerformanceCounterKHR> counters(counterCount, vku::InitStruct<VkPerformanceCounterKHR>());
std::vector<VkPerformanceCounterDescriptionKHR> counterDescriptions(counterCount,
vku::InitStruct<VkPerformanceCounterDescriptionKHR>());
vk::EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(m_device->Physical(), m_device->graphics_queue_node_index_,
&counterCount, counters.data(), counterDescriptions.data());
std::vector<uint32_t> enabledCounters(128);
const uint32_t enabledCounterCount = std::min(counterCount, static_cast<uint32_t>(enabledCounters.size()));
for (uint32_t i = 0; i < enabledCounterCount; ++i) {
enabledCounters[i] = i;
}
auto query_pool_performance_ci = vku::InitStruct<VkQueryPoolPerformanceCreateInfoKHR>();
query_pool_performance_ci.queueFamilyIndex = m_device->graphics_queue_node_index_;
query_pool_performance_ci.counterIndexCount = enabledCounterCount;
query_pool_performance_ci.pCounterIndices = enabledCounters.data();
uint32_t num_passes = 0u;
vk::GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(m_device->Physical(), &query_pool_performance_ci, &num_passes);
auto query_pool_ci = vku::InitStruct<VkQueryPoolCreateInfo>(&query_pool_performance_ci);
query_pool_ci.queryType = VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR;
query_pool_ci.queryCount = 1u;
vkt::QueryPool query_pool(*m_device, query_pool_ci);
{
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0u, 1u);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
vkt::CommandBuffer cmd_buffer(*m_device, m_command_pool);
auto acquire_profiling_lock_info = vku::InitStruct<VkAcquireProfilingLockInfoKHR>();
acquire_profiling_lock_info.timeout = vvl::kU64Max;
vk::AcquireProfilingLockKHR(*m_device, &acquire_profiling_lock_info);
VkCommandBufferBeginInfo info = vku::InitStructHelper();
cmd_buffer.Begin(&info);
vk::CmdBeginQuery(cmd_buffer, query_pool, 0u, 0u);
vk::CmdPipelineBarrier(cmd_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, nullptr,
0u, nullptr, 0u, nullptr);
vk::CmdEndQuery(cmd_buffer, query_pool, 0u);
cmd_buffer.End();
for (uint32_t counterPass = 0u; counterPass < num_passes; ++counterPass) {
auto performance_query_submit_info = vku::InitStruct<VkPerformanceQuerySubmitInfoKHR>();
performance_query_submit_info.counterPassIndex = counterPass;
auto submit_info = vku::InitStruct<VkSubmitInfo>(&performance_query_submit_info);
submit_info.commandBufferCount = 1u;
submit_info.pCommandBuffers = &cmd_buffer.handle();
vk::QueueSubmit(m_default_queue->handle(), 1u, &submit_info, VK_NULL_HANDLE);
m_device->Wait();
}
vk::ReleaseProfilingLockKHR(*m_device);
std::vector<VkPerformanceCounterResultKHR> recordedCounters(enabledCounterCount);
vk::GetQueryPoolResults(*m_device, query_pool, 0u, 1u, sizeof(VkPerformanceCounterResultKHR) * enabledCounterCount,
recordedCounters.data(), sizeof(VkPerformanceCounterResultKHR) * enabledCounterCount, 0u);
}
TEST_F(PositiveQuery, HostQueryResetSuccess) {
TEST_DESCRIPTION("Use vkResetQueryPoolEXT normally");
AddRequiredExtensions(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::hostQueryReset);
RETURN_IF_SKIP(Init());
VkQueryPoolCreateInfo query_pool_create_info = vku::InitStructHelper();
query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
query_pool_create_info.queryCount = 1;
vkt::QueryPool query_pool(*m_device, query_pool_create_info);
vk::ResetQueryPoolEXT(device(), query_pool, 0, 1);
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7874
TEST_F(PositiveQuery, ReuseSecondaryWithQueryCommand) {
TEST_DESCRIPTION("Regression test for a deadlock when secondary command buffer is reused and records a query command");
RETURN_IF_SKIP(Init());
if (HasZeroTimestampValidBits()) {
GTEST_SKIP() << "Device graphic queue has timestampValidBits of 0, skipping.";
}
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_TIMESTAMP, 1);
vkt::CommandBuffer secondary_buffer(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary_buffer.Begin(VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
vk::CmdWriteTimestamp(secondary_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
secondary_buffer.End();
m_command_buffer.Begin(VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 1);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
// Submit the command buffer again.
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
}
TEST_F(PositiveQuery, PerformanceCountersWithoutEnumeration) {
TEST_DESCRIPTION("Create performance queries without enumerating queue family performance queries");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::performanceCounterQueryPools);
RETURN_IF_SKIP(Init());
uint32_t counterCount = 0u;
vk::EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(m_device->Physical(), m_device->graphics_queue_node_index_,
&counterCount, nullptr, nullptr);
if (counterCount < 128) {
GTEST_SKIP() << "Required performance query counter count not supported";
}
std::vector<uint32_t> enabledCounters(128);
const uint32_t enabledCounterCount = static_cast<uint32_t>(enabledCounters.size());
for (uint32_t i = 0; i < enabledCounterCount; ++i) {
enabledCounters[i] = i;
}
auto query_pool_performance_ci = vku::InitStruct<VkQueryPoolPerformanceCreateInfoKHR>();
query_pool_performance_ci.queueFamilyIndex = m_device->graphics_queue_node_index_;
query_pool_performance_ci.counterIndexCount = enabledCounterCount;
query_pool_performance_ci.pCounterIndices = enabledCounters.data();
uint32_t num_passes = 0u;
vk::GetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(m_device->Physical(), &query_pool_performance_ci, &num_passes);
auto query_pool_ci = vku::InitStruct<VkQueryPoolCreateInfo>(&query_pool_performance_ci);
query_pool_ci.queryType = VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR;
query_pool_ci.queryCount = 1u;
vkt::QueryPool query_pool(*m_device, query_pool_ci);
{
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0u, 1u);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
vkt::CommandBuffer cmd_buffer(*m_device, m_command_pool);
auto acquire_profiling_lock_info = vku::InitStruct<VkAcquireProfilingLockInfoKHR>();
acquire_profiling_lock_info.timeout = vvl::kU64Max;
vk::AcquireProfilingLockKHR(*m_device, &acquire_profiling_lock_info);
VkCommandBufferBeginInfo info = vku::InitStructHelper();
cmd_buffer.Begin(&info);
vk::CmdBeginQuery(cmd_buffer, query_pool, 0u, 0u);
vk::CmdPipelineBarrier(cmd_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, nullptr,
0u, nullptr, 0u, nullptr);
vk::CmdEndQuery(cmd_buffer, query_pool, 0u);
cmd_buffer.End();
for (uint32_t counterPass = 0u; counterPass < num_passes; ++counterPass) {
auto performance_query_submit_info = vku::InitStruct<VkPerformanceQuerySubmitInfoKHR>();
performance_query_submit_info.counterPassIndex = counterPass;
auto submit_info = vku::InitStruct<VkSubmitInfo>(&performance_query_submit_info);
submit_info.commandBufferCount = 1u;
submit_info.pCommandBuffers = &cmd_buffer.handle();
vk::QueueSubmit(m_default_queue->handle(), 1u, &submit_info, VK_NULL_HANDLE);
m_device->Wait();
}
vk::ReleaseProfilingLockKHR(*m_device);
std::vector<VkPerformanceCounterResultKHR> recordedCounters(enabledCounterCount);
vk::GetQueryPoolResults(*m_device, query_pool, 0u, 1u, sizeof(VkPerformanceCounterResultKHR) * enabledCounterCount,
recordedCounters.data(), sizeof(VkPerformanceCounterResultKHR) * enabledCounterCount, 0u);
}
TEST_F(PositiveQuery, QueryPoolResetBit) {
AddRequiredFeature(vkt::Feature::pipelineStatisticsQuery);
AddRequiredExtensions(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance9);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkQueryPoolCreateInfo qpci = vkt::QueryPool::CreateInfo(VK_QUERY_TYPE_PIPELINE_STATISTICS, 1, VK_QUERY_POOL_CREATE_RESET_BIT_KHR);
qpci.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT;
vkt::QueryPool query_pool(*m_device, qpci);
m_command_buffer.Begin();
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
}
TEST_F(PositiveQuery, QueryPoolResultsStride) {
AddRequiredFeature(vkt::Feature::pipelineStatisticsQuery);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkQueryPoolCreateInfo qpci = vkt::QueryPool::CreateInfo(VK_QUERY_TYPE_PIPELINE_STATISTICS, 1u);
qpci.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT;
vkt::QueryPool query_pool(*m_device, qpci);
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0u, 1u);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0u, 0u);
vk::CmdEndQuery(m_command_buffer, query_pool, 0u);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
uint32_t data_space[2];
vk::GetQueryPoolResults(*m_device, query_pool, 0u, 1u, sizeof(uint32_t) * 2, data_space, 0u,
VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
}