blob: 0b80c6d811cabd07bd0d09283347876530554d52 [file] [log] [blame]
/* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (C) 2015-2023 Google Inc.
* Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* 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 <assert.h>
#include <string>
#include <vulkan/vk_enum_string_helper.h>
#include "generated/chassis.h"
#include "core_validation.h"
#include "generated/enum_flag_bits.h"
static QueryState GetLocalQueryState(const QueryMap *localQueryToStateMap, VkQueryPool queryPool, uint32_t queryIndex,
uint32_t perfPass) {
QueryObject query = QueryObject(queryPool, queryIndex, perfPass);
auto iter = localQueryToStateMap->find(query);
if (iter != localQueryToStateMap->end()) return iter->second;
return QUERYSTATE_UNKNOWN;
}
bool CoreChecks::PreCallValidateDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator,
const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
if (queryPool == VK_NULL_HANDLE) return false;
const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
bool skip = false;
bool completed_by_get_results = true;
for (uint32_t i = 0; i < query_pool_state->createInfo.queryCount; ++i) {
auto state = query_pool_state->GetQueryState(i, 0);
if (state != QUERYSTATE_AVAILABLE) {
completed_by_get_results = false;
break;
}
}
if (!completed_by_get_results) {
skip |= ValidateObjectNotInUse(query_pool_state.get(), error_obj.location, "VUID-vkDestroyQueryPool-queryPool-00793");
}
return skip;
}
bool CoreChecks::ValidatePerformanceQueryResults(const QUERY_POOL_STATE &query_pool_state, uint32_t firstQuery, uint32_t queryCount,
VkQueryResultFlags flags, const Location &loc) const {
bool skip = false;
if (flags & (VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | VK_QUERY_RESULT_WITH_STATUS_BIT_KHR | VK_QUERY_RESULT_PARTIAL_BIT |
VK_QUERY_RESULT_64_BIT)) {
std::string invalid_flags_string;
for (auto flag : {VK_QUERY_RESULT_WITH_AVAILABILITY_BIT, VK_QUERY_RESULT_WITH_STATUS_BIT_KHR, VK_QUERY_RESULT_PARTIAL_BIT,
VK_QUERY_RESULT_64_BIT}) {
if (flag & flags) {
if (invalid_flags_string.size()) {
invalid_flags_string += " and ";
}
invalid_flags_string += string_VkQueryResultFlagBits(flag);
}
}
const char *vuid = loc.function == Func::vkGetQueryPoolResults ? "VUID-vkGetQueryPoolResults-queryType-03230"
: "VUID-vkCmdCopyQueryPoolResults-queryType-03233";
skip |= LogError(vuid, query_pool_state.pool(), loc.dot(Field::queryPool),
"(%s) was created with a queryType of"
"VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR but flags contains %s.",
FormatHandle(query_pool_state).c_str(), invalid_flags_string.c_str());
}
for (uint32_t query_index = firstQuery; query_index < queryCount; query_index++) {
uint32_t submitted = 0;
for (uint32_t pass_index = 0; pass_index < query_pool_state.n_performance_passes; pass_index++) {
auto state = query_pool_state.GetQueryState(query_index, pass_index);
if (state == QUERYSTATE_AVAILABLE) {
submitted++;
}
}
if (submitted < query_pool_state.n_performance_passes) {
const char *vuid = loc.function == Func::vkGetQueryPoolResults ? "VUID-vkGetQueryPoolResults-queryType-03231"
: "VUID-vkCmdCopyQueryPoolResults-queryType-03234";
skip |= LogError(vuid, query_pool_state.pool(), loc.dot(Field::queryPool),
"(%s) has %u performance query passes, but the query has only been "
"submitted for %u of the passes.",
FormatHandle(query_pool_state).c_str(), query_pool_state.n_performance_passes, submitted);
}
}
return skip;
}
bool CoreChecks::ValidateQueryPoolWasReset(const QUERY_POOL_STATE &query_pool_state, uint32_t firstQuery, uint32_t queryCount,
const Location &loc, QueryMap *localQueryToStateMap, uint32_t perfPass) const {
bool skip = false;
for (uint32_t i = firstQuery; i < firstQuery + queryCount; ++i) {
if (localQueryToStateMap &&
GetLocalQueryState(localQueryToStateMap, query_pool_state.pool(), i, perfPass) != QUERYSTATE_UNKNOWN) {
continue;
}
if (query_pool_state.GetQueryState(i, 0u) == QUERYSTATE_UNKNOWN) {
skip |= LogError(kVUID_Core_QueryPool_NotReset, query_pool_state.pool(), loc.dot(Field::queryPool),
"%s and query %" PRIu32
": query not reset. After query pool creation, each query must be reset before it is used. Queries "
"must also be reset between uses.",
FormatHandle(query_pool_state.pool()).c_str(), i);
break;
}
}
return skip;
}
bool CoreChecks::PreCallValidateGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride,
VkQueryResultFlags flags, const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
bool skip = false;
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
skip |= ValidateQueryPoolIndex(query_pool_state, firstQuery, queryCount, error_obj.location,
"VUID-vkGetQueryPoolResults-firstQuery-00813", "VUID-vkGetQueryPoolResults-firstQuery-00816");
if (query_pool_state.createInfo.queryType != VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
skip |= ValidateQueryPoolStride("VUID-vkGetQueryPoolResults-flags-02828", "VUID-vkGetQueryPoolResults-flags-00815", stride,
"dataSize", dataSize, flags, error_obj.location);
}
if ((query_pool_state.createInfo.queryType == VK_QUERY_TYPE_TIMESTAMP) && (flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
skip |= LogError("VUID-vkGetQueryPoolResults-queryType-00818", queryPool, error_obj.location.dot(Field::flags),
"(%s) includes VK_QUERY_RESULT_PARTIAL_BIT, but queryPool (%s) was created with a queryType of "
"VK_QUERY_TYPE_TIMESTAMP.",
string_VkQueryResultFlags(flags).c_str(), FormatHandle(queryPool).c_str());
}
if (query_pool_state.createInfo.queryType == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR &&
(flags & VK_QUERY_RESULT_WITH_STATUS_BIT_KHR) == 0) {
skip |= LogError("VUID-vkGetQueryPoolResults-queryType-04810", queryPool, error_obj.location.dot(Field::flags),
"(%s) doesn't have VK_QUERY_RESULT_WITH_STATUS_BIT_KHR, but queryPool %s was created with "
"VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR "
"queryType.",
string_VkQueryResultFlags(flags).c_str(), FormatHandle(queryPool).c_str());
}
if (skip) {
return skip;
}
uint32_t query_avail_data = (flags & (VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | VK_QUERY_RESULT_WITH_STATUS_BIT_KHR)) ? 1 : 0;
uint32_t query_size_in_bytes = (flags & VK_QUERY_RESULT_64_BIT) ? sizeof(uint64_t) : sizeof(uint32_t);
uint32_t query_items = 0;
uint32_t query_size = 0;
switch (query_pool_state.createInfo.queryType) {
case VK_QUERY_TYPE_OCCLUSION:
// Occlusion queries write one integer value - the number of samples passed.
query_items = 1;
query_size = query_size_in_bytes * (query_items + query_avail_data);
break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS:
// Pipeline statistics queries write one integer value for each bit that is enabled in the pipelineStatistics
// when the pool is created
{
query_items = GetBitSetCount(query_pool_state.createInfo.pipelineStatistics);
query_size = query_size_in_bytes * (query_items + query_avail_data);
}
break;
case VK_QUERY_TYPE_TIMESTAMP:
// Timestamp queries write one integer
query_items = 1;
query_size = query_size_in_bytes * (query_items + query_avail_data);
break;
case VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR:
// Result status only writes only status
query_items = 0;
query_size = query_size_in_bytes * (query_items + query_avail_data);
break;
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
// Transform feedback queries write two integers
query_items = 2;
query_size = query_size_in_bytes * (query_items + query_avail_data);
break;
case VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR:
// Performance queries store results in a tightly packed array of VkPerformanceCounterResultsKHR
query_items = query_pool_state.perf_counter_index_count;
query_size = sizeof(VkPerformanceCounterResultKHR) * query_items;
if (query_size > stride) {
skip |= LogError("VUID-vkGetQueryPoolResults-queryType-04519", queryPool, error_obj.location.dot(Field::queryPool),
"(%s) specified stride %" PRIu64
" which must be at least counterIndexCount (%d) "
"multiplied by sizeof(VkPerformanceCounterResultKHR) (%zu).",
FormatHandle(queryPool).c_str(), stride, query_items, sizeof(VkPerformanceCounterResultKHR));
}
if ((((uintptr_t)pData) % sizeof(VkPerformanceCounterResultKHR)) != 0 ||
(stride % sizeof(VkPerformanceCounterResultKHR)) != 0) {
skip |= LogError("VUID-vkGetQueryPoolResults-queryType-03229", queryPool, error_obj.location.dot(Field::queryPool),
"(%s) was created with a queryType of "
"VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR but pData & stride are not multiple of the "
"size of VkPerformanceCounterResultKHR.",
FormatHandle(queryPool).c_str());
}
skip |= ValidatePerformanceQueryResults(query_pool_state, firstQuery, queryCount, flags, error_obj.location);
break;
// These cases intentionally fall through to the default
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR: // VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR:
case VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL:
default:
query_size = 0;
break;
}
if (query_size && (((queryCount - 1) * stride + query_size) > dataSize)) {
skip |= LogError("VUID-vkGetQueryPoolResults-dataSize-00817", queryPool, error_obj.location.dot(Field::queryPool),
"(%s) specified dataSize %zu which is "
"incompatible with the specified query type and options.",
FormatHandle(queryPool).c_str(), dataSize);
}
skip |= ValidateQueryPoolWasReset(query_pool_state, firstQuery, queryCount, error_obj.location, nullptr, 0u);
return skip;
}
bool CoreChecks::PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool,
const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
bool skip = false;
const Location create_info_loc = error_obj.location.dot(Field::pCreateInfo);
switch (pCreateInfo->queryType) {
case VK_QUERY_TYPE_PIPELINE_STATISTICS: {
if (!enabled_features.core.pipelineStatisticsQuery) {
skip |= LogError("VUID-VkQueryPoolCreateInfo-queryType-00791", device, create_info_loc.dot(Field::queryType),
"is VK_QUERY_TYPE_PIPELINE_STATISTICS but pipelineStatisticsQuery feature was not enabled.");
} else if ((pCreateInfo->pipelineStatistics & (VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT |
VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT)) &&
!enabled_features.mesh_shader_features.meshShaderQueries) {
skip |= LogError("VUID-VkQueryPoolCreateInfo-meshShaderQueries-07069", device,
create_info_loc.dot(Field::pipelineStatistics),
"(%s) contains mesh/task shader bit, but "
"meshShaderQueries feature was not enabled.",
string_VkQueryPipelineStatisticFlags(pCreateInfo->pipelineStatistics).c_str());
}
break;
}
case VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR: {
if (!enabled_features.performance_query_features.performanceCounterQueryPools) {
skip |=
LogError("VUID-VkQueryPoolPerformanceCreateInfoKHR-performanceCounterQueryPools-03237", device,
create_info_loc.dot(Field::queryType),
"is VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR but performanceCounterQueryPools feature was not enabled.");
}
auto perf_ci = vku::FindStructInPNextChain<VkQueryPoolPerformanceCreateInfoKHR>(pCreateInfo->pNext);
if (!perf_ci) {
skip |= LogError("VUID-VkQueryPoolCreateInfo-queryType-03222", device, create_info_loc.dot(Field::queryType),
"is VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR, but the pNext does not contain in instance of "
"VkQueryPoolPerformanceCreateInfoKHR.");
} else {
const auto &perf_counter_iter = physical_device_state->perf_counters.find(perf_ci->queueFamilyIndex);
if (perf_counter_iter == physical_device_state->perf_counters.end()) {
skip |= LogError("VUID-VkQueryPoolPerformanceCreateInfoKHR-queueFamilyIndex-03236", device,
create_info_loc.pNext(Struct::VkQueryPoolPerformanceCreateInfoKHR, Field::queueFamilyIndex),
"(%" PRIu32 ") is not a valid queue family index.", perf_ci->queueFamilyIndex);
} else {
const QUEUE_FAMILY_PERF_COUNTERS *perf_counters = perf_counter_iter->second.get();
for (uint32_t idx = 0; idx < perf_ci->counterIndexCount; idx++) {
if (perf_ci->pCounterIndices[idx] >= perf_counters->counters.size()) {
skip |= LogError(
"VUID-VkQueryPoolPerformanceCreateInfoKHR-pCounterIndices-03321", device,
create_info_loc.pNext(Struct::VkQueryPoolPerformanceCreateInfoKHR, Field::pCounterIndices, idx),
"(%" PRIu32 ") is not a valid counter index.", perf_ci->pCounterIndices[idx]);
}
}
}
}
break;
}
case VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR: {
auto video_profile = vku::FindStructInPNextChain<VkVideoProfileInfoKHR>(pCreateInfo->pNext);
if (video_profile) {
skip |= ValidateVideoProfileInfo(video_profile, device, "vkCreateQueryPool",
"the VkVideoProfileInfoKHR structure included in the pCreateInfo->pNext chain");
}
break;
}
case VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT: {
if (!enabled_features.mesh_shader_features.meshShaderQueries) {
skip |=
LogError("VUID-VkQueryPoolCreateInfo-meshShaderQueries-07068", device, create_info_loc.dot(Field::queryType),
"is VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT but meshShaderQueries feature was not enabled.");
}
break;
}
default:
break;
}
return skip;
}
bool CoreChecks::ValidateCmdQueueFlags(const CMD_BUFFER_STATE &cb_state, const Location &loc, VkQueueFlags required_flags,
const char *vuid) const {
auto pool = cb_state.command_pool;
if (pool) {
const uint32_t queue_family_index = pool->queueFamilyIndex;
const VkQueueFlags queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
if (!(required_flags & queue_flags)) {
std::string required_flags_string;
for (const auto &flag : AllVkQueueFlags) {
if (flag & required_flags) {
if (required_flags_string.size()) {
required_flags_string += " or ";
}
required_flags_string += string_VkQueueFlagBits(flag);
}
}
return LogError(vuid, cb_state.commandBuffer(), loc,
"Called in command buffer %s which was allocated from the command pool %s which was created with "
"queueFamilyIndex %u which contains the capability flags %s (but requires %s).",
FormatHandle(cb_state).c_str(), FormatHandle(pool->commandPool()).c_str(), queue_family_index,
string_VkQueueFlags(queue_flags).c_str(), required_flags_string.c_str());
}
}
return false;
}
bool CoreChecks::ValidateBeginQuery(const CMD_BUFFER_STATE &cb_state, const QueryObject &query_obj, VkQueryControlFlags flags,
uint32_t index, const Location &loc, const ValidateBeginQueryVuids *vuids) const {
bool skip = false;
auto query_pool_state = Get<QUERY_POOL_STATE>(query_obj.pool);
const auto &query_pool_ci = query_pool_state->createInfo;
switch (query_pool_ci.queryType) {
case VK_QUERY_TYPE_TIMESTAMP: {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError("VUID-vkCmdBeginQuery-queryType-02804", objlist, loc.dot(Field::queryPool),
"(%s) was created with VK_QUERY_TYPE_TIMESTAMP.", FormatHandle(query_obj.pool).c_str());
break;
}
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT: {
// There are tighter queue constraints to test for certain query pools
skip |= ValidateCmdQueueFlags(cb_state, loc, VK_QUEUE_GRAPHICS_BIT, vuids->vuid_queue_feedback);
if (!phys_dev_ext_props.transform_feedback_props.transformFeedbackQueries) {
const char *vuid = loc.function == Func::vkCmdBeginQueryIndexedEXT
? "VUID-vkCmdBeginQueryIndexedEXT-queryType-02341"
: "VUID-vkCmdBeginQuery-queryType-02328";
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuid, objlist, loc.dot(Field::queryPool),
"(%s) was created with queryType VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, but "
"VkPhysicalDeviceTransformFeedbackPropertiesEXT::transformFeedbackQueries is not supported.",
FormatHandle(query_obj.pool).c_str());
}
break;
}
case VK_QUERY_TYPE_OCCLUSION:
skip |= ValidateCmdQueueFlags(cb_state, loc, VK_QUEUE_GRAPHICS_BIT, vuids->vuid_queue_occlusion);
break;
case VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR: {
if (!cb_state.performance_lock_acquired) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_profile_lock, objlist, loc,
"profiling lock must be held before vkBeginCommandBuffer is called on "
"a command buffer where performance queries are recorded.");
}
if (query_pool_state->has_perf_scope_command_buffer && cb_state.command_count > 0) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_scope_not_first, objlist, loc.dot(Field::queryPool),
"(%s) was created with a counter of scope "
"VK_QUERY_SCOPE_COMMAND_BUFFER_KHR but %s is not the first recorded "
"command in the command buffer.",
FormatHandle(query_obj.pool).c_str(), loc.StringFunc());
}
if (query_pool_state->has_perf_scope_render_pass && cb_state.activeRenderPass) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_scope_in_rp, objlist, loc.dot(Field::queryPool),
"(%s) was created with a counter of scope "
"VK_QUERY_SCOPE_RENDER_PASS_KHR but %s is inside a render pass.",
FormatHandle(query_obj.pool).c_str(), loc.StringFunc());
}
} break;
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR:
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR: {
const char *vuid = loc.function == Func::vkCmdBeginQueryIndexedEXT ? "VUID-vkCmdBeginQueryIndexedEXT-queryType-04728"
: "VUID-vkCmdBeginQuery-queryType-04728";
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuid, objlist, loc.dot(Field::queryPool), "(%s) was created with queryType %s.",
FormatHandle(query_obj.pool).c_str(), string_VkQueryType(query_pool_ci.queryType));
break;
}
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV: {
const char *vuid = loc.function == Func::vkCmdBeginQueryIndexedEXT ? "VUID-vkCmdBeginQueryIndexedEXT-queryType-04729"
: "VUID-vkCmdBeginQuery-queryType-04729";
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuid, objlist, loc.dot(Field::queryPool), "(%s) was created with queryType %s.",
FormatHandle(query_obj.pool).c_str(), string_VkQueryType(query_pool_ci.queryType));
break;
}
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR:
case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR: {
const char *vuid = loc.function == Func::vkCmdBeginQueryIndexedEXT ? "VUID-vkCmdBeginQueryIndexedEXT-queryType-06741"
: "VUID-vkCmdBeginQuery-queryType-06741";
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuid, objlist, loc.dot(Field::queryPool), "(%s) was created with queryType %s.",
FormatHandle(query_obj.pool).c_str(), string_VkQueryType(query_pool_ci.queryType));
break;
}
case VK_QUERY_TYPE_PIPELINE_STATISTICS: {
if ((cb_state.command_pool->queue_flags & VK_QUEUE_GRAPHICS_BIT) == 0) {
if (query_pool_ci.pipelineStatistics &
(VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT |
VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT |
VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT |
VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT |
VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT |
VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT |
VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT |
VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT |
VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT)) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(
vuids->vuid_graphics_support, objlist, loc.dot(Field::queryPool),
"(%s) was created with queryType VK_QUERY_TYPE_PIPELINE_STATISTICS (%s) and indicates graphics operations, "
"but "
"the command pool the command buffer %s was allocated from does not support graphics operations (%s).",
FormatHandle(query_obj.pool).c_str(),
string_VkQueryPipelineStatisticFlags(query_pool_ci.pipelineStatistics).c_str(),
FormatHandle(cb_state).c_str(), string_VkQueueFlags(cb_state.command_pool->queue_flags).c_str());
}
}
if ((cb_state.command_pool->queue_flags & VK_QUEUE_COMPUTE_BIT) == 0) {
if (query_pool_ci.pipelineStatistics & VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(
vuids->vuid_compute_support, objlist, loc.dot(Field::queryPool),
"(%s) was created with queryType VK_QUERY_TYPE_PIPELINE_STATISTICS (%s) and indicates compute operations, "
"but "
"the command pool the command buffer %s was allocated from does not support compute operations (%s).",
FormatHandle(query_obj.pool).c_str(),
string_VkQueryPipelineStatisticFlags(query_pool_ci.pipelineStatistics).c_str(),
FormatHandle(cb_state).c_str(), string_VkQueueFlags(cb_state.command_pool->queue_flags).c_str());
}
}
break;
}
case VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT: {
if ((cb_state.command_pool->queue_flags & VK_QUEUE_GRAPHICS_BIT) == 0) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |=
LogError(vuids->vuid_primitives_generated, objlist, loc.dot(Field::queryPool),
"(%s) was created with queryType VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT, but "
"the command pool the command buffer %s was allocated from does not support graphics operations (%s).",
FormatHandle(query_obj.pool).c_str(), FormatHandle(cb_state).c_str(),
string_VkQueueFlags(cb_state.command_pool->queue_flags).c_str());
}
break;
}
case VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR: {
const auto &qf_ext_props = queue_family_ext_props[cb_state.command_pool->queueFamilyIndex];
if (!qf_ext_props.query_result_status_props.queryResultStatusSupport) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_result_status_support, objlist, loc,
"the command pool's queue family (index %u) the command buffer %s was allocated "
"from does not support result status queries.",
cb_state.command_pool->queueFamilyIndex, FormatHandle(cb_state).c_str());
}
break;
}
case VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT: {
if (loc.function == Func::vkCmdBeginQueryIndexedEXT) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError("VUID-vkCmdBeginQueryIndexedEXT-queryType-07071", objlist, loc.dot(Field::queryPool),
"(%s) was created with queryType %s.", FormatHandle(query_obj.pool).c_str(),
string_VkQueryType(query_pool_ci.queryType));
} else {
skip |= ValidateCmdQueueFlags(cb_state, loc, VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdBeginQuery-queryType-07070");
}
break;
}
default:
break;
}
// Check for nested queries
if (cb_state.activeQueries.size()) {
for (const auto &active_query_obj : cb_state.activeQueries) {
auto active_query_pool_state = Get<QUERY_POOL_STATE>(active_query_obj.pool);
if (active_query_pool_state->createInfo.queryType == query_pool_ci.queryType && active_query_obj.index == index) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool, active_query_obj.pool);
skip |= LogError(vuids->vuid_dup_query_type, objlist, loc,
"Within the same command buffer %s, query %d from pool %s has same queryType as active query "
"%d from pool %s.",
FormatHandle(cb_state).c_str(), query_obj.index, FormatHandle(query_obj.pool).c_str(),
active_query_obj.index, FormatHandle(active_query_obj.pool).c_str());
}
}
}
if (flags & VK_QUERY_CONTROL_PRECISE_BIT) {
if (!enabled_features.core.occlusionQueryPrecise) {
skip |= LogError(vuids->vuid_precise, cb_state.commandBuffer(), loc.dot(Field::flags),
"includes VK_QUERY_CONTROL_PRECISE_BIT, but occlusionQueryPrecise feature was not enabled.");
}
if (query_pool_ci.queryType != VK_QUERY_TYPE_OCCLUSION) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_precise, objlist, loc.dot(Field::flags),
"includes VK_QUERY_CONTROL_PRECISE_BIT provided, but pool query type is not VK_QUERY_TYPE_OCCLUSION.");
}
}
if (query_obj.slot >= query_pool_ci.queryCount) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_query_count, objlist, loc,
"Query index %" PRIu32 " must be less than query count %" PRIu32 " of %s.", query_obj.slot,
query_pool_ci.queryCount, FormatHandle(query_obj.pool).c_str());
}
if (cb_state.unprotected == false) {
skip |= LogError(vuids->vuid_protected_cb, cb_state.commandBuffer(), loc,
"command can't be used in protected command buffers.");
}
if (cb_state.activeRenderPass) {
const auto *render_pass_info = cb_state.activeRenderPass->createInfo.ptr();
if (!cb_state.activeRenderPass->UsesDynamicRendering()) {
const auto *subpass_desc = &render_pass_info->pSubpasses[cb_state.GetActiveSubpass()];
if (subpass_desc) {
uint32_t bits = GetBitSetCount(subpass_desc->viewMask);
if (query_obj.slot + bits > query_pool_state->createInfo.queryCount) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_multiview_query, objlist, loc,
"query (%" PRIu32 ") + bits set in current subpass view mask (%" PRIx32
") is greater than the number of queries in queryPool (%" PRIu32 ").",
query_obj.slot, subpass_desc->viewMask, query_pool_state->createInfo.queryCount);
}
}
}
}
if (cb_state.bound_video_session) {
if (cb_state.activeQueries.size() > 0) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(cb_state.bound_video_session->Handle());
skip |= LogError(vuids->vuid_no_active_in_vc_scope, objlist, loc,
"cannot start another query while there is already an active query in a "
"video coding scope (%s is bound)",
FormatHandle(cb_state.bound_video_session->videoSession()).c_str());
}
if (cb_state.bound_video_session->profile != query_pool_state->supported_video_profile) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(query_pool_state->pool());
objlist.add(cb_state.bound_video_session->Handle());
skip |= LogError(vuids->vuid_result_status_profile_in_vc_scope, objlist, loc,
"the video profile %s was created with does not match the video profile of %s",
FormatHandle(query_pool_state->pool()).c_str(),
FormatHandle(cb_state.bound_video_session->videoSession()).c_str());
}
if (query_pool_ci.queryType != VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) {
LogObjectList objlist(cb_state.commandBuffer());
objlist.add(cb_state.bound_video_session->Handle());
skip |= LogError(vuids->vuid_vc_scope_query_type, objlist, loc,
"invalid query type used in a video coding scope (%s is bound)",
FormatHandle(cb_state.bound_video_session->videoSession()).c_str());
}
}
return skip;
}
bool CoreChecks::PreCallValidateCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
VkQueryControlFlags flags, const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
bool skip = false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
QueryObject query_obj = {queryPool, slot};
auto query_pool_state = Get<QUERY_POOL_STATE>(query_obj.pool);
if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT) {
if (!enabled_features.primitives_generated_query_features.primitivesGeneratedQuery) {
skip |= LogError("VUID-vkCmdBeginQuery-queryType-06688", device, error_obj.location.dot(Field::queryPool),
"was created with a queryType VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT, but "
"primitivesGeneratedQuery feature was not enabled.");
}
}
struct BeginQueryVuids : ValidateBeginQueryVuids {
BeginQueryVuids() : ValidateBeginQueryVuids() {
vuid_queue_feedback = "VUID-vkCmdBeginQuery-queryType-02327";
vuid_queue_occlusion = "VUID-vkCmdBeginQuery-queryType-00803";
vuid_precise = "VUID-vkCmdBeginQuery-queryType-00800";
vuid_query_count = "VUID-vkCmdBeginQuery-query-00802";
vuid_profile_lock = "VUID-vkCmdBeginQuery-queryPool-03223";
vuid_scope_not_first = "VUID-vkCmdBeginQuery-queryPool-03224";
vuid_scope_in_rp = "VUID-vkCmdBeginQuery-queryPool-03225";
vuid_dup_query_type = "VUID-vkCmdBeginQuery-queryPool-01922";
vuid_protected_cb = "VUID-vkCmdBeginQuery-commandBuffer-01885";
vuid_multiview_query = "VUID-vkCmdBeginQuery-query-00808";
vuid_graphics_support = "VUID-vkCmdBeginQuery-queryType-00804";
vuid_compute_support = "VUID-vkCmdBeginQuery-queryType-00805";
vuid_primitives_generated = "VUID-vkCmdBeginQuery-queryType-06687";
vuid_result_status_support = "VUID-vkCmdBeginQuery-queryType-07126";
vuid_no_active_in_vc_scope = "VUID-vkCmdBeginQuery-None-07127";
vuid_result_status_profile_in_vc_scope = "VUID-vkCmdBeginQuery-queryType-07128";
vuid_vc_scope_query_type = "VUID-vkCmdBeginQuery-queryType-07131";
}
};
BeginQueryVuids vuids;
skip |= ValidateBeginQuery(*cb_state, query_obj, flags, 0, error_obj.location, &vuids);
skip |= ValidateCmd(*cb_state, error_obj.location);
return skip;
}
bool CoreChecks::VerifyQueryIsReset(const CMD_BUFFER_STATE &cb_state, const QueryObject &query_obj, Func command,
VkQueryPool &firstPerfQueryPool, uint32_t perfPass, QueryMap *localQueryToStateMap) {
bool skip = false;
auto state_data = cb_state.dev_data;
auto query_pool_state = state_data->Get<QUERY_POOL_STATE>(query_obj.pool);
const auto &query_pool_ci = query_pool_state->createInfo;
QueryState state = GetLocalQueryState(localQueryToStateMap, query_obj.pool, query_obj.slot, perfPass);
// If reset was in another command buffer, check the global map
if (state == QUERYSTATE_UNKNOWN) {
state = query_pool_state->GetQueryState(query_obj.slot, perfPass);
}
// Performance queries have limitation upon when they can be
// reset.
if (query_pool_ci.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR && state == QUERYSTATE_UNKNOWN &&
perfPass >= query_pool_state->n_performance_passes) {
// If the pass is invalid, assume RESET state, another error
// will be raised in ValidatePerformanceQuery().
state = QUERYSTATE_RESET;
}
if (state != QUERYSTATE_RESET) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
const Location loc(command);
const char *vuid = (command == Func::vkCmdBeginQuery) ? "VUID-vkCmdBeginQuery-None-00807"
: (command == Func::vkCmdBeginQueryIndexedEXT) ? "VUID-vkCmdBeginQueryIndexedEXT-None-00807"
: (command == Func::vkCmdWriteTimestamp) ? "VUID-vkCmdWriteTimestamp-None-00830"
: "VUID-vkCmdWriteTimestamp2-None-03864";
skip |= state_data->LogError(vuid, objlist, loc,
"%s and query %" PRIu32
": query not reset. "
"After query pool creation, each query must be reset before it is used. "
"Queries must also be reset between uses.",
state_data->FormatHandle(query_obj.pool).c_str(), query_obj.slot);
}
return skip;
}
bool CoreChecks::ValidatePerformanceQuery(const CMD_BUFFER_STATE &cb_state, const QueryObject &query_obj, Func command,
VkQueryPool &firstPerfQueryPool, uint32_t perfPass, QueryMap *localQueryToStateMap) {
auto state_data = cb_state.dev_data;
auto query_pool_state = state_data->Get<QUERY_POOL_STATE>(query_obj.pool);
const auto &query_pool_ci = query_pool_state->createInfo;
const Location loc(command);
if (query_pool_ci.queryType != VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) return false;
bool skip = false;
if (perfPass >= query_pool_state->n_performance_passes) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= state_data->LogError("VUID-VkPerformanceQuerySubmitInfoKHR-counterPassIndex-03221", objlist, loc,
"Invalid counterPassIndex (%u, maximum allowed %u) value for query pool %s.", perfPass,
query_pool_state->n_performance_passes, state_data->FormatHandle(query_obj.pool).c_str());
}
if (!cb_state.performance_lock_acquired || cb_state.performance_lock_released) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= state_data->LogError("VUID-vkQueueSubmit-pCommandBuffers-03220", objlist, loc,
"Commandbuffer %s was submitted and contains a performance query but the"
"profiling lock was not held continuously throughout the recording of commands.",
state_data->FormatHandle(cb_state).c_str());
}
QueryState command_buffer_state = GetLocalQueryState(localQueryToStateMap, query_obj.pool, query_obj.slot, perfPass);
if (command_buffer_state == QUERYSTATE_RESET) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= state_data->LogError(
query_obj.indexed ? "VUID-vkCmdBeginQueryIndexedEXT-None-02863" : "VUID-vkCmdBeginQuery-None-02863", objlist, loc,
"VkQuery begin command recorded in a command buffer that, either directly or "
"through secondary command buffers, also contains a vkCmdResetQueryPool command "
"affecting the same query.");
}
if (firstPerfQueryPool != VK_NULL_HANDLE) {
if (firstPerfQueryPool != query_obj.pool &&
!state_data->enabled_features.performance_query_features.performanceCounterMultipleQueryPools) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= state_data->LogError(
query_obj.indexed ? "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03226" : "VUID-vkCmdBeginQuery-queryPool-03226",
objlist, loc,
"Commandbuffer %s contains more than one performance query pool but "
"performanceCounterMultipleQueryPools is not enabled.",
state_data->FormatHandle(cb_state).c_str());
}
} else {
firstPerfQueryPool = query_obj.pool;
}
return skip;
}
void CoreChecks::EnqueueVerifyBeginQuery(VkCommandBuffer command_buffer, const QueryObject &query_obj, Func command) {
auto cb_state = GetWrite<CMD_BUFFER_STATE>(command_buffer);
// Enqueue the submit time validation here, ahead of the submit time state update in the StateTracker's PostCallRecord
cb_state->queryUpdates.emplace_back([query_obj, command](CMD_BUFFER_STATE &cb_state_arg, bool do_validate,
VkQueryPool &firstPerfQueryPool, uint32_t perfPass,
QueryMap *localQueryToStateMap) {
if (!do_validate) return false;
bool skip = false;
skip |= ValidatePerformanceQuery(cb_state_arg, query_obj, command, firstPerfQueryPool, perfPass, localQueryToStateMap);
skip |= VerifyQueryIsReset(cb_state_arg, query_obj, command, firstPerfQueryPool, perfPass, localQueryToStateMap);
return skip;
});
}
void CoreChecks::PreCallRecordCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
VkQueryControlFlags flags) {
if (disabled[query_validation]) return;
QueryObject query_obj = {queryPool, slot};
EnqueueVerifyBeginQuery(commandBuffer, query_obj, Func::vkCmdBeginQuery);
}
void CoreChecks::EnqueueVerifyEndQuery(CMD_BUFFER_STATE &cb_state, const QueryObject &query_obj, Func command) {
// Enqueue the submit time validation here, ahead of the submit time state update in the StateTracker's PostCallRecord
cb_state.queryUpdates.emplace_back([this, query_obj, command](CMD_BUFFER_STATE &cb_state_arg, bool do_validate,
VkQueryPool &firstPerfQueryPool, uint32_t perfPass,
QueryMap *localQueryToStateMap) {
if (!do_validate) return false;
bool skip = false;
// NOTE: dev_data == this, but the compiler "Visual Studio 16" complains Get is ambiguous if dev_data isn't used
auto query_pool_state = cb_state_arg.dev_data->Get<QUERY_POOL_STATE>(query_obj.pool);
if (query_pool_state->has_perf_scope_command_buffer && (cb_state_arg.command_count - 1) != query_obj.end_command_index) {
const LogObjectList objlist(cb_state_arg.commandBuffer(), query_pool_state->pool());
const Location loc(command);
skip |= LogError("VUID-vkCmdEndQuery-queryPool-03227", objlist, loc,
"Query pool %s was created with a counter of scope "
"VK_QUERY_SCOPE_COMMAND_BUFFER_KHR but the end of the query is not the last "
"command in the command buffer %s.",
FormatHandle(query_obj.pool).c_str(), FormatHandle(cb_state_arg).c_str());
}
return skip;
});
}
bool CoreChecks::ValidateCmdEndQuery(const CMD_BUFFER_STATE &cb_state, const QueryObject &query_obj, uint32_t index,
const Location &loc, const ValidateEndQueryVuids *vuids) const {
bool skip = false;
if (!cb_state.activeQueries.count(query_obj)) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_active_queries, objlist, loc, "Ending a query before it was started: %s, index %d.",
FormatHandle(query_obj.pool).c_str(), query_obj.slot);
}
auto query_pool_state = Get<QUERY_POOL_STATE>(query_obj.pool);
const auto &query_pool_ci = query_pool_state->createInfo;
if (query_pool_ci.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
if (query_pool_state->has_perf_scope_render_pass && cb_state.activeRenderPass) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError("VUID-vkCmdEndQuery-queryPool-03228", objlist, loc,
"Query pool %s was created with a counter of scope "
"VK_QUERY_SCOPE_RENDER_PASS_KHR but %s is inside a render pass.",
FormatHandle(query_obj.pool).c_str(), loc.StringFunc());
}
}
if (cb_state.unprotected == false) {
skip |= LogError(vuids->vuid_protected_cb, cb_state.commandBuffer(), loc,
"command can't be used in protected command buffers.");
}
if (cb_state.activeRenderPass) {
const auto *render_pass_info = cb_state.activeRenderPass->createInfo.ptr();
if (!cb_state.activeRenderPass->UsesDynamicRendering()) {
const auto *subpass_desc = &render_pass_info->pSubpasses[cb_state.GetActiveSubpass()];
if (subpass_desc) {
const uint32_t bits = GetBitSetCount(subpass_desc->viewMask);
if (query_obj.slot + bits > query_pool_state->createInfo.queryCount) {
const LogObjectList objlist(cb_state.commandBuffer(), query_obj.pool);
skip |= LogError(vuids->vuid_multiview_query, objlist, loc,
"query (%" PRIu32 ") + bits set in current subpass view mask (%" PRIx32
") is greater than the number of queries in queryPool (%" PRIu32 ").",
query_obj.slot, subpass_desc->viewMask, query_pool_state->createInfo.queryCount);
}
}
}
}
return skip;
}
bool CoreChecks::PreCallValidateCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
bool skip = false;
QueryObject query_obj = {queryPool, slot};
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
const uint32_t available_query_count = query_pool_state.createInfo.queryCount;
// Only continue validating if the slot is even within range
if (slot >= available_query_count) {
const LogObjectList objlist(commandBuffer, query_obj.pool);
skip |= LogError("VUID-vkCmdEndQuery-query-00810", objlist, error_obj.location.dot(Field::query),
"(%u) is greater or equal to the queryPool size (%u).", slot, available_query_count);
} else {
struct EndQueryVuids : ValidateEndQueryVuids {
EndQueryVuids() : ValidateEndQueryVuids() {
vuid_active_queries = "VUID-vkCmdEndQuery-None-01923";
vuid_protected_cb = "VUID-vkCmdEndQuery-commandBuffer-01886";
vuid_multiview_query = "VUID-vkCmdEndQuery-query-00812";
}
};
EndQueryVuids vuids;
skip |= ValidateCmdEndQuery(*cb_state, query_obj, 0, error_obj.location, &vuids);
skip |= ValidateCmd(*cb_state, error_obj.location);
}
return skip;
}
void CoreChecks::PreCallRecordCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
if (disabled[query_validation]) return;
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
QueryObject query_obj = {queryPool, slot};
query_obj.end_command_index = cb_state->command_count; // off by one because cb_state hasn't recorded this yet
EnqueueVerifyEndQuery(*cb_state, query_obj, Func::vkCmdEndQuery);
}
bool CoreChecks::ValidateQueryPoolIndex(const QUERY_POOL_STATE &query_pool_state, uint32_t firstQuery, uint32_t queryCount,
const Location &loc, const char *first_vuid, const char *sum_vuid) const {
bool skip = false;
const uint32_t available_query_count = query_pool_state.createInfo.queryCount;
if (firstQuery >= available_query_count) {
skip |= LogError(first_vuid, query_pool_state.pool(), loc,
"In Query %s the firstQuery (%" PRIu32 ") is greater or equal to the queryPool size (%" PRIu32 ").",
FormatHandle(query_pool_state).c_str(), firstQuery, available_query_count);
}
if ((firstQuery + queryCount) > available_query_count) {
skip |= LogError(sum_vuid, query_pool_state.pool(), loc,
"In Query %s the sum of firstQuery (%" PRIu32 ") + queryCount (%" PRIu32
") is greater than the queryPool size (%" PRIu32 ").",
FormatHandle(query_pool_state).c_str(), firstQuery, queryCount, available_query_count);
}
return skip;
}
bool CoreChecks::ValidateQueriesNotActive(const CMD_BUFFER_STATE &cb_state, VkQueryPool queryPool, uint32_t firstQuery,
uint32_t queryCount, const Location &loc, const char *vuid) const {
bool skip = false;
for (uint32_t i = 0; i < queryCount; i++) {
const uint32_t slot = firstQuery + i;
QueryObject query_obj = {queryPool, slot};
if (cb_state.activeQueries.count(query_obj)) {
const LogObjectList objlist(cb_state.commandBuffer(), queryPool);
skip |= LogError(vuid, objlist, loc,
"Query index %" PRIu32 " is still active (firstQuery = %" PRIu32 ", queryCount = %" PRIu32 ").", slot,
firstQuery, queryCount);
}
}
return skip;
}
bool CoreChecks::PreCallValidateCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
uint32_t queryCount, const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
bool skip = false;
skip |= ValidateCmd(*cb_state, error_obj.location);
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
skip |= ValidateQueryPoolIndex(query_pool_state, firstQuery, queryCount, error_obj.location,
"VUID-vkCmdResetQueryPool-firstQuery-00796", "VUID-vkCmdResetQueryPool-firstQuery-00797");
skip |= ValidateQueriesNotActive(*cb_state, queryPool, firstQuery, queryCount, error_obj.location,
"VUID-vkCmdResetQueryPool-None-02841");
return skip;
}
void CoreChecks::PreCallRecordCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
uint32_t queryCount) {
if (disabled[query_validation]) return;
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
if (query_pool_state.createInfo.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
cb_state->queryUpdates.emplace_back([queryPool, firstQuery, queryCount](CMD_BUFFER_STATE &cb_state_arg, bool do_validate,
VkQueryPool &firstPerfQueryPool, uint32_t perfPass,
QueryMap *localQueryToStateMap) {
if (!do_validate) return false;
const auto state_data = cb_state_arg.dev_data;
bool skip = false;
for (uint32_t i = 0; i < queryCount; i++) {
QueryState state = GetLocalQueryState(localQueryToStateMap, queryPool, firstQuery + i, perfPass);
if (state == QUERYSTATE_ENDED) {
const LogObjectList objlist(cb_state_arg.commandBuffer(), queryPool);
const Location loc(Func::vkCmdResetQueryPool);
skip |= state_data->LogError("VUID-vkCmdResetQueryPool-firstQuery-02862", objlist, loc,
"Query index %" PRIu32 " was begun and reset in the same command buffer.",
firstQuery + i);
break;
}
}
return skip;
});
}
}
static QueryResultType GetQueryResultType(QueryState state, VkQueryResultFlags flags) {
switch (state) {
case QUERYSTATE_UNKNOWN:
return QUERYRESULT_UNKNOWN;
case QUERYSTATE_RESET:
case QUERYSTATE_RUNNING:
if (flags & VK_QUERY_RESULT_WAIT_BIT) {
return ((state == QUERYSTATE_RESET) ? QUERYRESULT_WAIT_ON_RESET : QUERYRESULT_WAIT_ON_RUNNING);
} else if ((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) {
return QUERYRESULT_SOME_DATA;
} else {
return QUERYRESULT_NO_DATA;
}
case QUERYSTATE_ENDED:
if ((flags & VK_QUERY_RESULT_WAIT_BIT) || (flags & VK_QUERY_RESULT_PARTIAL_BIT) ||
(flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) {
return QUERYRESULT_SOME_DATA;
} else {
return QUERYRESULT_UNKNOWN;
}
case QUERYSTATE_AVAILABLE:
return QUERYRESULT_SOME_DATA;
}
assert(false);
return QUERYRESULT_UNKNOWN;
}
bool CoreChecks::PreCallValidateCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
VkDeviceSize stride, VkQueryResultFlags flags,
const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
auto dst_buff_state = Get<BUFFER_STATE>(dstBuffer);
assert(cb_state);
assert(dst_buff_state);
const LogObjectList buffer_objlist(commandBuffer, dstBuffer);
bool skip = ValidateMemoryIsBoundToBuffer(commandBuffer, *dst_buff_state, error_obj.location.dot(Field::dstBuffer),
"VUID-vkCmdCopyQueryPoolResults-dstBuffer-00826");
skip |= ValidateQueryPoolStride("VUID-vkCmdCopyQueryPoolResults-flags-00822", "VUID-vkCmdCopyQueryPoolResults-flags-00823",
stride, "dstOffset", dstOffset, flags, error_obj.location);
// Validate that DST buffer has correct usage flags set
skip |= ValidateBufferUsageFlags(buffer_objlist, *dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
"VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825", error_obj.location.dot(Field::dstBuffer));
skip |= ValidateCmd(*cb_state, error_obj.location);
if (dstOffset >= dst_buff_state->requirements.size) {
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-dstOffset-00819", buffer_objlist, error_obj.location.dot(Field::dstOffset),
"(%" PRIu64 ") is not less than the size (%" PRIu64 ") of buffer (%s).", dstOffset,
dst_buff_state->requirements.size, FormatHandle(dst_buff_state->buffer()).c_str());
} else if (dstOffset + (queryCount * stride) > dst_buff_state->requirements.size) {
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-dstBuffer-00824", buffer_objlist, error_obj.location,
"storage required (%" PRIu64
") equal to dstOffset + (queryCount * stride) is greater than the size (%" PRIu64 ") of buffer (%s).",
dstOffset + (queryCount * stride), dst_buff_state->requirements.size,
FormatHandle(dst_buff_state->buffer()).c_str());
}
if ((flags & VK_QUERY_RESULT_WITH_STATUS_BIT_KHR) && (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) {
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-flags-06902", commandBuffer, error_obj.location.dot(Field::flags),
"(%s) include both STATUS_BIT and AVAILABILITY_BIT.", string_VkQueryResultFlags(flags).c_str());
}
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
skip |= ValidateQueryPoolIndex(query_pool_state, firstQuery, queryCount, error_obj.location,
"VUID-vkCmdCopyQueryPoolResults-firstQuery-00820",
"VUID-vkCmdCopyQueryPoolResults-firstQuery-00821");
skip |= ValidateQueriesNotActive(*cb_state, queryPool, firstQuery, queryCount, error_obj.location,
"VUID-vkCmdCopyQueryPoolResults-None-07429");
if (query_pool_state.createInfo.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
skip |= ValidatePerformanceQueryResults(query_pool_state, firstQuery, queryCount, flags, error_obj.location);
if (!phys_dev_ext_props.performance_query_props.allowCommandBufferQueryCopies) {
const LogObjectList objlist(commandBuffer, queryPool);
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-queryType-03232", objlist, error_obj.location.dot(Field::queryPool),
"(%s) was created with VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR but "
"VkPhysicalDevicePerformanceQueryPropertiesKHR::allowCommandBufferQueryCopies is not supported.",
FormatHandle(queryPool).c_str());
}
}
if ((query_pool_state.createInfo.queryType == VK_QUERY_TYPE_TIMESTAMP) && ((flags & VK_QUERY_RESULT_PARTIAL_BIT) != 0)) {
const LogObjectList objlist(commandBuffer, queryPool);
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-queryType-00827", objlist, error_obj.location.dot(Field::flags),
"(%s) includes VK_QUERY_RESULT_PARTIAL_BIT, but %s was created with VK_QUERY_TYPE_TIMESTAMP.",
string_VkQueryResultFlags(flags).c_str(), FormatHandle(queryPool).c_str());
}
if (query_pool_state.createInfo.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL) {
const LogObjectList objlist(commandBuffer, queryPool);
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-queryType-02734", objlist, error_obj.location.dot(Field::queryPool),
"(%s) was created with queryType VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL.", FormatHandle(queryPool).c_str());
}
if (query_pool_state.createInfo.queryType == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR &&
(flags & VK_QUERY_RESULT_WITH_STATUS_BIT_KHR) == 0) {
const LogObjectList objlist(commandBuffer, queryPool);
skip |= LogError("VUID-vkCmdCopyQueryPoolResults-queryType-06901", objlist, error_obj.location.dot(Field::flags),
"(%s) does not include VK_QUERY_RESULT_WITH_STATUS_BIT_KHR, but %s was created with queryType "
"VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR.",
string_VkQueryResultFlags(flags).c_str(), FormatHandle(queryPool).c_str());
}
return skip;
}
void CoreChecks::PreCallRecordCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
VkDeviceSize stride, VkQueryResultFlags flags) {
if (disabled[query_validation]) return;
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
cb_state->queryUpdates.emplace_back([queryPool, firstQuery, queryCount, flags, this](
CMD_BUFFER_STATE &cb_state_arg, bool do_validate, VkQueryPool &firstPerfQueryPool,
uint32_t perfPass, QueryMap *localQueryToStateMap) {
if (!do_validate) return false;
const auto state_data = cb_state_arg.dev_data;
bool skip = false;
const Location loc(Func::vkCmdCopyQueryPoolResults);
for (uint32_t i = 0; i < queryCount; i++) {
QueryState state = GetLocalQueryState(localQueryToStateMap, queryPool, firstQuery + i, perfPass);
QueryResultType result_type = GetQueryResultType(state, flags);
if (result_type != QUERYRESULT_SOME_DATA && result_type != QUERYRESULT_UNKNOWN) {
const LogObjectList objlist(cb_state_arg.commandBuffer(), queryPool);
skip |= state_data->LogError("VUID-vkCmdCopyQueryPoolResults-None-08752", objlist, loc,
"Requesting a copy from query to buffer on %s query %" PRIu32 ": %s",
state_data->FormatHandle(queryPool).c_str(), firstQuery + i,
string_QueryResultType(result_type));
}
}
// NOTE: dev_data == this, but the compiler "Visual Studio 16" complains Get is ambiguous if dev_data isn't used
auto query_pool_state = cb_state_arg.dev_data->Get<QUERY_POOL_STATE>(queryPool);
skip |= ValidateQueryPoolWasReset(*query_pool_state, firstQuery, queryCount, loc, localQueryToStateMap, perfPass);
return skip;
});
}
bool CoreChecks::ValidateCmdWriteTimestamp(const CMD_BUFFER_STATE &cb_state, VkQueryPool queryPool, uint32_t slot,
const Location &loc) const {
bool skip = false;
skip |= ValidateCmd(cb_state, loc);
const bool is_2 = loc.function == Func::vkCmdWriteTimestamp2 || loc.function == Func::vkCmdWriteTimestamp2KHR;
const uint32_t timestamp_valid_bits =
physical_device_state->queue_family_properties[cb_state.command_pool->queueFamilyIndex].timestampValidBits;
if (timestamp_valid_bits == 0) {
const char *vuid =
is_2 ? "VUID-vkCmdWriteTimestamp2-timestampValidBits-03863" : "VUID-vkCmdWriteTimestamp-timestampValidBits-00829";
const LogObjectList objlist(cb_state.commandBuffer(), queryPool);
skip |= LogError(vuid, objlist, loc, "Query Pool %s has a timestampValidBits value of zero for queueFamilyIndex %u.",
FormatHandle(queryPool).c_str(), cb_state.command_pool->queueFamilyIndex);
}
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
if (query_pool_state.createInfo.queryType != VK_QUERY_TYPE_TIMESTAMP) {
const char *vuid = is_2 ? "VUID-vkCmdWriteTimestamp2-queryPool-03861" : "VUID-vkCmdWriteTimestamp-queryPool-01416";
const LogObjectList objlist(cb_state.commandBuffer(), queryPool);
skip |= LogError(vuid, objlist, loc, "Query Pool %s was not created with VK_QUERY_TYPE_TIMESTAMP.",
FormatHandle(queryPool).c_str());
}
if (slot >= query_pool_state.createInfo.queryCount) {
const char *vuid = is_2 ? "VUID-vkCmdWriteTimestamp2-query-04903" : "VUID-vkCmdWriteTimestamp-query-04904";
const LogObjectList objlist(cb_state.commandBuffer(), queryPool);
skip |= LogError(vuid, objlist, loc,
"query (%" PRIu32 ") is not lower than the number of queries (%" PRIu32 ") in Query pool %s.", slot,
query_pool_state.createInfo.queryCount, FormatHandle(queryPool).c_str());
}
return skip;
}
bool CoreChecks::PreCallValidateCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
VkQueryPool queryPool, uint32_t slot, const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
bool skip = false;
skip |= ValidateCmdWriteTimestamp(*cb_state, queryPool, slot, error_obj.location);
const Location stage_loc = error_obj.location.dot(Field::pipelineStage);
skip |= ValidatePipelineStage(LogObjectList(commandBuffer), stage_loc, cb_state->GetQueueFlags(), pipelineStage);
return skip;
}
bool CoreChecks::PreCallValidateCmdWriteTimestamp2(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage,
VkQueryPool queryPool, uint32_t slot, const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
bool skip = false;
skip |= ValidateCmdWriteTimestamp(*cb_state, queryPool, slot, error_obj.location);
if (!enabled_features.core13.synchronization2) {
skip |= LogError("VUID-vkCmdWriteTimestamp2-synchronization2-03858", commandBuffer, error_obj.location,
"Synchronization2 feature is not enabled.");
}
const Location stage_loc = error_obj.location.dot(Field::stage);
if ((stage & (stage - 1)) != 0) {
skip |= LogError("VUID-vkCmdWriteTimestamp2-stage-03859", commandBuffer, stage_loc,
"(%s) must only set a single pipeline stage.", string_VkPipelineStageFlags2(stage).c_str());
}
skip |= ValidatePipelineStage(LogObjectList(commandBuffer), stage_loc, cb_state->GetQueueFlags(), stage);
return skip;
}
bool CoreChecks::PreCallValidateCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage,
VkQueryPool queryPool, uint32_t query, const ErrorObject &error_obj) const {
return PreCallValidateCmdWriteTimestamp2(commandBuffer, stage, queryPool, query, error_obj);
}
void CoreChecks::RecordCmdWriteTimestamp2(CMD_BUFFER_STATE &cb_state, VkQueryPool queryPool, uint32_t slot, Func command) const {
if (disabled[query_validation]) return;
// Enqueue the submit time validation check here, before the submit time state update in StateTracker::PostCall...
QueryObject query_obj = {queryPool, slot};
cb_state.queryUpdates.emplace_back([query_obj, command](CMD_BUFFER_STATE &cb_state_arg, bool do_validate,
VkQueryPool &firstPerfQueryPool, uint32_t perfPass,
QueryMap *localQueryToStateMap) {
if (!do_validate) return false;
return VerifyQueryIsReset(cb_state_arg, query_obj, command, firstPerfQueryPool, perfPass, localQueryToStateMap);
});
}
void CoreChecks::PreCallRecordCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
VkQueryPool queryPool, uint32_t slot) {
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
return RecordCmdWriteTimestamp2(*cb_state, queryPool, slot, Func::vkCmdWriteTimestamp);
}
void CoreChecks::PreCallRecordCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage,
VkQueryPool queryPool, uint32_t slot) {
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
return RecordCmdWriteTimestamp2(*cb_state, queryPool, slot, Func::vkCmdWriteTimestamp2KHR);
}
void CoreChecks::PreCallRecordCmdWriteTimestamp2(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage,
VkQueryPool queryPool, uint32_t slot) {
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
return RecordCmdWriteTimestamp2(*cb_state, queryPool, slot, Func::vkCmdWriteTimestamp2);
}
bool CoreChecks::PreCallValidateCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
VkQueryControlFlags flags, uint32_t index,
const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
QueryObject query_obj = {queryPool, slot, flags, 0, true, index};
struct BeginQueryIndexedVuids : ValidateBeginQueryVuids {
BeginQueryIndexedVuids() : ValidateBeginQueryVuids() {
vuid_queue_feedback = "VUID-vkCmdBeginQueryIndexedEXT-queryType-02338";
vuid_queue_occlusion = "VUID-vkCmdBeginQueryIndexedEXT-queryType-00803";
vuid_precise = "VUID-vkCmdBeginQueryIndexedEXT-queryType-00800";
vuid_query_count = "VUID-vkCmdBeginQueryIndexedEXT-query-00802";
vuid_profile_lock = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03223";
vuid_scope_not_first = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03224";
vuid_scope_in_rp = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03225";
vuid_dup_query_type = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-04753";
vuid_protected_cb = "VUID-vkCmdBeginQueryIndexedEXT-commandBuffer-01885";
vuid_multiview_query = "VUID-vkCmdBeginQueryIndexedEXT-query-00808";
vuid_graphics_support = "VUID-vkCmdBeginQueryIndexedEXT-queryType-00804";
vuid_compute_support = "VUID-vkCmdBeginQueryIndexedEXT-queryType-00805";
vuid_primitives_generated = "VUID-vkCmdBeginQueryIndexedEXT-queryType-06689";
vuid_result_status_support = "VUID-vkCmdBeginQueryIndexedEXT-queryType-07126";
vuid_no_active_in_vc_scope = "VUID-vkCmdBeginQueryIndexedEXT-None-07127";
vuid_result_status_profile_in_vc_scope = "VUID-vkCmdBeginQueryIndexedEXT-queryType-07128";
vuid_vc_scope_query_type = "VUID-vkCmdBeginQueryIndexedEXT-queryType-07131";
}
};
BeginQueryIndexedVuids vuids;
bool skip = false;
skip |= ValidateBeginQuery(*cb_state, query_obj, flags, index, error_obj.location, &vuids);
skip |= ValidateCmd(*cb_state, error_obj.location);
// Extension specific VU's
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(query_obj.pool);
const auto &query_pool_ci = query_pool_state.createInfo;
if (query_pool_ci.queryType == VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT) {
if (!enabled_features.primitives_generated_query_features.primitivesGeneratedQuery) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdBeginQueryIndexedEXT-queryType-06693", objlist, error_obj.location.dot(Field::queryPool),
"was created with queryType of VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT, "
"but the primitivesGeneratedQuery feature is not enabled.");
}
if (index >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdBeginQueryIndexedEXT-queryType-06690", objlist, error_obj.location.dot(Field::queryPool),
"was created with queryType of VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT, but "
"index (%" PRIu32
") is greater than or equal to "
"VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams (%" PRIu32 ")",
index, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
}
if ((index != 0) && (!enabled_features.primitives_generated_query_features.primitivesGeneratedQueryWithNonZeroStreams)) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdBeginQueryIndexedEXT-queryType-06691", objlist, error_obj.location.dot(Field::queryPool),
"was created with queryType of VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT, but "
"index (%" PRIu32
") is not zero and the primitivesGeneratedQueryWithNonZeroStreams feature is not enabled",
index);
}
} else if (query_pool_ci.queryType == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
if (IsExtEnabled(device_extensions.vk_ext_transform_feedback) &&
(index >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams)) {
skip |= LogError(
"VUID-vkCmdBeginQueryIndexedEXT-queryType-02339", commandBuffer, error_obj.location.dot(Field::index),
"(%" PRIu32
") must be less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams %" PRIu32 ".",
index, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
}
} else if (index != 0) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdBeginQueryIndexedEXT-queryType-06692", objlist, error_obj.location.dot(Field::index),
"(%" PRIu32
") must be zero if %s was not created with type VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT or "
"VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT",
index, FormatHandle(queryPool).c_str());
}
return skip;
}
void CoreChecks::PreCallRecordCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
VkQueryControlFlags flags, uint32_t index) {
if (disabled[query_validation]) return;
QueryObject query_obj = {queryPool, slot, flags, 0, true, index};
EnqueueVerifyBeginQuery(commandBuffer, query_obj, Func::vkCmdBeginQueryIndexedEXT);
}
void CoreChecks::PreCallRecordCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
uint32_t index) {
if (disabled[query_validation]) return;
auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer);
QueryObject query_obj = {queryPool, slot, 0, 0, true, index};
query_obj.end_command_index = cb_state->command_count; // off by one because cb_state hasn't recorded this yet
EnqueueVerifyEndQuery(*cb_state, query_obj, Func::vkCmdEndQueryIndexedEXT);
}
bool CoreChecks::PreCallValidateCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
uint32_t index, const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
QueryObject query_obj = {queryPool, slot, 0, 0, true, index};
auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
assert(cb_state);
struct EndQueryIndexedVuids : ValidateEndQueryVuids {
EndQueryIndexedVuids() : ValidateEndQueryVuids() {
vuid_active_queries = "VUID-vkCmdEndQueryIndexedEXT-None-02342";
vuid_protected_cb = "VUID-vkCmdEndQueryIndexedEXT-commandBuffer-02344";
vuid_multiview_query = "VUID-vkCmdEndQueryIndexedEXT-query-02345";
}
};
EndQueryIndexedVuids vuids;
bool skip = false;
skip |= ValidateCmdEndQuery(*cb_state, query_obj, index, error_obj.location, &vuids);
skip |= ValidateCmd(*cb_state, error_obj.location);
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
const auto &query_pool_ci = query_pool_state.createInfo;
const uint32_t available_query_count = query_pool_state.createInfo.queryCount;
if (slot >= available_query_count) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdEndQueryIndexedEXT-query-02343", objlist, error_obj.location.dot(Field::index),
"(%" PRIu32 ") is greater or equal to the queryPool size (%" PRIu32 ").", index, available_query_count);
}
if (query_pool_ci.queryType == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT ||
query_pool_ci.queryType == VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT) {
if (index >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams) {
skip |= LogError("VUID-vkCmdEndQueryIndexedEXT-queryType-06694", commandBuffer, error_obj.location.dot(Field::index),
"(%" PRIu32
") must be less than "
"VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams %" PRIu32 ".",
index, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
}
for (const auto &query_object : cb_state->startedQueries) {
if (query_object.pool == queryPool && query_object.slot == slot) {
if (query_object.index != index) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdEndQueryIndexedEXT-queryType-06696", objlist, error_obj.location,
"queryPool is of type %s, but "
"index (%" PRIu32 ") is not equal to the index used to begin the query (%" PRIu32 ")",
string_VkQueryType(query_pool_ci.queryType), index, query_object.index);
}
break;
}
}
} else if (index != 0) {
const LogObjectList objlist(commandBuffer, query_pool_state.pool());
skip |= LogError("VUID-vkCmdEndQueryIndexedEXT-queryType-06695", objlist, error_obj.location.dot(Field::index),
"(%" PRIu32
") must be zero if %s was not created with type VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT and not"
" VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT.",
index, FormatHandle(queryPool).c_str());
}
return skip;
}
bool CoreChecks::PreCallValidateResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
const ErrorObject &error_obj) const {
if (disabled[query_validation]) return false;
bool skip = false;
if (!enabled_features.core12.hostQueryReset) {
skip |= LogError("VUID-vkResetQueryPool-None-02665", device, error_obj.location, "hostQueryReset feature was not enabled.");
}
const auto &query_pool_state = *Get<QUERY_POOL_STATE>(queryPool);
if (firstQuery >= query_pool_state.createInfo.queryCount) {
skip |= LogError("VUID-vkResetQueryPool-firstQuery-02666", queryPool, error_obj.location.dot(Field::firstQuery),
"(%" PRIu32 ") is greater than or equal to query pool count (%" PRIu32 ") for %s.", firstQuery,
query_pool_state.createInfo.queryCount, FormatHandle(queryPool).c_str());
}
if ((firstQuery + queryCount) > query_pool_state.createInfo.queryCount) {
skip |= LogError("VUID-vkResetQueryPool-firstQuery-02667", queryPool, error_obj.location,
"Query range [%" PRIu32 ", %" PRIu32 ") goes beyond query pool count (%" PRIu32 ") for %s.", firstQuery,
firstQuery + queryCount, query_pool_state.createInfo.queryCount, FormatHandle(queryPool).c_str());
}
return skip;
}
bool CoreChecks::PreCallValidateResetQueryPoolEXT(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
const ErrorObject &error_obj) const {
return PreCallValidateResetQueryPool(device, queryPool, firstQuery, queryCount, error_obj);
}
bool CoreChecks::ValidateQueryPoolStride(const std::string &vuid_not_64, const std::string &vuid_64, const VkDeviceSize stride,
const char *parameter_name, const uint64_t parameter_value, const VkQueryResultFlags flags,
const Location &loc) const {
bool skip = false;
if (flags & VK_QUERY_RESULT_64_BIT) {
static const int condition_multiples = 0b0111;
if ((stride & condition_multiples) || (parameter_value & condition_multiples)) {
skip |= LogError(vuid_64, device, loc, "stride %" PRIu64 " or %s %" PRIu64 " is invalid.", stride, parameter_name,
parameter_value);
}
} else {
static const int condition_multiples = 0b0011;
if ((stride & condition_multiples) || (parameter_value & condition_multiples)) {
skip |= LogError(vuid_not_64, device, loc, "stride %" PRIu64 " or %s %" PRIu64 " is invalid.", stride, parameter_name,
parameter_value);
}
}
return skip;
}
void CoreChecks::PostCallRecordGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags,
const RecordObject &record_obj) {
if (record_obj.result != VK_SUCCESS) {
return;
}
auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
if ((flags & VK_QUERY_RESULT_PARTIAL_BIT) == 0) {
for (uint32_t i = firstQuery; i < queryCount; ++i) {
query_pool_state->SetQueryState(i, 0, QUERYSTATE_AVAILABLE);
}
}
}
bool CoreChecks::PreCallValidateReleaseProfilingLockKHR(VkDevice device, const ErrorObject &error_obj) const {
bool skip = false;
if (!performance_lock_acquired) {
skip |= LogError("VUID-vkReleaseProfilingLockKHR-device-03235", device, error_obj.location,
"The profiling lock of device must have been held via a previous successful "
"call to vkAcquireProfilingLockKHR.");
}
return skip;
}