| /* 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; |
| } |