diff --git a/layers/core_checks/cc_spirv.cpp b/layers/core_checks/cc_spirv.cpp index 1bf2c99b2b8..3672aab02c9 100644 --- a/layers/core_checks/cc_spirv.cpp +++ b/layers/core_checks/cc_spirv.cpp @@ -39,6 +39,7 @@ #include "core_validation.h" #include "generated/spirv_grammar_helper.h" #include "generated/spirv_validation_helper.h" +#include "generated/dispatch_functions.h" #include "state_tracker/shader_instruction.h" #include "state_tracker/shader_module.h" #include "state_tracker/shader_stage_state.h" @@ -3227,9 +3228,48 @@ bool CoreChecks::ValidateDataGraphConstants(const spirv::Module &module_spirv, c return skip; } +const VkQueueFamilyDataGraphPropertiesARM tosa_1_0_property { + VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM, + nullptr, + {VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM, false}, + {VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM, "TOSA.001000.1", 0} +}; + bool CoreChecks::ValidateDataGraphOperations(const vvl::Pipeline& pipeline, uint32_t queueFamilyIndex, const Location& loc) const { bool skip = false; - // TODO - https://github.com/KhronosGroup/Vulkan-ValidationLayers/pull/11713 + + const ShaderStageState *stage_state_ptr = GetDataGraphShaderStage(pipeline); + if (!stage_state_ptr) { + return skip; + } + const spirv::EntryPoint *entry_point = stage_state_ptr->entrypoint.get(); + if (!entry_point) { + return skip; + } + + // this checks only the ARM operation type with TOSA, not any of the other operation types (QCOM). + + if (!entry_point->uses_tosa_1_0) { + return skip; + } + + bool queue_uses_tosa_1_0 = false; + for (const auto& p : physical_device_state->queue_family_data_graph_properties.at(queueFamilyIndex)) { + if (CompareVkQueueFamilyDataGraphPropertiesARM(tosa_1_0_property, p)) { + queue_uses_tosa_1_0 = true; + break; + } + } + + if (!queue_uses_tosa_1_0) { + skip |= + LogError("VUID-vkCmdDispatchDataGraphARM-commandBuffer-09941", device, loc, + "Entrypoint %s includes \"TOSA.001000.1\" instructions but the queue associated with the command buffer does not include the required property:\n%s" + "vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM for queueFamilyIndex %u returned:\n%s", + entry_point->name.c_str(), string_VkQueueFamilyDataGraphPropertiesARM(tosa_1_0_property).c_str(), queueFamilyIndex, + string_VkQueueFamilyDataGraphPropertiesARM(physical_device_state->queue_family_data_graph_properties.at(queueFamilyIndex)).c_str()); + } + return skip; } diff --git a/layers/state_tracker/device_state.cpp b/layers/state_tracker/device_state.cpp index bdbbda9e6cd..6dad7c88359 100644 --- a/layers/state_tracker/device_state.cpp +++ b/layers/state_tracker/device_state.cpp @@ -54,6 +54,24 @@ const std::vector PhysicalDevice::GetQueueFamilyProps(V return result; } +const std::unordered_map> PhysicalDevice::GetQueueFamilyDataGraphProps(VkPhysicalDevice phys_dev) { + uint32_t n_families = static_cast(queue_family_properties.size()); + if (n_families == 0) { + // queue_family_properties not yet initialized. We should've done it before now, this is just in case + DispatchGetPhysicalDeviceQueueFamilyProperties(phys_dev, &n_families, nullptr); + } + + std::unordered_map> all_properties; + for (uint32_t i = 0; i < n_families; i++) { + uint32_t n_properties = 0; + assert(VK_SUCCESS == DispatchGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(phys_dev, i, &n_properties, nullptr)); + std::vector family_properties(n_properties, vku::InitStruct()); + assert(VK_SUCCESS == DispatchGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(phys_dev, i, &n_properties, family_properties.data())); + all_properties.try_emplace(i, std::move(family_properties)); + } + return all_properties; +} + VkQueueFlags PhysicalDevice::GetSupportedQueues() { VkQueueFlags flags = 0; for (const auto& prop : queue_family_properties) { @@ -65,6 +83,7 @@ VkQueueFlags PhysicalDevice::GetSupportedQueues() { PhysicalDevice::PhysicalDevice(VkPhysicalDevice handle) : StateObject(handle, kVulkanObjectTypePhysicalDevice), queue_family_properties(GetQueueFamilyProps(handle)), + queue_family_data_graph_properties(GetQueueFamilyDataGraphProps(handle)), supported_queues(GetSupportedQueues()) {} } // namespace vvl diff --git a/layers/state_tracker/device_state.h b/layers/state_tracker/device_state.h index 855152e4ba4..296a0a6d2e5 100644 --- a/layers/state_tracker/device_state.h +++ b/layers/state_tracker/device_state.h @@ -47,6 +47,8 @@ class PhysicalDevice : public StateObject { public: uint32_t queue_family_known_count = 1; // spec implies one QF must always be supported const std::vector queue_family_properties; + const std::unordered_map> queue_family_data_graph_properties; + const VkQueueFlags supported_queues; uint32_t display_plane_property_count = 0; uint32_t surface_formats_count = 0; @@ -77,6 +79,8 @@ class PhysicalDevice : public StateObject { vvl::unordered_map call_state_; const std::vector GetQueueFamilyProps(VkPhysicalDevice phys_dev); + const std::unordered_map> GetQueueFamilyDataGraphProps(VkPhysicalDevice phys_dev); + VkQueueFlags GetSupportedQueues(); }; diff --git a/layers/vulkan/generated/test_icd_helper.h b/layers/vulkan/generated/test_icd_helper.h index ffb8dc3ae0f..8b34680c12c 100644 --- a/layers/vulkan/generated/test_icd_helper.h +++ b/layers/vulkan/generated/test_icd_helper.h @@ -5969,12 +5969,6 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetDataGraphPipelinePropertiesARM(VkDevice return VK_SUCCESS; } -static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM( - VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pQueueFamilyDataGraphPropertyCount, - VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties) { - return VK_SUCCESS; -} - static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceQueueFamilyDataGraphProcessingEngineInfoARM* pQueueFamilyDataGraphProcessingEngineInfo, diff --git a/scripts/generators/test_icd_generator.py b/scripts/generators/test_icd_generator.py index 54b4a3bde34..487cd17e32e 100644 --- a/scripts/generators/test_icd_generator.py +++ b/scripts/generators/test_icd_generator.py @@ -71,6 +71,7 @@ def __init__(self): 'vkGetPhysicalDeviceExternalSemaphoreProperties', 'vkGetPhysicalDeviceExternalFenceProperties', 'vkGetPhysicalDeviceExternalBufferProperties', + 'vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM', 'vkGetBufferMemoryRequirements', 'vkGetBufferMemoryRequirements2', 'vkGetDeviceBufferMemoryRequirements', diff --git a/tests/icd/test_icd.cpp b/tests/icd/test_icd.cpp index 7d647e76f14..924d5c888b4 100644 --- a/tests/icd/test_icd.cpp +++ b/tests/icd/test_icd.cpp @@ -1454,6 +1454,20 @@ static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceExternalTensorPropertiesARM( } } +static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t *pQueueFamilyDataGraphPropertyCount, VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties) { + + // TODO: Need a way for test to decide to support or not support various engines + + if (pQueueFamilyDataGraphProperties == nullptr) { + *pQueueFamilyDataGraphPropertyCount = 1; + } else { + pQueueFamilyDataGraphProperties[0].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM; + pQueueFamilyDataGraphProperties[0].engine = { VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM, false }; + pQueueFamilyDataGraphProperties[0].operation = { VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM, "TOSA.001000.1", 0 }; + } + return VK_SUCCESS; +} + static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) { diff --git a/tests/unit/data_graph.cpp b/tests/unit/data_graph.cpp index ef11b8196bf..cebd9eda3b8 100644 --- a/tests/unit/data_graph.cpp +++ b/tests/unit/data_graph.cpp @@ -14,6 +14,7 @@ #include "descriptor_helper.h" #include "data_graph_objects.h" #include "generated/pnext_chain_extraction.h" +#include "../layers/utils/vk_struct_compare.h" #include class NegativeDataGraph : public DataGraphTest {}; @@ -2371,3 +2372,70 @@ TEST_F(NegativeDataGraph, BindWrongBindPoint) { vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline); m_errorMonitor->VerifyFound(); } + +TEST_F(NegativeDataGraph, CmdDispatchWrongQueue) { + TEST_DESCRIPTION("Try to create a datagraph where the command buffer is allocated on a queue that does not support TOSA 1.0"); + InitBasicDataGraph(); + RETURN_IF_SKIP(Init()); + + // find a queue family that does NOT support TOSA + const VkQueueFamilyDataGraphPropertiesARM tosa_1_0_property { + VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM, + nullptr, + {VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM, false}, + {VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM, "TOSA.001000.1", 0} + }; + uint32_t queue_without_tosa_1_0_idx = UINT32_MAX; + uint32_t n_queue_families; + vk::GetPhysicalDeviceQueueFamilyProperties(Gpu(), &n_queue_families, nullptr); + for (uint32_t qfi = 0; qfi < n_queue_families; qfi++) { + uint32_t n_properties; + ASSERT_TRUE(VK_SUCCESS == vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), qfi, &n_properties, nullptr)); + std::vector properties(n_properties, {VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM}); + ASSERT_TRUE(VK_SUCCESS == vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), qfi, &n_properties, properties.data())); + + bool queue_supports_tosa_1_0 = false; + for (const auto& p : properties) { + if (CompareVkQueueFamilyDataGraphPropertiesARM(tosa_1_0_property, p)) { + queue_supports_tosa_1_0 = true; + break; + } + } + if (!queue_supports_tosa_1_0) { + queue_without_tosa_1_0_idx = qfi; + break; + } + } + + if (UINT32_MAX == queue_without_tosa_1_0_idx) { + GTEST_SKIP() << "All queues support TOSA, impossible to create the error condition, skip."; + } + + vkt::dg::DataGraphPipelineHelper pipeline(*this); + pipeline.CreateDataGraphPipeline(); + + VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper(); + session_ci.dataGraphPipeline = pipeline; + vkt::DataGraphPipelineSession session(*m_device, session_ci); + session.GetMemoryReqs(); + CheckSessionMemory(session); + + auto &bind_point_reqs = session.BindPointReqs(); + std::vector device_mem(bind_point_reqs.size()); + session.AllocSessionMem(device_mem); + auto session_bind_infos = InitSessionBindInfo(session, device_mem); + vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data()); + + pipeline.descriptor_set_->WriteDescriptorTensorInfo(0, &pipeline.tensor_views_[0]->handle(), 0); + pipeline.descriptor_set_->WriteDescriptorTensorInfo(1, &pipeline.tensor_views_[1]->handle(), 0); + pipeline.descriptor_set_->UpdateDescriptorSets(); + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline); + vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline.pipeline_layout_, 0, 1, + &pipeline.descriptor_set_.get()->set_, 0, nullptr); + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-commandBuffer-09941"); + vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr); + m_errorMonitor->VerifyFound(); + m_command_buffer.End(); +}